All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Jiangshan Yi" <yijiangshan@kylinos.cn>
Cc: dmitry.torokhov@gmail.com, linux-input@vger.kernel.org
Subject: Re: [PATCH v2 2/3] HID: mcp2221: clear rxbuf after I2C/SMBus transfer completes
Date: Tue, 28 Jul 2026 13:30:11 +0000	[thread overview]
Message-ID: <20260728133012.2C7401F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260728131442.834604-3-yijiangshan@kylinos.cn>

Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:

New issues:
- [High] Time-Of-Check to Time-Of-Use (TOCTOU) race condition leading to NULL pointer dereference or Use-After-Free.

Pre-existing issues:
- [High] Silent I2C data corruption due to brittle lock-step synchronization.
- [High] Unkillable task hang (infinite loop) on 0-length payload.
- [High] Kernel stack buffer overflow or broken I2C_SMBUS_BLOCK_DATA read due to SMBus API misuse.
- [High] Out-of-bounds read in the HID raw event handler due to missing report size validation.
--

--- Patch [2]: [PATCH v2 2/3] HID: mcp2221: clear rxbuf after I2C/SMBus transfer completes ---
commit 3603851056413fb3957e5edfb92c7c98a7d4fdf4
Author: Jiangshan Yi <yijiangshan@kylinos.cn>
Subject: HID: mcp2221: clear rxbuf after I2C/SMBus transfer completes

This patch clears the caller-supplied buffer pointer in mcp->rxbuf and resets
mcp->rxbuf_size when an I2C/SMBus transfer completes or times out. This aims
to prevent a write use-after-free where a delayed or spurious
MCP2221_I2C_GET_DATA report could memcpy device data into a freed memory
region.

