iio: adc: ina2xx: avoid kthread_stop() with stale task_struct
authorAkinobu Mita <akinobu.mita@gmail.com>
Sun, 24 Jun 2018 15:05:21 +0000 (00:05 +0900)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 4 Oct 2018 00:00:45 +0000 (17:00 -0700)
[ Upstream commit 7d6cd21d82bacab2d1786fe5e989e4815b75d9a3 ]

When the buffer is enabled for ina2xx driver, a dedicated kthread is
invoked to capture mesurement data.  When the buffer is disabled, the
kthread is stopped.

However if the kthread gets register access errors, it immediately exits
and when the malfunctional buffer is disabled, the stale task_struct
pointer is accessed as there is no kthread to be stopped.

A similar issue in the usbip driver is prevented by kthread_get_run and
kthread_stop_put helpers by increasing usage count of the task_struct.
This change applies the same solution.

Cc: Stefan BrĂ¼ns <stefan.bruens@rwth-aachen.de>
Cc: Jonathan Cameron <jic23@kernel.org>
Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
Fixes: c43a102e67db ("iio: ina2xx: add support for TI INA2xx Power Monitors")
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/iio/adc/ina2xx-adc.c

index 59f99b3a180d7332c4bc41f45d14bdbc12ada06c..d5b9f831eba77e0ce32db8f812cee197df7b44a7 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/module.h>
 #include <linux/of_device.h>
 #include <linux/regmap.h>
+#include <linux/sched/task.h>
 #include <linux/util_macros.h>
 
 #include <linux/platform_data/ina2xx.h>
@@ -701,6 +702,7 @@ static int ina2xx_buffer_enable(struct iio_dev *indio_dev)
 {
        struct ina2xx_chip_info *chip = iio_priv(indio_dev);
        unsigned int sampling_us = SAMPLING_PERIOD(chip);
+       struct task_struct *task;
 
        dev_dbg(&indio_dev->dev, "Enabling buffer w/ scan_mask %02x, freq = %d, avg =%u\n",
                (unsigned int)(*indio_dev->active_scan_mask),
@@ -710,11 +712,17 @@ static int ina2xx_buffer_enable(struct iio_dev *indio_dev)
        dev_dbg(&indio_dev->dev, "Async readout mode: %d\n",
                chip->allow_async_readout);
 
-       chip->task = kthread_run(ina2xx_capture_thread, (void *)indio_dev,
-                                "%s:%d-%uus", indio_dev->name, indio_dev->id,
-                                sampling_us);
+       task = kthread_create(ina2xx_capture_thread, (void *)indio_dev,
+                             "%s:%d-%uus", indio_dev->name, indio_dev->id,
+                             sampling_us);
+       if (IS_ERR(task))
+               return PTR_ERR(task);
+
+       get_task_struct(task);
+       wake_up_process(task);
+       chip->task = task;
 
-       return PTR_ERR_OR_ZERO(chip->task);
+       return 0;
 }
 
 static int ina2xx_buffer_disable(struct iio_dev *indio_dev)
@@ -723,6 +731,7 @@ static int ina2xx_buffer_disable(struct iio_dev *indio_dev)
 
        if (chip->task) {
                kthread_stop(chip->task);
+               put_task_struct(chip->task);
                chip->task = NULL;
        }