Messages in this thread Patch in this message | | | From | "Eric W. Biederman" <> | Date | Thu, 10 Feb 2022 20:13:24 -0600 | Subject | [PATCH 8/8] ucounts: Use the same code to enforce RLIMIT_NPROC in fork and exec |
| |
Historically these pieces of code have slightly diverged and caused problems. To avoid that in the future create a common function to see if RLIMIT_NPROC is over a limit and the limit should be enforced.
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com> --- fs/exec.c | 7 ++----- include/linux/sched/signal.h | 2 ++ kernel/fork.c | 25 +++++++++++++++++++------ 3 files changed, 23 insertions(+), 11 deletions(-)
diff --git a/fs/exec.c b/fs/exec.c index 01c8c7bae9b4..8913dbb9a479 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1875,14 +1875,11 @@ static int do_execveat_common(int fd, struct filename *filename, return PTR_ERR(filename); /* - * After calling set*uid() is RLIMT_NPROC exceeded? + * After calling set*uid() is RLIMIT_NPROC exceeded? * This can not be checked in set*uid() because too many programs don't * check the setuid() return code. */ - if ((current->flags & PF_NPROC_CHECK) && - is_ucounts_overlimit(current_ucounts(), UCOUNT_RLIMIT_NPROC, rlimit(RLIMIT_NPROC)) && - (current_ucounts() != &init_ucounts) && - !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN)) { + if ((current->flags & PF_NPROC_CHECK) && is_nproc_overlimit()) { retval = -EAGAIN; goto out_ret; } diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h index b6ecb9fc4cd2..b682131c52fa 100644 --- a/include/linux/sched/signal.h +++ b/include/linux/sched/signal.h @@ -742,4 +742,6 @@ static inline unsigned long rlimit_max(unsigned int limit) return task_rlimit_max(current, limit); } +extern bool is_nproc_overlimit(void); + #endif /* _LINUX_SCHED_SIGNAL_H */ diff --git a/kernel/fork.c b/kernel/fork.c index 79661678a5bf..a18f15053e22 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1891,6 +1891,23 @@ static void copy_oom_score_adj(u64 clone_flags, struct task_struct *tsk) mutex_unlock(&oom_adj_mutex); } +static bool is_task_nproc_overlimit(struct task_struct *task) +{ + struct ucounts *ucounts = task_ucounts(task); + /* clone does not change RLIMIT_NPROC. The parents value is safe. */ + unsigned long limit = rlimit(RLIMIT_NPROC); + + return is_ucounts_overlimit(ucounts, UCOUNT_RLIMIT_NPROC, limit) && + (ucounts != &init_ucounts) && + !has_capability(task, CAP_SYS_RESOURCE) && + !has_capability(task, CAP_SYS_ADMIN); +} + +bool is_nproc_overlimit(void) +{ + return is_task_nproc_overlimit(current); +} + /* * This creates a new process as a copy of the old one, * but does not actually start it yet. @@ -2028,12 +2045,8 @@ static __latent_entropy struct task_struct *copy_process( retval = -EAGAIN; if (inc_rlimit_ucounts(task_ucounts(p), UCOUNT_RLIMIT_NPROC, 1) == LONG_MAX) goto bad_fork_cleanup_count; - if (is_ucounts_overlimit(task_ucounts(p), UCOUNT_RLIMIT_NPROC, rlimit(RLIMIT_NPROC))) { - if ((task_ucounts(p) != &init_ucounts) && - !has_capability(p, CAP_SYS_RESOURCE) && - !has_capability(p, CAP_SYS_ADMIN)) - goto bad_fork_cleanup_count; - } + if (is_task_nproc_overlimit(p)) + goto bad_fork_cleanup_count; current->flags &= ~PF_NPROC_CHECK; /* -- 2.29.2
| |