All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCHSET v2] sched/psi: Fix psimon fork deadlock and rtpoll_timer UAF
@ 2026-07-12 17:46 Tejun Heo
  2026-07-12 17:46 ` [PATCH 1/2] sched/psi: Create the psimon kthread outside of cgroup_mutex Tejun Heo
                   ` (2 more replies)
  0 siblings, 3 replies; 13+ messages in thread
From: Tejun Heo @ 2026-07-12 17:46 UTC (permalink / raw)
  To: Matt Fleming
  Cc: David Vernet, Andrea Righi, Changwoo Min, Johannes Weiner,
	Suren Baghdasaryan, Peter Zijlstra, Edward Adam Davis,
	Chen Ridong, Zhaoyang Huang, ziwei . dai, ke . wang, Matt Fleming,
	sched-ext, cgroups, linux-kernel, stable, kernel-team, Tejun Heo

Hello,

v2: - Retagged sched/psi (was cgroup) (patch 1).
    - Added a fix for a pre-existing rtpoll_timer use-after-free that the
      Sashiko AI review flagged on the previous posting (patch 2).

v1: https://lore.kernel.org/r/20260710134945-psimon-fix-tj@kernel.org

a5b98009f16d ("sched/psi: fix race between file release and pressure
write") made pressure_write() fork the psimon kthread while holding
cgroup_mutex, which deadlocks against the sched_ext enable path blocking
forks before grabbing cgroup_mutex. Patch 1 moves the fork outside
cgroup_mutex. Patch 2 fixes the use-after-free from a schedule attempt
re-arming group->rtpoll_timer behind psi_trigger_destroy() by shutting
down the timer when the group is freed.

Matt, patch 1 is unchanged from the previous posting except for the
subject prefix, so test results against that posting still apply.

Peter, once these are reviewed and tested, how do you want them routed?
I can take them through the cgroup tree if that works for you.

Patches:

  [PATCH 1/2] sched/psi: Create the psimon kthread outside of cgroup_mutex
  [PATCH 2/2] sched/psi: Shut down rtpoll_timer in psi_cgroup_free()

Based on cgroup/for-7.2-fixes (97fef6025844).

 include/linux/psi.h    |  4 ++-
 kernel/cgroup/cgroup.c | 23 +++++++++++++++-
 kernel/sched/psi.c     | 75 +++++++++++++++++++++++++++++++++++++++-----------
 3 files changed, 84 insertions(+), 18 deletions(-)

Thanks.

--
tejun

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH 1/2] sched/psi: Create the psimon kthread outside of cgroup_mutex
  2026-07-12 17:46 [PATCHSET v2] sched/psi: Fix psimon fork deadlock and rtpoll_timer UAF Tejun Heo
