mirror of
https://github.com/freebsd/freebsd-src
synced 2024-09-20 00:33:57 +00:00
Fix #! script exec under linux emulation. If a script is exec'd from a
program running under linux emulation, the script binary is checked for in /compat/linux first. Without this patch the wrong script binary (i.e. the FreeBSD binary) will be run instead of the linux binary. For example, #!/bin/sh, thus breaking out of linux compatibility mode. This solves a number of problems people have had installing linux software on FreeBSD boxes.
This commit is contained in:
parent
599fcb028d
commit
d323ddf317
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=59663
|
@ -224,6 +224,8 @@ struct linux_sigframe {
|
|||
|
||||
extern int bsd_to_linux_signal[];
|
||||
extern int linux_to_bsd_signal[];
|
||||
extern struct sysentvec linux_sysvec;
|
||||
extern struct sysentvec elf_linux_sysvec;
|
||||
|
||||
/*
|
||||
* Pluggable ioctl handlers
|
||||
|
|
|
@ -55,9 +55,16 @@
|
|||
|
||||
#include <i386/linux/linux.h>
|
||||
#include <i386/linux/linux_proto.h>
|
||||
#include <i386/linux/linux_util.h>
|
||||
|
||||
MALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures");
|
||||
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
#define SHELLMAGIC 0x2123 /* #! */
|
||||
#else
|
||||
#define SHELLMAGIC 0x2321
|
||||
#endif
|
||||
|
||||
extern char linux_sigcode[];
|
||||
extern int linux_szsigcode;
|
||||
|
||||
|
@ -401,6 +408,50 @@ linux_prepsyscall(struct trapframe *tf, int *args, u_int *code, caddr_t *params)
|
|||
*params = NULL; /* no copyin */
|
||||
}
|
||||
|
||||
/*
|
||||
* If a linux binary is exec'ing something, try this image activator
|
||||
* first. We override standard shell script execution in order to
|
||||
* be able to modify the interpreter path. We only do this if a linux
|
||||
* binary is doing the exec, so we do not create an EXEC module for it.
|
||||
*/
|
||||
static int exec_linux_imgact_try __P((struct image_params *iparams));
|
||||
|
||||
static int
|
||||
exec_linux_imgact_try(imgp)
|
||||
struct image_params *imgp;
|
||||
{
|
||||
const char *head = (const char *)imgp->image_header;
|
||||
int error = -1;
|
||||
|
||||
/*
|
||||
* The interpreter for shell scripts run from a linux binary needs
|
||||
* to be located in /compat/linux if possible in order to recursively
|
||||
* maintain linux path emulation.
|
||||
*/
|
||||
if (((const short *)head)[0] == SHELLMAGIC) {
|
||||
/*
|
||||
* Run our normal shell image activator. If it succeeds attempt
|
||||
* to use the alternate path for the interpreter. If an alternate
|
||||
* path is found, use our stringspace to store it.
|
||||
*/
|
||||
if ((error = exec_shell_imgact(imgp)) == 0) {
|
||||
char *rpath = NULL;
|
||||
|
||||
linux_emul_find(imgp->proc, NULL, linux_emul_path,
|
||||
imgp->interpreter_name, &rpath, 0);
|
||||
if (rpath != imgp->interpreter_name) {
|
||||
int len = strlen(rpath) + 1;
|
||||
|
||||
if (len <= MAXSHELLCMDLEN) {
|
||||
memcpy(imgp->interpreter_name, rpath, len);
|
||||
}
|
||||
free(rpath, M_TEMP);
|
||||
}
|
||||
}
|
||||
}
|
||||
return(error);
|
||||
}
|
||||
|
||||
struct sysentvec linux_sysvec = {
|
||||
LINUX_SYS_MAXSYSCALL,
|
||||
linux_sysent,
|
||||
|
@ -416,7 +467,8 @@ struct sysentvec linux_sysvec = {
|
|||
&linux_szsigcode,
|
||||
linux_prepsyscall,
|
||||
"Linux a.out",
|
||||
aout_coredump
|
||||
aout_coredump,
|
||||
exec_linux_imgact_try
|
||||
};
|
||||
|
||||
struct sysentvec elf_linux_sysvec = {
|
||||
|
@ -434,7 +486,8 @@ struct sysentvec elf_linux_sysvec = {
|
|||
&linux_szsigcode,
|
||||
linux_prepsyscall,
|
||||
"Linux ELF",
|
||||
elf_coredump
|
||||
elf_coredump,
|
||||
exec_linux_imgact_try
|
||||
};
|
||||
|
||||
static Elf32_Brandinfo linux_brand = {
|
||||
|
|
|
@ -52,8 +52,6 @@
|
|||
|
||||
#include <i386/linux/linux.h>
|
||||
|
||||
extern struct sysentvec linux_sysvec;
|
||||
|
||||
static int exec_linux_imgact __P((struct image_params *iparams));
|
||||
|
||||
static int
|
||||
|
|
|
@ -224,6 +224,8 @@ struct linux_sigframe {
|
|||
|
||||
extern int bsd_to_linux_signal[];
|
||||
extern int linux_to_bsd_signal[];
|
||||
extern struct sysentvec linux_sysvec;
|
||||
extern struct sysentvec elf_linux_sysvec;
|
||||
|
||||
/*
|
||||
* Pluggable ioctl handlers
|
||||
|
|
|
@ -55,9 +55,16 @@
|
|||
|
||||
#include <i386/linux/linux.h>
|
||||
#include <i386/linux/linux_proto.h>
|
||||
#include <i386/linux/linux_util.h>
|
||||
|
||||
MALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures");
|
||||
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
#define SHELLMAGIC 0x2123 /* #! */
|
||||
#else
|
||||
#define SHELLMAGIC 0x2321
|
||||
#endif
|
||||
|
||||
extern char linux_sigcode[];
|
||||
extern int linux_szsigcode;
|
||||
|
||||
|
@ -401,6 +408,50 @@ linux_prepsyscall(struct trapframe *tf, int *args, u_int *code, caddr_t *params)
|
|||
*params = NULL; /* no copyin */
|
||||
}
|
||||
|
||||
/*
|
||||
* If a linux binary is exec'ing something, try this image activator
|
||||
* first. We override standard shell script execution in order to
|
||||
* be able to modify the interpreter path. We only do this if a linux
|
||||
* binary is doing the exec, so we do not create an EXEC module for it.
|
||||
*/
|
||||
static int exec_linux_imgact_try __P((struct image_params *iparams));
|
||||
|
||||
static int
|
||||
exec_linux_imgact_try(imgp)
|
||||
struct image_params *imgp;
|
||||
{
|
||||
const char *head = (const char *)imgp->image_header;
|
||||
int error = -1;
|
||||
|
||||
/*
|
||||
* The interpreter for shell scripts run from a linux binary needs
|
||||
* to be located in /compat/linux if possible in order to recursively
|
||||
* maintain linux path emulation.
|
||||
*/
|
||||
if (((const short *)head)[0] == SHELLMAGIC) {
|
||||
/*
|
||||
* Run our normal shell image activator. If it succeeds attempt
|
||||
* to use the alternate path for the interpreter. If an alternate
|
||||
* path is found, use our stringspace to store it.
|
||||
*/
|
||||
if ((error = exec_shell_imgact(imgp)) == 0) {
|
||||
char *rpath = NULL;
|
||||
|
||||
linux_emul_find(imgp->proc, NULL, linux_emul_path,
|
||||
imgp->interpreter_name, &rpath, 0);
|
||||
if (rpath != imgp->interpreter_name) {
|
||||
int len = strlen(rpath) + 1;
|
||||
|
||||
if (len <= MAXSHELLCMDLEN) {
|
||||
memcpy(imgp->interpreter_name, rpath, len);
|
||||
}
|
||||
free(rpath, M_TEMP);
|
||||
}
|
||||
}
|
||||
}
|
||||
return(error);
|
||||
}
|
||||
|
||||
struct sysentvec linux_sysvec = {
|
||||
LINUX_SYS_MAXSYSCALL,
|
||||
linux_sysent,
|
||||
|
@ -416,7 +467,8 @@ struct sysentvec linux_sysvec = {
|
|||
&linux_szsigcode,
|
||||
linux_prepsyscall,
|
||||
"Linux a.out",
|
||||
aout_coredump
|
||||
aout_coredump,
|
||||
exec_linux_imgact_try
|
||||
};
|
||||
|
||||
struct sysentvec elf_linux_sysvec = {
|
||||
|
@ -434,7 +486,8 @@ struct sysentvec elf_linux_sysvec = {
|
|||
&linux_szsigcode,
|
||||
linux_prepsyscall,
|
||||
"Linux ELF",
|
||||
elf_coredump
|
||||
elf_coredump,
|
||||
exec_linux_imgact_try
|
||||
};
|
||||
|
||||
static Elf32_Brandinfo linux_brand = {
|
||||
|
|
|
@ -39,15 +39,11 @@
|
|||
#define SHELLMAGIC 0x2321
|
||||
#endif
|
||||
|
||||
#define MAXSHELLCMDLEN 64
|
||||
|
||||
static int exec_shell_imgact __P((struct image_params *imgp));
|
||||
|
||||
/*
|
||||
* Shell interpreter image activator. A interpreter name beginning
|
||||
* at imgp->stringbase is the minimal successful exit requirement.
|
||||
*/
|
||||
static int
|
||||
int
|
||||
exec_shell_imgact(imgp)
|
||||
struct image_params *imgp;
|
||||
{
|
||||
|
|
|
@ -106,6 +106,7 @@ execve(p, uap)
|
|||
int error, len, i;
|
||||
struct image_params image_params, *imgp;
|
||||
struct vattr attr;
|
||||
int (*img_first) __P((struct image_params *));
|
||||
|
||||
imgp = &image_params;
|
||||
|
||||
|
@ -174,40 +175,48 @@ execve(p, uap)
|
|||
goto exec_fail_dealloc;
|
||||
|
||||
/*
|
||||
* Loop through list of image activators, calling each one.
|
||||
* If there is no match, the activator returns -1. If there
|
||||
* is a match, but there was an error during the activation,
|
||||
* the error is returned. Otherwise 0 means success. If the
|
||||
* image is interpreted, loop back up and try activating
|
||||
* the interpreter.
|
||||
* If the current process has a special image activator it
|
||||
* wants to try first, call it. For example, emulating shell
|
||||
* scripts differently.
|
||||
*/
|
||||
for (i = 0; execsw[i]; ++i) {
|
||||
if (execsw[i]->ex_imgact)
|
||||
error = (*execsw[i]->ex_imgact)(imgp);
|
||||
else
|
||||
error = -1;
|
||||
if ((img_first = imgp->proc->p_sysent->sv_imgact_try) != NULL)
|
||||
error = img_first(imgp);
|
||||
|
||||
/*
|
||||
* Loop through the list of image activators, calling each one.
|
||||
* An activator returns -1 if there is no match, 0 on success,
|
||||
* and an error otherwise.
|
||||
*/
|
||||
for (i = 0; error == -1 && execsw[i]; ++i) {
|
||||
if (execsw[i]->ex_imgact == NULL ||
|
||||
execsw[i]->ex_imgact == img_first) {
|
||||
continue;
|
||||
if (error == -1)
|
||||
continue;
|
||||
if (error)
|
||||
goto exec_fail_dealloc;
|
||||
if (imgp->interpreted) {
|
||||
exec_unmap_first_page(imgp);
|
||||
/* free name buffer and old vnode */
|
||||
NDFREE(ndp, NDF_ONLY_PNBUF);
|
||||
vrele(ndp->ni_vp);
|
||||
/* set new name to that of the interpreter */
|
||||
NDINIT(ndp, LOOKUP, LOCKLEAF | FOLLOW | SAVENAME,
|
||||
UIO_SYSSPACE, imgp->interpreter_name, p);
|
||||
goto interpret;
|
||||
}
|
||||
break;
|
||||
error = (*execsw[i]->ex_imgact)(imgp);
|
||||
}
|
||||
/* If we made it through all the activators and none matched, exit. */
|
||||
if (error == -1) {
|
||||
error = ENOEXEC;
|
||||
|
||||
if (error) {
|
||||
if (error == -1)
|
||||
error = ENOEXEC;
|
||||
goto exec_fail_dealloc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Special interpreter operation, cleanup and loop up to try to
|
||||
* activate the interpreter.
|
||||
*/
|
||||
if (imgp->interpreted) {
|
||||
exec_unmap_first_page(imgp);
|
||||
/* free name buffer and old vnode */
|
||||
NDFREE(ndp, NDF_ONLY_PNBUF);
|
||||
vrele(ndp->ni_vp);
|
||||
/* set new name to that of the interpreter */
|
||||
NDINIT(ndp, LOOKUP, LOCKLEAF | FOLLOW | SAVENAME,
|
||||
UIO_SYSSPACE, imgp->interpreter_name, p);
|
||||
goto interpret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy out strings (args and env) and initialize stack base
|
||||
*/
|
||||
|
|
|
@ -36,6 +36,8 @@
|
|||
#ifndef _SYS_IMGACT_H_
|
||||
#define _SYS_IMGACT_H_
|
||||
|
||||
#define MAXSHELLCMDLEN 64
|
||||
|
||||
struct image_params {
|
||||
struct proc *proc; /* our process struct */
|
||||
struct execve_args *uap; /* syscall arguments */
|
||||
|
@ -51,7 +53,7 @@ struct image_params {
|
|||
unsigned long entry_addr; /* entry address of target executable */
|
||||
char vmspace_destroyed; /* flag - we've blown away original vm space */
|
||||
char interpreted; /* flag - this executable is interpreted */
|
||||
char interpreter_name[64]; /* name of the interpreter */
|
||||
char interpreter_name[MAXSHELLCMDLEN]; /* name of the interpreter */
|
||||
void *auxargs; /* ELF Auxinfo structure pointer */
|
||||
struct vm_page *firstpage; /* first page that we mapped */
|
||||
char *fname; /* pointer to filename of executable (user space) */
|
||||
|
@ -62,6 +64,7 @@ struct image_params {
|
|||
int exec_check_permissions __P((struct image_params *));
|
||||
int exec_extract_strings __P((struct image_params *));
|
||||
int exec_new_vmspace __P((struct image_params *));
|
||||
int exec_shell_imgact __P((struct image_params *));
|
||||
#endif
|
||||
|
||||
#endif /* !_SYS_IMGACT_H_ */
|
||||
|
|
|
@ -79,6 +79,7 @@ struct sysentvec {
|
|||
int (*sv_coredump) __P((struct proc *, struct vnode *,
|
||||
off_t));
|
||||
/* function to dump core, or NULL */
|
||||
int (*sv_imgact_try) __P((struct image_params *));
|
||||
};
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
|
Loading…
Reference in a new issue