Messages in this thread Patch in this message |  | | | Date | Tue, 2 Sep 2008 14:06:52 +0300 | | From | "Kirill A. Shutemov" <> | | Subject | [PATCH] [RFC] Allow recursion in binfmt_script and binfmt_misc |
| |
binfmt_script and binfmt_misc disallow recursion to avoid stack overflow using sh_bang and misc_bang. It causes problem in some cases:
$ echo '#!/bin/ls' > /tmp/t0 $ echo '#!/tmp/t0' > /tmp/t1 $ echo '#!/tmp/t1' > /tmp/t2 $ chmod +x /tmp/t* $ /tmp/t2 zsh: exec format error: /tmp/t2 Similar problem with binfmt_misc.
I propose allow recursion, but limit its deep.
There is one more problem: on Alpha sh_bang used to remember if the application is TASO. I have no experience with Alpha. Is it possible to use separate flag in struct linux_binprm for it?
Signed-off-by: Kirill A. Shutemov <kirill@shutemov.name>
diff --git a/fs/binfmt_em86.c b/fs/binfmt_em86.c index f9c88d0..f95ae97 100644 --- a/fs/binfmt_em86.c +++ b/fs/binfmt_em86.c @@ -43,7 +43,7 @@ static int load_em86(struct linux_binprm *bprm,struct pt_regs *regs) return -ENOEXEC; } - bprm->sh_bang = 1; /* Well, the bang-shell is implicit... */ + bprm->sh_bang++; /* Well, the bang-shell is implicit... */ allow_write_access(bprm->file); fput(bprm->file); bprm->file = NULL; diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index 8d7e88e..50c665f 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c @@ -43,6 +43,8 @@ enum {Enabled, Magic}; #define MISC_FMT_OPEN_BINARY (1<<30) #define MISC_FMT_CREDENTIALS (1<<29) +#define MISC_FMT_MAX_RECURSION 4 + typedef struct { struct list_head list; unsigned long flags; /* type, status, etc. */ @@ -117,7 +119,7 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs) goto _ret; retval = -ENOEXEC; - if (bprm->misc_bang) + if (bprm->misc_bang >= MISC_FMT_MAX_RECURSION) goto _ret; /* to keep locking time low, we copy the interpreter string */ @@ -197,7 +199,7 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs) if (retval < 0) goto _error; - bprm->misc_bang = 1; + bprm->misc_bang++; retval = search_binary_handler (bprm, regs); if (retval < 0) diff --git a/fs/binfmt_script.c b/fs/binfmt_script.c index 9e3963f..172c954 100644 --- a/fs/binfmt_script.c +++ b/fs/binfmt_script.c @@ -15,6 +15,8 @@ #include <linux/err.h> #include <linux/fs.h> +#define SCRIPT_FMT_MAX_RECURSION 4 + static int load_script(struct linux_binprm *bprm,struct pt_regs *regs) { char *cp, *i_name, *i_arg; @@ -22,14 +24,15 @@ static int load_script(struct linux_binprm *bprm,struct pt_regs *regs) char interp[BINPRM_BUF_SIZE]; int retval; - if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!') || (bprm->sh_bang)) + if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!') || + (bprm->sh_bang >= SCRIPT_FMT_MAX_RECURSION)) return -ENOEXEC; /* * This section does the #! interpretation. * Sorta complicated, but hopefully it will work. -TYT */ - bprm->sh_bang = 1; + bprm->sh_bang++; allow_write_access(bprm->file); fput(bprm->file); bprm->file = NULL; diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h index 826f623..1e21ff0 100644 --- a/include/linux/binfmts.h +++ b/include/linux/binfmts.h @@ -34,8 +34,8 @@ struct linux_binprm{ #endif struct mm_struct *mm; unsigned long p; /* current top of mem */ - unsigned int sh_bang:1, - misc_bang:1; + unsigned char sh_bang; + unsigned char misc_bang; struct file * file; int e_uid, e_gid; kernel_cap_t cap_post_exec_permitted;[unhandled content-type:application/pgp-signature] |  |