@ 2026-07-12 17:46 ` Tejun Heo
  2026-07-12 18:00   ` sashiko-bot
                     ` (2 more replies)
  2026-07-12 17:46 ` [PATCH 2/2] sched/psi: Shut down rtpoll_timer in psi_cgroup_free() Tejun Heo
  2026-07-13 13:49 ` [PATCHSET v2] sched/psi: Fix psimon fork deadlock and rtpoll_timer UAF Matt Fleming
  2 siblings, 3 replies; 13+ messages in thread
From: Tejun Heo @ 2026-07-12 17:46 UTC (permalink / raw)
  To: Matt Fleming
  Cc: David Vernet, Andrea Righi, Changwoo Min, Johannes Weiner,
	Suren Baghdasaryan, Peter Zijlstra, Edward Adam Davis,
	Chen Ridong, Zhaoyang Huang, ziwei . dai, ke . wang, Matt Fleming,
	sched-ext, cgroups, linux-kernel, stable, kernel-team, Tejun Heo

a5b98009f16d ("sched/psi: fix race between file release and pressure write")
made pressure_write() hold cgroup_mutex across psi_trigger_create(), which
forks the psimon kthread for the first rtpoll trigger. As kthread creation
depends on the whole fork path, the commit inadvertently created a lot of
unwanted locking dependencies from cgroup_mutex.

sched_ext got hit by one: its enable path blocks forks and then grabs
cgroup_mutex, so a pressure write racing a scheduler enable deadlocks, with
every other fork piling up behind.

Fix it by splitting trigger creation so that the worker is forked with
cgroup_mutex dropped and the kernfs active reference left broken. The latter
matters because rmdir and cgroup.pressure writes drain active references
under cgroup_mutex. Publishing the trigger last keeps error reporting
synchronous and preserves the of->priv lifetime rules.

The trigger registered in the first stage pins the group's rtpoll machinery
across the unlocked window, leaving only creation races to resolve. The
catch-up poll on installation covers scheduling attempts dropped while there
was no worker.

v2: Retagged sched/psi (was cgroup).

Fixes: a5b98009f16d ("sched/psi: fix race between file release and pressure write")
Cc: stable@vger.kernel.org
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Edward Adam Davis <eadavis@qq.com>
Cc: Chen Ridong <chenridong@huaweicloud.com>
Reported-by: Matt Fleming <mfleming@cloudflare.com>
Closes: https://lore.kernel.org/all/20260710100441.2653477-1-matt@readmodwrite.com/
Signed-off-by: Tejun Heo <tj@kernel.org>
---
 include/linux/psi.h    |  4 ++-
 kernel/cgroup/cgroup.c | 23 +++++++++++++-
 kernel/sched/psi.c     | 69 ++++++++++++++++++++++++++++++++----------
 3 files changed, 78 insertions(+), 18 deletions(-)

diff --git a/include/linux/psi.h b/include/linux/psi.h
index e0745873e3f2..7966e3ac03b9 100644
--- a/include/linux/psi.h
+++ b/include/linux/psi.h
@@ -25,7 +25,9 @@ void psi_memstall_leave(unsigned long *flags);
 int psi_show(struct seq_file *s, struct psi_group *group, enum psi_res res);
 struct psi_trigger *psi_trigger_create(struct psi_group *group, char *buf,
 				       enum psi_res res, struct file *file,
-				       struct kernfs_open_file *of);
+				       struct kernfs_open_file *of,
+				       bool *need_rtpoll_worker);
+int psi_trigger_create_rtpoll_worker(struct psi_group *group);
 void psi_trigger_destroy(struct psi_trigger *t);
 
 __poll_t psi_trigger_poll(void **trigger_ptr, struct file *file,
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
index 38f8d9df8fbc..b5b461d4418b 100644
--- a/kernel/cgroup/cgroup.c
+++ b/kernel/cgroup/cgroup.c
@@ -3996,6 +3996,7 @@ static ssize_t pressure_write(struct kernfs_open_file *of, char *buf,
 	struct psi_trigger *new;
 	struct cgroup *cgrp;
 	struct psi_group *psi;
+	bool need_rtpoll_worker;
 	ssize_t ret = 0;
 
 	cgrp = cgroup_kn_lock_live(of->kn, false);
@@ -4015,12 +4016,32 @@ static ssize_t pressure_write(struct kernfs_open_file *of, char *buf,
 	}
 
 	psi = cgroup_psi(cgrp);
-	new = psi_trigger_create(psi, buf, res, of->file, of);
+	new = psi_trigger_create(psi, buf, res, of->file, of,
+				 &need_rtpoll_worker);
 	if (IS_ERR(new)) {
 		ret = PTR_ERR(new);
 		goto out_unlock;
 	}
 
+	/*
+	 * The worker fork must run with neither cgroup_mutex nor the file's
+	 * kernfs active reference held. The latter is broken since
+	 * cgroup_kn_lock_live(). @of->priv may be released while unlocked, so
+	 * recheck before publishing @new.
+	 */
+	if (need_rtpoll_worker) {
+		cgroup_unlock();
+		ret = psi_trigger_create_rtpoll_worker(psi);
+		cgroup_lock();
+
+		if (!ret && !of->priv)
+			ret = -ENODEV;
+		if (ret) {
+			psi_trigger_destroy(new);
+			goto out_unlock;
+		}
+	}
+
 	smp_store_release(&ctx->psi.trigger, new);
 
 out_unlock:
diff --git a/kernel/sched/psi.c b/kernel/sched/psi.c
index d9c9d9480a45..565ec7b80743 100644
--- a/kernel/sched/psi.c
+++ b/kernel/sched/psi.c
@@ -1292,9 +1292,44 @@ int psi_show(struct seq_file *m, struct psi_group *group, enum psi_res res)
 	return 0;
 }
 
+/*
+ * Create @group's rtpoll worker after psi_trigger_create() reported the need
+ * for one. kthread creation depends on the whole fork path and we don't want
+ * all of that nested inside cgroup_mutex, so the caller must drop it and any
+ * other lock that forks can wait behind. If two callers race, the loser stops
+ * its never-woken kthread.
+ */
+int psi_trigger_create_rtpoll_worker(struct psi_group *group)
+{
+	struct task_struct *task;
+
+	task = kthread_create(psi_rtpoll_worker, group, "psimon");
+	if (IS_ERR(task))
+		return PTR_ERR(task);
+
+	scoped_guard(mutex, &group->rtpoll_trigger_lock) {
+		if (!rcu_access_pointer(group->rtpoll_task)) {
+			atomic_set(&group->rtpoll_wakeup, 0);
+			wake_up_process(task);
+			rcu_assign_pointer(group->rtpoll_task, task);
+
+			/*
+			 * Poll once to catch up on scheduling attempts dropped
+			 * while there was no rtpoll worker.
+			 */
+			psi_schedule_rtpoll_work(group, 1, true);
+			return 0;
+		}
+	}
+
+	kthread_stop(task);
+	return 0;
+}
+
 struct psi_trigger *psi_trigger_create(struct psi_group *group, char *buf,
 				       enum psi_res res, struct file *file,
-				       struct kernfs_open_file *of)
+				       struct kernfs_open_file *of,
+				       bool *need_rtpoll_worker)
 {
 	struct psi_trigger *t;
 	enum psi_states state;
@@ -1302,6 +1337,8 @@ struct psi_trigger *psi_trigger_create(struct psi_group *group, char *buf,
 	bool privileged;
 	u32 window_us;
 
+	*need_rtpoll_worker = false;
+
 	if (static_branch_likely(&psi_disabled))
 		return ERR_PTR(-EOPNOTSUPP);
 
@@ -1362,26 +1399,14 @@ struct psi_trigger *psi_trigger_create(struct psi_group *group, char *buf,
 	if (privileged) {
 		mutex_lock(&group->rtpoll_trigger_lock);
 
-		if (!rcu_access_pointer(group->rtpoll_task)) {
-			struct task_struct *task;
-
-			task = kthread_create(psi_rtpoll_worker, group, "psimon");
-			if (IS_ERR(task)) {
-				kfree(t);
-				mutex_unlock(&group->rtpoll_trigger_lock);
-				return ERR_CAST(task);
-			}
-			atomic_set(&group->rtpoll_wakeup, 0);
-			wake_up_process(task);
-			rcu_assign_pointer(group->rtpoll_task, task);
-		}
-
 		list_add(&t->node, &group->rtpoll_triggers);
 		group->rtpoll_min_period = min(group->rtpoll_min_period,
 			div_u64(t->win.size, UPDATES_PER_WINDOW));
 		group->rtpoll_nr_triggers[t->state]++;
 		group->rtpoll_states |= (1 << t->state);
 
+		*need_rtpoll_worker = !rcu_access_pointer(group->rtpoll_task);
+
 		mutex_unlock(&group->rtpoll_trigger_lock);
 	} else {
 		mutex_lock(&group->avgs_lock);
@@ -1541,6 +1566,8 @@ static ssize_t psi_write(struct file *file, const char __user *user_buf,
 	size_t buf_size;
 	struct seq_file *seq;
 	struct psi_trigger *new;
+	bool need_rtpoll_worker;
+	int ret;
 
 	if (static_branch_likely(&psi_disabled))
 		return -EOPNOTSUPP;
@@ -1565,12 +1592,22 @@ static ssize_t psi_write(struct file *file, const char __user *user_buf,
 		return -EBUSY;
 	}
 
-	new = psi_trigger_create(&psi_system, buf, res, file, NULL);
+	new = psi_trigger_create(&psi_system, buf, res, file, NULL,
+				 &need_rtpoll_worker);
 	if (IS_ERR(new)) {
 		mutex_unlock(&seq->lock);
 		return PTR_ERR(new);
 	}
 
+	if (need_rtpoll_worker) {
+		ret = psi_trigger_create_rtpoll_worker(&psi_system);
+		if (ret) {
+			psi_trigger_destroy(new);
+			mutex_unlock(&seq->lock);
+			return ret;
+		}
+	}
+
 	smp_store_release(&seq->private, new);
 	mutex_unlock(&seq->lock);
 
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 2/2] sched/psi: Shut down rtpoll_timer in psi_cgroup_free()
  2026-07-12 17:46 [PATCHSET v2] sched/psi: Fix psimon fork deadlock and rtpoll_timer UAF Tejun Heo
  2026-07-12 17:46 ` [PATCH 1/2] sched/psi: Create the psimon kthread outside of cgroup_mutex Tejun Heo
