On 06/03/14 09:33, Krzysztof Kozlowski wrote:
During probe the driver allocates dummy I2C devices (i2c_new_dummy())
but they aren't unregistered during driver remove or probe failure.

Additionally driver does not check the return value of i2c_new_dummy().
In case of error (i2c_new_device(): memory allocation failure or I2C
address cannot be used) this function returns NULL which is later
dereferenced by i2c_smbus_{read,write}_data() functions.

Fix issues by properly checking for i2c_new_dummy() return value and
unregistering I2C devices on driver remove or probe failure.

Signed-off-by: Krzysztof Kozlowski <k.kozlow...@samsung.com>
Good catch, but the error path needs more care.
---
  drivers/iio/light/cm36651.c |   12 ++++++++++++
  1 file changed, 12 insertions(+)

diff --git a/drivers/iio/light/cm36651.c b/drivers/iio/light/cm36651.c
index a45e07492db3..e7e9a597159f 100644
--- a/drivers/iio/light/cm36651.c
+++ b/drivers/iio/light/cm36651.c
@@ -653,6 +653,11 @@ static int cm36651_probe(struct i2c_client *client,
        cm36651->ps_client = i2c_new_dummy(client->adapter,
                                                     CM36651_I2C_ADDR_PS);
        cm36651->ara_client = i2c_new_dummy(client->adapter, CM36651_ARA);
+       if (!cm36651->ps_client || !cm36651->ara_client) {
+               dev_err(&client->dev, "%s: new i2c device failed\n", __func__);
+               ret = -ENODEV;
+               goto error_i2c_unregister;
+       }
The two failures need to be handled independently as we only want to unregister
those that succeeded.  i2c_new_dummy will not return an error and leave a device
registered.  This is particularly true given the first thing that 
i2c_unregister_device
does is to derefence the client pointer.  That will cause a segfault if you do 
it
for NULL as here.

        mutex_init(&cm36651->lock);
        indio_dev->dev.parent = &client->dev;
        indio_dev->channels = cm36651_channels;
@@ -687,6 +692,11 @@ error_free_irq:
        free_irq(client->irq, indio_dev);
  error_disable_reg:
        regulator_disable(cm36651->vled_reg);
+error_i2c_unregister:
+       if (cm36651->ps_client)
+               i2c_unregister_device(cm36651->ps_client);
+       if (cm36651->ara_client)
+               i2c_unregister_device(cm36651->ara_client);
        return ret;
  }

@@ -698,6 +708,8 @@ static int cm36651_remove(struct i2c_client *client)
        iio_device_unregister(indio_dev);
        regulator_disable(cm36651->vled_reg);
        free_irq(client->irq, indio_dev);
+       i2c_unregister_device(cm36651->ps_client);
+       i2c_unregister_device(cm36651->ara_client);
Good catch.

        return 0;
  }


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to