diff options
| author | Krzysztof Kozlowski <k.kozlowski@samsung.com> | 2014-03-18 04:13:00 -0400 |
|---|---|---|
| committer | Jonathan Cameron <jic23@kernel.org> | 2014-03-22 08:22:49 -0400 |
| commit | d0a588a57c2b0748df8307a0865a1bbbf1624c53 (patch) | |
| tree | 38af1f01d38a1b036aef4e9060aea61af1c84336 | |
| parent | 2076a20fc1a06f7b0333c62a2bb4eeeac7ed1bcb (diff) | |
iio: cm36651: Fix i2c client leak and possible NULL pointer dereference
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.kozlowski@samsung.com>
Acked-by: Beomho Seo <beomho.seo@samsung.com>
Cc: stable@vger.kernel.org
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
| -rw-r--r-- | drivers/iio/light/cm36651.c | 22 |
1 files changed, 20 insertions, 2 deletions
diff --git a/drivers/iio/light/cm36651.c b/drivers/iio/light/cm36651.c index a45e07492db3..39fc67e82138 100644 --- a/drivers/iio/light/cm36651.c +++ b/drivers/iio/light/cm36651.c | |||
| @@ -652,7 +652,19 @@ static int cm36651_probe(struct i2c_client *client, | |||
| 652 | cm36651->client = client; | 652 | cm36651->client = client; |
| 653 | cm36651->ps_client = i2c_new_dummy(client->adapter, | 653 | cm36651->ps_client = i2c_new_dummy(client->adapter, |
| 654 | CM36651_I2C_ADDR_PS); | 654 | CM36651_I2C_ADDR_PS); |
| 655 | if (!cm36651->ps_client) { | ||
| 656 | dev_err(&client->dev, "%s: new i2c device failed\n", __func__); | ||
| 657 | ret = -ENODEV; | ||
| 658 | goto error_disable_reg; | ||
| 659 | } | ||
| 660 | |||
| 655 | cm36651->ara_client = i2c_new_dummy(client->adapter, CM36651_ARA); | 661 | cm36651->ara_client = i2c_new_dummy(client->adapter, CM36651_ARA); |
| 662 | if (!cm36651->ara_client) { | ||
| 663 | dev_err(&client->dev, "%s: new i2c device failed\n", __func__); | ||
| 664 | ret = -ENODEV; | ||
| 665 | goto error_i2c_unregister_ps; | ||
| 666 | } | ||
| 667 | |||
| 656 | mutex_init(&cm36651->lock); | 668 | mutex_init(&cm36651->lock); |
| 657 | indio_dev->dev.parent = &client->dev; | 669 | indio_dev->dev.parent = &client->dev; |
| 658 | indio_dev->channels = cm36651_channels; | 670 | indio_dev->channels = cm36651_channels; |
| @@ -664,7 +676,7 @@ static int cm36651_probe(struct i2c_client *client, | |||
| 664 | ret = cm36651_setup_reg(cm36651); | 676 | ret = cm36651_setup_reg(cm36651); |
| 665 | if (ret) { | 677 | if (ret) { |
| 666 | dev_err(&client->dev, "%s: register setup failed\n", __func__); | 678 | dev_err(&client->dev, "%s: register setup failed\n", __func__); |
| 667 | goto error_disable_reg; | 679 | goto error_i2c_unregister_ara; |
| 668 | } | 680 | } |
| 669 | 681 | ||
| 670 | ret = request_threaded_irq(client->irq, NULL, cm36651_irq_handler, | 682 | ret = request_threaded_irq(client->irq, NULL, cm36651_irq_handler, |
| @@ -672,7 +684,7 @@ static int cm36651_probe(struct i2c_client *client, | |||
| 672 | "cm36651", indio_dev); | 684 | "cm36651", indio_dev); |
| 673 | if (ret) { | 685 | if (ret) { |
| 674 | dev_err(&client->dev, "%s: request irq failed\n", __func__); | 686 | dev_err(&client->dev, "%s: request irq failed\n", __func__); |
| 675 | goto error_disable_reg; | 687 | goto error_i2c_unregister_ara; |
| 676 | } | 688 | } |
| 677 | 689 | ||
| 678 | ret = iio_device_register(indio_dev); | 690 | ret = iio_device_register(indio_dev); |
| @@ -685,6 +697,10 @@ static int cm36651_probe(struct i2c_client *client, | |||
| 685 | 697 | ||
| 686 | error_free_irq: | 698 | error_free_irq: |
| 687 | free_irq(client->irq, indio_dev); | 699 | free_irq(client->irq, indio_dev); |
| 700 | error_i2c_unregister_ara: | ||
| 701 | i2c_unregister_device(cm36651->ara_client); | ||
| 702 | error_i2c_unregister_ps: | ||
| 703 | i2c_unregister_device(cm36651->ps_client); | ||
| 688 | error_disable_reg: | 704 | error_disable_reg: |
| 689 | regulator_disable(cm36651->vled_reg); | 705 | regulator_disable(cm36651->vled_reg); |
| 690 | return ret; | 706 | return ret; |
| @@ -698,6 +714,8 @@ static int cm36651_remove(struct i2c_client *client) | |||
| 698 | iio_device_unregister(indio_dev); | 714 | iio_device_unregister(indio_dev); |
| 699 | regulator_disable(cm36651->vled_reg); | 715 | regulator_disable(cm36651->vled_reg); |
| 700 | free_irq(client->irq, indio_dev); | 716 | free_irq(client->irq, indio_dev); |
| 717 | i2c_unregister_device(cm36651->ps_client); | ||
| 718 | i2c_unregister_device(cm36651->ara_client); | ||
| 701 | 719 | ||
| 702 | return 0; | 720 | return 0; |
| 703 | } | 721 | } |
