summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/alpha/linux/linux.h2
-rw-r--r--sys/alpha/linux/linux_sysvec.c57
-rw-r--r--sys/i386/linux/imgact_linux.c2
-rw-r--r--sys/i386/linux/linux.h2
-rw-r--r--sys/i386/linux/linux_sysvec.c57
-rw-r--r--sys/kern/imgact_shell.c6
-rw-r--r--sys/kern/kern_exec.c63
-rw-r--r--sys/sys/imgact.h5
-rw-r--r--sys/sys/sysent.h1
9 files changed, 156 insertions, 39 deletions
diff --git a/sys/alpha/linux/linux.h b/sys/alpha/linux/linux.h
index 528a591..3bb4654 100644
--- a/sys/alpha/linux/linux.h
+++ b/sys/alpha/linux/linux.h
@@ -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
diff --git a/sys/alpha/linux/linux_sysvec.c b/sys/alpha/linux/linux_sysvec.c
index bd2211b..0adf0ab 100644
--- a/sys/alpha/linux/linux_sysvec.c
+++ b/sys/alpha/linux/linux_sysvec.c
@@ -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 = {
diff --git a/sys/i386/linux/imgact_linux.c b/sys/i386/linux/imgact_linux.c
index 36f6946..c560d74 100644
--- a/sys/i386/linux/imgact_linux.c
+++ b/sys/i386/linux/imgact_linux.c
@@ -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
diff --git a/sys/i386/linux/linux.h b/sys/i386/linux/linux.h
index 528a591..3bb4654 100644
--- a/sys/i386/linux/linux.h
+++ b/sys/i386/linux/linux.h
@@ -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
diff --git a/sys/i386/linux/linux_sysvec.c b/sys/i386/linux/linux_sysvec.c
index bd2211b..0adf0ab 100644
--- a/sys/i386/linux/linux_sysvec.c
+++ b/sys/i386/linux/linux_sysvec.c
@@ -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 = {
diff --git a/sys/kern/imgact_shell.c b/sys/kern/imgact_shell.c
index 78479da..a15b56c 100644
--- a/sys/kern/imgact_shell.c
+++ b/sys/kern/imgact_shell.c
@@ -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;
{
diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c
index 6f40dcc..41a20df 100644
--- a/sys/kern/kern_exec.c
+++ b/sys/kern/kern_exec.c
@@ -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,41 +175,49 @@ interpret:
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
- continue;
- if (error == -1)
+ 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)
- 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
*/
stack_base = exec_copyout_strings(imgp);
diff --git a/sys/sys/imgact.h b/sys/sys/imgact.h
index 9cb2e35..c13d81f 100644
--- a/sys/sys/imgact.h
+++ b/sys/sys/imgact.h
@@ -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_ */
diff --git a/sys/sys/sysent.h b/sys/sys/sysent.h
index fff1ed0..15dbdbf 100644
--- a/sys/sys/sysent.h
+++ b/sys/sys/sysent.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
OpenPOWER on IntegriCloud