Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

staging:iio:dummy: Fix potential NULL pointer dereference

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>

authored by

Lars-Peter Clausen and committed by
Jonathan Cameron
3fff2274 e60fea79

+22 -17
+8 -14
drivers/staging/iio/iio_simple_dummy.c
··· 445 445 if (ret < 0) 446 446 goto error_free_device; 447 447 448 - /* Configure buffered capture support. */ 449 - ret = iio_simple_dummy_configure_buffer(indio_dev); 448 + /* 449 + * Configure buffered capture support and register the channels with the 450 + * buffer, but avoid the output channel being registered by reducing the 451 + * number of channels by 1. 452 + */ 453 + ret = iio_simple_dummy_configure_buffer(indio_dev, iio_dummy_channels, 5); 450 454 if (ret < 0) 451 455 goto error_unregister_events; 452 456 453 - /* 454 - * Register the channels with the buffer, but avoid the output 455 - * channel being registered by reducing the number of channels by 1. 456 - */ 457 - ret = iio_buffer_register(indio_dev, iio_dummy_channels, 5); 457 + ret = iio_device_register(indio_dev); 458 458 if (ret < 0) 459 459 goto error_unconfigure_buffer; 460 460 461 - ret = iio_device_register(indio_dev); 462 - if (ret < 0) 463 - goto error_unregister_buffer; 464 - 465 461 return 0; 466 - error_unregister_buffer: 467 - iio_buffer_unregister(indio_dev); 468 462 error_unconfigure_buffer: 469 463 iio_simple_dummy_unconfigure_buffer(indio_dev); 470 464 error_unregister_events: ··· 493 499 /* Device specific code to power down etc */ 494 500 495 501 /* Buffered capture related cleanup */ 496 - iio_buffer_unregister(indio_dev); 497 502 iio_simple_dummy_unconfigure_buffer(indio_dev); 498 503 499 504 ret = iio_simple_dummy_events_unregister(indio_dev); ··· 523 530 instances = 1; 524 531 return -EINVAL; 525 532 } 533 + 526 534 /* Fake a bus */ 527 535 iio_dummy_devs = kcalloc(instances, sizeof(*iio_dummy_devs), 528 536 GFP_KERNEL);
+4 -2
drivers/staging/iio/iio_simple_dummy.h
··· 95 95 }; 96 96 97 97 #ifdef CONFIG_IIO_SIMPLE_DUMMY_BUFFER 98 - int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev); 98 + int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev, 99 + const struct iio_chan_spec *channels, unsigned int num_channels); 99 100 void iio_simple_dummy_unconfigure_buffer(struct iio_dev *indio_dev); 100 101 #else 101 - static inline int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev) 102 + static inline int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev, 103 + const struct iio_chan_spec *channels, unsigned int num_channels) 102 104 { 103 105 return 0; 104 106 };
+10 -1
drivers/staging/iio/iio_simple_dummy_buffer.c
··· 126 126 .predisable = &iio_triggered_buffer_predisable, 127 127 }; 128 128 129 - int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev) 129 + int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev, 130 + const struct iio_chan_spec *channels, unsigned int num_channels) 130 131 { 131 132 int ret; 132 133 struct iio_buffer *buffer; ··· 183 182 * driven by a trigger. 184 183 */ 185 184 indio_dev->modes |= INDIO_BUFFER_TRIGGERED; 185 + 186 + ret = iio_buffer_register(indio_dev, channels, num_channels); 187 + if (ret) 188 + goto error_dealloc_pollfunc; 189 + 186 190 return 0; 187 191 192 + error_dealloc_pollfunc: 193 + iio_dealloc_pollfunc(indio_dev->pollfunc); 188 194 error_free_buffer: 189 195 iio_kfifo_free(indio_dev->buffer); 190 196 error_ret: ··· 205 197 */ 206 198 void iio_simple_dummy_unconfigure_buffer(struct iio_dev *indio_dev) 207 199 { 200 + iio_buffer_unregister(indio_dev); 208 201 iio_dealloc_pollfunc(indio_dev->pollfunc); 209 202 iio_kfifo_free(indio_dev->buffer); 210 203 }