staging:iio:dummy: Fix potential NULL pointer dereference
authorLars-Peter Clausen <lars@metafoo.de>
Wed, 12 Sep 2012 11:06:00 +0000 (12:06 +0100)
committerJonathan Cameron <jic23@kernel.org>
Sat, 22 Sep 2012 09:55:08 +0000 (10:55 +0100)
If the config contains CONFIG_IIO_BUFFER=y and CONFIG_IIO_SIMPLE_DUMMY_BUFFER=n
iio_simple_dummy_configure_buffer() is stubbed out and iio_buffer_register() is
not. As a result we try to register a buffer which has not been configured.
This will causes a NULL pointer deref in iio_buffer_register. To solve this
issue move the iio_buffer_register() call to iio_simple_dummy_configure_buffer(),
so it will only be called if iio_simple_dummy_configure_buffer() has been called.

Reported-by: Fengguang Wu <fengguang.wu@intel.com>
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
drivers/staging/iio/iio_simple_dummy.c
drivers/staging/iio/iio_simple_dummy.h
drivers/staging/iio/iio_simple_dummy_buffer.c

index 029bcc67f1643f3769a70c5614e3b03cb4f66e96..dc6c728ea47a56fe29a3c0f5ce6ed20cda32a95a 100644 (file)
@@ -445,26 +445,20 @@ static int __devinit iio_dummy_probe(int index)
        if (ret < 0)
                goto error_free_device;
 
-       /* Configure buffered capture support. */
-       ret = iio_simple_dummy_configure_buffer(indio_dev);
-       if (ret < 0)
-               goto error_unregister_events;
-
        /*
-        * Register the channels with the buffer, but avoid the output
-        * channel being registered by reducing the number of channels by 1.
+        * Configure buffered capture support and register the channels with the
+        * buffer, but avoid the output channel being registered by reducing the
+        * number of channels by 1.
         */
-       ret = iio_buffer_register(indio_dev, iio_dummy_channels, 5);
+       ret = iio_simple_dummy_configure_buffer(indio_dev, iio_dummy_channels, 5);
        if (ret < 0)
-               goto error_unconfigure_buffer;
+               goto error_unregister_events;
 
        ret = iio_device_register(indio_dev);
        if (ret < 0)
-               goto error_unregister_buffer;
+               goto error_unconfigure_buffer;
 
        return 0;
-error_unregister_buffer:
-       iio_buffer_unregister(indio_dev);
 error_unconfigure_buffer:
        iio_simple_dummy_unconfigure_buffer(indio_dev);
 error_unregister_events:
@@ -499,7 +493,6 @@ static int iio_dummy_remove(int index)
        /* Device specific code to power down etc */
 
        /* Buffered capture related cleanup */
-       iio_buffer_unregister(indio_dev);
        iio_simple_dummy_unconfigure_buffer(indio_dev);
 
        ret = iio_simple_dummy_events_unregister(indio_dev);
@@ -530,6 +523,7 @@ static __init int iio_dummy_init(void)
                instances = 1;
                return -EINVAL;
        }
+
        /* Fake a bus */
        iio_dummy_devs = kcalloc(instances, sizeof(*iio_dummy_devs),
                                 GFP_KERNEL);
index 53975d916fc984134a9fcb5267adffa780146c54..c9e8702caca41890ce5f9f6e14b91ea07f0a4329 100644 (file)
@@ -95,10 +95,12 @@ enum iio_simple_dummy_scan_elements {
 };
 
 #ifdef CONFIG_IIO_SIMPLE_DUMMY_BUFFER
-int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev);
+int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev,
+       const struct iio_chan_spec *channels, unsigned int num_channels);
 void iio_simple_dummy_unconfigure_buffer(struct iio_dev *indio_dev);
 #else
-static inline int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev)
+static inline int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev,
+       const struct iio_chan_spec *channels, unsigned int num_channels)
 {
        return 0;
 };
index 1fd38095b2ca55727530ab9359e36a05851a968b..697d9700db2f698619145363dc4b8a591d67fad4 100644 (file)
@@ -126,7 +126,8 @@ static const struct iio_buffer_setup_ops iio_simple_dummy_buffer_setup_ops = {
        .predisable = &iio_triggered_buffer_predisable,
 };
 
-int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev)
+int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev,
+       const struct iio_chan_spec *channels, unsigned int num_channels)
 {
        int ret;
        struct iio_buffer *buffer;
@@ -182,8 +183,15 @@ int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev)
         * driven by a trigger.
         */
        indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
+
+       ret = iio_buffer_register(indio_dev, channels, num_channels);
+       if (ret)
+               goto error_dealloc_pollfunc;
+
        return 0;
 
+error_dealloc_pollfunc:
+       iio_dealloc_pollfunc(indio_dev->pollfunc);
 error_free_buffer:
        iio_kfifo_free(indio_dev->buffer);
 error_ret:
@@ -197,6 +205,7 @@ error_ret:
  */
 void iio_simple_dummy_unconfigure_buffer(struct iio_dev *indio_dev)
 {
+       iio_buffer_unregister(indio_dev);
        iio_dealloc_pollfunc(indio_dev->pollfunc);
        iio_kfifo_free(indio_dev->buffer);
 }