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:
Matthew Dillon 2000-04-26 20:58:40 +00:00
parent 599fcb028d
commit d323ddf317
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=59663
9 changed files with 156 additions and 39 deletions

View File

@ -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

View File

@ -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 = {

View File

@ -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

View File

@ -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

View File

@ -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 = {

View File

@ -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;
{

View File

@ -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
*/

View File

@ -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_ */

View File

@ -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