The SMBus block read path trusts the device-provided count byte and copies that many bytes from the master buffer:
buf[0] = readb(p3); read_count = buf[0]; memcpy_fromio(&buf[1], p3 + 1, read_count);
Without validating 'read_count', a malicious or misbehaving device can cause an out-of-bounds write to the caller's buffer and may also trigger out-of-range MMIO reads beyond the controller's buffer window.
SMBus Block Read returns up to 32 data bytes as per the kernel documentation, so clamp the length to [1, I2C_SMBUS_BLOCK_MAX], verify the caller's buffer has at least 'read_count + 1' bytes available, and defensively ensure it does not exceed the controller buffer. Also break out of the chunking loop after a successful SMBus read.
Return -EPROTO for invalid counts and -EMSGSIZE when the provided buffer is too small.
Fixes: 361693697249 ("i2c: microchip: pci1xxxx: Add driver for I2C host controller in multifunction endpoint of pci1xxxx switch") Cc: stable@vger.kernel.org Signed-off-by: Guangshuo Li lgs201920130244@gmail.com --- drivers/i2c/busses/i2c-mchp-pci1xxxx.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/drivers/i2c/busses/i2c-mchp-pci1xxxx.c b/drivers/i2c/busses/i2c-mchp-pci1xxxx.c index 5ef136c3ecb1..2307c8ec2dc7 100644 --- a/drivers/i2c/busses/i2c-mchp-pci1xxxx.c +++ b/drivers/i2c/busses/i2c-mchp-pci1xxxx.c @@ -880,7 +880,22 @@ static int pci1xxxx_i2c_read(struct pci1xxxx_i2c *i2c, u8 slaveaddr, }
if (i2c->flags & I2C_FLAGS_SMB_BLK_READ) { - buf[0] = readb(p3); + u8 cnt = readb(p3); + + if (!cnt || cnt > I2C_SMBUS_BLOCK_MAX) { + retval = -EPROTO; + goto cleanup; + } + if (cnt > total_len - 1) { + retval = -EMSGSIZE; + goto cleanup; + } + if (cnt > (SMBUS_BUF_MAX_SIZE - 1)) { + retval = -EOVERFLOW; + goto cleanup; + } + + buf[0] = cnt; read_count = buf[0]; memcpy_fromio(&buf[1], p3 + 1, read_count); } else {
linux-stable-mirror@lists.linaro.org