From: sashiko-bot@kernel.org
To: "Tim Michals" <tcmichals@gmail.com>
Cc: linux-sunxi@lists.linux.dev, devicetree@vger.kernel.org,
robh@kernel.org, conor+dt@kernel.org
Subject: Re: [PATCH v3 4/7] remoteproc: sunxi: Add Allwinner A523 XuanTie E906 driver
Date: Sun, 01 Nov 2026 19:24:20 +0000 [thread overview]
Message-ID: <sashiko-outbox-192595@kernel.org> (raw)
In-Reply-To: <20261101185735.762559-5-tcmichals@gmail.com>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] remoteproc: sunxi: missing IRQ sync in sunxi_rproc_stop() races crash handler
- [High] remoteproc: sunxi: race and UAF in sunxi_rproc_vq_work() on notifyids
--
commit f895edd61f6cf2e80a5341959b347c747139fe48
Author: Tim Michals <tcmichals@gmail.com>
remoteproc: sunxi: Add Allwinner A523 XuanTie E906 driver
This commit adds a remoteproc driver for the XuanTie E906 RISC-V core on
Allwinner A523, A527, and T527 SoCs, handling power domains, clocks, resets,
SRAM mappings, memory-region carveouts, mailbox notifications, and crash
reporting.
> diff --git a/drivers/remoteproc/sunxi_rproc.c b/drivers/remoteproc/sunxi_rproc.c
> new file mode 100644
> index 0000000000000..1cee7110f0b8c
> --- /dev/null
> +++ b/drivers/remoteproc/sunxi_rproc.c
> @@ -0,0 +1,855 @@
[ ... ]
> +VISIBLE_IF_KUNIT
> +int sunxi_rproc_vq_notify(int id, void *ptr, void *data)
> +{
> + KUNIT_STATIC_STUB_REDIRECT(sunxi_rproc_vq_notify, id, ptr, data);
> + rproc_vq_interrupt(data, id);
> + return 0;
> +}
> +EXPORT_SYMBOL_IF_KUNIT(sunxi_rproc_vq_notify);
> +
> +/* One channel carries all notifications: check every vring */
> +VISIBLE_IF_KUNIT
> +void sunxi_rproc_vq_work(struct work_struct *work)
> +{
> + struct sunxi_rproc *priv = container_of(work, struct sunxi_rproc, vq_work);
> +
> + idr_for_each(&priv->rproc->notifyids, sunxi_rproc_vq_notify, priv->rproc);
> +}
> +EXPORT_SYMBOL_IF_KUNIT(sunxi_rproc_vq_work);
[Severity: High]
As reported by Sashiko on v2 [1], in drivers/remoteproc/sunxi_rproc.c, can
sunxi_rproc_vq_work() race with rproc_resource_cleanup() during
rproc_shutdown(), rproc_boot_recovery(), or sunxi_rproc_remove() ->
rproc_del() and trigger a use-after-free?
Because priv->mbox_chan stays active across remoteproc stops, crash
recoveries, and throughout rproc_del() in sunxi_rproc_remove(), and neither
sunxi_rproc_stop() nor sunxi_rproc_unprepare() cancels priv->vq_work,
sunxi_rproc_vq_work() can run concurrently with rproc_resource_cleanup().
In sunxi_rproc_vq_work(), idr_for_each() iterates priv->rproc->notifyids
without holding priv->rproc->lock (unlike stm32_rproc_mb_vq_work() or
imx_dsp_rproc_vq_work()) and without RCU read-side protection (which cannot
be held across sunxi_rproc_vq_notify() because rproc_vq_interrupt() invokes
virtqueue callbacks that can sleep):
lib/idr.c:idr_for_each()
radix_tree_for_each_slot(slot, &idr->idr_rt, &iter, 0)
fn(id, rcu_dereference_raw(*slot), data)
While sunxi_rproc_vq_notify() is executing, a concurrent teardown runs:
rproc_resource_cleanup()
platform_device_unregister(rvdev->pdev)
rproc_virtio_remove()
rproc_free_vring()
idr_remove(&rproc->notifyids, rvring->notifyid)
If removing the vring frees the underlying struct radix_tree_node via
call_rcu(), the grace period can finish while sunxi_rproc_vq_notify() sleeps,
leaving radix_tree_next_slot() in idr_for_each() to dereference a freed slot
pointer.
In addition, although __rproc_virtio_del_vqs() clears rvring->vq and runs
synchronize_srcu(&rproc->vq_srcu) during rproc_stop_subdevices(), the rvring
entry stays in rproc->notifyids until platform_device_unregister(rvdev->pdev)
removes it and immediately frees the devm-allocated struct rproc_vdev
without another synchronize_srcu(&rproc->vq_srcu). If rproc_vq_interrupt()
looks up rvring in rproc->notifyids just before idr_remove(), it can
dereference rvring->vq after rvdev has been freed.
Should sunxi_rproc_vq_work() hold mutex_lock(&priv->rproc->lock) around
idr_for_each(), or should the driver synchronize and stop queuing vq_work
before rproc_resource_cleanup() tears down the vrings?
> +
> +/*
> + * Mailbox rx callbacks run in atomic context, but the virtio/rpmsg receive
> + * path takes mutexes, so the vring notifications are handled from a work item.
> + */
> +VISIBLE_IF_KUNIT
> +void sunxi_rproc_mb_rx_callback(struct mbox_client *cl, void *data)
> +{
> + struct sunxi_rproc *priv = container_of(cl, struct sunxi_rproc, cl);
> +
> + queue_work(priv->workqueue, &priv->vq_work);
> +}
> +EXPORT_SYMBOL_IF_KUNIT(sunxi_rproc_mb_rx_callback);
> +
> +VISIBLE_IF_KUNIT
> +irqreturn_t sunxi_rproc_crash_handler(int irq, void *data)
> +{
> + struct sunxi_rproc *priv = data;
> +
> + /*
> + * Stays masked until the next start(); recovery runs stop() first. A
> + * stop() that already disarmed it has disabled the line itself.
> + */
> + if (test_and_clear_bit(SUNXI_RPROC_CRASH_IRQ_ARMED, &priv->flags))
> + disable_irq_nosync(irq);
> +
> + rproc_report_crash(priv->rproc, RPROC_FATAL_ERROR);
> +
> + return IRQ_HANDLED;
> +}
> +EXPORT_SYMBOL_IF_KUNIT(sunxi_rproc_crash_handler);
[ ... ]
> +VISIBLE_IF_KUNIT
> +int sunxi_rproc_start(struct rproc *rproc)
> +{
> + struct sunxi_rproc *priv = rproc->priv;
> + const struct sunxi_rproc_cfg *cfg = priv->cfg;
> + int ret;
> +
> + dev_dbg(priv->dev, "Starting %s core at entry 0x%llx\n",
> + cfg->name, (u64)rproc->bootaddr);
> +
> + if (rproc->bootaddr > U32_MAX)
> + return -EINVAL;
> +
> + /* Program the reset vector and flush it before releasing the core */
> + sunxi_rproc_writel((u32)rproc->bootaddr, priv->cfg_va + cfg->boot_reg_offset);
> + sunxi_rproc_readl(priv->cfg_va + cfg->boot_reg_offset);
> +
> + ret = reset_control_deassert(priv->rst_core);
> + if (ret) {
> + dev_err(priv->dev, "failed to release core reset: %d\n", ret);
> + return ret;
> + }
> +
> + if (priv->crash_irq > 0 &&
> + !test_and_set_bit(SUNXI_RPROC_CRASH_IRQ_ARMED, &priv->flags))
> + enable_irq(priv->crash_irq);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_IF_KUNIT(sunxi_rproc_start);
> +
> +static int sunxi_rproc_stop(struct rproc *rproc)
> +{
> + struct sunxi_rproc *priv = rproc->priv;
> + const struct sunxi_rproc_cfg *cfg = priv->cfg;
> +
> + dev_dbg(priv->dev, "Halting %s core...\n", cfg->name);
> +
> + /* Assert reset so the core stops executing */
> + reset_control_assert(priv->rst_core);
> +
> + if (priv->crash_irq > 0 &&
> + test_and_clear_bit(SUNXI_RPROC_CRASH_IRQ_ARMED, &priv->flags))
> + disable_irq(priv->crash_irq);
> +
> + return 0;
> +}
[Severity: High]
As reported by Sashiko on v2 [2], in drivers/remoteproc/sunxi_rproc.c, what
happens if sunxi_rproc_stop() runs right after sunxi_rproc_crash_handler()
clears SUNXI_RPROC_CRASH_IRQ_ARMED, while the threaded handler is still
executing?
Because sunxi_rproc_crash_handler() is a preemptible IRQ thread, it can clear
SUNXI_RPROC_CRASH_IRQ_ARMED and be preempted before calling
disable_irq_nosync(irq) or rproc_report_crash(priv->rproc, RPROC_FATAL_ERROR):
CPU0 (IRQ thread) CPU1 (rproc_shutdown / recovery)
sunxi_rproc_crash_handler()
test_and_clear_bit(
SUNXI_RPROC_CRASH_IRQ_ARMED,
&priv->flags) -> true
sunxi_rproc_stop()
test_and_clear_bit(
SUNXI_RPROC_CRASH_IRQ_ARMED,
&priv->flags) -> false
/* returns without waiting */
If a subsequent rproc_boot() calls sunxi_rproc_start() before CPU0 reaches
disable_irq_nosync(irq), sunxi_rproc_start() sets SUNXI_RPROC_CRASH_IRQ_ARMED
and calls enable_irq(priv->crash_irq) while the IRQ disable depth is still 0,
triggering an unbalanced enable warning in __enable_irq(). When CPU0 then
runs disable_irq_nosync(irq), the IRQ is left disabled while
SUNXI_RPROC_CRASH_IRQ_ARMED is set, and the next sunxi_rproc_stop() will
increment the disable depth to 2, leaving the crash IRQ permanently masked on
later boots.
Furthermore, because sunxi_rproc_stop() does not call
synchronize_irq(priv->crash_irq) when test_and_clear_bit() returns false, the
in-flight sunxi_rproc_crash_handler() thread can call rproc_report_crash()
after the stop (and a subsequent restart) has already completed.
Should sunxi_rproc_stop() still call synchronize_irq(priv->crash_irq) when
priv->crash_irq > 0 and SUNXI_RPROC_CRASH_IRQ_ARMED was already cleared by
the crash handler?
[1] https://lore.kernel.org/r/20260927003338.CB0E21F000FF@smtp.kernel.org
[2] https://lore.kernel.org/r/20260927003338.CB0E21F000FF@smtp.kernel.org
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261101185735.762559-1-tcmichals@gmail.com?part=4
next prev parent reply other threads:[~2026-11-01 19:24 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-01 18:57 [PATCH v3 0/7] Add Allwinner A523 message box and XuanTie E906 remoteproc support Tim Michals
2026-11-01 18:57 ` [PATCH v3 1/7] dt-bindings: mailbox: Add Allwinner A523 message box Tim Michals
2026-11-01 19:06 ` sashiko-bot
2026-11-02 10:17 ` Krzysztof Kozlowski
2026-11-01 18:57 ` [PATCH v3 2/7] mailbox: sun55i: Add Allwinner A523 message box driver Tim Michals
2026-11-01 19:17 ` sashiko-bot
2026-11-01 18:57 ` [PATCH v3 3/7] dt-bindings: remoteproc: Add Allwinner A523 RISC-V remote processor Tim Michals
2026-11-02 10:19 ` Krzysztof Kozlowski
2026-11-01 18:57 ` [PATCH v3 4/7] remoteproc: sunxi: Add Allwinner A523 XuanTie E906 driver Tim Michals
2026-11-01 19:24 ` sashiko-bot [this message]
2026-11-01 18:57 ` [PATCH v3 5/7] arm64: dts: allwinner: a523: Add message box and remoteproc nodes Tim Michals
2026-11-01 18:57 ` [PATCH v3 6/7] mailbox: sun55i: Add KUnit tests Tim Michals
2026-11-01 18:57 ` [PATCH v3 7/7] remoteproc: sunxi: " Tim Michals
2026-11-01 19:13 ` sashiko-bot
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=sashiko-outbox-192595@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=linux-sunxi@lists.linux.dev \
--cc=robh@kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
--cc=tcmichals@gmail.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