@ 2026-07-12 17:46 ` Tejun Heo
  2026-07-13 10:56   ` Johannes Weiner
  2026-07-13 13:48   ` Matt Fleming
  2026-07-13 13:49 ` [PATCHSET v2] sched/psi: Fix psimon fork deadlock and rtpoll_timer UAF Matt Fleming
  2 siblings, 2 replies; 13+ messages in thread
From: Tejun Heo @ 2026-07-12 17:46 UTC (permalink / raw)
  To: Matt Fleming
  Cc: David Vernet, Andrea Righi, Changwoo Min, Johannes Weiner,
	Suren Baghdasaryan, Peter Zijlstra, Edward Adam Davis,
	Chen Ridong, Zhaoyang Huang, ziwei . dai, ke . wang, Matt Fleming,
	sched-ext, cgroups, linux-kernel, stable, kernel-team, Tejun Heo,
	Sashiko AI

psi_schedule_rtpoll_work() is called locklessly from the scheduler hotpath
and can race psi_trigger_destroy() taking down the last rtpoll trigger under
rtpoll_trigger_lock:

  psi_schedule_rtpoll_work()        psi_trigger_destroy()

  rcu_read_lock();
  task = rcu_dereference(rtpoll_task);
                                    rcu_assign_pointer(rtpoll_task, NULL);
                                    timer_delete(&rtpoll_timer);
  mod_timer(&rtpoll_timer, ...);
  rcu_read_unlock();
                                    synchronize_rcu();
                                    kthread_stop(task_to_destroy);

The group can then be freed with the re-armed timer still pending, and
poll_timer_fn() runs on freed memory.

461daba06bdc ("psi: eliminate kthread_worker from psi trigger scheduling
mechanism") deleted the timer synchronously after the synchronize_rcu(),
which prevented this but raced trigger creation instead: the deletion could
cancel the timer that a new trigger set armed during the grace period and,
as creation also reinitialized the timer at the time, corrupt it.
8f91efd870ea ("psi: Fix race between psi_trigger_create/destroy") moved the
initialization into group_init() and the deletion into the locked section,
trading the creation races for the window above.

Neither placement in the destruction path works. A pending timer firing
while the group is alive is harmless though. poll_timer_fn() just wakes the
rtpoll waitqueue and doesn't re-arm itself. Bind the timer to the group's
lifetime instead and shut it down in psi_cgroup_free(). Nothing can arm it
by then. timer_shutdown_sync() because the timer is never armed again.

Fixes: 8f91efd870ea ("psi: Fix race between psi_trigger_create/destroy")
Cc: stable@vger.kernel.org # v5.10+
Reported-by: Sashiko AI <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/all/20260711000434.36C4A1F000E9@smtp.kernel.org/
Signed-off-by: Tejun Heo <tj@kernel.org>
---
 kernel/sched/psi.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/kernel/sched/psi.c b/kernel/sched/psi.c
index 565ec7b80743..e2e825dcd088 100644
--- a/kernel/sched/psi.c
+++ b/kernel/sched/psi.c
@@ -1134,6 +1134,12 @@ void psi_cgroup_free(struct cgroup *cgroup)
 		return;
 
 	cancel_delayed_work_sync(&cgroup->psi->avgs_work);
+	/*
+	 * A psi_schedule_rtpoll_work() call racing the last trigger's
+	 * destruction may have re-armed the timer after psi_trigger_destroy()
+	 * deleted it. Spurious firing while the group is alive is harmless.
+	 */
+	timer_shutdown_sync(&cgroup->psi->rtpoll_timer);
 	free_percpu(cgroup->psi->pcpu);
 	/* All triggers must be removed by now */
 	WARN_ONCE(cgroup->psi->rtpoll_states, "psi: trigger leak\n");
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH 1/2] sched/psi: Create the psimon kthread outside of cgroup_mutex
  2026-07-12 17:46 ` [PATCH 1/2] sched/psi: Create the psimon kthread outside of cgroup_mutex Tejun Heo
@ 2026-07-12 18:00   ` sashiko-bot
  2026-07-12 20:26     ` Tejun Heo
  2026-07-13 10:51   ` Johannes Weiner
  2026-07-13 13:48   ` Matt Fleming
  2 siblings, 1 reply; 13+ messages in thread
From: sashiko-bot @ 2026-07-12 18:00 UTC (permalink / raw)
  To: Tejun Heo; +Cc: hannes, mkoutny, tj, sched-ext

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Calling psi_trigger_destroy() while holding cgroup_mutex introduces severe system-wide latency spikes.
--

--- Patch [1]: [PATCH 1/2] sched/psi: Create the psimon kthread outside of cgroup_mutex ---
commit 4990aba341f12c025b0b99ecf8869c68be847294
Author: Tejun Heo <tj@kernel.org>
sched/psi: Create the psimon kthread outside of cgroup_mutex

This commit splits psi trigger creation into two stages to avoid locking
dependencies. It drops cgroup_mutex before forking the psimon kthread, then
reacquires the mutex to verify the cgroup is still alive before publishing
the new trigger.

Closes: https://lore.kernel.org/all/20260710100441.2653477-1-matt@readmodwrite.com/

> diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
> index 38f8d9df8fbc4..b5b461d4418b1 100644
> --- a/kernel/cgroup/cgroup.c
> +++ b/kernel/cgroup/cgroup.c
[ ... ]
> @@ -4015,12 +4016,32 @@ static ssize_t pressure_write(struct kernfs_open_file *of, char *buf,
>  	}
>  
>  	psi = cgroup_psi(cgrp);
> -	new = psi_trigger_create(psi, buf, res, of->file, of);
> +	new = psi_trigger_create(psi, buf, res, of->file, of,
> +				 &need_rtpoll_worker);
>  	if (IS_ERR(new)) {
>  		ret = PTR_ERR(new);
>  		goto out_unlock;
>  	}
>  
> +	/*
> +	 * The worker fork must run with neither cgroup_mutex nor the file's
> +	 * kernfs active reference held. The latter is broken since
> +	 * cgroup_kn_lock_live(). @of->priv may be released while unlocked, so
> +	 * recheck before publishing @new.
> +	 */
> +	if (need_rtpoll_worker) {
> +		cgroup_unlock();
> +		ret = psi_trigger_create_rtpoll_worker(psi);
> +		cgroup_lock();
> +
> +		if (!ret && !of->priv)
> +			ret = -ENODEV;
> +		if (ret) {
> +			psi_trigger_destroy(new);

[Severity: High]
Since psi_trigger_destroy() unconditionally blocks on synchronize_rcu(), will
calling it here while holding cgroup_mutex cause system-wide latency spikes?

Looking at psi_trigger_destroy() in kernel/sched/psi.c, it does:

	/*
	 * Wait for psi_schedule_rtpoll_work RCU to complete its read-side
	 * critical section before destroying the trigger and optionally the
	 * rtpoll_task.
	 */
	synchronize_rcu();

If this error path is reached (e.g. by racing pressure_write() with cgroup
rmdir making of->priv NULL), the calling thread would sleep for an RCU grace
period while holding cgroup_mutex, stalling all other cgroup operations.

Could the trigger destruction be deferred until after cgroup_mutex is dropped,
or handled asynchronously to avoid stalling the cgroup subsystem?

> +			goto out_unlock;
> +		}
> +	}
> +
>  	smp_store_release(&ctx->psi.trigger, new);
>  
>  out_unlock:

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260712174619.3553231-1-tj@kernel.org?part=1

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 1/2] sched/psi: Create the psimon kthread outside of cgroup_mutex
  2026-07-12 18:00   ` sashiko-bot
