浏览代码

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.

This patch introduces field 'recursion_depth' into struct linux_binprm to
track recursion level in binfmt_misc and binfmt_script.  If recursion
level more then BINPRM_MAX_RECURSION it generates -ENOEXEC.

[akpm@linux-foundation.org: make linux_binprm.recursion_depth a uint]
Signed-off-by: Kirill A. Shutemov <kirill@shutemov.name>
Cc: Pavel Emelyanov <xemul@openvz.org>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Kirill A. Shutemov 16 年之前
父节点
当前提交
bf2a9a3963
共有 4 个文件被更改,包括 8 次插入5 次删除
  1. 1 1
      fs/binfmt_em86.c
  2. 2 2
      fs/binfmt_misc.c
  3. 3 2
      fs/binfmt_script.c
  4. 2 0
      include/linux/binfmts.h

+ 1 - 1
fs/binfmt_em86.c

@@ -43,7 +43,7 @@ static int load_em86(struct linux_binprm *bprm,struct pt_regs *regs)
 			return -ENOEXEC;
 			return -ENOEXEC;
 	}
 	}
 
 
-	bprm->sh_bang = 1;	/* Well, the bang-shell is implicit... */
+	bprm->recursion_depth++; /* Well, the bang-shell is implicit... */
 	allow_write_access(bprm->file);
 	allow_write_access(bprm->file);
 	fput(bprm->file);
 	fput(bprm->file);
 	bprm->file = NULL;
 	bprm->file = NULL;

+ 2 - 2
fs/binfmt_misc.c

@@ -117,7 +117,7 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
 		goto _ret;
 		goto _ret;
 
 
 	retval = -ENOEXEC;
 	retval = -ENOEXEC;
-	if (bprm->misc_bang)
+	if (bprm->recursion_depth > BINPRM_MAX_RECURSION)
 		goto _ret;
 		goto _ret;
 
 
 	/* to keep locking time low, we copy the interpreter string */
 	/* to keep locking time low, we copy the interpreter string */
@@ -197,7 +197,7 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
 	if (retval < 0)
 	if (retval < 0)
 		goto _error;
 		goto _error;
 
 
-	bprm->misc_bang = 1;
+	bprm->recursion_depth++;
 
 
 	retval = search_binary_handler (bprm, regs);
 	retval = search_binary_handler (bprm, regs);
 	if (retval < 0)
 	if (retval < 0)

+ 3 - 2
fs/binfmt_script.c

@@ -22,14 +22,15 @@ static int load_script(struct linux_binprm *bprm,struct pt_regs *regs)
 	char interp[BINPRM_BUF_SIZE];
 	char interp[BINPRM_BUF_SIZE];
 	int retval;
 	int retval;
 
 
-	if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!') || (bprm->sh_bang)) 
+	if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!') ||
+	    (bprm->recursion_depth > BINPRM_MAX_RECURSION))
 		return -ENOEXEC;
 		return -ENOEXEC;
 	/*
 	/*
 	 * This section does the #! interpretation.
 	 * This section does the #! interpretation.
 	 * Sorta complicated, but hopefully it will work.  -TYT
 	 * Sorta complicated, but hopefully it will work.  -TYT
 	 */
 	 */
 
 
-	bprm->sh_bang = 1;
+	bprm->recursion_depth++;
 	allow_write_access(bprm->file);
 	allow_write_access(bprm->file);
 	fput(bprm->file);
 	fput(bprm->file);
 	bprm->file = NULL;
 	bprm->file = NULL;

+ 2 - 0
include/linux/binfmts.h

@@ -39,6 +39,7 @@ struct linux_binprm{
 #ifdef __alpha__
 #ifdef __alpha__
 	unsigned int taso:1;
 	unsigned int taso:1;
 #endif
 #endif
+	unsigned int recursion_depth;
 	struct file * file;
 	struct file * file;
 	int e_uid, e_gid;
 	int e_uid, e_gid;
 	kernel_cap_t cap_post_exec_permitted;
 	kernel_cap_t cap_post_exec_permitted;
@@ -61,6 +62,7 @@ struct linux_binprm{
 #define BINPRM_FLAGS_EXECFD_BIT 1
 #define BINPRM_FLAGS_EXECFD_BIT 1
 #define BINPRM_FLAGS_EXECFD (1 << BINPRM_FLAGS_EXECFD_BIT)
 #define BINPRM_FLAGS_EXECFD (1 << BINPRM_FLAGS_EXECFD_BIT)
 
 
+#define BINPRM_MAX_RECURSION 4
 
 
 /*
 /*
  * This structure defines the functions that are used to load the binary formats that
  * This structure defines the functions that are used to load the binary formats that