Linux-i3c Archive on lore.kernel.org
 help / color / mirror / Atom feed
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

  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