summaryrefslogtreecommitdiffstats
path: root/sys/alpha
diff options
context:
space:
mode:
authordillon <dillon@FreeBSD.org>2000-04-26 20:58:40 +0000
committerdillon <dillon@FreeBSD.org>2000-04-26 20:58:40 +0000
commitce08285d5ac062de6a96e6491313b81bea80ecaa (patch)
tree9c48fa81d6c9503f7a1fd3b5440dc0d58696221e /sys/alpha
parentc816580dfb530d84c2396d9f0d10a9f8e44d4ea4 (diff)
downloadFreeBSD-src-ce08285d5ac062de6a96e6491313b81bea80ecaa.zip
FreeBSD-src-ce08285d5ac062de6a96e6491313b81bea80ecaa.tar.gz
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.
Diffstat (limited to 'sys/alpha')
-rw-r--r--sys/alpha/linux/linux.h2
-rw-r--r--sys/alpha/linux/linux_sysvec.c57
2 files changed, 57 insertions, 2 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 = {
OpenPOWER on IntegriCloud