Commit f097d246 authored by Florian Pradines's avatar Florian Pradines Committed by Jiri Kosina
Browse files

HID: mcp2221: fix OOB write in mcp2221_raw_event()



mcp2221_raw_event() copies device-supplied data into mcp->rxbuf at
offset rxbuf_idx without checking that the copy fits within the
destination buffer. A device responding with up to 60 bytes to a
small I2C/SMBus read can overflow the buffer.

Add a rxbuf_size field to struct mcp2221, set it alongside rxbuf in
mcp_i2c_smbus_read(), and check rxbuf_idx + data[3] <= rxbuf_size
before the memcpy.

Reported-by: default avatarBenoît Sevens <bsevens@google.com>
Signed-off-by: default avatarFlorian Pradines <florian.pradines@gmail.com>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.com>
parent 5f90dcfa
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -128,6 +128,7 @@ struct mcp2221 {
	u8 *rxbuf;
	u8 txbuf[64];
	int rxbuf_idx;
	int rxbuf_size;
	int status;
	u8 cur_i2c_clk_div;
	struct gpio_chip *gc;
@@ -330,12 +331,14 @@ static int mcp_i2c_smbus_read(struct mcp2221 *mcp,
		mcp->txbuf[3] = (u8)(msg->addr << 1);
		total_len = msg->len;
		mcp->rxbuf = msg->buf;
		mcp->rxbuf_size = msg->len;
	} else {
		mcp->txbuf[1] = smbus_len;
		mcp->txbuf[2] = 0;
		mcp->txbuf[3] = (u8)(smbus_addr << 1);
		total_len = smbus_len;
		mcp->rxbuf = smbus_buf;
		mcp->rxbuf_size = smbus_len;
	}

	ret = mcp_send_data_req_status(mcp, mcp->txbuf, 4);
@@ -919,6 +922,10 @@ static int mcp2221_raw_event(struct hid_device *hdev,
					mcp->status = -EINVAL;
					break;
				}
				if (mcp->rxbuf_idx + data[3] > mcp->rxbuf_size) {
					mcp->status = -EINVAL;
					break;
				}
				buf = mcp->rxbuf;
				memcpy(&buf[mcp->rxbuf_idx], &data[4], data[3]);
				mcp->rxbuf_idx = mcp->rxbuf_idx + data[3];