From 41216a0385b9d2ff1f42a860109bba286fe9d28b Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Wed, 15 Oct 2025 13:49:05 +0200 Subject: [PATCH] hid-mcp2221: validate message length The message passed to raw_event is of indeterminate length. Check for length before accessing members. Signed-off-by: Oliver Neukum --- drivers/hid/hid-mcp2221.c | 44 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-mcp2221.c b/drivers/hid/hid-mcp2221.c index 33603b019f97..d5e9f7ef8ba8 100644 --- a/drivers/hid/hid-mcp2221.c +++ b/drivers/hid/hid-mcp2221.c @@ -849,12 +849,18 @@ static int mcp2221_raw_event(struct hid_device *hdev, u8 *buf; struct mcp2221 *mcp = hid_get_drvdata(hdev); + if (size <= 0) + goto bail; + 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 < 2) + goto bail; + switch (data[1]) { case MCP2221_SUCCESS: mcp->status = 0; @@ -866,6 +872,8 @@ static int mcp2221_raw_event(struct hid_device *hdev, break; case MCP2221_I2C_PARAM_OR_STATUS: + if (size < 4) + goto bail; switch (data[1]) { case MCP2221_SUCCESS: if ((mcp->txbuf[3] == MCP2221_I2C_SET_SPEED) && @@ -873,6 +881,8 @@ static int mcp2221_raw_event(struct hid_device *hdev, mcp->status = -EAGAIN; break; } + if (size < 21) + goto bail; if (data[20] & MCP2221_I2C_MASK_ADDR_NACK) { mcp->status = -ENXIO; break; @@ -889,12 +899,19 @@ static int mcp2221_raw_event(struct hid_device *hdev, break; case MCP2221_I2C_GET_DATA: + if (size < 2) + goto bail; + switch (data[1]) { case MCP2221_SUCCESS: + if (size < 3) + goto bail; if (data[2] == MCP2221_I2C_ADDR_NACK) { mcp->status = -ENXIO; break; } + if (size < 4) + goto bail; if (!mcp_get_i2c_eng_state(mcp, data, 2) && (data[3] == 0)) { mcp->status = 0; @@ -906,7 +923,9 @@ 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 || + data[3] > size - 4 ) { mcp->status = -EINVAL; break; } @@ -925,8 +944,13 @@ static int mcp2221_raw_event(struct hid_device *hdev, break; case MCP2221_GPIO_GET: + if (size < 2) + goto bail; + switch (data[1]) { case MCP2221_SUCCESS: + if (mcp->gp_idx < size) + goto bail; if ((data[mcp->gp_idx] == MCP2221_ALT_F_NOT_GPIOV) || (data[mcp->gp_idx + 1] == MCP2221_ALT_F_NOT_GPIOD)) { mcp->status = -ENOENT; @@ -942,8 +966,13 @@ static int mcp2221_raw_event(struct hid_device *hdev, break; case MCP2221_GPIO_SET: + if (size < 2) + goto bail; + switch (data[1]) { case MCP2221_SUCCESS: + if (size < mcp->gp_idx) + goto bail; if ((data[mcp->gp_idx] == MCP2221_ALT_F_NOT_GPIOV) || (data[mcp->gp_idx - 1] == MCP2221_ALT_F_NOT_GPIOV)) { mcp->status = -ENOENT; @@ -958,6 +987,9 @@ static int mcp2221_raw_event(struct hid_device *hdev, break; case MCP2221_SET_SRAM_SETTINGS: + if (size < 2) + goto bail; + switch (data[1]) { case MCP2221_SUCCESS: mcp->status = 0; @@ -969,8 +1001,13 @@ static int mcp2221_raw_event(struct hid_device *hdev, break; case MCP2221_GET_SRAM_SETTINGS: + if (size < 2) + goto bail; + switch (data[1]) { case MCP2221_SUCCESS: + if (size < 22 + 4) + goto bail; memcpy(&mcp->mode, &data[22], 4); #if IS_REACHABLE(CONFIG_IIO) mcp->dac_value = data[6] & GENMASK(4, 0); @@ -984,6 +1021,8 @@ static int mcp2221_raw_event(struct hid_device *hdev, break; case MCP2221_READ_FLASH_DATA: + if (size < 2) + goto bail; switch (data[1]) { case MCP2221_SUCCESS: mcp->status = 0; @@ -997,6 +1036,8 @@ static int mcp2221_raw_event(struct hid_device *hdev, #if IS_REACHABLE(CONFIG_IIO) { u8 tmp; + if (size < 8) + goto bail; /* DAC scale value */ tmp = FIELD_GET(GENMASK(7, 6), data[6]); if ((data[6] & BIT(5)) && tmp) @@ -1021,6 +1062,7 @@ static int mcp2221_raw_event(struct hid_device *hdev, break; default: +bail: mcp->status = -EIO; complete(&mcp->wait_in_report); } -- 2.51.0