From: sashiko-bot@kernel.org
To: "Pengpeng Hou" <pengpeng@iscas.ac.cn>
Cc: Frank.Li@kernel.org, imx@lists.linux.dev, linux-i3c@lists.infradead.org
Subject: Re: [PATCH] i3c: master: svc: report timeout waiting for STOP idle
Date: Tue, 23 Jun 2026 06:25:18 +0000 [thread overview]
Message-ID: <20260623062518.7B7B81F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260623060821.23238-1-pengpeng@iscas.ac.cn>
Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
Pre-existing issues:
- [Critical] Missing synchronization between IBI processing and device detachment causes Use-After-Free.
- [Critical] Stack Buffer Overflow during Dynamic Address Assignment (DAA).
- [Critical] Heap Buffer Overflow in IBI payload reading loop.
- [High] Use of sleeping polling macro in atomic/hardirq context.
- [High] DDR write payload is written twice to the FIFO when SVC_I3C_QUIRK_FIFO_EMPTY is active.
- [High] Hard lockup (infinite loop) in hardirq handler if hardware reports RX pending without bytes.
- [High] Endianness Portability Bug (Mixed I/O accessors on FIFO).
--
commit f5ce1c99dd938b33fc88fc935174301f58c2a87a
Author: Pengpeng Hou <pengpeng@iscas.ac.cn>
i3c: master: svc: report timeout waiting for STOP idle
The commit modifies svc_i3c_master_xfer() to capture the return value
of readl_poll_timeout() when waiting for the controller state to become
idle. It routes the error through the cleanup path to ensure the caller
observes the failed transfer.
> diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c
> index 93805df8a9406..ae38ceee5abf8 100644
> --- a/drivers/i3c/master/svc-i3c-master.c
> +++ b/drivers/i3c/master/svc-i3c-master.c
> @@ -1488,8 +1488,11 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master,
> svc_i3c_master_emit_force_exit(master);
>
> /* Wait idle if stop is sent. */
> - readl_poll_timeout(master->regs + SVC_I3C_MSTATUS, reg,
> - SVC_I3C_MSTATUS_STATE_IDLE(reg), 0, 1000);
> + ret = readl_poll_timeout(master->regs + SVC_I3C_MSTATUS, reg,
> + SVC_I3C_MSTATUS_STATE_IDLE(reg),
> + 0, 1000);
[Severity: High]
This isn't a bug introduced by this patch, but does this code use a
sleeping polling macro in an atomic context?
The readl_poll_timeout macro uses ktime_get() for non-zero timeouts.
Calling this from an atomic context, such as while holding a spinlock
with interrupts disabled, can cause kernel deadlocks when
CONFIG_DEBUG_ATOMIC_SLEEP is enabled.
This also appears in svc_i3c_master_handle_ibi() where
readl_relaxed_poll_timeout() is used inside a hardirq handler.
> + if (ret)
> + goto cleanup;
> }
>
> return 0;
> @@ -1500,6 +1503,7 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master,
> else
> svc_i3c_master_emit_force_exit(master);
>
> +cleanup:
> svc_i3c_master_clear_merrwarn(master);
> svc_i3c_master_flush_fifo(master);
While reviewing this file, I noticed a few other pre-existing issues:
[Severity: High]
This is a pre-existing issue, but does this code write the DDR payload to
the FIFO twice when the SVC_I3C_QUIRK_FIFO_EMPTY quirk is active?
In svc_i3c_master_xfer(), if the transfer is SVC_I3C_MCTRL_TYPE_DDR and
is a write, the full payload is pushed into the FIFO:
drivers/i3c/master/svc-i3c-master.c:svc_i3c_master_xfer() {
...
if (xfer_type == SVC_I3C_MCTRL_TYPE_DDR) {
writel(rnw_cmd, master->regs + SVC_I3C_MWDATAB);
if (!rnw) {
ret = svc_i3c_master_write(master, out, xfer_len);
...
}
However, xfer_len is not modified. Later, the quirk workaround triggers
and pushes the same payload bytes into the FIFO again:
drivers/i3c/master/svc-i3c-master.c:svc_i3c_master_xfer() {
...
if (svc_has_quirk(master, SVC_I3C_QUIRK_FIFO_EMPTY) && !rnw && xfer_len) {
...
writesb(master->regs + SVC_I3C_MWDATAB1, out, len - 1);
...
}
[Severity: High]
This is a pre-existing issue, but does this code mix stream and register
I/O accessors on the same FIFO, potentially causing data corruption on
big-endian architectures?
The subsystem architecture guidelines explicitly forbid mixing accessors
like writesb() and writel() on the same FIFO address because register
accessors perform implicit byte-swapping while stream accessors do not.
In svc_i3c_master_xfer(), both are mixed for bulk and remainder writes:
drivers/i3c/master/svc-i3c-master.c:svc_i3c_master_xfer() {
...
writesb(master->regs + SVC_I3C_MWDATAB1, out, len - 1);
/* Mark END bit if this is the last byte */
writel(out[len - 1] | end, master->regs + SVC_I3C_MWDATAB);
...
}
Similarly, readsb() is used in svc_i3c_master_handle_ibi() on the RX FIFO,
whereas svc_i3c_master_read() uses readl() on the same FIFO.
[Severity: Critical]
This is a pre-existing issue, but is there missing synchronization between
IBI processing and device detachment that could cause a use-after-free?
In svc_i3c_master_ibi_isr(), the device descriptor is fetched under
master->ibi.lock, but the lock is dropped before handling the IBI:
drivers/i3c/master/svc-i3c-master.c:svc_i3c_master_ibi_isr() {
...
spin_lock(&master->ibi.lock);
dev = master->ibi.slots[ibiaddr];
spin_unlock(&master->ibi.lock);
...
svc_i3c_master_handle_ibi(master, dev);
...
}
If the I3C core detaches the device concurrently,
svc_i3c_master_detach_i3c_dev() can free the device data without
synchronizing against the IRQ handler:
drivers/i3c/master/svc-i3c-master.c:svc_i3c_master_detach_i3c_dev() {
...
kfree(data);
...
}
[Severity: Critical]
This is a pre-existing issue, but does this code lack bounds checking on
dev_nb, potentially causing a stack buffer overflow?
The svc_i3c_master_do_daa_locked() function defines fixed-size arrays on
the stack for up to SVC_I3C_MAX_DEVS (32) devices:
drivers/i3c/master/svc-i3c-master.c:svc_i3c_master_do_daa_locked() {
u64 prov_id[SVC_I3C_MAX_DEVS] = {}, nacking_prov_id = 0;
unsigned int dev_nb = 0, last_addr = 0, dyn_addr = 0;
...
}
The loop assigns addresses to responding devices and writes to these arrays
using dev_nb without verifying it hasn't exceeded the array bounds:
drivers/i3c/master/svc-i3c-master.c:svc_i3c_master_do_daa_locked() {
...
addrs[dev_nb] = dyn_addr;
...
dev_nb++;
...
}
[Severity: Critical]
This is a pre-existing issue, but does the loop draining the hardware
RX FIFO use a hardcoded bound that could exceed the dynamically allocated
buffer size?
The slot->data buffer is allocated based on the device's max_payload_len,
which can be small. However, the loop condition checks against
SVC_I3C_FIFO_SIZE (16 bytes):
drivers/i3c/master/svc-i3c-master.c:svc_i3c_master_handle_ibi() {
...
while (SVC_I3C_MSTATUS_RXPEND(readl(master->regs + SVC_I3C_MSTATUS)) &&
slot->len < SVC_I3C_FIFO_SIZE) {
...
count = SVC_I3C_MDATACTRL_RXCOUNT(mdatactrl);
readsb(master->regs + SVC_I3C_MRDATAB, buf, count);
slot->len += count;
...
}
Because the check evaluates slot->len < 16 before adding count (which
can also be up to 16 bytes), up to 31 bytes could be written to a buffer
that might only be 1 or 2 bytes long.
[Severity: High]
This is a pre-existing issue, but could this loop cause a hard lockup in
the hardirq handler if the hardware reports RXPEND is true but RXCOUNT
is 0?
drivers/i3c/master/svc-i3c-master.c:svc_i3c_master_handle_ibi() {
...
while (SVC_I3C_MSTATUS_RXPEND(readl(master->regs + SVC_I3C_MSTATUS)) &&
slot->len < SVC_I3C_FIFO_SIZE) {
...
count = SVC_I3C_MDATACTRL_RXCOUNT(mdatactrl);
readsb(master->regs + SVC_I3C_MRDATAB, buf, count);
slot->len += count;
buf += count;
}
...
}
The loop relies entirely on the hardware state to terminate. If RXCOUNT
is 0, count will be 0, slot->len will not increase, and the loop will
spin indefinitely.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260623060821.23238-1-pengpeng@iscas.ac.cn?part=1
--
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c
next prev parent reply other threads:[~2026-06-23 6:25 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-23 6:08 [PATCH] i3c: master: svc: report timeout waiting for STOP idle Pengpeng Hou
2026-06-23 6:25 ` sashiko-bot [this message]
2026-06-23 9:16 ` Miquel Raynal
2026-06-23 14:23 ` Frank Li
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=20260623062518.7B7B81F000E9@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=Frank.Li@kernel.org \
--cc=imx@lists.linux.dev \
--cc=linux-i3c@lists.infradead.org \
--cc=pengpeng@iscas.ac.cn \
--cc=sashiko-reviews@lists.linux.dev \
/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