diff options
-rw-r--r-- | fs/exec.c | 17 | ||||
-rw-r--r-- | include/linux/sched.h | 1 | ||||
-rw-r--r-- | kernel/cred.c | 6 | ||||
-rw-r--r-- | kernel/fork.c | 1 | ||||
-rw-r--r-- | kernel/sys.c | 15 |
5 files changed, 32 insertions, 8 deletions
@@ -1459,6 +1459,23 @@ static int do_execve_common(const char *filename, | |||
1459 | struct files_struct *displaced; | 1459 | struct files_struct *displaced; |
1460 | bool clear_in_exec; | 1460 | bool clear_in_exec; |
1461 | int retval; | 1461 | int retval; |
1462 | const struct cred *cred = current_cred(); | ||
1463 | |||
1464 | /* | ||
1465 | * We move the actual failure in case of RLIMIT_NPROC excess from | ||
1466 | * set*uid() to execve() because too many poorly written programs | ||
1467 | * don't check setuid() return code. Here we additionally recheck | ||
1468 | * whether NPROC limit is still exceeded. | ||
1469 | */ | ||
1470 | if ((current->flags & PF_NPROC_EXCEEDED) && | ||
1471 | atomic_read(&cred->user->processes) > rlimit(RLIMIT_NPROC)) { | ||
1472 | retval = -EAGAIN; | ||
1473 | goto out_ret; | ||
1474 | } | ||
1475 | |||
1476 | /* We're below the limit (still or again), so we don't want to make | ||
1477 | * further execve() calls fail. */ | ||
1478 | current->flags &= ~PF_NPROC_EXCEEDED; | ||
1462 | 1479 | ||
1463 | retval = unshare_files(&displaced); | 1480 | retval = unshare_files(&displaced); |
1464 | if (retval) | 1481 | if (retval) |
diff --git a/include/linux/sched.h b/include/linux/sched.h index 20b03bf94748..4ac2c0578e0f 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -1767,6 +1767,7 @@ extern void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t * | |||
1767 | #define PF_DUMPCORE 0x00000200 /* dumped core */ | 1767 | #define PF_DUMPCORE 0x00000200 /* dumped core */ |
1768 | #define PF_SIGNALED 0x00000400 /* killed by a signal */ | 1768 | #define PF_SIGNALED 0x00000400 /* killed by a signal */ |
1769 | #define PF_MEMALLOC 0x00000800 /* Allocating memory */ | 1769 | #define PF_MEMALLOC 0x00000800 /* Allocating memory */ |
1770 | #define PF_NPROC_EXCEEDED 0x00001000 /* set_user noticed that RLIMIT_NPROC was exceeded */ | ||
1770 | #define PF_USED_MATH 0x00002000 /* if unset the fpu must be initialized before use */ | 1771 | #define PF_USED_MATH 0x00002000 /* if unset the fpu must be initialized before use */ |
1771 | #define PF_FREEZING 0x00004000 /* freeze in progress. do not account to load */ | 1772 | #define PF_FREEZING 0x00004000 /* freeze in progress. do not account to load */ |
1772 | #define PF_NOFREEZE 0x00008000 /* this thread should not be frozen */ | 1773 | #define PF_NOFREEZE 0x00008000 /* this thread should not be frozen */ |
diff --git a/kernel/cred.c b/kernel/cred.c index 174fa84eca30..8ef31f53c44c 100644 --- a/kernel/cred.c +++ b/kernel/cred.c | |||
@@ -508,10 +508,8 @@ int commit_creds(struct cred *new) | |||
508 | key_fsgid_changed(task); | 508 | key_fsgid_changed(task); |
509 | 509 | ||
510 | /* do it | 510 | /* do it |
511 | * - What if a process setreuid()'s and this brings the | 511 | * RLIMIT_NPROC limits on user->processes have already been checked |
512 | * new uid over his NPROC rlimit? We can check this now | 512 | * in set_user(). |
513 | * cheaply with the new uid cache, so if it matters | ||
514 | * we should be checking for it. -DaveM | ||
515 | */ | 513 | */ |
516 | alter_cred_subscribers(new, 2); | 514 | alter_cred_subscribers(new, 2); |
517 | if (new->user != old->user) | 515 | if (new->user != old->user) |
diff --git a/kernel/fork.c b/kernel/fork.c index e7ceaca89609..8e6b6f4fb272 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -1111,6 +1111,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
1111 | p->real_cred->user != INIT_USER) | 1111 | p->real_cred->user != INIT_USER) |
1112 | goto bad_fork_free; | 1112 | goto bad_fork_free; |
1113 | } | 1113 | } |
1114 | current->flags &= ~PF_NPROC_EXCEEDED; | ||
1114 | 1115 | ||
1115 | retval = copy_creds(p, clone_flags); | 1116 | retval = copy_creds(p, clone_flags); |
1116 | if (retval < 0) | 1117 | if (retval < 0) |
diff --git a/kernel/sys.c b/kernel/sys.c index a101ba36c444..dd948a1fca4c 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -621,11 +621,18 @@ static int set_user(struct cred *new) | |||
621 | if (!new_user) | 621 | if (!new_user) |
622 | return -EAGAIN; | 622 | return -EAGAIN; |
623 | 623 | ||
624 | /* | ||
625 | * We don't fail in case of NPROC limit excess here because too many | ||
626 | * poorly written programs don't check set*uid() return code, assuming | ||
627 | * it never fails if called by root. We may still enforce NPROC limit | ||
628 | * for programs doing set*uid()+execve() by harmlessly deferring the | ||
629 | * failure to the execve() stage. | ||
630 | */ | ||
624 | if (atomic_read(&new_user->processes) >= rlimit(RLIMIT_NPROC) && | 631 | if (atomic_read(&new_user->processes) >= rlimit(RLIMIT_NPROC) && |
625 | new_user != INIT_USER) { | 632 | new_user != INIT_USER) |
626 | free_uid(new_user); | 633 | current->flags |= PF_NPROC_EXCEEDED; |
627 | return -EAGAIN; | 634 | else |
628 | } | 635 | current->flags &= ~PF_NPROC_EXCEEDED; |
629 | 636 | ||
630 | free_uid(new->user); | 637 | free_uid(new->user); |
631 | new->user = new_user; | 638 | new->user = new_user; |