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; |
