aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/exec.c17
-rw-r--r--include/linux/sched.h1
-rw-r--r--kernel/cred.c6
-rw-r--r--kernel/fork.c1
-rw-r--r--kernel/sys.c15
5 files changed, 32 insertions, 8 deletions
diff --git a/fs/exec.c b/fs/exec.c
index da80612a35f4..25dcbe5fc356 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -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;