From 38bf603d1ea5d5a65a9cb277df75327ffec01ff1 Mon Sep 17 00:00:00 2001 From: Nickolai Zeldovich Date: Fri, 23 Oct 2026 21:55:13 -0400 Subject: ucount: read the parent ucounts before dropping the rlimit count do_dec_rlimit_put_ucounts() drops its share of iter->rlimit[type] and only then loads iter->ns->ucounts. If the decrement leaves the count non-zero, a concurrent caller can take it to zero and put the last reference, which frees the ucounts and possibly its user namespace with kfree_rcu(). An exiting task frees its pending signals without siglock or any RCU read-side section, so when it is preempted between the decrement and the load for a grace period it reads freed memory and then decrements a counter through the pointer it found there. A pending signal holds no reference on its ucounts: the reference is taken by whoever moves the count from 0 to 1 and dropped by whoever moves it back to 0, so the caller's share of the count is all that keeps iter alive, and only until it is dropped. Load the parent first; it stays pinned by the caller's share of its own count. Fixes: 15bc01effefe ("ucounts: Fix signal ucount refcounting") Signed-off-by: Nickolai Zeldovich Link: https://patch.msgid.link/20261024015513.830312-1-nickolai@csail.mit.edu Reviewed-by: Bradley Morgan Signed-off-by: Christian Brauner (Amutable) --- kernel/ucount.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/kernel/ucount.c b/kernel/ucount.c index c3de5b94d25f..94b70502dc9d 100644 --- a/kernel/ucount.c +++ b/kernel/ucount.c @@ -285,9 +285,12 @@ static void do_dec_rlimit_put_ucounts(struct ucounts *ucounts, { struct ucounts *iter, *next; for (iter = ucounts; iter != last; iter = next) { - long dec = atomic_long_sub_return(1, &iter->rlimit[type]); - WARN_ON_ONCE(dec < 0); + long dec; + + /* Our count pins @iter; once it is dropped @iter may be freed. */ next = iter->ns->ucounts; + dec = atomic_long_sub_return(1, &iter->rlimit[type]); + WARN_ON_ONCE(dec < 0); if (dec == 0) put_ucounts(iter); } -- cgit v1.2.3