FAILED: patch "[PATCH] exit: hold a reference to thread_pid across proc_flush_pid" failed to apply to 6.18-stable tree
[email protected]
maintainerThe patch below does not apply to the 6.18-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.18.y
git checkout FETCH_HEAD
git cherry-pick -x cdd812d0683dee14ead02c9eded568685e61b23f
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026091657-curry-myself-be92@gregkh' --subject-prefix 'PATCH 6.18.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From cdd812d0683dee14ead02c9eded568685e61b23f Mon Sep 17 00:00:00 2001
From: Daehyeon Ko <[email protected]>
Date: Mon, 31 Aug 2026 09:12:21 +0900
Subject: [PATCH] exit: hold a reference to thread_pid across proc_flush_pid
Commit 0a36bad01731 ("release_task: kill the no longer needed get/put_pid(thread_pid)") removed the reference around proc_flush_pid(). It assumed that free_pids(post.pids) at the end of release_task() would keep thread_pid alive until then.
That assumption is wrong. __change_pid() only records a detached PID in post.pids when pid_has_task() is false for every PIDTYPE. If another task still uses the exiting task's PID as its process group or session ID, __unhash_process() removes the exiting task's PIDTYPE_PID link but leaves the PID out of post.pids. release_task() therefore holds no reference to it after dropping tasklist_lock.
The other task can then remove the remaining PIDTYPE links. Its free_pids() call schedules delayed_put_pid(), and the RCU callback can free the PID before the first release_task() reaches proc_flush_pid().
An unprivileged reproducer races wait4(-1) against setsid() to trigger this ordering. Three of three fresh v7.2 KASAN boots reported:
BUG: KASAN: slab-use-after-free in
proc_invalidate_siblings_dcache+0x3e2/0x3f0
Read of size 8 by task h7_pid_reaper/1921
Call Trace:
proc_invalidate_siblings_dcache
release_task
wait_consider_task
__do_wait
do_wait
kernel_wait4
Freed by task 0:
kmem_cache_free
put_pid
delayed_put_pid
rcu_core
Last potentially related work creation:
__call_rcu_common
free_pids
ksys_setsidKASAN identified a 144-byte object from the pid cache and located the bad read 80 bytes into the freed object, matching pid->inodes. With an explicit reference, three of three fresh boots completed without a KASAN report. The concurrent RCU callback dropped its reference while proc_flush_pid() was protected, and the balancing put_pid() performed the final free afterward.
Take a reference before __unhash_process() clears p->thread_pid and release it after proc_flush_pid() completes.
A tested source reproducer is available privately on request. No controlled read or write, information leak, or privilege escalation is claimed. The mainline patch applies directly to v6.19.y and newer; v6.16.y through v6.18.y need a context-adjusted backport.
kernel/exit.c +6 -3
@@ -261,8 +261,11 @@ void release_task(struct task_struct *p)pidfs_exit (p);cgroup_task_release (p); -/* Retrieve @thread_pid before __unhash_process() may set it to NULL. */ - thread_pid =task_pid (p); +/* +* Pin @thread_pid before __unhash_process() clears it. The last +* PIDTYPE detach can otherwise free it before proc_flush_pid(). +*/ + thread_pid =get_pid (task_pid (p));write_lock_irq (&tasklist_lock);ptrace_release_task (p);
@@ -291,8 +294,8 @@ void release_task(struct task_struct *p) }write_unlock_irq (&tasklist_lock); -/* @thread_pid can't go away until free_pids() below */ proc_flush_pid (thread_pid); +put_pid (thread_pid);exit_cred_namespaces (p);add_device_randomness (&p->se.sum_exec_runtime,sizeof (p->se.sum_exec_runtime));
Sasha Levin
maintainerPATCH 1/3 ns: add __ns_ref_read()
From: Christian Brauner <[email protected]>
[ Upstream commit 6b053576edb12c7739ea9c7c9900031361922631 ]
Implement ns_ref_read() the same way as ns_ref_{get,put}(). No point in making that any more special or different from the other helpers.
Stable-dep-of: cdd812d0683d ("exit: hold a reference to thread_pid across proc_flush_pid")
--- include/linux/ns_common.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
include/linux/ns_common.h +6 -1
@@ -156,7 +156,12 @@ static __always_inline __must_check bool __ns_ref_get(struct ns_common *ns)return refcount_inc_not_zero (&ns->__ns_ref); } -#define ns_ref_read (__ns) refcount_read(&to_ns_common((__ns))->__ns_ref) +static __always_inline __must_check int __ns_ref_read(const struct ns_common *ns) +{ +return refcount_read (&ns->__ns_ref); +} + +#define ns_ref_read (__ns) __ns_ref_read(to_ns_common((__ns)))#define ns_ref_inc (__ns) refcount_inc(&to_ns_common((__ns))->__ns_ref)#define ns_ref_get (__ns) __ns_ref_get(to_ns_common((__ns)))#define ns_ref_put (__ns) __ns_ref_put(to_ns_common((__ns)))
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/3 ns: rename to exit_nsproxy_namespaces()
From: Christian Brauner <[email protected]>
[ Upstream commit 4b06b70c8244b442d58ae0fb59870cf31fdb422e ]
The current naming is very misleading as this really isn't exiting all of the task's namespaces. It is only exiting the namespaces that hang of off nsproxy. Reflect that in the name.
Stable-dep-of: cdd812d0683d ("exit: hold a reference to thread_pid across proc_flush_pid")
--- include/linux/nsproxy.h | 2 +- kernel/cgroup/cgroup.c | 6 +++--- kernel/exit.c | 2 +- kernel/fork.c | 2 +- kernel/nsproxy.c | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-)
include/linux/nsproxy.h +1 -1
@@ -93,7 +93,7 @@ static inline struct cred *nsset_cred(struct nsset *set)*/ int copy_namespaces (u64 flags,struct task_struct *tsk); -void exit_task_namespaces (struct task_struct *tsk); +void exit_nsproxy_namespaces (struct task_struct *tsk);void switch_task_namespaces (struct task_struct *tsk,struct nsproxy *new);int exec_task_namespaces (void );void free_nsproxy (struct nsproxy *ns);
kernel/cgroup/cgroup.c +3 -3
@@ -1522,9 +1522,9 @@ static struct cgroup *current_cgns_cgroup_dfl(void) }else {/* * NOTE: This function may be called from bpf_cgroup_from_id() -* on a task which has already passed exit_task_namespaces() and -* nsproxy == NULL. Fall back to cgrp_dfl_root which will make all -* cgroups visible for lookups. +* on a task which has already passed exit_nsproxy_namespaces() +* and nsproxy == NULL. Fall back to cgrp_dfl_root which will +* make all cgroups visible for lookups. */ return &cgrp_dfl_root.cgrp; }
kernel/exit.c +1 -1
@@ -973,7 +973,7 @@ void __noreturn do_exit(long code)exit_fs (tsk);if (group_dead)disassociate_ctty (1 ); -exit_task_namespaces (tsk); +exit_nsproxy_namespaces (tsk);exit_task_work (tsk);exit_thread (tsk);
kernel/fork.c +1 -1
@@ -2455,7 +2455,7 @@ __latent_entropy struct task_struct *copy_process(if (p->io_context)exit_io_context (p); bad_fork_cleanup_namespaces: -exit_task_namespaces (p); +exit_nsproxy_namespaces (p); bad_fork_cleanup_mm:if (p->mm) {mm_clear_owner (p->mm, p);
kernel/nsproxy.c +1 -1
@@ -241,7 +241,7 @@ void switch_task_namespaces(struct task_struct *p, struct nsproxy *new)put_nsproxy (ns); } -void exit_task_namespaces (struct task_struct *p) +void exit_nsproxy_namespaces (struct task_struct *p) {switch_task_namespaces (p,NULL ); }
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 3/3 exit: hold a reference to thread_pid across proc_flush_pid
In reply to Sasha LevinFrom: Daehyeon Ko <[email protected]>
[ Upstream commit cdd812d0683dee14ead02c9eded568685e61b23f ]
Commit 0a36bad01731 ("release_task: kill the no longer needed get/put_pid(thread_pid)") removed the reference around proc_flush_pid(). It assumed that free_pids(post.pids) at the end of release_task() would keep thread_pid alive until then.
That assumption is wrong. __change_pid() only records a detached PID in post.pids when pid_has_task() is false for every PIDTYPE. If another task still uses the exiting task's PID as its process group or session ID, __unhash_process() removes the exiting task's PIDTYPE_PID link but leaves the PID out of post.pids. release_task() therefore holds no reference to it after dropping tasklist_lock.
The other task can then remove the remaining PIDTYPE links. Its free_pids() call schedules delayed_put_pid(), and the RCU callback can free the PID before the first release_task() reaches proc_flush_pid().
An unprivileged reproducer races wait4(-1) against setsid() to trigger this ordering. Three of three fresh v7.2 KASAN boots reported:
BUG: KASAN: slab-use-after-free in
proc_invalidate_siblings_dcache+0x3e2/0x3f0
Read of size 8 by task h7_pid_reaper/1921
Call Trace:
proc_invalidate_siblings_dcache
release_task
wait_consider_task
__do_wait
do_wait
kernel_wait4
Freed by task 0:
kmem_cache_free
put_pid
delayed_put_pid
rcu_core
Last potentially related work creation:
__call_rcu_common
free_pids
ksys_setsidKASAN identified a 144-byte object from the pid cache and located the bad read 80 bytes into the freed object, matching pid->inodes. With an explicit reference, three of three fresh boots completed without a KASAN report. The concurrent RCU callback dropped its reference while proc_flush_pid() was protected, and the balancing put_pid() performed the final free afterward.
Take a reference before __unhash_process() clears p->thread_pid and release it after proc_flush_pid() completes.
A tested source reproducer is available privately on request. No controlled read or write, information leak, or privilege escalation is claimed. The mainline patch applies directly to v6.19.y and newer; v6.16.y through v6.18.y need a context-adjusted backport.
--- kernel/exit.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
kernel/exit.c +6 -3
@@ -264,8 +264,11 @@ void release_task(struct task_struct *p)pidfs_exit (p);cgroup_release (p); -/* Retrieve @thread_pid before __unhash_process() may set it to NULL. */ - thread_pid =task_pid (p); +/* +* Pin @thread_pid before __unhash_process() clears it. The last +* PIDTYPE detach can otherwise free it before proc_flush_pid(). +*/ + thread_pid =get_pid (task_pid (p));write_lock_irq (&tasklist_lock);ptrace_release_task (p);
@@ -294,8 +297,8 @@ void release_task(struct task_struct *p) }write_unlock_irq (&tasklist_lock); -/* @thread_pid can't go away until free_pids() below */ proc_flush_pid (thread_pid); +put_pid (thread_pid);add_device_randomness (&p->se.sum_exec_runtime,sizeof (p->se.sum_exec_runtime));free_pids (post.pids);
Signature · 1 line
2.53.0
Re: [PATCH 6.18.y 3/3] exit: hold a reference to thread_pid across proc_flush_pid
Quoted 75 lines · Sasha Levin
From: Daehyeon Ko <[email protected]>
[ Upstream commit
cdd812d0683dee14ead02c9eded568685e61b23f]Commit
0a36bad01731("release_task: kill the no longer needed get/put_pid(thread_pid)") removed the reference aroundproc_flush_pid(). It assumed thatfree_pids(post.pids)at the end ofrelease_task()would keepthread_pidalive until then.That assumption is wrong.
__change_pid()only records a detached PID in post.pids whenpid_has_task()is false for every PIDTYPE. If another task still uses the exiting task's PID as its process group or session ID,__unhash_process()removes the exiting task'sPIDTYPE_PIDlink but leaves the PID out of post.pids.release_task()therefore holds no reference to it after droppingtasklist_lock.The other task can then remove the remaining PIDTYPE links. Its
free_pids()call schedulesdelayed_put_pid(), and the RCU callback can free
the PID before the firstrelease_task()reachesproc_flush_pid().An unprivileged reproducer races wait4(-1) against
setsid()to trigger this
ordering. Three of three fresh v7.2 KASAN boots reported:BUG: KASAN: slab-use-after-free in proc_invalidate_siblings_dcache+0x3e2/0x3f0 Read of size 8 by task h7_pid_reaper/1921 Call Trace: proc_invalidate_siblings_dcache release_task wait_consider_task __do_wait do_wait kernel_wait4 Freed by task 0: kmem_cache_free put_pid delayed_put_pid rcu_core Last potentially related work creation: __call_rcu_common free_pids ksys_setsidKASAN identified a 144-byte object from the pid cache and located the bad read 80 bytes into the freed object, matching
pid->inodes. With an explicit reference, three of three fresh boots completed without a KASAN report. The concurrent RCU callback dropped its reference whileproc_flush_pid()was protected, and the balancingput_pid()performed the final free afterward.Take a reference before
__unhash_process()clearsp->thread_pidand release
it afterproc_flush_pid()completes.A tested source reproducer is available privately on request. No controlled read or write, information leak, or privilege escalation is claimed. The mainline patch applies directly to v6.19.y and newer; v6.16.y through v6.18.y need a context-adjusted backport.
Fixes 0a36bad01731 ("release_task: kill the no longer needed get/put_pid(thread_pid)")Reported-by [email protected]Reported-by [email protected]Cc [email protected] # see patch description, needs adjustments for 6.16.y-6.18.ySigned-off-by Daehyeon Ko <[email protected]>Acked-by Oleg Nesterov <[email protected]>Reviewed-by Bradley Morgan <[email protected]>Signed-off-by Christian Brauner (Amutable) <[email protected]>
Quoted 2 lines
[ Adjusted context for
cgroup_release()and the missingexit_cred_namespaces()call. ]
Do you manually do all these? Or use a AI program to do these.
If you use a AI program to do automated backporting, please add something like:
[LLM: Thing it's done to fix the conflict]
If you do all these manually then Im shocked (also thank you)
Quoted 25 lines
Signed-off-by Sasha Levin <[email protected]>---
kernel/exit.c| 9 ++++++---1 file changed, 6 insertions(+), 3 deletions(-)kernel/exit.c +5
-2@@ -264,8 +264,11 @@ void release_task(struct task_struct *p)pidfs_exit (p);cgroup_release (p); -/* Retrieve @thread_pid before __unhash_process() may set it to NULL. */ - thread_pid =task_pid (p); +/* +* Pin @thread_pid before __unhash_process() clears it. The last +* PIDTYPE detach can otherwise free it before proc_flush_pid(). +*/ + thread_pid =get_pid (task_pid (p));write_lock_irq (&tasklist_lock);ptrace_release_task (p);
kernel/exit.c void release_task(struct task_struct *p) · line 304
Quoted 9 lines
kernel/exit.c +1
-1@@ -294,8 +297,8 @@ void release_task(struct task_struct *p) }write_unlock_irq (&tasklist_lock); -/* @thread_pid can't go away until free_pids() below */ proc_flush_pid (thread_pid); +put_pid (thread_pid);add_device_randomness (&p->se.sum_exec_runtime,sizeof (p->se.sum_exec_runtime));free_pids (post.pids);
Sasha Levin
maintainerRe: [PATCH 6.18.y 3/3] exit: hold a reference to thread_pid across proc_flush_pid
Quoted 1 line · Bradley Morgan
Do you manually do all these? Or use a AI program to do these.
Some LLM, and some other tools that don't involve LLMs.
Quoted 4 lines
If you use a AI program to do automated backporting, please add something like:
[LLM: Thing it's done to fix the conflict]
That gets added on commits that get modified by the LLM to backport cleanly. An example would be:
https://lore.kernel.org/all/[email protected]/
In this instance, there were no LLM tools involved in the resolution of the conflict. Instead, I took two prerequesite commits which allowed this last one to apply cleanly, thus there is no backport note on it.
Signature · 2 lines
Thanks, Sasha