@ 2026-07-12 20:26     ` Tejun Heo
  0 siblings, 0 replies; 13+ messages in thread
From: Tejun Heo @ 2026-07-12 20:26 UTC (permalink / raw)
  To: sashiko-reviews; +Cc: Johannes Weiner, Michal Koutny, tj, sched-ext

Hello.

> If this error path is reached (e.g. by racing pressure_write() with cgroup
> rmdir making of->priv NULL), the calling thread would sleep for an RCU grace
> period while holding cgroup_mutex, stalling all other cgroup operations.
>
> Could the trigger destruction be deferred until after cgroup_mutex is dropped,
> or handled asynchronously to avoid stalling the cgroup subsystem?

This is pre-existing - rmdir and cgroup.pressure disable already destroy
triggers under cgroup_mutex when draining open fds. Maybe something to
improve in the future.

Thanks.

--
tejun

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 1/2] sched/psi: Create the psimon kthread outside of cgroup_mutex
  2026-07-12 17:46 ` [PATCH 1/2] sched/psi: Create the psimon kthread outside of cgroup_mutex Tejun Heo
  2026-07-12 18:00   ` sashiko-bot
@ 2026-07-13 10:51   ` Johannes Weiner
  2026-07-13 13:48   ` Matt Fleming
  2 siblings, 0 replies; 13+ messages in thread
From: Johannes Weiner @ 2026-07-13 10:51 UTC (permalink / raw)
  To: Tejun Heo
  Cc: Matt Fleming, David Vernet, Andrea Righi, Changwoo Min,
	Suren Baghdasaryan, Peter Zijlstra, Edward Adam Davis,
	Chen Ridong, Zhaoyang Huang, ziwei . dai, ke . wang, Matt Fleming,
	sched-ext, cgroups, linux-kernel, stable, kernel-team

On Sun, Jul 12, 2026 at 07:46:18AM -1000, Tejun Heo wrote:
> a5b98009f16d ("sched/psi: fix race between file release and pressure write")
> made pressure_write() hold cgroup_mutex across psi_trigger_create(), which
> forks the psimon kthread for the first rtpoll trigger. As kthread creation
> depends on the whole fork path, the commit inadvertently created a lot of
> unwanted locking dependencies from cgroup_mutex.
> 
> sched_ext got hit by one: its enable path blocks forks and then grabs
> cgroup_mutex, so a pressure write racing a scheduler enable deadlocks, with
> every other fork piling up behind.
> 
> Fix it by splitting trigger creation so that the worker is forked with
> cgroup_mutex dropped and the kernfs active reference left broken. The latter
> matters because rmdir and cgroup.pressure writes drain active references
> under cgroup_mutex. Publishing the trigger last keeps error reporting
> synchronous and preserves the of->priv lifetime rules.
> 
> The trigger registered in the first stage pins the group's rtpoll machinery
> across the unlocked window, leaving only creation races to resolve. The
> catch-up poll on installation covers scheduling attempts dropped while there
> was no worker.
> 
> v2: Retagged sched/psi (was cgroup).
> 
> Fixes: a5b98009f16d ("sched/psi: fix race between file release and pressure write")
> Cc: stable@vger.kernel.org
> Cc: Johannes Weiner <hannes@cmpxchg.org>
> Cc: Edward Adam Davis <eadavis@qq.com>
> Cc: Chen Ridong <chenridong@huaweicloud.com>
> Reported-by: Matt Fleming <mfleming@cloudflare.com>
> Closes: https://lore.kernel.org/all/20260710100441.2653477-1-matt@readmodwrite.com/
> Signed-off-by: Tejun Heo <tj@kernel.org>

Acked-by: Johannes Weiner <hannes@cmpxchg.org>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 2/2] sched/psi: Shut down rtpoll_timer in psi_cgroup_free()
  2026-07-12 17:46 ` [PATCH 2/2] sched/psi: Shut down rtpoll_timer in psi_cgroup_free() Tejun Heo
