Skip to content

Commit 0ac983f

Browse files
committed
ucounts: Fix systemd LimitNPROC with private users regression
Long story short recursively enforcing RLIMIT_NPROC when it is not enforced on the process that creates a new user namespace, causes currently working code to fail. There is no reason to enforce RLIMIT_NPROC recursively when we don't enforce it normally so update the code to detect this case. I would like to simply use capable(CAP_SYS_RESOURCE) to detect when RLIMIT_NPROC is not enforced upon the caller. Unfortunately because RLIMIT_NPROC is charged and checked for enforcement based upon the real uid, using capable() which is euid based is inconsistent with reality. Come as close as possible to testing for capable(CAP_SYS_RESOURCE) by testing for when the real uid would match the conditions when CAP_SYS_RESOURCE would be present if the real uid was the effective uid. Reported-by: Etienne Dechamps <[email protected]> Link: https://bugzilla.kernel.org/show_bug.cgi?id=215596 Link: https://lkml.kernel.org/r/[email protected] Link: https://lkml.kernel.org/r/[email protected] Cc: [email protected] Fixes: 21d1c5e ("Reimplement RLIMIT_NPROC on top of ucounts") Reviewed-by: Kees Cook <[email protected]> Signed-off-by: "Eric W. Biederman" <[email protected]>
1 parent 0cbae9e commit 0ac983f

File tree

1 file changed

+13
-1
lines changed

1 file changed

+13
-1
lines changed

kernel/user_namespace.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,18 @@ static void set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns)
5858
cred->user_ns = user_ns;
5959
}
6060

61+
static unsigned long enforced_nproc_rlimit(void)
62+
{
63+
unsigned long limit = RLIM_INFINITY;
64+
65+
/* Is RLIMIT_NPROC currently enforced? */
66+
if (!uid_eq(current_uid(), GLOBAL_ROOT_UID) ||
67+
(current_user_ns() != &init_user_ns))
68+
limit = rlimit(RLIMIT_NPROC);
69+
70+
return limit;
71+
}
72+
6173
/*
6274
* Create a new user namespace, deriving the creator from the user in the
6375
* passed credentials, and replacing that user with the new root user for the
@@ -122,7 +134,7 @@ int create_user_ns(struct cred *new)
122134
for (i = 0; i < MAX_PER_NAMESPACE_UCOUNTS; i++) {
123135
ns->ucount_max[i] = INT_MAX;
124136
}
125-
set_rlimit_ucount_max(ns, UCOUNT_RLIMIT_NPROC, rlimit(RLIMIT_NPROC));
137+
set_rlimit_ucount_max(ns, UCOUNT_RLIMIT_NPROC, enforced_nproc_rlimit());
126138
set_rlimit_ucount_max(ns, UCOUNT_RLIMIT_MSGQUEUE, rlimit(RLIMIT_MSGQUEUE));
127139
set_rlimit_ucount_max(ns, UCOUNT_RLIMIT_SIGPENDING, rlimit(RLIMIT_SIGPENDING));
128140
set_rlimit_ucount_max(ns, UCOUNT_RLIMIT_MEMLOCK, rlimit(RLIMIT_MEMLOCK));

0 commit comments

Comments
 (0)