> diff --git a/drivers/hid/hid-mcp2221.c b/drivers/hid/hid-mcp2221.c
> index 5c7fc56c7c671..9e03d1f733ff8 100644
> --- a/drivers/hid/hid-mcp2221.c
> +++ b/drivers/hid/hid-mcp2221.c
> @@ -343,7 +343,7 @@ static int mcp_i2c_smbus_read(struct mcp2221 *mcp,
>  
>  	ret = mcp_send_data_req_status(mcp, mcp->txbuf, 4);
>  	if (ret)
> -		return ret;
> +		goto out;

[Severity: High]
This isn't a bug introduced by this patch, but does the driver's timeout
handling lead to silent data corruption?

When waiting for a report, the driver uses a lock-step timeout:

drivers/hid/hid-mcp2221.c:mcp_send_data_req_status() {
        t = wait_for_completion_timeout(&mcp->wait_in_report,
                                        msecs_to_jiffies(4000));
        if (!t)
                return -ETIMEDOUT;
}

If this times out, the driver starts a new transfer. However, if a delayed HID
report from the timed-out transfer arrives later, mcp2221_raw_event()
unconditionally completes the wait:

drivers/hid/hid-mcp2221.c:mcp2221_raw_event() {
        buf = mcp->rxbuf;
        memcpy(&buf[mcp->rxbuf_idx], &data[4], data[3]);
        mcp->rxbuf_idx = mcp->rxbuf_idx + data[3];
        mcp->status = 0;
        break;
        ...
        complete(&mcp->wait_in_report);
}

Can this wake up the new transfer and mistakenly copy the old, delayed data
into the new transfer's buffer?

>  
>  	mcp->rxbuf_idx = 0;
>  
> @@ -365,7 +365,7 @@ static int mcp_i2c_smbus_read(struct mcp2221 *mcp,
>  			} else {
>  				usleep_range(980, 1000);
>  				mcp_cancel_last_cmd(mcp);
> -				return ret;
> +				goto out;
>  			}
>  		} else {
>  			retries = 0;

[Severity: High]
This is a pre-existing issue, but does this loop risk an unkillable task hang
if a 0-length payload is received?

drivers/hid/hid-mcp2221.c:mcp2221_raw_event() {
        if (!mcp_get_i2c_eng_state(mcp, data, 2)
                && (data[3] == 0)) {
                mcp->status = 0;
                break;
        }
}

If a USB device continuously returns a 0-length payload, mcp2221_raw_event()
sets mcp->status = 0 and calls complete().

The read loop then observes a success and resets retries = 0, but rxbuf_idx
does not advance. Does this cause the loop to spin infinitely?

> @@ -375,6 +375,10 @@ static int mcp_i2c_smbus_read(struct mcp2221 *mcp,
>  	usleep_range(980, 1000);
>  	ret = mcp_chk_last_cmd_status_free_bus(mcp);
>  
> +out:
> +	mcp->rxbuf = NULL;
> +	mcp->rxbuf_size = 0;

[Severity: High]
Could this lockless clearing introduce a Time-Of-Check to Time-Of-Use race?

In mcp2221_raw_event(), which runs asynchronously in softirq context, the
code checks the pointer and then dereferences it:

drivers/hid/hid-mcp2221.c:mcp2221_raw_event() {
        if (!mcp->rxbuf || mcp->rxbuf_idx < 0 || data[3] > 60) {
        ...
        buf = mcp->rxbuf;
        memcpy(&buf[mcp->rxbuf_idx], &data[4], data[3]);
}

If this function clears mcp->rxbuf concurrently after mcp2221_raw_event()
passes the check but before assigning it to buf, couldn't buf become NULL,
causing memcpy() to trigger a panic?

> +
>  	return ret;
>  }

[Severity: High]
This is a pre-existing issue, but does the driver misuse the SMBus API,
potentially causing a kernel stack buffer overflow?

For I2C_SMBUS_BLOCK_DATA reads, the driver uses data->block[0] as the
input read length:

drivers/hid/hid-mcp2221.c:mcp_smbus_xfer() {
        case I2C_SMBUS_BLOCK_DATA:
                if (read_write == I2C_SMBUS_READ) {
                        ...
                        ret = mcp_i2c_smbus_read(mcp, NULL,
                                                MCP2221_I2C_RD_RPT_START,
                                                addr, data->block[0] + 1,
                                                data->block);
}

If an in-kernel driver calls i2c_smbus_read_block_data(), data.block[0] is an
uninitialized stack variable. Does the driver then use this uninitialized
stack garbage as the read length, causing mcp2221_raw_event() to blindly copy
up to 255 bytes into the 34-byte data.block array on the caller's kernel
stack?

[Severity: High]
This isn't a bug introduced by this patch, but does mcp2221_raw_event()
perform out-of-bounds reads due to missing report size validation?

The function receives the size of the incoming HID report but never validates
it before accessing fields far into the buffer:

drivers/hid/hid-mcp2221.c:mcp2221_raw_event() {
#if IS_REACHABLE(CONFIG_IIO)
                memcpy(&mcp->adc_values, &data[50], sizeof(mcp->adc_values));
#endif
...
        case MCP2221_GET_SRAM_SETTINGS:
                switch (data[1]) {
                case MCP2221_SUCCESS:
                        memcpy(&mcp->mode, &data[22], 4);
}

If a malicious USB device presents a HID report descriptor with a very small
report size, will the driver read past the bounds of the allocation on the
kernel heap?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260728131442.834604-1-yijiangshan@kylinos.cn?part=2

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

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-28 13:14 [PATCH v2 0/3] DO-NOT-MERGE: HID: mcp2221: stop device IO before hid_hw_stop and fix UAF/OOB-read Jiangshan Yi
2026-07-28 13:14 ` [PATCH v2 1/3] HID: mcp2221: stop device IO before hid_hw_stop Jiangshan Yi
2026-07-28 13:14 ` [PATCH v2 2/3] HID: mcp2221: clear rxbuf after I2C/SMBus transfer completes Jiangshan Yi
2026-07-28 13:30   ` sashiko-bot [this message]
2026-07-28 13:14 ` [PATCH v2 3/3] HID: mcp2221: validate report size in mcp2221_raw_event() Jiangshan Yi
2026-07-28 13:28   ` 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=20260728133012.2C7401F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=dmitry.torokhov@gmail.com \
    --cc=linux-input@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=yijiangshan@kylinos.cn \
    /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 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.