@ 2026-07-13 10:56   ` Johannes Weiner
  2026-07-13 14:07     ` Suren Baghdasaryan
  2026-07-13 13:48   ` Matt Fleming
  1 sibling, 1 reply; 13+ messages in thread
From: Johannes Weiner @ 2026-07-13 10:56 UTC (permalink / raw)
  To: Tejun Heo
  Cc: Matt Fleming, David Vernet, Andrea Righi, Changwoo Min,
	Suren Baghdasaryan, Peter Zijlstra, Edward Adam Davis,
	Chen Ridong, Zhaoyang Huang, ziwei . dai, ke . wang, Matt Fleming,
	sched-ext, cgroups, linux-kernel, stable, kernel-team, Sashiko AI

On Sun, Jul 12, 2026 at 07:46:19AM -1000, Tejun Heo wrote:
> psi_schedule_rtpoll_work() is called locklessly from the scheduler hotpath
> and can race psi_trigger_destroy() taking down the last rtpoll trigger under
> rtpoll_trigger_lock:
> 
>   psi_schedule_rtpoll_work()        psi_trigger_destroy()
> 
>   rcu_read_lock();
>   task = rcu_dereference(rtpoll_task);
>                                     rcu_assign_pointer(rtpoll_task, NULL);
>                                     timer_delete(&rtpoll_timer);
>   mod_timer(&rtpoll_timer, ...);
>   rcu_read_unlock();
>                                     synchronize_rcu();
>                                     kthread_stop(task_to_destroy);
> 
> The group can then be freed with the re-armed timer still pending, and
> poll_timer_fn() runs on freed memory.
> 
> 461daba06bdc ("psi: eliminate kthread_worker from psi trigger scheduling
> mechanism") deleted the timer synchronously after the synchronize_rcu(),
> which prevented this but raced trigger creation instead: the deletion could
> cancel the timer that a new trigger set armed during the grace period and,
> as creation also reinitialized the timer at the time, corrupt it.
> 8f91efd870ea ("psi: Fix race between psi_trigger_create/destroy") moved the
> initialization into group_init() and the deletion into the locked section,
> trading the creation races for the window above.
> 
> Neither placement in the destruction path works. A pending timer firing
> while the group is alive is harmless though. poll_timer_fn() just wakes the
> rtpoll waitqueue and doesn't re-arm itself. Bind the timer to the group's
> lifetime instead and shut it down in psi_cgroup_free(). Nothing can arm it
> by then. timer_shutdown_sync() because the timer is never armed again.
> 
> Fixes: 8f91efd870ea ("psi: Fix race between psi_trigger_create/destroy")
> Cc: stable@vger.kernel.org # v5.10+
> Reported-by: Sashiko AI <sashiko-bot@kernel.org>
> Closes: https://lore.kernel.org/all/20260711000434.36C4A1F000E9@smtp.kernel.org/
> Signed-off-by: Tejun Heo <tj@kernel.org>

Acked-by: Johannes Weiner <hannes@cmpxchg.org>

Both these patches look good to me, but Suren can you please also take
a look?

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 1/2] sched/psi: Create the psimon kthread outside of cgroup_mutex
  2026-07-12 17:46 ` [PATCH 1/2] sched/psi: Create the psimon kthread outside of cgroup_mutex Tejun Heo
  2026-07-12 18:00   ` sashiko-bot
  2026-07-13 10:51   ` Johannes Weiner
@ 2026-07-13 13:48   ` Matt Fleming
  2026-07-13 15:19     ` Suren Baghdasaryan
  2 siblings, 1 reply; 13+ messages in thread
From: Matt Fleming @ 2026-07-13 13:48 UTC (permalink / raw)
  To: Tejun Heo
  Cc: David Vernet, Andrea Righi, Changwoo Min, Johannes Weiner,
	Suren Baghdasaryan, Peter Zijlstra, Edward Adam Davis,
	Chen Ridong, Zhaoyang Huang, ziwei . dai, ke . wang, Matt Fleming,
	sched-ext, cgroups, linux-kernel, stable, kernel-team

On Sun, Jul 12, 2026 at 07:46:18AM -1000, Tejun Heo wrote:
> a5b98009f16d ("sched/psi: fix race between file release and pressure write")
> made pressure_write() hold cgroup_mutex across psi_trigger_create(), which
> forks the psimon kthread for the first rtpoll trigger. As kthread creation
> depends on the whole fork path, the commit inadvertently created a lot of
> unwanted locking dependencies from cgroup_mutex.
> 
> sched_ext got hit by one: its enable path blocks forks and then grabs
> cgroup_mutex, so a pressure write racing a scheduler enable deadlocks, with
> every other fork piling up behind.
> 
> Fix it by splitting trigger creation so that the worker is forked with
> cgroup_mutex dropped and the kernfs active reference left broken. The latter
> matters because rmdir and cgroup.pressure writes drain active references
> under cgroup_mutex. Publishing the trigger last keeps error reporting
> synchronous and preserves the of->priv lifetime rules.
> 
> The trigger registered in the first stage pins the group's rtpoll machinery
> across the unlocked window, leaving only creation races to resolve. The
> catch-up poll on installation covers scheduling attempts dropped while there
> was no worker.
> 
> v2: Retagged sched/psi (was cgroup).
> 
> Fixes: a5b98009f16d ("sched/psi: fix race between file release and pressure write")
> Cc: stable@vger.kernel.org
> Cc: Johannes Weiner <hannes@cmpxchg.org>
> Cc: Edward Adam Davis <eadavis@qq.com>
> Cc: Chen Ridong <chenridong@huaweicloud.com>
> Reported-by: Matt Fleming <mfleming@cloudflare.com>
> Closes: https://lore.kernel.org/all/20260710100441.2653477-1-matt@readmodwrite.com/
> Signed-off-by: Tejun Heo <tj@kernel.org>
> ---
>  include/linux/psi.h    |  4 ++-
>  kernel/cgroup/cgroup.c | 23 +++++++++++++-
>  kernel/sched/psi.c     | 69 ++++++++++++++++++++++++++++++++----------
>  3 files changed, 78 insertions(+), 18 deletions(-)

