summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorKees Cook <keescook@chromium.org>2018-04-10 19:35:01 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2018-04-11 13:28:37 -0400
commitc31dbb146dd44af44bc60780ce8fa7a9f5f746df (patch)
treeac3f22913cec3082511ab9143d153ad30975a884 /fs
parentb83838313386f617d6bd8201be7f5b532059bba1 (diff)
exec: pin stack limit during exec
Since the stack rlimit is used in multiple places during exec and it can be changed via other threads (via setrlimit()) or processes (via prlimit()), the assumption that the value doesn't change cannot be made. This leads to races with mm layout selection and argument size calculations. This changes the exec path to use the rlimit stored in bprm instead of in current. Before starting the thread, the bprm stack rlimit is stored back to current. Link: http://lkml.kernel.org/r/1518638796-20819-4-git-send-email-keescook@chromium.org Fixes: 64701dee4178e ("exec: Use sane stack rlimit under secureexec") Signed-off-by: Kees Cook <keescook@chromium.org> Reported-by: Ben Hutchings <ben.hutchings@codethink.co.uk> Reported-by: Andy Lutomirski <luto@kernel.org> Reported-by: Brad Spengler <spender@grsecurity.net> Acked-by: Michal Hocko <mhocko@suse.com> Cc: Ben Hutchings <ben@decadent.org.uk> Cc: Greg KH <greg@kroah.com> Cc: Hugh Dickins <hughd@google.com> Cc: "Jason A. Donenfeld" <Jason@zx2c4.com> Cc: Laura Abbott <labbott@redhat.com> Cc: Oleg Nesterov <oleg@redhat.com> Cc: Rik van Riel <riel@redhat.com> Cc: Willy Tarreau <w@1wt.eu> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/exec.c27
1 files changed, 15 insertions, 12 deletions
diff --git a/fs/exec.c b/fs/exec.c
index 422ad79a7a03..183059c427b9 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -257,7 +257,7 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
257 * to work from. 257 * to work from.
258 */ 258 */
259 limit = _STK_LIM / 4 * 3; 259 limit = _STK_LIM / 4 * 3;
260 limit = min(limit, rlimit(RLIMIT_STACK) / 4); 260 limit = min(limit, bprm->rlim_stack.rlim_cur / 4);
261 if (size > limit) 261 if (size > limit)
262 goto fail; 262 goto fail;
263 } 263 }
@@ -411,6 +411,11 @@ static int bprm_mm_init(struct linux_binprm *bprm)
411 if (!mm) 411 if (!mm)
412 goto err; 412 goto err;
413 413
414 /* Save current stack limit for all calculations made during exec. */
415 task_lock(current->group_leader);
416 bprm->rlim_stack = current->signal->rlim[RLIMIT_STACK];
417 task_unlock(current->group_leader);
418
414 err = __bprm_mm_init(bprm); 419 err = __bprm_mm_init(bprm);
415 if (err) 420 if (err)
416 goto err; 421 goto err;
@@ -697,7 +702,7 @@ int setup_arg_pages(struct linux_binprm *bprm,
697 702
698#ifdef CONFIG_STACK_GROWSUP 703#ifdef CONFIG_STACK_GROWSUP
699 /* Limit stack size */ 704 /* Limit stack size */
700 stack_base = rlimit_max(RLIMIT_STACK); 705 stack_base = bprm->rlim_stack.rlim_max;
701 if (stack_base > STACK_SIZE_MAX) 706 if (stack_base > STACK_SIZE_MAX)
702 stack_base = STACK_SIZE_MAX; 707 stack_base = STACK_SIZE_MAX;
703 708
@@ -770,7 +775,7 @@ int setup_arg_pages(struct linux_binprm *bprm,
770 * Align this down to a page boundary as expand_stack 775 * Align this down to a page boundary as expand_stack
771 * will align it up. 776 * will align it up.
772 */ 777 */
773 rlim_stack = rlimit(RLIMIT_STACK) & PAGE_MASK; 778 rlim_stack = bprm->rlim_stack.rlim_cur & PAGE_MASK;
774#ifdef CONFIG_STACK_GROWSUP 779#ifdef CONFIG_STACK_GROWSUP
775 if (stack_size + stack_expand > rlim_stack) 780 if (stack_size + stack_expand > rlim_stack)
776 stack_base = vma->vm_start + rlim_stack; 781 stack_base = vma->vm_start + rlim_stack;
@@ -1323,8 +1328,6 @@ EXPORT_SYMBOL(would_dump);
1323 1328
1324void setup_new_exec(struct linux_binprm * bprm) 1329void setup_new_exec(struct linux_binprm * bprm)
1325{ 1330{
1326 struct rlimit rlim_stack;
1327
1328 /* 1331 /*
1329 * Once here, prepare_binrpm() will not be called any more, so 1332 * Once here, prepare_binrpm() will not be called any more, so
1330 * the final state of setuid/setgid/fscaps can be merged into the 1333 * the final state of setuid/setgid/fscaps can be merged into the
@@ -1343,15 +1346,11 @@ void setup_new_exec(struct linux_binprm * bprm)
1343 * RLIMIT_STACK, but after the point of no return to avoid 1346 * RLIMIT_STACK, but after the point of no return to avoid
1344 * needing to clean up the change on failure. 1347 * needing to clean up the change on failure.
1345 */ 1348 */
1346 if (current->signal->rlim[RLIMIT_STACK].rlim_cur > _STK_LIM) 1349 if (bprm->rlim_stack.rlim_cur > _STK_LIM)
1347 current->signal->rlim[RLIMIT_STACK].rlim_cur = _STK_LIM; 1350 bprm->rlim_stack.rlim_cur = _STK_LIM;
1348 } 1351 }
1349 1352
1350 task_lock(current->group_leader); 1353 arch_pick_mmap_layout(current->mm, &bprm->rlim_stack);
1351 rlim_stack = current->signal->rlim[RLIMIT_STACK];
1352 task_unlock(current->group_leader);
1353
1354 arch_pick_mmap_layout(current->mm, &rlim_stack);
1355 1354
1356 current->sas_ss_sp = current->sas_ss_size = 0; 1355 current->sas_ss_sp = current->sas_ss_size = 0;
1357 1356
@@ -1387,6 +1386,10 @@ EXPORT_SYMBOL(setup_new_exec);
1387/* Runs immediately before start_thread() takes over. */ 1386/* Runs immediately before start_thread() takes over. */
1388void finalize_exec(struct linux_binprm *bprm) 1387void finalize_exec(struct linux_binprm *bprm)
1389{ 1388{
1389 /* Store any stack rlimit changes before starting thread. */
1390 task_lock(current->group_leader);
1391 current->signal->rlim[RLIMIT_STACK] = bprm->rlim_stack;
1392 task_unlock(current->group_leader);
1390} 1393}
1391EXPORT_SYMBOL(finalize_exec); 1394EXPORT_SYMBOL(finalize_exec);
1392 1395