--- drivers/i2c/i2c-core-smbus.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/i2c/i2c-core-smbus.c b/drivers/i2c/i2c-core-smbus.c --- a/drivers/i2c/i2c-core-smbus.c +++ b/drivers/i2c/i2c-core-smbus.c @@ -576,6 +576,35 @@ s32 __i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, flags &= I2C_M_TEN | I2C_CLIENT_PEC | I2C_CLIENT_SCCB; + /* + * Validate block transfer sizes so that adapters that implement + * native smbus_xfer see the same contract as the emulated path. + */ + if (data) { + switch (protocol) { + case I2C_SMBUS_BLOCK_DATA: + case I2C_SMBUS_I2C_BLOCK_DATA: + if (data->block[0] > I2C_SMBUS_BLOCK_MAX) { + dev_err(&adapter->dev, + "Invalid block size %d (max %d)\n", + data->block[0], I2C_SMBUS_BLOCK_MAX); + return -EINVAL; + } + break; + case I2C_SMBUS_BLOCK_PROC_CALL: + if (read_write == I2C_SMBUS_WRITE && + data->block[0] > I2C_SMBUS_BLOCK_MAX) { + dev_err(&adapter->dev, + "Invalid block write size %d (max %d)\n", + data->block[0], I2C_SMBUS_BLOCK_MAX); + return -EINVAL; + } + break; + default: + break; + } + } + xfer_func = adapter->algo->smbus_xfer; if (i2c_in_atomic_xfer_mode()) { if (adapter->algo->smbus_xfer_atomic)