Tested-by: Matt Fleming <mfleming@cloudflare.com>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 2/2] sched/psi: Shut down rtpoll_timer in psi_cgroup_free()
  2026-07-12 17:46 ` [PATCH 2/2] sched/psi: Shut down rtpoll_timer in psi_cgroup_free() Tejun Heo
  2026-07-13 10:56   ` Johannes Weiner
@ 2026-07-13 13:48   ` Matt Fleming
  1 sibling, 0 replies; 13+ messages in thread
From: Matt Fleming @ 2026-07-13 13:48 UTC (permalink / raw)
  To: Tejun Heo
  Cc: David Vernet, Andrea Righi, Changwoo Min, Johannes Weiner,
	Suren Baghdasaryan, Peter Zijlstra, Edward Adam Davis,
	Chen Ridong, Zhaoyang Huang, ziwei . dai, ke . wang, Matt Fleming,
	sched-ext, cgroups, linux-kernel, stable, kernel-team, Sashiko AI

On Sun, Jul 12, 2026 at 07:46:19AM -1000, Tejun Heo wrote:
> psi_schedule_rtpoll_work() is called locklessly from the scheduler hotpath
> and can race psi_trigger_destroy() taking down the last rtpoll trigger under
> rtpoll_trigger_lock:
> 
>   psi_schedule_rtpoll_work()        psi_trigger_destroy()
> 
>   rcu_read_lock();
>   task = rcu_dereference(rtpoll_task);
>                                     rcu_assign_pointer(rtpoll_task, NULL);
>                                     timer_delete(&rtpoll_timer);
>   mod_timer(&rtpoll_timer, ...);
>   rcu_read_unlock();
>                                     synchronize_rcu();
>                                     kthread_stop(task_to_destroy);
> 
> The group can then be freed with the re-armed timer still pending, and
> poll_timer_fn() runs on freed memory.
> 
> 461daba06bdc ("psi: eliminate kthread_worker from psi trigger scheduling
> mechanism") deleted the timer synchronously after the synchronize_rcu(),
> which prevented this but raced trigger creation instead: the deletion could
> cancel the timer that a new trigger set armed during the grace period and,
> as creation also reinitialized the timer at the time, corrupt it.
> 8f91efd870ea ("psi: Fix race between psi_trigger_create/destroy") moved the
> initialization into group_init() and the deletion into the locked section,
> trading the creation races for the window above.
> 
> Neither placement in the destruction path works. A pending timer firing
> while the group is alive is harmless though. poll_timer_fn() just wakes the
> rtpoll waitqueue and doesn't re-arm itself. Bind the timer to the group's
> lifetime instead and shut it down in psi_cgroup_free(). Nothing can arm it
> by then. timer_shutdown_sync() because the timer is never armed again.
> 
> Fixes: 8f91efd870ea ("psi: Fix race between psi_trigger_create/destroy")
> Cc: stable@vger.kernel.org # v5.10+
> Reported-by: Sashiko AI <sashiko-bot@kernel.org>
> Closes: https://lore.kernel.org/all/20260711000434.36C4A1F000E9@smtp.kernel.org/
> Signed-off-by: Tejun Heo <tj@kernel.org>
> ---
>  kernel/sched/psi.c | 6 ++++++
>  1 file changed, 6 insertions(+)
 
Tested-by: Matt Fleming <mfleming@cloudflare.com>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCHSET v2] sched/psi: Fix psimon fork deadlock and rtpoll_timer UAF
  2026-07-12 17:46 [PATCHSET v2] sched/psi: Fix psimon fork deadlock and rtpoll_timer UAF Tejun Heo
  2026-07-12 17:46 ` [PATCH 1/2] sched/psi: Create the psimon kthread outside of cgroup_mutex Tejun Heo
  2026-07-12 17:46 ` [PATCH 2/2] sched/psi: Shut down rtpoll_timer in psi_cgroup_free() Tejun Heo
@ 2026-07-13 13:49 ` Matt Fleming
  2 siblings, 0 replies; 13+ messages in thread
From: Matt Fleming @ 2026-07-13 13:49 UTC (permalink / raw)
  To: Tejun Heo
  Cc: David Vernet, Andrea Righi, Changwoo Min, Johannes Weiner,
	Suren Baghdasaryan, Peter Zijlstra, Edward Adam Davis,
	Chen Ridong, Zhaoyang Huang, ziwei . dai, ke . wang, Matt Fleming,
	sched-ext, cgroups, linux-kernel, stable, kernel-team

