i2c: core-smbus: prevent stack corruption on read I2C_BLOCK_DATA
[pandora-kernel.git] / drivers / i2c / i2c-core.c
index 131079a..8d96a47 100644 (file)
@@ -539,8 +539,10 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
        client->dev.type = &i2c_client_type;
        client->dev.of_node = info->of_node;
 
+       /* For 10-bit clients, add an arbitrary offset to avoid collisions */
        dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap),
-                    client->addr);
+                    client->addr | ((client->flags & I2C_CLIENT_TEN)
+                                    ? 0xa000 : 0));
        status = device_register(&client->dev);
        if (status)
                goto out_err;
@@ -1137,6 +1139,7 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
        /* add the driver to the list of i2c drivers in the driver core */
        driver->driver.owner = owner;
        driver->driver.bus = &i2c_bus_type;
+       INIT_LIST_HEAD(&driver->clients);
 
        /* When registration returns, the driver core
         * will have called probe() for all matching-but-unbound devices.
@@ -1155,7 +1158,6 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
 
        pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
 
-       INIT_LIST_HEAD(&driver->clients);
        /* Walk the adapters that are already present */
        i2c_for_each_dev(driver, __process_new_driver);
 
@@ -2007,16 +2009,17 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,
                                   the underlying bus driver */
                break;
        case I2C_SMBUS_I2C_BLOCK_DATA:
+               if (data->block[0] > I2C_SMBUS_BLOCK_MAX) {
+                       dev_err(&adapter->dev, "Invalid block %s size %d\n",
+                               read_write == I2C_SMBUS_READ ? "read" : "write",
+                               data->block[0]);
+                       return -EINVAL;
+               }
+
                if (read_write == I2C_SMBUS_READ) {
                        msg[1].len = data->block[0];
                } else {
                        msg[0].len = data->block[0] + 1;
-                       if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 1) {
-                               dev_err(&adapter->dev,
-                                       "Invalid block write size %d\n",
-                                       data->block[0]);
-                               return -EINVAL;
-                       }
                        for (i = 1; i <= data->block[0]; i++)
                                msgbuf0[i] = data->block[i];
                }