aboutsummaryrefslogtreecommitdiffstats
path: root/fs/exec.c
diff options
context:
space:
mode:
authorKees Cook <keescook@chromium.org>2012-12-17 19:03:20 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2012-12-17 20:15:23 -0500
commitd740269867021faf4ce38a449353d2b986c34a67 (patch)
treee0476e1be1dfb6e852adbaa8fb72ecea87bdb088 /fs/exec.c
parent8d238027b87e654be552eabdf492042a34c5c300 (diff)
exec: use -ELOOP for max recursion depth
To avoid an explosion of request_module calls on a chain of abusive scripts, fail maximum recursion with -ELOOP instead of -ENOEXEC. As soon as maximum recursion depth is hit, the error will fail all the way back up the chain, aborting immediately. This also has the side-effect of stopping the user's shell from attempting to reexecute the top-level file as a shell script. As seen in the dash source: if (cmd != path_bshell && errno == ENOEXEC) { *argv-- = cmd; *argv = cmd = path_bshell; goto repeat; } The above logic was designed for running scripts automatically that lacked the "#!" header, not to re-try failed recursion. On a legitimate -ENOEXEC, things continue to behave as the shell expects. Additionally, when tracking recursion, the binfmt handlers should not be involved. The recursion being tracked is the depth of calls through search_binary_handler(), so that function should be exclusively responsible for tracking the depth. Signed-off-by: Kees Cook <keescook@chromium.org> Cc: halfdog <me@halfdog.net> Cc: P J P <ppandit@redhat.com> 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>
Diffstat (limited to 'fs/exec.c')
-rw-r--r--fs/exec.c10
1 files changed, 5 insertions, 5 deletions
diff --git a/fs/exec.c b/fs/exec.c
index 721a29929511..d5eb9e605ffd 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1356,6 +1356,10 @@ int search_binary_handler(struct linux_binprm *bprm)
1356 struct linux_binfmt *fmt; 1356 struct linux_binfmt *fmt;
1357 pid_t old_pid, old_vpid; 1357 pid_t old_pid, old_vpid;
1358 1358
1359 /* This allows 4 levels of binfmt rewrites before failing hard. */
1360 if (depth > 5)
1361 return -ELOOP;
1362
1359 retval = security_bprm_check(bprm); 1363 retval = security_bprm_check(bprm);
1360 if (retval) 1364 if (retval)
1361 return retval; 1365 return retval;
@@ -1380,12 +1384,8 @@ int search_binary_handler(struct linux_binprm *bprm)
1380 if (!try_module_get(fmt->module)) 1384 if (!try_module_get(fmt->module))
1381 continue; 1385 continue;
1382 read_unlock(&binfmt_lock); 1386 read_unlock(&binfmt_lock);
1387 bprm->recursion_depth = depth + 1;
1383 retval = fn(bprm); 1388 retval = fn(bprm);
1384 /*
1385 * Restore the depth counter to its starting value
1386 * in this call, so we don't have to rely on every
1387 * load_binary function to restore it on return.
1388 */
1389 bprm->recursion_depth = depth; 1389 bprm->recursion_depth = depth;
1390 if (retval >= 0) { 1390 if (retval >= 0) {
1391 if (depth == 0) { 1391 if (depth == 0) {