On Sun, Jul 12, 2026 at 07:46:17AM -1000, Tejun Heo wrote:
> Hello,
> 
> v2: - Retagged sched/psi (was cgroup) (patch 1).
>     - Added a fix for a pre-existing rtpoll_timer use-after-free that the
>       Sashiko AI review flagged on the previous posting (patch 2).
> 
> v1: https://lore.kernel.org/r/20260710134945-psimon-fix-tj@kernel.org
> 
> a5b98009f16d ("sched/psi: fix race between file release and pressure
> write") made pressure_write() fork the psimon kthread while holding
> cgroup_mutex, which deadlocks against the sched_ext enable path blocking
> forks before grabbing cgroup_mutex. Patch 1 moves the fork outside
> cgroup_mutex. Patch 2 fixes the use-after-free from a schedule attempt
> re-arming group->rtpoll_timer behind psi_trigger_destroy() by shutting
> down the timer when the group is freed.
> 
> Matt, patch 1 is unchanged from the previous posting except for the
> subject prefix, so test results against that posting still apply.

I ended up testing both patches. This resolves the issue for me!

Thanks,
Matt

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 2/2] sched/psi: Shut down rtpoll_timer in psi_cgroup_free()
  2026-07-13 10:56   ` Johannes Weiner
@ 2026-07-13 14:07     ` Suren Baghdasaryan
  2026-07-13 15:19       ` Suren Baghdasaryan
  0 siblings, 1 reply; 13+ messages in thread
From: Suren Baghdasaryan @ 2026-07-13 14:07 UTC (permalink / raw)
  To: Johannes Weiner
  Cc: Tejun Heo, Matt Fleming, David Vernet, Andrea Righi, Changwoo Min,
	Peter Zijlstra, Edward Adam Davis, Chen Ridong, Zhaoyang Huang,
	ziwei . dai, ke . wang, Matt Fleming, sched-ext, cgroups,
	linux-kernel, stable, kernel-team, Sashiko AI

On Mon, Jul 13, 2026 at 3:56 AM Johannes Weiner <hannes@cmpxchg.org> wrote:
>
> On Sun, Jul 12, 2026 at 07:46:19AM -1000, Tejun Heo wrote:
> > psi_schedule_rtpoll_work() is called locklessly from the scheduler hotpath
> > and can race psi_trigger_destroy() taking down the last rtpoll trigger under
> > rtpoll_trigger_lock:
> >
> >   psi_schedule_rtpoll_work()        psi_trigger_destroy()
> >
> >   rcu_read_lock();
> >   task = rcu_dereference(rtpoll_task);
> >                                     rcu_assign_pointer(rtpoll_task, NULL);
> >                                     timer_delete(&rtpoll_timer);
> >   mod_timer(&rtpoll_timer, ...);
> >   rcu_read_unlock();
> >                                     synchronize_rcu();
> >                                     kthread_stop(task_to_destroy);
> >
> > The group can then be freed with the re-armed timer still pending, and
> > poll_timer_fn() runs on freed memory.
> >
> > 461daba06bdc ("psi: eliminate kthread_worker from psi trigger scheduling
> > mechanism") deleted the timer synchronously after the synchronize_rcu(),
> > which prevented this but raced trigger creation instead: the deletion could
> > cancel the timer that a new trigger set armed during the grace period and,
> > as creation also reinitialized the timer at the time, corrupt it.
> > 8f91efd870ea ("psi: Fix race between psi_trigger_create/destroy") moved the
> > initialization into group_init() and the deletion into the locked section,
> > trading the creation races for the window above.
> >
> > Neither placement in the destruction path works. A pending timer firing
> > while the group is alive is harmless though. poll_timer_fn() just wakes the
> > rtpoll waitqueue and doesn't re-arm itself. Bind the timer to the group's
> > lifetime instead and shut it down in psi_cgroup_free(). Nothing can arm it
> > by then. timer_shutdown_sync() because the timer is never armed again.
> >
> > Fixes: 8f91efd870ea ("psi: Fix race between psi_trigger_create/destroy")
> > Cc: stable@vger.kernel.org # v5.10+
> > Reported-by: Sashiko AI <sashiko-bot@kernel.org>
> > Closes: https://lore.kernel.org/all/20260711000434.36C4A1F000E9@smtp.kernel.org/
> > Signed-off-by: Tejun Heo <tj@kernel.org>
>
> Acked-by: Johannes Weiner <hannes@cmpxchg.org>
>
> Both these patches look good to me, but Suren can you please also take
> a look?

Yes, I'm on it. Need some time to remind myself of all the details of
the implementation.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 1/2] sched/psi: Create the psimon kthread outside of cgroup_mutex
  2026-07-13 13:48   ` Matt Fleming
@ 2026-07-13 15:19     ` Suren Baghdasaryan
  0 siblings, 0 replies; 13+ messages in thread
From: Suren Baghdasaryan @ 2026-07-13 15:19 UTC (permalink / raw)
  To: Matt Fleming
  Cc: Tejun Heo, David Vernet, Andrea Righi, Changwoo Min,
	Johannes Weiner, Peter Zijlstra, Edward Adam Davis, Chen Ridong,
	Zhaoyang Huang, ziwei . dai, ke . wang, Matt Fleming, sched-ext,
	cgroups, linux-kernel, stable, kernel-team

On Mon, Jul 13, 2026 at 6:48 AM Matt Fleming <matt@readmodwrite.com> wrote:
>
> On Sun, Jul 12, 2026 at 07:46:18AM -1000, Tejun Heo wrote:
> > a5b98009f16d ("sched/psi: fix race between file release and pressure write")
> > made pressure_write() hold cgroup_mutex across psi_trigger_create(), which
> > forks the psimon kthread for the first rtpoll trigger. As kthread creation
> > depends on the whole fork path, the commit inadvertently created a lot of
> > unwanted locking dependencies from cgroup_mutex.
> >
> > sched_ext got hit by one: its enable path blocks forks and then grabs
> > cgroup_mutex, so a pressure write racing a scheduler enable deadlocks, with
> > every other fork piling up behind.
> >
> > Fix it by splitting trigger creation so that the worker is forked with
> > cgroup_mutex dropped and the kernfs active reference left broken. The latter
> > matters because rmdir and cgroup.pressure writes drain active references
> > under cgroup_mutex. Publishing the trigger last keeps error reporting
> > synchronous and preserves the of->priv lifetime rules.
> >
> > The trigger registered in the first stage pins the group's rtpoll machinery
> > across the unlocked window, leaving only creation races to resolve. The
> > catch-up poll on installation covers scheduling attempts dropped while there
> > was no worker.
> >
> > v2: Retagged sched/psi (was cgroup).
> >
> > Fixes: a5b98009f16d ("sched/psi: fix race between file release and pressure write")
> > Cc: stable@vger.kernel.org
> > Cc: Johannes Weiner <hannes@cmpxchg.org>
> > Cc: Edward Adam Davis <eadavis@qq.com>
> > Cc: Chen Ridong <chenridong@huaweicloud.com>
> > Reported-by: Matt Fleming <mfleming@cloudflare.com>
> > Closes: https://lore.kernel.org/all/20260710100441.2653477-1-matt@readmodwrite.com/
> > Signed-off-by: Tejun Heo <tj@kernel.org>
> > ---
> >  include/linux/psi.h    |  4 ++-
> >  kernel/cgroup/cgroup.c | 23 +++++++++++++-
> >  kernel/sched/psi.c     | 69 ++++++++++++++++++++++++++++++++----------
> >  3 files changed, 78 insertions(+), 18 deletions(-)
>
> Tested-by: Matt Fleming <mfleming@cloudflare.com>

Acked-by: Suren Baghdasaryan <surenb@google.com>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 2/2] sched/psi: Shut down rtpoll_timer in psi_cgroup_free()
  2026-07-13 14:07     ` Suren Baghdasaryan
@ 2026-07-13 15:19       ` Suren Baghdasaryan
  0 siblings, 0 replies; 13+ messages in thread
From: Suren Baghdasaryan @ 2026-07-13 15:19 UTC (permalink / raw)
  To: Johannes Weiner
  Cc: Tejun Heo, Matt Fleming, David Vernet, Andrea Righi, Changwoo Min,
	Peter Zijlstra, Edward Adam Davis, Chen Ridong, Zhaoyang Huang,
	ziwei . dai, ke . wang, Matt Fleming, sched-ext, cgroups,
	linux-kernel, stable, kernel-team, Sashiko AI

On Mon, Jul 13, 2026 at 7:07 AM Suren Baghdasaryan <surenb@google.com> wrote:
>
> On Mon, Jul 13, 2026 at 3:56 AM Johannes Weiner <hannes@cmpxchg.org> wrote:
> >
> > On Sun, Jul 12, 2026 at 07:46:19AM -1000, Tejun Heo wrote:
> > > psi_schedule_rtpoll_work() is called locklessly from the scheduler hotpath
> > > and can race psi_trigger_destroy() taking down the last rtpoll trigger under
> > > rtpoll_trigger_lock:
> > >
> > >   psi_schedule_rtpoll_work()        psi_trigger_destroy()
> > >
> > >   rcu_read_lock();
> > >   task = rcu_dereference(rtpoll_task);
> > >                                     rcu_assign_pointer(rtpoll_task, NULL);
> > >                                     timer_delete(&rtpoll_timer);
> > >   mod_timer(&rtpoll_timer, ...);
> > >   rcu_read_unlock();
> > >                                     synchronize_rcu();
> > >                                     kthread_stop(task_to_destroy);
> > >
> > > The group can then be freed with the re-armed timer still pending, and
> > > poll_timer_fn() runs on freed memory.
> > >
> > > 461daba06bdc ("psi: eliminate kthread_worker from psi trigger scheduling
> > > mechanism") deleted the timer synchronously after the synchronize_rcu(),
> > > which prevented this but raced trigger creation instead: the deletion could
> > > cancel the timer that a new trigger set armed during the grace period and,
> > > as creation also reinitialized the timer at the time, corrupt it.
> > > 8f91efd870ea ("psi: Fix race between psi_trigger_create/destroy") moved the
> > > initialization into group_init() and the deletion into the locked section,
> > > trading the creation races for the window above.
> > >
> > > Neither placement in the destruction path works. A pending timer firing
> > > while the group is alive is harmless though. poll_timer_fn() just wakes the
> > > rtpoll waitqueue and doesn't re-arm itself. Bind the timer to the group's
> > > lifetime instead and shut it down in psi_cgroup_free(). Nothing can arm it
> > > by then. timer_shutdown_sync() because the timer is never armed again.
> > >
> > > Fixes: 8f91efd870ea ("psi: Fix race between psi_trigger_create/destroy")
> > > Cc: stable@vger.kernel.org # v5.10+
> > > Reported-by: Sashiko AI <sashiko-bot@kernel.org>
> > > Closes: https://lore.kernel.org/all/20260711000434.36C4A1F000E9@smtp.kernel.org/
> > > Signed-off-by: Tejun Heo <tj@kernel.org>
> >
> > Acked-by: Johannes Weiner <hannes@cmpxchg.org>

Acked-by: Suren Baghdasaryan <surenb@google.com>


> >
> > Both these patches look good to me, but Suren can you please also take
> > a look?
>
> Yes, I'm on it. Need some time to remind myself of all the details of
> the implementation.

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2026-07-13 15:19 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-12 17:46 [PATCHSET v2] sched/psi: Fix psimon fork deadlock and rtpoll_timer UAF Tejun Heo
2026-07-12 17:46 ` [PATCH 1/2] sched/psi: Create the psimon kthread outside of cgroup_mutex Tejun Heo
2026-07-12 18:00   ` sashiko-bot
2026-07-12 20:26     ` Tejun Heo
2026-07-13 10:51   ` Johannes Weiner
2026-07-13 13:48   ` Matt Fleming
2026-07-13 15:19     ` Suren Baghdasaryan
2026-07-12 17:46 ` [PATCH 2/2] sched/psi: Shut down rtpoll_timer in psi_cgroup_free() Tejun Heo
2026-07-13 10:56   ` Johannes Weiner
2026-07-13 14:07     ` Suren Baghdasaryan
2026-07-13 15:19       ` Suren Baghdasaryan
2026-07-13 13:48   ` Matt Fleming
2026-07-13 13:49 ` [PATCHSET v2] sched/psi: Fix psimon fork deadlock and rtpoll_timer UAF Matt Fleming

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.