Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Jie Gan <jie.gan@oss.qualcomm.com>
To: Mohamed Ayman <mohamedaymanworkspace@gmail.com>,
	Suzuki K Poulose <suzuki.poulose@arm.com>,
	Mike Leach <mike.leach@arm.com>,
	James Clark <james.clark@linaro.org>, Leo Yan <leo.yan@arm.com>,
	Alexander Shishkin <alexander.shishkin@linux.intel.com>,
	Sebastian Andrzej Siewior <bigeasy@linutronix.de>,
	Clark Williams <clrkwllms@kernel.org>,
	Steven Rostedt <rostedt@goodmis.org>,
	"moderated list:ARM/CORESIGHT FRAMEWORK AND DRIVERS"
	<coresight@lists.linaro.org>,
	"moderated list:ARM/CORESIGHT FRAMEWORK AND DRIVERS"
	<linux-arm-kernel@lists.infradead.org>,
	open list <linux-kernel@vger.kernel.org>,
	"open list:Real-time Linux (PREEMPT_RT):Keyword:PREEMPT_RT"
	<linux-rt-devel@lists.linux.dev>
Subject: Re: [PATCH] coresight: Fix scheduling while atomic in coresight_device_release()
Date: Mon, 13 Jul 2026 11:07:24 +0800	[thread overview]
Message-ID: <03d9499c-4566-423d-9bdc-ef3efd4f0119@oss.qualcomm.com> (raw)
In-Reply-To: <20260712210446.14290-1-mohamedaymanworkspace@gmail.com>



On 7/13/2026 5:04 AM, Mohamed Ayman wrote:
> Dropping the last reference to a coresight_device can trigger a kernel
> panic on PREEMPT_RT builds due to a "scheduling while atomic" violation.
> 
> When the CPU enters an idle state, coresight_cpu_pm_notify() is invoked
> with local interrupts disabled (atomic context). This function eventually
> calls coresight_put_percpu_source_ref(), which drops the device reference
> via put_device(). If this is the last reference, it triggers the release
> chain:
> 
>    coresight_cpu_pm_notify() (IRQs off)
>      -> coresight_put_percpu_source_ref()
>        -> put_device()
>          -> coresight_device_release()
>            -> free_percpu()
> 
> On a PREEMPT_RT kernel, free_percpu() acquires pcpu_lock, which is
> implemented as a sleeping rt-mutex. Sleeping while in an atomic context
> causes a system crash.
> 
> Fix this by deferring the teardown of the coresight_device to process
> context. Add a work_struct to `struct coresight_device` and use
> schedule_work() inside coresight_device_release() to safely execute
> free_percpu() and kfree() in a worker thread, away from the atomic PM
> notifier path.
> 
> Additionally, remove the redundant raw_spinlock_irqsave guard in

The code diff doesnt include this description.

> coresight_put_percpu_source_ref(). The lock was originally intended to
> protect the per-CPU pointer table, but dropping a reference does not
> touch this table.
> 
> Signed-off-by: Mohamed Ayman <mohamedaymanworkspace@gmail.com>
> ---
>   drivers/hwtracing/coresight/coresight-core.c | 28 +++++++++++++-------
>   include/linux/coresight.h                    |  2 ++
>   2 files changed, 21 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
> index 6d65c43d5..9dbdb2977 100644
> --- a/drivers/hwtracing/coresight/coresight-core.c
> +++ b/drivers/hwtracing/coresight/coresight-core.c
> @@ -165,13 +165,6 @@ void coresight_put_percpu_source_ref(struct coresight_device *csdev)
>   
>   	guard(raw_spinlock_irqsave)(&coresight_dev_lock);
>   
> -	/*
> -	 * TODO: coresight_device_release() is invoked to release resources when
> -	 * the device's refcount reaches zero. It then calls free_percpu(),
> -	 * which acquires pcpu_lock — a sleepable lock when PREEMPT_RT is
> -	 * enabled. Since the raw spinlock coresight_dev_lock is held, this can
> -	 * lead to a potential "scheduling while atomic" issue.
> -	 */
>   	put_device(&csdev->dev);
>   }
>   
> @@ -1257,13 +1250,30 @@ static void coresight_clear_default_sink(struct coresight_device *csdev)
>   	}
>   }
>   
> +static void coresight_device_release_work(struct work_struct *work)
> +{
> +	struct coresight_device *csdev =
> +		container_of(work, struct coresight_device, free_work);
> +
> +	free_percpu(csdev->perf_sink_id_map.cpu_map);
> +	kfree(csdev);
> +}
> +
>   static void coresight_device_release(struct device *dev)
>   {
>   	struct coresight_device *csdev = to_coresight_device(dev);
>   
>   	fwnode_handle_put(csdev->dev.fwnode);
> -	free_percpu(csdev->perf_sink_id_map.cpu_map);
> -	kfree(csdev);
> +
> +	/*
> +	 * This release callback can run with the last reference dropped
> +	 * from atomic/IRQs-off context (e.g. coresight_put_percpu_source_ref()
> +	 * called from the CPU_PM notifier). free_percpu() takes pcpu_lock,
> +	 * which is a sleeping lock under PREEMPT_RT, so defer the actual
> +	 * teardown to process context.
> +	 */
> +	INIT_WORK(&csdev->free_work, coresight_device_release_work);
> +	schedule_work(&csdev->free_work);

Consider the module unload process, the async work can lead to UAF:
For example:

1. unload ETM4X module:
coresight_unregister() -> device_unregister() -> put_device() -> ref 0
-> coresight_device_release() -> schedule_work(&csdev->free_work)

At this point, the release work is only queued, while the ETM4X module 
unload path proceeds as if the release operation has finished.

2. unload the coresight module without flushing the workqueue
3. A UAF occurs when the pending work is eventually executed and 
attempts to free csdev via coresight_device_release_work(), after the 
relevant code or resources have already been unloaded.

We must drain out the workqueue in coresight_exit to close the gap.

Thanks,
Jie

>   }
>   
>   static int coresight_orphan_match(struct device *dev, void *data)
> diff --git a/include/linux/coresight.h b/include/linux/coresight.h
> index ddf18c970..63253f6c4 100644
> --- a/include/linux/coresight.h
> +++ b/include/linux/coresight.h
> @@ -13,6 +13,7 @@
>   #include <linux/perf_event.h>
>   #include <linux/sched.h>
>   #include <linux/platform_device.h>
> +#include <linux/workqueue.h>
>   
>   /* Peripheral id registers (0xFD0-0xFEC) */
>   #define CORESIGHT_PERIPHIDR4	0xfd0
> @@ -293,6 +294,7 @@ struct coresight_device {
>   	struct csdev_access access;
>   	struct device dev;
>   	struct coresight_path *path;
> +	struct work_struct free_work;
>   	atomic_t mode;
>   	int refcnt;
>   	int cpu;



  reply	other threads:[~2026-07-13  3:07 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-12 21:04 [PATCH] coresight: Fix scheduling while atomic in coresight_device_release() Mohamed Ayman
2026-07-13  3:07 ` Jie Gan [this message]
2026-07-13 23:00 ` [PATCH v2] coresight: Fix scheduling while atomic in coresight_put_percpu_source_ref() Mohamed Ayman

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=03d9499c-4566-423d-9bdc-ef3efd4f0119@oss.qualcomm.com \
    --to=jie.gan@oss.qualcomm.com \
    --cc=alexander.shishkin@linux.intel.com \
    --cc=bigeasy@linutronix.de \
    --cc=clrkwllms@kernel.org \
    --cc=coresight@lists.linaro.org \
    --cc=james.clark@linaro.org \
    --cc=leo.yan@arm.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-rt-devel@lists.linux.dev \
    --cc=mike.leach@arm.com \
    --cc=mohamedaymanworkspace@gmail.com \
    --cc=rostedt@goodmis.org \
    --cc=suzuki.poulose@arm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox