* [PATCH 2/4] HID: corsair-void: fix out-of-bounds read in corsair_void_raw_event
2026-07-14 13:16 [PATCH 1/4] HID: cougar: fix out-of-bounds read in cougar_raw_event Jiale Yao
@ 2026-07-14 13:16 ` Jiale Yao
2026-07-17 22:55 ` Stuart Hayhurst
2026-07-14 13:16 ` [PATCH 3/4] HID: mcp2221: fix out-of-bounds read in mcp2221_raw_event Jiale Yao
2026-07-14 13:16 ` [PATCH 4/4] HID: cp2112: fix out-of-bounds read in cp2112_raw_event Jiale Yao
2 siblings, 1 reply; 5+ messages in thread
From: Jiale Yao @ 2026-07-14 13:16 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires, linux-input, linux-kernel; +Cc: Jiale Yao
Both the STATUS_REPORT and FIRMWARE_REPORT paths access data[4].
Add a size < 5 guard before the report dispatch.
Assisted-by: Claude:deepseek-v4-pro
Signed-off-by: Jiale Yao <yaojiale02@163.com>
---
drivers/hid/hid-corsair-void.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/hid/hid-corsair-void.c b/drivers/hid/hid-corsair-void.c
index 5e9a5b8f7f16..7c5435de6aae 100644
--- a/drivers/hid/hid-corsair-void.c
+++ b/drivers/hid/hid-corsair-void.c
@@ -740,6 +740,8 @@ static int corsair_void_raw_event(struct hid_device *hid_dev,
struct corsair_void_drvdata *drvdata = hid_get_drvdata(hid_dev);
bool was_connected = drvdata->connected;
+ if (size < 5)
+ return 0;
/* Description of packets are documented at the top of this file */
if (hid_report->id == CORSAIR_VOID_STATUS_REPORT_ID) {
drvdata->mic_up = FIELD_GET(CORSAIR_VOID_MIC_MASK, data[2]);
--
2.34.1
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [PATCH 2/4] HID: corsair-void: fix out-of-bounds read in corsair_void_raw_event
2026-07-14 13:16 ` [PATCH 2/4] HID: corsair-void: fix out-of-bounds read in corsair_void_raw_event Jiale Yao
@ 2026-07-17 22:55 ` Stuart Hayhurst
0 siblings, 0 replies; 5+ messages in thread
From: Stuart Hayhurst @ 2026-07-17 22:55 UTC (permalink / raw)
To: Jiale Yao, Jiri Kosina, Benjamin Tissoires, linux-input,
linux-kernel, stuart.a.hayhurst
Hi,
Looking through this, I had a couple thoughts:
- It should send a warning for unexpected sizes, since most likely
it's a format we haven't seen yet
- 5 is a bit of a magic number, especially as some packets of other
sizes pass through, but we don't do anything with them (yet?)
- AFAIK returning 0 indicates everything was OK, when actually we
bailed out. By convention, shouldn't this return 1 on failure?
The patch I submitted a few weeks ago handled these:
https://lore.kernel.org/all/20260630010656.626157-3-stuart.a.hayhurst@gmail.com/
Stuart
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 3/4] HID: mcp2221: fix out-of-bounds read in mcp2221_raw_event
2026-07-14 13:16 [PATCH 1/4] HID: cougar: fix out-of-bounds read in cougar_raw_event Jiale Yao
2026-07-14 13:16 ` [PATCH 2/4] HID: corsair-void: fix out-of-bounds read in corsair_void_raw_event Jiale Yao
@ 2026-07-14 13:16 ` Jiale Yao
2026-07-14 13:16 ` [PATCH 4/4] HID: cp2112: fix out-of-bounds read in cp2112_raw_event Jiale Yao
2 siblings, 0 replies; 5+ messages in thread
From: Jiale Yao @ 2026-07-14 13:16 UTC (permalink / raw)
To: Rishi Gupta, Jiri Kosina, Benjamin Tissoires, linux-i2c,
linux-input, linux-kernel
Cc: Jiale Yao
The handler dispatches on data[0] without checking size >= 1.
Add a top-level guard and per-case minimum-size checks:
data[2] for the I2C_WR_DATA group, data[20] and
data[50+sizeof(adc_values)] for I2C_PARAM_OR_STATUS,
sizeof(struct mcp_get/set_gpio) for GPIO paths,
and 4+data[3] for the I2C_GET_DATA partial-read memcpy.
Assisted-by: Claude:deepseek-v4-pro
Signed-off-by: Jiale Yao <yaojiale02@163.com>
---
drivers/hid/hid-mcp2221.c | 26 +++++++++++++++++++++++++-
1 file changed, 25 insertions(+), 1 deletion(-)
diff --git a/drivers/hid/hid-mcp2221.c b/drivers/hid/hid-mcp2221.c
index e4ddd8e9293b..0423b5affe8f 100644
--- a/drivers/hid/hid-mcp2221.c
+++ b/drivers/hid/hid-mcp2221.c
@@ -861,12 +861,17 @@ static int mcp2221_raw_event(struct hid_device *hdev,
u8 *buf;
struct mcp2221 *mcp = hid_get_drvdata(hdev);
+ if (size < 1)
+ return 1;
+
switch (data[0]) {
case MCP2221_I2C_WR_DATA:
case MCP2221_I2C_WR_NO_STOP:
case MCP2221_I2C_RD_DATA:
case MCP2221_I2C_RD_RPT_START:
+ if (size < 3)
+ return 1;
switch (data[1]) {
case MCP2221_SUCCESS:
mcp->status = 0;
@@ -878,6 +883,12 @@ static int mcp2221_raw_event(struct hid_device *hdev,
break;
case MCP2221_I2C_PARAM_OR_STATUS:
+ if (size < 21)
+ return 1;
+#if IS_REACHABLE(CONFIG_IIO)
+ if (size < 50 + sizeof(mcp->adc_values))
+ return 1;
+#endif
switch (data[1]) {
case MCP2221_SUCCESS:
if ((mcp->txbuf[3] == MCP2221_I2C_SET_SPEED) &&
@@ -901,6 +912,8 @@ static int mcp2221_raw_event(struct hid_device *hdev,
break;
case MCP2221_I2C_GET_DATA:
+ if (size < 4)
+ return 1;
switch (data[1]) {
case MCP2221_SUCCESS:
if (data[2] == MCP2221_I2C_ADDR_NACK) {
@@ -918,7 +931,8 @@ static int mcp2221_raw_event(struct hid_device *hdev,
}
if (data[2] == MCP2221_I2C_READ_COMPL ||
data[2] == MCP2221_I2C_READ_PARTIAL) {
- if (!mcp->rxbuf || mcp->rxbuf_idx < 0 || data[3] > 60) {
+ if (!mcp->rxbuf || mcp->rxbuf_idx < 0 ||
+ data[3] > 60 || size < 4 + data[3]) {
mcp->status = -EINVAL;
break;
}
@@ -941,6 +955,8 @@ static int mcp2221_raw_event(struct hid_device *hdev,
break;
case MCP2221_GPIO_GET:
+ if (size < sizeof(struct mcp_get_gpio))
+ return 1;
switch (data[1]) {
case MCP2221_SUCCESS:
if ((data[mcp->gp_idx] == MCP2221_ALT_F_NOT_GPIOV) ||
@@ -958,6 +974,8 @@ static int mcp2221_raw_event(struct hid_device *hdev,
break;
case MCP2221_GPIO_SET:
+ if (size < sizeof(struct mcp_set_gpio))
+ return 1;
switch (data[1]) {
case MCP2221_SUCCESS:
if ((data[mcp->gp_idx] == MCP2221_ALT_F_NOT_GPIOV) ||
@@ -974,6 +992,8 @@ static int mcp2221_raw_event(struct hid_device *hdev,
break;
case MCP2221_SET_SRAM_SETTINGS:
+ if (size < 2)
+ return 1;
switch (data[1]) {
case MCP2221_SUCCESS:
mcp->status = 0;
@@ -985,6 +1005,8 @@ static int mcp2221_raw_event(struct hid_device *hdev,
break;
case MCP2221_GET_SRAM_SETTINGS:
+ if (size < 26)
+ return 1;
switch (data[1]) {
case MCP2221_SUCCESS:
memcpy(&mcp->mode, &data[22], 4);
@@ -1000,6 +1022,8 @@ static int mcp2221_raw_event(struct hid_device *hdev,
break;
case MCP2221_READ_FLASH_DATA:
+ if (size < 8)
+ return 1;
switch (data[1]) {
case MCP2221_SUCCESS:
mcp->status = 0;
--
2.34.1
^ permalink raw reply [flat|nested] 5+ messages in thread* [PATCH 4/4] HID: cp2112: fix out-of-bounds read in cp2112_raw_event
2026-07-14 13:16 [PATCH 1/4] HID: cougar: fix out-of-bounds read in cougar_raw_event Jiale Yao
2026-07-14 13:16 ` [PATCH 2/4] HID: corsair-void: fix out-of-bounds read in corsair_void_raw_event Jiale Yao
2026-07-14 13:16 ` [PATCH 3/4] HID: mcp2221: fix out-of-bounds read in mcp2221_raw_event Jiale Yao
@ 2026-07-14 13:16 ` Jiale Yao
2 siblings, 0 replies; 5+ messages in thread
From: Jiale Yao @ 2026-07-14 13:16 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires, linux-input, linux-kernel; +Cc: Jiale Yao
The TRANSFER_STATUS_RESPONSE path dereferences xfer->length at
offset 6, requiring sizeof(*xfer) bytes. The DATA_READ_RESPONSE
path uses the device-supplied read_length to drive memcpy()
without clamping it to the remaining report size. Add both
checks, and clamp read_length to size - 3.
Assisted-by: Claude:deepseek-v4-pro
Signed-off-by: Jiale Yao <yaojiale02@163.com>
---
drivers/hid/hid-cp2112.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/drivers/hid/hid-cp2112.c b/drivers/hid/hid-cp2112.c
index 04379db93571..99e31724a421 100644
--- a/drivers/hid/hid-cp2112.c
+++ b/drivers/hid/hid-cp2112.c
@@ -1430,6 +1430,11 @@ static int cp2112_raw_event(struct hid_device *hdev, struct hid_report *report,
switch (data[0]) {
case CP2112_TRANSFER_STATUS_RESPONSE:
+ if (size < sizeof(*xfer)) {
+ hid_err(hdev, "short transfer status report(%d < %zu)\n", size,
+ sizeof(*xfer));
+ return 0;
+ }
hid_dbg(hdev, "xfer status: %02x %02x %04x %04x\n",
xfer->status0, xfer->status1,
be16_to_cpu(xfer->retries), be16_to_cpu(xfer->length));
@@ -1463,12 +1468,18 @@ static int cp2112_raw_event(struct hid_device *hdev, struct hid_report *report,
atomic_set(&dev->xfer_avail, 1);
break;
case CP2112_DATA_READ_RESPONSE:
+ if (size < 4) {
+ hid_err(hdev, "short data read response(%d < 4)\n", size);
+ return 0;
+ }
hid_dbg(hdev, "read response: %02x %02x\n", data[1], data[2]);
dev->read_length = data[2];
if (dev->read_length > sizeof(dev->read_data))
dev->read_length = sizeof(dev->read_data);
+ if (dev->read_length > size - 3)
+ dev->read_length = size - 3;
memcpy(dev->read_data, &data[3], dev->read_length);
atomic_set(&dev->read_avail, 1);
break;
--
2.34.1
^ permalink raw reply [flat|nested] 5+ messages in thread