Linux Input/HID development
 help / color / mirror / Atom feed
* [PATCH] HID: mcp2200: validate input report length
@ 2026-07-06  9:09 Pengpeng Hou
  2026-07-06  9:19 ` sashiko-bot
  0 siblings, 1 reply; 2+ messages in thread
From: Pengpeng Hou @ 2026-07-06  9:09 UTC (permalink / raw)
  To: Jiri Kosina; +Cc: Pengpeng, Benjamin Tissoires, linux-input, linux-kernel

From: Pengpeng <pengpeng@iscas.ac.cn>

mcp2200_raw_event() dispatches on the first byte of the HID input
report and overlays the READ_ALL response structure on the same buffer.
The HID core passes the actual report size to the callback, so validate
that the command byte and READ_ALL response fields are present before
reading them.

Reject truncated reports for the pending command instead of reading
beyond the current input report payload.

Signed-off-by: Pengpeng <pengpeng@iscas.ac.cn>
---
 drivers/hid/hid-mcp2200.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/drivers/hid/hid-mcp2200.c b/drivers/hid/hid-mcp2200.c
index dafdd5b4a079..d2f45892dc22 100644
--- a/drivers/hid/hid-mcp2200.c
+++ b/drivers/hid/hid-mcp2200.c
@@ -299,8 +299,19 @@ static int mcp2200_raw_event(struct hid_device *hdev, struct hid_report *report,
 	struct mcp2200 *mcp = hid_get_drvdata(hdev);
 	struct mcp_read_all_resp *all_resp;
 
+	if (size < 1) {
+		mcp->status = -EINVAL;
+		complete(&mcp->wait_in_report);
+		return 0;
+	}
+
 	switch (data[0]) {
 	case READ_ALL:
+		if (size < sizeof(*all_resp)) {
+			mcp->status = -EINVAL;
+			break;
+		}
+
 		all_resp = (struct mcp_read_all_resp *) data;
 		mcp->status = 0;
 		mcp->gpio_inval = all_resp->io_port_val_bmap;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH] HID: mcp2200: validate input report length
  2026-07-06  9:09 [PATCH] HID: mcp2200: validate input report length Pengpeng Hou
@ 2026-07-06  9:19 ` sashiko-bot
  0 siblings, 0 replies; 2+ messages in thread
From: sashiko-bot @ 2026-07-06  9:19 UTC (permalink / raw)
  To: Pengpeng Hou; +Cc: dmitry.torokhov, linux-input

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

Pre-existing issues:
- [High] A raw event arriving immediately after `hid_hw_open` will cause a NULL pointer dereference because driver data and synchronization primitives are not yet initialized.
- [High] Concurrent calls to `mcp_cmd_read_all` can lead to corrupted state, lost wakeups, and data races because `wait_in_report` and shared response fields are not protected by locks during command execution.
- [High] The GPIO chip is managed via devres and unregistered after the HID hardware is stopped, leading to potential use-after-free or invalid hardware accesses.
--

commit d11b6ebfc1ea2a8baf37113e30af821787d261be
Author: Pengpeng <pengpeng@iscas.ac.cn>
Subject: HID: mcp2200: validate input report length

This commit updates mcp2200_raw_event() to validate that the command byte
and response fields are present in the HID input report before accessing
them. It rejects truncated reports instead of reading past the end of the
payload.

> diff --git a/drivers/hid/hid-mcp2200.c b/drivers/hid/hid-mcp2200.c
> index dafdd5b4a0797..d2f45892dc22a 100644
> --- a/drivers/hid/hid-mcp2200.c
> +++ b/drivers/hid/hid-mcp2200.c
> @@ -299,8 +299,19 @@ static int mcp2200_raw_event(struct hid_device *hdev, struct hid_report *report,
>  	struct mcp2200 *mcp = hid_get_drvdata(hdev);
>  	struct mcp_read_all_resp *all_resp;
>  
> +	if (size < 1) {
> +		mcp->status = -EINVAL;

[Severity: High]
This is a pre-existing issue, but is it possible for an interrupt to fire
immediately after hid_hw_open() in mcp2200_probe() and trigger a NULL
pointer dereference here?

If mcp2200_raw_event() is called before hid_set_drvdata() and lock
initialization complete:

drivers/hid/hid-mcp2200.c:mcp2200_probe() {
        ...
        ret = hid_hw_open(hdev);
        ...
        mutex_init(&mcp->lock);
        init_completion(&mcp->wait_in_report);
        hid_set_drvdata(hdev, mcp);
        ...
}

Could mcp be NULL here, leading to a crash when accessing mcp->status?

> +		complete(&mcp->wait_in_report);
> +		return 0;
> +	}
> +
>  	switch (data[0]) {
>  	case READ_ALL:
> +		if (size < sizeof(*all_resp)) {
> +			mcp->status = -EINVAL;
> +			break;
> +		}
> +
>  		all_resp = (struct mcp_read_all_resp *) data;
>  		mcp->status = 0;
>  		mcp->gpio_inval = all_resp->io_port_val_bmap;

[Severity: High]
This isn't a bug introduced by this patch, but can concurrent calls to
mcp_cmd_read_all() lead to corrupted state or lost wakeups?

In mcp_cmd_read_all(), the mutex is released before waiting for the
response:

drivers/hid/hid-mcp2200.c:mcp_cmd_read_all() {
        ...
        mutex_unlock(&mcp->lock);
        t = wait_for_completion_timeout(&mcp->wait_in_report, ...);
        ...
}

Does modifying mcp->status and mcp->gpio_inval locklessly here in
mcp2200_raw_event() create a data race if multiple threads are reading or
writing GPIO state concurrently?

[ ... ]

[Severity: High]
This is a pre-existing issue, but does using devres for the GPIO chip
create a use-after-free risk during device removal?

In mcp2200_probe(), the chip is registered with devres:

drivers/hid/hid-mcp2200.c:mcp2200_probe() {
        ...
        ret = devm_gpiochip_add_data(&hdev->dev, &mcp->gc, mcp);
        ...
}

Then in mcp2200_remove(), the hardware is stopped before the chip is
unregistered:

drivers/hid/hid-mcp2200.c:mcp2200_remove() {
        ...
        hid_hw_close(hdev);
        hid_hw_stop(hdev);
        ...
}

Could a user-space process continue interacting with the GPIO device while
the USB device is physically removed, causing invalid hardware accesses
before devres cleans up the GPIO chip?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260706090932.75673-1-pengpeng@iscas.ac.cn?part=1

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-07-06  9:19 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-06  9:09 [PATCH] HID: mcp2200: validate input report length Pengpeng Hou
2026-07-06  9:19 ` sashiko-bot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox