Messages in this thread Patch in this message |  | | Date | Thu, 16 May 1996 00:13:22 +1000 (EST) | From | Bradley Broom <> | Subject | Patch to binfmt_script to support arbitrary interpreters |
| |
Several people seem to have independently suggested the following (including me), so here it is.
The attached patch (to the old, decrepit 1.3.100 actually) causes a userland program (/bin/usrexec) to be invoked on unrecognised executable files. (It's done within binfmt_script to avoid duplicate code, but you could easily do it as a separate binfmt if you wanted too.)
/bin/usrexec is supposed to look for and invoke a userland interpreter to execute the "executable".
Also attached is version 0.000001 of such an interpreter that can recognise windows binaries (seems to work, but it's a hack) and java binaries and invoke their respective interpreters. Clearly it can be improved.
With this patch, there is no need for all that BINFMT_JAVA stuff in the kernel.
Cheers,
Dr. Bradley Broom, School of Data Communications, Email: broom@fit.qut.edu.au Queensland University of Technology, Bus. : +61 7 3864 2769 GPO Box 2434, Brisbane, 4001, Australia. Fax : +61 7 3221 2384
--- linux/fs/exec.c.old Wed May 15 23:08:00 1996 +++ linux/fs/exec.c Wed May 15 23:08:06 1996 @@ -63,19 +63,24 @@ void binfmt_setup(void) { -#ifdef CONFIG_BINFMT_ELF - init_elf_binfmt(); -#endif + /* This cannot be configured out of the kernel */ + /* Formats are actually tried in the reverse order of + * registration, and script format must be the last one + * tried. + */ + init_script_binfmt(); #ifdef CONFIG_BINFMT_AOUT init_aout_binfmt(); #endif +#ifdef CONFIG_BINFMT_ELF + init_elf_binfmt(); +#endif + #ifdef CONFIG_BINFMT_JAVA init_java_binfmt(); #endif - /* This cannot be configured out of the kernel */ - init_script_binfmt(); } int register_binfmt(struct linux_binfmt * fmt) --- linux/fs/binfmt_script.c.old Wed May 15 22:45:51 1996 +++ linux/fs/binfmt_script.c Wed May 15 23:01:49 1996 @@ -11,45 +11,63 @@ #include <linux/malloc.h> #include <linux/binfmts.h> +#define _PATH_USREXEC "/bin/usrexec" + static int do_load_script(struct linux_binprm *bprm,struct pt_regs *regs) { char *cp, *interp, *i_name, *i_arg; int retval; - if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!') || (bprm->sh_bang)) + + if (bprm->sh_bang) return -ENOEXEC; - /* - * This section does the #! interpretation. - * Sorta complicated, but hopefully it will work. -TYT - */ bprm->sh_bang++; - iput(bprm->inode); - bprm->dont_iput=1; - - bprm->buf[127] = '\0'; - if ((cp = strchr(bprm->buf, '\n')) == NULL) - cp = bprm->buf+127; - *cp = '\0'; - while (cp > bprm->buf) { - cp--; - if ((*cp == ' ') || (*cp == '\t')) - *cp = '\0'; + /* Determine interp, i_name, and i_arg. + */ + if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!')) { + strcpy (bprm->buf, _PATH_USREXEC); + interp = bprm->buf; + if ((i_name = strrchr (bprm->buf, '/')) != NULL) + i_name++; else - break; + i_name = bprm->buf; + i_arg = 0; } - for (cp = bprm->buf+2; (*cp == ' ') || (*cp == '\t'); cp++); - if (!cp || *cp == '\0') - return -ENOEXEC; /* No interpreter name found */ - interp = i_name = cp; - i_arg = 0; - for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) { - if (*cp == '/') - i_name = cp+1; + else { + /* + * This section does the #! interpretation. + * Sorta complicated, but hopefully it will work. -TYT + */ + + iput(bprm->inode); + bprm->dont_iput=1; + + bprm->buf[127] = '\0'; + if ((cp = strchr(bprm->buf, '\n')) == NULL) + cp = bprm->buf+127; + *cp = '\0'; + while (cp > bprm->buf) { + cp--; + if ((*cp == ' ') || (*cp == '\t')) + *cp = '\0'; + else + break; + } + for (cp = bprm->buf+2; (*cp == ' ') || (*cp == '\t'); cp++); + if (!cp || *cp == '\0') + return -ENOEXEC; /* No interpreter name found */ + interp = i_name = cp; + i_arg = 0; + for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) { + if (*cp == '/') + i_name = cp+1; + } + while ((*cp == ' ') || (*cp == '\t')) + *cp++ = '\0'; + if (*cp) + i_arg = cp; } - while ((*cp == ' ') || (*cp == '\t')) - *cp++ = '\0'; - if (*cp) - i_arg = cp; + /* * OK, we've parsed out the interpreter name and * (optional) argument.#include <stdio.h> #include <stdlib.h> #include <fcntl.h>
unsigned char buf[1024]; int len;
int main (int argc, char *argv[]) { int fd;
if (argc != 2) { fprintf (stderr, "Usage: %s filetoexec\n", argv[0]); exit (1); } #if 1 fprintf (stderr, "%s %s\n", argv[0], argv[1]); #endif if ((fd = open (argv[1], O_RDONLY)) < 0) { perror (argv[1]); exit (1); } if ((len = read (fd, buf, sizeof (buf))) < 0) { perror (argv[1]); exit (1); } close (fd);
/* Extensibility of the following could be easily improved! */
/* Don't know about the truth of the following test, but it'll * do as a hack. */ if (buf[0] == 'M' && buf[1] == 'Z') { execl ("/usr/local/bin/wine", "wine", argv[1], NULL); perror (argv[1]); exit (1); }
if (buf[0] == 0xca && buf[1] == 0xfe && buf[2] == 0xba && buf[3] == 0xbe) { char * cp = strstr (argv[1], ".class");
if (cp) *cp = '\0'; execl ("/usr/local/bin/java", "java", argv[1], NULL); perror (argv[1]); exit (1); }
fprintf (stderr, "%s: unknown binary format for %s\n", argv[0], argv[1]); exit (1); }
|  |