* [PATCH 0/7] iio: fix possible race condition during access of available info lists
@ 2024-10-03 17:34 Matteo Martelli
2024-10-03 17:34 ` [PATCH 1/7] iio: core: add read_avail_release_resource callback to fix race Matteo Martelli
` (7 more replies)
0 siblings, 8 replies; 13+ messages in thread
From: Matteo Martelli @ 2024-10-03 17:34 UTC (permalink / raw)
To: Jonathan Cameron, Lars-Peter Clausen, Michael Hennerich,
Alisa-Dariana Roman, Christian Eggers, Peter Rosin, Paul Cercueil,
Sebastian Reichel
Cc: linux-iio, linux-kernel, linux-mips, linux-pm, Matteo Martelli
Some iio drivers currently share an available info list buffer that
might be changed while iio core prints it to sysfs. This could cause the
buffer shared with iio core to be corrupted. However, note that I was
able to trigger the race condition only by adding a delay between each
sysfs_emit_at calls in the iio_format_list() to force the concurrent
access to the shared available list buffer.
This patch set extends the iio APIs and fixes some affected drivers.
Summary:
- Patch 1: iio core: introduce a iio info release callback to let
drivers share a copy of their available info list and later free it.
- Patch 2: pac1921: handle the current scale available info via the
read_avail+read_avail_release_resource APIs instead of using an ad-hoc
ext_info attribute. The latter was used to avoid the risk of a race in
the available list.
- Patch 3,4: ad7192, as73211: fix the possible race in the drivers by
copying/releasing the affected available lists.
- Patch 5: inkern: make consumers copy and release the available info
lists of their producers, necessary after patch 1.
- Patch 6,7: iio-mux, iio-rescale, dpot-dac, ingenic-battery: adapt
consumers to inkern API change by freeing the now copied available
lists of their producers.
Tested:
- pac1921: could not reproduce the race condition with the new APIs,
even with additional delays among the sysfs_emit_at calls during a
shunt resistor write. No new issue found after the change.
- iio-mux, iio-rescale, dpot-dac: tested with pac1921 as producer, which
was adapted to produce a mock raw available info list.
The tests did not cover the driver features but focused on assessing
the function call sequence. For example the following traced function
graph shows a read of the dpot mocked out voltage (with ftrace
filters: pac1921* iio* dpot* kmemdup_array* kfree*):
3) | iio_read_channel_info_avail [industrialio]() {
3) | dpot_dac_read_avail [dpot_dac]() {
3) | iio_read_avail_channel_raw [industrialio]() {
3) | iio_channel_read_avail [industrialio]() {
3) | pac1921_read_avail [pac1921]() {
3) 5.208 us | kmemdup_array();
3) + 11.459 us | }
3) 3.167 us | kmemdup_array();
3) | pac1921_read_avail_release_res [pac1921]() {
3) 1.709 us | kfree();
3) 4.458 us | }
3) + 25.750 us | }
3) + 31.792 us | }
3) + 35.000 us | }
3) + 37.083 us | iio_format_list [industrialio]();
3) | dpot_dac_read_avail_release_res [dpot_dac]() {
3) 1.583 us | kfree();
3) 4.250 us | }
3) + 84.292 us | }
- ingenic-battery: also tested with mock available info produced by the
pac1921 driver. Following the traced graph part that should correspond
to the ingenic_battery_set_scale() flow (which is not traceable with
the additional ingenic* ftrace filter for some reason):
2) | ingenic_battery_probe [ingenic_battery]() {
...
2) | iio_read_max_channel_raw [industrialio]() {
2) | iio_channel_read_avail [industrialio]() {
2) | pac1921_read_avail [pac1921]() {
2) 4.333 us | kmemdup_array();
2) + 10.834 us | }
2) 3.500 us | kmemdup_array();
2) | pac1921_read_avail_release_res [pac1921]() {
2) 1.791 us | kfree();
2) 4.625 us | }
2) + 26.291 us | }
2) 1.583 us | kfree();
2) + 35.750 us | }
2) | iio_read_avail_channel_attribute [industrialio]() {
2) | iio_channel_read_avail [industrialio]() {
2) | pac1921_read_avail [pac1921]() {
2) 3.250 us | kmemdup_array();
2) 8.209 us | }
2) 3.458 us | kmemdup_array();
2) | pac1921_read_avail_release_res [pac1921]() {
2) 1.542 us | kfree();
2) 4.292 us | }
2) + 21.417 us | }
2) + 26.333 us | }
2) | iio_write_channel_attribute [industrialio]() {
2) 4.375 us | pac1921_write_raw [pac1921]();
2) 9.625 us | }
2) 1.666 us | kfree();
2) * 47810.08 us | }
Not tested:
- ad7192, as73211
Link: https://lore.kernel.org/linux-iio/20240724-iio-pac1921-v4-0-723698e903a3@gmail.com/
Signed-off-by: Matteo Martelli <matteomartelli3@gmail.com>
---
Matteo Martelli (7):
iio: core: add read_avail_release_resource callback to fix race
iio: pac1921: use read_avail+release APIs instead of custom ext_info
iio: ad7192: copy/release available filter frequencies to fix race
iio: as73211: copy/release available integration times to fix race
iio: inkern: copy/release available info from producer
iio: consumers: release available info buffer copied from producer
power: supply: ingenic-battery: free scale buffer after use
drivers/iio/adc/ad7192.c | 22 +++++-
drivers/iio/adc/pac1921.c | 128 ++++++++++++---------------------
drivers/iio/afe/iio-rescale.c | 8 +++
drivers/iio/dac/dpot-dac.c | 8 +++
drivers/iio/industrialio-core.c | 14 +++-
drivers/iio/inkern.c | 64 ++++++++++++-----
drivers/iio/light/as73211.c | 23 +++++-
drivers/iio/multiplexer/iio-mux.c | 8 +++
drivers/power/supply/ingenic-battery.c | 16 +++--
include/linux/iio/consumer.h | 4 +-
include/linux/iio/iio.h | 4 ++
11 files changed, 185 insertions(+), 114 deletions(-)
---
base-commit: fec496684388685647652ab4213454fbabdab099
change-id: 20240802-iio-read-avail-release-cb3d2a1e1b98
Best regards,
--
Matteo Martelli <matteomartelli3@gmail.com>
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 1/7] iio: core: add read_avail_release_resource callback to fix race
2024-10-03 17:34 [PATCH 0/7] iio: fix possible race condition during access of available info lists Matteo Martelli
@ 2024-10-03 17:34 ` Matteo Martelli
2024-10-03 17:34 ` [PATCH 2/7] iio: pac1921: use read_avail+release APIs instead of custom ext_info Matteo Martelli
` (6 subsequent siblings)
7 siblings, 0 replies; 13+ messages in thread
From: Matteo Martelli @ 2024-10-03 17:34 UTC (permalink / raw)
To: Jonathan Cameron, Lars-Peter Clausen, Michael Hennerich,
Alisa-Dariana Roman, Christian Eggers, Peter Rosin, Paul Cercueil,
Sebastian Reichel
Cc: linux-iio, linux-kernel, linux-mips, linux-pm, Matteo Martelli
Some iio drivers currently share an available info buffer that might be
changed while iio core prints it to sysfs. To avoid the buffer
corruption, add a release callback to let iio drivers allocate a copy of
the available info buffer and later free it in the release callback.
Such control is kept in the driver logic so that some driver that needs
a big available info buffer might also perform some check to keep the
copied buffer around in case no race has occurred.
Signed-off-by: Matteo Martelli <matteomartelli3@gmail.com>
---
drivers/iio/industrialio-core.c | 14 +++++++++++---
include/linux/iio/iio.h | 4 ++++
2 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index 6a6568d4a2cb3a3f63381d5a6f25a2881b3ba2ed..4aea9de9f15a4d70f9d02fb3d47df49eef8c8423 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -859,12 +859,20 @@ static ssize_t iio_read_channel_info_avail(struct device *dev,
return ret;
switch (ret) {
case IIO_AVAIL_LIST:
- return iio_format_avail_list(buf, vals, type, length);
+ ret = iio_format_avail_list(buf, vals, type, length);
+ break;
case IIO_AVAIL_RANGE:
- return iio_format_avail_range(buf, vals, type);
+ ret = iio_format_avail_range(buf, vals, type);
+ break;
default:
- return -EINVAL;
+ ret = -EINVAL;
}
+
+ if (indio_dev->info->read_avail_release_resource)
+ indio_dev->info->read_avail_release_resource(
+ indio_dev, this_attr->c, vals, this_attr->address);
+
+ return ret;
}
/**
diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
index 18779b631e9071801958fc9d50b941b548fab940..55326f0310b2e9b3fa561c4728e7eabe1d7a5e78 100644
--- a/include/linux/iio/iio.h
+++ b/include/linux/iio/iio.h
@@ -491,6 +491,10 @@ struct iio_info {
int *length,
long mask);
+ void (*read_avail_release_resource)(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int *vals, long mask);
+
int (*write_raw)(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val,
--
2.46.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 2/7] iio: pac1921: use read_avail+release APIs instead of custom ext_info
2024-10-03 17:34 [PATCH 0/7] iio: fix possible race condition during access of available info lists Matteo Martelli
2024-10-03 17:34 ` [PATCH 1/7] iio: core: add read_avail_release_resource callback to fix race Matteo Martelli
@ 2024-10-03 17:34 ` Matteo Martelli
2024-10-03 17:34 ` [PATCH 3/7] iio: ad7192: copy/release available filter frequencies to fix race Matteo Martelli
` (5 subsequent siblings)
7 siblings, 0 replies; 13+ messages in thread
From: Matteo Martelli @ 2024-10-03 17:34 UTC (permalink / raw)
To: Jonathan Cameron, Lars-Peter Clausen, Michael Hennerich,
Alisa-Dariana Roman, Christian Eggers, Peter Rosin, Paul Cercueil,
Sebastian Reichel
Cc: linux-iio, linux-kernel, linux-mips, linux-pm, Matteo Martelli
The pac1921 driver was exposing the available scale info via an ad-hoc
ext_info attribute instead of using the read_avail API. This to avoid a
possible race condition: while the available current scales were being
printed to sysfs by iio core (iio_read_channel_info_avail), the shunt
resistor might have been changed concurrently.
Switch to the read_avail+release APIs now that the race condition has
been addressed.
Signed-off-by: Matteo Martelli <matteomartelli3@gmail.com>
---
drivers/iio/adc/pac1921.c | 128 ++++++++++++++++------------------------------
1 file changed, 45 insertions(+), 83 deletions(-)
diff --git a/drivers/iio/adc/pac1921.c b/drivers/iio/adc/pac1921.c
index 4c2a1c07bc399028f0334885fc9cd4552d5892b1..f491a4923380ef9b406a68f8cc413df873869e3e 100644
--- a/drivers/iio/adc/pac1921.c
+++ b/drivers/iio/adc/pac1921.c
@@ -445,11 +445,52 @@ static int pac1921_read_avail(struct iio_dev *indio_dev,
*vals = pac1921_int_num_samples;
*length = ARRAY_SIZE(pac1921_int_num_samples);
return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->channel) {
+ case PAC1921_CHAN_VBUS:
+ *vals = (const int *)pac1921_vbus_scales;
+ *length = ARRAY_SIZE(pac1921_vbus_scales) * 2;
+ *type = IIO_VAL_INT_PLUS_NANO;
+ return IIO_AVAIL_LIST;
+
+ case PAC1921_CHAN_VSENSE:
+ *vals = (const int *)pac1921_vsense_scales;
+ *length = ARRAY_SIZE(pac1921_vsense_scales) * 2;
+ *type = IIO_VAL_INT_PLUS_NANO;
+ return IIO_AVAIL_LIST;
+
+ case PAC1921_CHAN_CURRENT: {
+ struct pac1921_priv *priv = iio_priv(indio_dev);
+
+ *length = ARRAY_SIZE(priv->current_scales) * 2;
+ *type = IIO_VAL_INT_PLUS_NANO;
+
+ guard(mutex)(&priv->lock);
+
+ *vals = kmemdup_array((int *)priv->current_scales,
+ *length, sizeof(int), GFP_KERNEL);
+ if (!*vals)
+ return -ENOMEM;
+
+ return IIO_AVAIL_LIST;
+ }
+ default:
+ return -EINVAL;
+ }
default:
return -EINVAL;
}
}
+static void pac1921_read_avail_release_res(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int *vals, long mask)
+{
+ if (mask == IIO_CHAN_INFO_SCALE &&
+ chan->channel == PAC1921_CHAN_CURRENT)
+ kfree(vals);
+}
+
/*
* Perform configuration update sequence: set the device into read state, then
* write the config register and set the device back into integration state.
@@ -749,6 +790,7 @@ static int pac1921_read_event_value(struct iio_dev *indio_dev,
static const struct iio_info pac1921_iio = {
.read_raw = pac1921_read_raw,
.read_avail = pac1921_read_avail,
+ .read_avail_release_resource = pac1921_read_avail_release_res,
.write_raw = pac1921_write_raw,
.write_raw_get_fmt = pac1921_write_raw_get_fmt,
.read_label = pac1921_read_label,
@@ -806,88 +848,7 @@ static ssize_t pac1921_write_shunt_resistor(struct iio_dev *indio_dev,
return len;
}
-/*
- * Emit on sysfs the list of available scales contained in scales_tbl
- *
- * TODO:: this function can be replaced with iio_format_avail_list() if the
- * latter will ever be exported.
- *
- * Must be called with lock held if the scales_tbl can change runtime (e.g. for
- * the current scales table)
- */
-static ssize_t pac1921_format_scale_avail(const int (*const scales_tbl)[2],
- size_t size, char *buf)
-{
- ssize_t len = 0;
-
- for (unsigned int i = 0; i < size; i++) {
- if (i != 0) {
- len += sysfs_emit_at(buf, len, " ");
- if (len >= PAGE_SIZE)
- return -EFBIG;
- }
- len += sysfs_emit_at(buf, len, "%d.%09d", scales_tbl[i][0],
- scales_tbl[i][1]);
- if (len >= PAGE_SIZE)
- return -EFBIG;
- }
-
- len += sysfs_emit_at(buf, len, "\n");
- return len;
-}
-
-/*
- * Read available scales for a specific channel
- *
- * NOTE: using extended info insted of iio.read_avail() because access to
- * current scales must be locked as they depend on shunt resistor which may
- * change runtime. Caller of iio.read_avail() would access the table unlocked
- * instead.
- */
-static ssize_t pac1921_read_scale_avail(struct iio_dev *indio_dev,
- uintptr_t private,
- const struct iio_chan_spec *chan,
- char *buf)
-{
- struct pac1921_priv *priv = iio_priv(indio_dev);
- const int (*scales_tbl)[2];
- size_t size;
-
- switch (chan->channel) {
- case PAC1921_CHAN_VBUS:
- scales_tbl = pac1921_vbus_scales;
- size = ARRAY_SIZE(pac1921_vbus_scales);
- return pac1921_format_scale_avail(scales_tbl, size, buf);
-
- case PAC1921_CHAN_VSENSE:
- scales_tbl = pac1921_vsense_scales;
- size = ARRAY_SIZE(pac1921_vsense_scales);
- return pac1921_format_scale_avail(scales_tbl, size, buf);
-
- case PAC1921_CHAN_CURRENT: {
- guard(mutex)(&priv->lock);
- scales_tbl = priv->current_scales;
- size = ARRAY_SIZE(priv->current_scales);
- return pac1921_format_scale_avail(scales_tbl, size, buf);
- }
- default:
- return -EINVAL;
- }
-}
-
-#define PAC1921_EXT_INFO_SCALE_AVAIL { \
- .name = "scale_available", \
- .read = pac1921_read_scale_avail, \
- .shared = IIO_SEPARATE, \
-}
-
-static const struct iio_chan_spec_ext_info pac1921_ext_info_voltage[] = {
- PAC1921_EXT_INFO_SCALE_AVAIL,
- {}
-};
-
static const struct iio_chan_spec_ext_info pac1921_ext_info_current[] = {
- PAC1921_EXT_INFO_SCALE_AVAIL,
{
.name = "shunt_resistor",
.read = pac1921_read_shunt_resistor,
@@ -911,6 +872,7 @@ static const struct iio_chan_spec pac1921_channels[] = {
.type = IIO_VOLTAGE,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
+ .info_mask_separate_available = BIT(IIO_CHAN_INFO_SCALE),
.info_mask_shared_by_all =
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) |
BIT(IIO_CHAN_INFO_SAMP_FREQ),
@@ -928,12 +890,12 @@ static const struct iio_chan_spec pac1921_channels[] = {
.indexed = 1,
.event_spec = pac1921_overflow_event,
.num_event_specs = ARRAY_SIZE(pac1921_overflow_event),
- .ext_info = pac1921_ext_info_voltage,
},
{
.type = IIO_VOLTAGE,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
+ .info_mask_separate_available = BIT(IIO_CHAN_INFO_SCALE),
.info_mask_shared_by_all =
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) |
BIT(IIO_CHAN_INFO_SAMP_FREQ),
@@ -951,12 +913,12 @@ static const struct iio_chan_spec pac1921_channels[] = {
.indexed = 1,
.event_spec = pac1921_overflow_event,
.num_event_specs = ARRAY_SIZE(pac1921_overflow_event),
- .ext_info = pac1921_ext_info_voltage,
},
{
.type = IIO_CURRENT,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
+ .info_mask_separate_available = BIT(IIO_CHAN_INFO_SCALE),
.info_mask_shared_by_all =
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) |
BIT(IIO_CHAN_INFO_SAMP_FREQ),
--
2.46.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 3/7] iio: ad7192: copy/release available filter frequencies to fix race
2024-10-03 17:34 [PATCH 0/7] iio: fix possible race condition during access of available info lists Matteo Martelli
2024-10-03 17:34 ` [PATCH 1/7] iio: core: add read_avail_release_resource callback to fix race Matteo Martelli
2024-10-03 17:34 ` [PATCH 2/7] iio: pac1921: use read_avail+release APIs instead of custom ext_info Matteo Martelli
@ 2024-10-03 17:34 ` Matteo Martelli
2024-10-03 17:34 ` [PATCH 4/7] iio: as73211: copy/release available integration times " Matteo Martelli
` (4 subsequent siblings)
7 siblings, 0 replies; 13+ messages in thread
From: Matteo Martelli @ 2024-10-03 17:34 UTC (permalink / raw)
To: Jonathan Cameron, Lars-Peter Clausen, Michael Hennerich,
Alisa-Dariana Roman, Christian Eggers, Peter Rosin, Paul Cercueil,
Sebastian Reichel
Cc: linux-iio, linux-kernel, linux-mips, linux-pm, Matteo Martelli
While available filter frequencies are being printed to sysfs by iio
core (iio_read_channel_info_avail), the sampling frequency might be
changed. This could cause the buffer shared with iio core to be
corrupted. To prevent it, make a copy of the filter frequencies buffer
and free it in the read_avail_release_resource callback.
Signed-off-by: Matteo Martelli <matteomartelli3@gmail.com>
---
drivers/iio/adc/ad7192.c | 22 ++++++++++++++++++++--
1 file changed, 20 insertions(+), 2 deletions(-)
diff --git a/drivers/iio/adc/ad7192.c b/drivers/iio/adc/ad7192.c
index 7042ddfdfc03ee5ea58ca07fb1943feb6538175b..acf625ced0b21db8d44f77929e8a875b3c10e1b1 100644
--- a/drivers/iio/adc/ad7192.c
+++ b/drivers/iio/adc/ad7192.c
@@ -1056,12 +1056,19 @@ static int ad7192_read_avail(struct iio_dev *indio_dev,
*length = ARRAY_SIZE(st->scale_avail) * 2;
return IIO_AVAIL_LIST;
- case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
- *vals = (int *)st->filter_freq_avail;
+ case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: {
*type = IIO_VAL_FRACTIONAL;
*length = ARRAY_SIZE(st->filter_freq_avail) * 2;
+ guard(mutex)(&st->lock);
+
+ *vals = kmemdup_array((int *)st->filter_freq_avail, *length,
+ sizeof(int), GFP_KERNEL);
+ if (!*vals)
+ return -ENOMEM;
+
return IIO_AVAIL_LIST;
+ }
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
*vals = (int *)st->oversampling_ratio_avail;
*type = IIO_VAL_INT;
@@ -1073,6 +1080,14 @@ static int ad7192_read_avail(struct iio_dev *indio_dev,
return -EINVAL;
}
+static void ad7192_read_avail_release_res(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int *vals, long mask)
+{
+ if (mask == IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY)
+ kfree(vals);
+}
+
static int ad7192_update_scan_mode(struct iio_dev *indio_dev, const unsigned long *scan_mask)
{
struct ad7192_state *st = iio_priv(indio_dev);
@@ -1098,6 +1113,7 @@ static const struct iio_info ad7192_info = {
.write_raw = ad7192_write_raw,
.write_raw_get_fmt = ad7192_write_raw_get_fmt,
.read_avail = ad7192_read_avail,
+ .read_avail_release_resource = ad7192_read_avail_release_res,
.attrs = &ad7192_attribute_group,
.validate_trigger = ad_sd_validate_trigger,
.update_scan_mode = ad7192_update_scan_mode,
@@ -1108,6 +1124,7 @@ static const struct iio_info ad7194_info = {
.write_raw = ad7192_write_raw,
.write_raw_get_fmt = ad7192_write_raw_get_fmt,
.read_avail = ad7192_read_avail,
+ .read_avail_release_resource = ad7192_read_avail_release_res,
.validate_trigger = ad_sd_validate_trigger,
};
@@ -1116,6 +1133,7 @@ static const struct iio_info ad7195_info = {
.write_raw = ad7192_write_raw,
.write_raw_get_fmt = ad7192_write_raw_get_fmt,
.read_avail = ad7192_read_avail,
+ .read_avail_release_resource = ad7192_read_avail_release_res,
.attrs = &ad7195_attribute_group,
.validate_trigger = ad_sd_validate_trigger,
.update_scan_mode = ad7192_update_scan_mode,
--
2.46.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 4/7] iio: as73211: copy/release available integration times to fix race
2024-10-03 17:34 [PATCH 0/7] iio: fix possible race condition during access of available info lists Matteo Martelli
` (2 preceding siblings ...)
2024-10-03 17:34 ` [PATCH 3/7] iio: ad7192: copy/release available filter frequencies to fix race Matteo Martelli
@ 2024-10-03 17:34 ` Matteo Martelli
2024-10-06 14:18 ` Jonathan Cameron
2024-10-03 17:34 ` [PATCH 5/7] iio: inkern: copy/release available info from producer Matteo Martelli
` (3 subsequent siblings)
7 siblings, 1 reply; 13+ messages in thread
From: Matteo Martelli @ 2024-10-03 17:34 UTC (permalink / raw)
To: Jonathan Cameron, Lars-Peter Clausen, Michael Hennerich,
Alisa-Dariana Roman, Christian Eggers, Peter Rosin, Paul Cercueil,
Sebastian Reichel
Cc: linux-iio, linux-kernel, linux-mips, linux-pm, Matteo Martelli
While available integration times are being printed to sysfs by iio core
(iio_read_channel_info_avail), the sampling frequency might be changed.
This could cause the buffer shared with iio core to be corrupted. To
prevent it, make a copy of the integration times buffer and free it in
the read_avail_release_resource callback.
Signed-off-by: Matteo Martelli <matteomartelli3@gmail.com>
---
drivers/iio/light/as73211.c | 23 ++++++++++++++++++++---
1 file changed, 20 insertions(+), 3 deletions(-)
diff --git a/drivers/iio/light/as73211.c b/drivers/iio/light/as73211.c
index be0068081ebbbb37fdfb252b67a77b302ff725f6..520c898e0ff9c530b4fdd45589559f9014d7992c 100644
--- a/drivers/iio/light/as73211.c
+++ b/drivers/iio/light/as73211.c
@@ -493,17 +493,33 @@ static int as73211_read_avail(struct iio_dev *indio_dev, struct iio_chan_spec co
*type = IIO_VAL_INT;
return IIO_AVAIL_LIST;
- case IIO_CHAN_INFO_INT_TIME:
+ case IIO_CHAN_INFO_INT_TIME: {
*length = ARRAY_SIZE(data->int_time_avail);
- *vals = data->int_time_avail;
*type = IIO_VAL_INT_PLUS_MICRO;
- return IIO_AVAIL_LIST;
+ guard(mutex)(&data->mutex);
+
+ *vals = kmemdup_array(data->int_time_avail, *length,
+ sizeof(int), GFP_KERNEL);
+ if (!*vals)
+ return -ENOMEM;
+
+ return IIO_AVAIL_LIST;
+ }
default:
return -EINVAL;
}
}
+static void as73211_read_avail_release_res(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int *vals, long mask)
+{
+ if (mask == IIO_CHAN_INFO_INT_TIME)
+ kfree(vals);
+}
+
+
static int _as73211_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan __always_unused,
int val, int val2, long mask)
@@ -699,6 +715,7 @@ static irqreturn_t as73211_trigger_handler(int irq __always_unused, void *p)
static const struct iio_info as73211_info = {
.read_raw = as73211_read_raw,
.read_avail = as73211_read_avail,
+ .read_avail_release_resource = as73211_read_avail_release_res,
.write_raw = as73211_write_raw,
};
--
2.46.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 5/7] iio: inkern: copy/release available info from producer
2024-10-03 17:34 [PATCH 0/7] iio: fix possible race condition during access of available info lists Matteo Martelli
` (3 preceding siblings ...)
2024-10-03 17:34 ` [PATCH 4/7] iio: as73211: copy/release available integration times " Matteo Martelli
@ 2024-10-03 17:34 ` Matteo Martelli
2024-10-03 17:34 ` [PATCH 6/7] iio: consumers: release available info buffer copied " Matteo Martelli
` (2 subsequent siblings)
7 siblings, 0 replies; 13+ messages in thread
From: Matteo Martelli @ 2024-10-03 17:34 UTC (permalink / raw)
To: Jonathan Cameron, Lars-Peter Clausen, Michael Hennerich,
Alisa-Dariana Roman, Christian Eggers, Peter Rosin, Paul Cercueil,
Sebastian Reichel
Cc: linux-iio, linux-kernel, linux-mips, linux-pm, Matteo Martelli
Consumers need to call the read_avail_release_resource after reading the
available info. To call the release with info_exists locked, copy the
available info from the producer and immediately call its release
callback. With this change, users of iio_read_avail_channel_raw() and
iio_read_avail_channel_attribute() must free the copied avail info after
calling them.
Signed-off-by: Matteo Martelli <matteomartelli3@gmail.com>
---
drivers/iio/inkern.c | 64 +++++++++++++++++++++++++++++++++-----------
include/linux/iio/consumer.h | 4 +--
2 files changed, 50 insertions(+), 18 deletions(-)
diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
index 7f325b3ed08fae6674245312cf8f57bb151006c0..cc65ef79451e5aa2cea447e168007a447ffc0d91 100644
--- a/drivers/iio/inkern.c
+++ b/drivers/iio/inkern.c
@@ -760,9 +760,25 @@ static int iio_channel_read_avail(struct iio_channel *chan,
if (!iio_channel_has_available(chan->channel, info))
return -EINVAL;
- if (iio_info->read_avail)
- return iio_info->read_avail(chan->indio_dev, chan->channel,
- vals, type, length, info);
+ if (iio_info->read_avail) {
+ const int *vals_tmp;
+ int ret;
+
+ ret = iio_info->read_avail(chan->indio_dev, chan->channel,
+ &vals_tmp, type, length, info);
+ if (ret < 0)
+ return ret;
+
+ *vals = kmemdup_array(vals_tmp, *length, sizeof(int), GFP_KERNEL);
+ if (!*vals)
+ return -ENOMEM;
+
+ if (iio_info->read_avail_release_resource)
+ iio_info->read_avail_release_resource(
+ chan->indio_dev, chan->channel, vals_tmp, info);
+
+ return ret;
+ }
return -EINVAL;
}
@@ -789,9 +805,11 @@ int iio_read_avail_channel_raw(struct iio_channel *chan,
ret = iio_read_avail_channel_attribute(chan, vals, &type, length,
IIO_CHAN_INFO_RAW);
- if (ret >= 0 && type != IIO_VAL_INT)
+ if (ret >= 0 && type != IIO_VAL_INT) {
/* raw values are assumed to be IIO_VAL_INT */
+ kfree(*vals);
ret = -EINVAL;
+ }
return ret;
}
@@ -820,24 +838,31 @@ static int iio_channel_read_max(struct iio_channel *chan,
if (val2)
*val2 = vals[5];
}
- return 0;
+ ret = 0;
+ break;
case IIO_AVAIL_LIST:
- if (length <= 0)
- return -EINVAL;
+ if (length <= 0) {
+ ret = -EINVAL;
+ goto out;
+ }
switch (*type) {
case IIO_VAL_INT:
*val = max_array(vals, length);
+ ret = 0;
break;
default:
/* TODO: learn about max for other iio values */
- return -EINVAL;
+ ret = -EINVAL;
}
- return 0;
+ break;
default:
- return -EINVAL;
+ ret = -EINVAL;
}
+out:
+ kfree(vals);
+ return ret;
}
int iio_read_max_channel_raw(struct iio_channel *chan, int *val)
@@ -876,24 +901,31 @@ static int iio_channel_read_min(struct iio_channel *chan,
if (val2)
*val2 = vals[1];
}
- return 0;
+ ret = 0;
+ break;
case IIO_AVAIL_LIST:
- if (length <= 0)
- return -EINVAL;
+ if (length <= 0) {
+ ret = -EINVAL;
+ goto out;
+ }
switch (*type) {
case IIO_VAL_INT:
*val = min_array(vals, length);
+ ret = 0;
break;
default:
/* TODO: learn about min for other iio values */
- return -EINVAL;
+ ret = -EINVAL;
}
- return 0;
+ break;
default:
- return -EINVAL;
+ ret = -EINVAL;
}
+out:
+ kfree(vals);
+ return ret;
}
int iio_read_min_channel_raw(struct iio_channel *chan, int *val)
diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h
index 333d1d8ccb37f387fe531577ac5e0bfc7f752cec..e3e268d2574b3e01c9412449d90d627de7efcd84 100644
--- a/include/linux/iio/consumer.h
+++ b/include/linux/iio/consumer.h
@@ -316,7 +316,7 @@ int iio_read_min_channel_raw(struct iio_channel *chan, int *val);
/**
* iio_read_avail_channel_raw() - read available raw values from a given channel
* @chan: The channel being queried.
- * @vals: Available values read back.
+ * @vals: Available values read back. Must be freed after use.
* @length: Number of entries in vals.
*
* Returns an error code, IIO_AVAIL_RANGE or IIO_AVAIL_LIST.
@@ -334,7 +334,7 @@ int iio_read_avail_channel_raw(struct iio_channel *chan,
/**
* iio_read_avail_channel_attribute() - read available channel attribute values
* @chan: The channel being queried.
- * @vals: Available values read back.
+ * @vals: Available values read back. Must be freed after use.
* @type: Type of values read back.
* @length: Number of entries in vals.
* @attribute: info attribute to be read back.
--
2.46.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 6/7] iio: consumers: release available info buffer copied from producer
2024-10-03 17:34 [PATCH 0/7] iio: fix possible race condition during access of available info lists Matteo Martelli
` (4 preceding siblings ...)
2024-10-03 17:34 ` [PATCH 5/7] iio: inkern: copy/release available info from producer Matteo Martelli
@ 2024-10-03 17:34 ` Matteo Martelli
2024-10-06 14:20 ` Jonathan Cameron
2024-10-03 17:34 ` [PATCH 7/7] power: supply: ingenic-battery: free scale buffer after use Matteo Martelli
2024-10-06 14:23 ` [PATCH 0/7] iio: fix possible race condition during access of available info lists Jonathan Cameron
7 siblings, 1 reply; 13+ messages in thread
From: Matteo Martelli @ 2024-10-03 17:34 UTC (permalink / raw)
To: Jonathan Cameron, Lars-Peter Clausen, Michael Hennerich,
Alisa-Dariana Roman, Christian Eggers, Peter Rosin, Paul Cercueil,
Sebastian Reichel
Cc: linux-iio, linux-kernel, linux-mips, linux-pm, Matteo Martelli
The iio_read_avail_channel_raw() inkern interface now allocates a copy
of the available info buffer that must be freed after use. To do so,
free the buffer in the consumers read_avail_relese_resource callback.
Signed-off-by: Matteo Martelli <matteomartelli3@gmail.com>
---
drivers/iio/afe/iio-rescale.c | 8 ++++++++
drivers/iio/dac/dpot-dac.c | 8 ++++++++
drivers/iio/multiplexer/iio-mux.c | 8 ++++++++
3 files changed, 24 insertions(+)
diff --git a/drivers/iio/afe/iio-rescale.c b/drivers/iio/afe/iio-rescale.c
index 56e5913ab82d1c045c9ca27012008a4495502cbf..78bb86c291706748b4072a484532ad20c415ff9f 100644
--- a/drivers/iio/afe/iio-rescale.c
+++ b/drivers/iio/afe/iio-rescale.c
@@ -249,9 +249,17 @@ static int rescale_read_avail(struct iio_dev *indio_dev,
}
}
+static void rescale_read_avail_release_res(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int *vals, long mask)
+{
+ kfree(vals);
+}
+
static const struct iio_info rescale_info = {
.read_raw = rescale_read_raw,
.read_avail = rescale_read_avail,
+ .read_avail_release_resource = rescale_read_avail_release_res,
};
static ssize_t rescale_read_ext_info(struct iio_dev *indio_dev,
diff --git a/drivers/iio/dac/dpot-dac.c b/drivers/iio/dac/dpot-dac.c
index 7332064d0852d979620f90066fb027f6f68f8c95..beec76247acb5170b81058d28a71ed17c831c905 100644
--- a/drivers/iio/dac/dpot-dac.c
+++ b/drivers/iio/dac/dpot-dac.c
@@ -108,6 +108,13 @@ static int dpot_dac_read_avail(struct iio_dev *indio_dev,
return -EINVAL;
}
+static void dpot_dac_read_avail_release_res(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int *vals, long mask)
+{
+ kfree(vals);
+}
+
static int dpot_dac_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
@@ -125,6 +132,7 @@ static int dpot_dac_write_raw(struct iio_dev *indio_dev,
static const struct iio_info dpot_dac_info = {
.read_raw = dpot_dac_read_raw,
.read_avail = dpot_dac_read_avail,
+ .read_avail_release_resource = dpot_dac_read_avail_release_res,
.write_raw = dpot_dac_write_raw,
};
diff --git a/drivers/iio/multiplexer/iio-mux.c b/drivers/iio/multiplexer/iio-mux.c
index 2953403bef53bbe47a97a8ab1c475ed88d7f86d2..31345437784b01c5d6f8ea70263f4c2574388e7a 100644
--- a/drivers/iio/multiplexer/iio-mux.c
+++ b/drivers/iio/multiplexer/iio-mux.c
@@ -142,6 +142,13 @@ static int mux_read_avail(struct iio_dev *indio_dev,
return ret;
}
+static void mux_read_avail_release_res(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int *vals, long mask)
+{
+ kfree(vals);
+}
+
static int mux_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
@@ -171,6 +178,7 @@ static int mux_write_raw(struct iio_dev *indio_dev,
static const struct iio_info mux_info = {
.read_raw = mux_read_raw,
.read_avail = mux_read_avail,
+ .read_avail_release_resource = mux_read_avail_release_res,
.write_raw = mux_write_raw,
};
--
2.46.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 7/7] power: supply: ingenic-battery: free scale buffer after use
2024-10-03 17:34 [PATCH 0/7] iio: fix possible race condition during access of available info lists Matteo Martelli
` (5 preceding siblings ...)
2024-10-03 17:34 ` [PATCH 6/7] iio: consumers: release available info buffer copied " Matteo Martelli
@ 2024-10-03 17:34 ` Matteo Martelli
2024-10-04 21:55 ` kernel test robot
2024-10-04 23:38 ` kernel test robot
2024-10-06 14:23 ` [PATCH 0/7] iio: fix possible race condition during access of available info lists Jonathan Cameron
7 siblings, 2 replies; 13+ messages in thread
From: Matteo Martelli @ 2024-10-03 17:34 UTC (permalink / raw)
To: Jonathan Cameron, Lars-Peter Clausen, Michael Hennerich,
Alisa-Dariana Roman, Christian Eggers, Peter Rosin, Paul Cercueil,
Sebastian Reichel
Cc: linux-iio, linux-kernel, linux-mips, linux-pm, Matteo Martelli
The iio_read_avail_channel_attribute() iio interface now allocates a
copy of the available info buffer that must be freed after use.
Signed-off-by: Matteo Martelli <matteomartelli3@gmail.com>
---
drivers/power/supply/ingenic-battery.c | 16 +++++++++++-----
1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/drivers/power/supply/ingenic-battery.c b/drivers/power/supply/ingenic-battery.c
index 0a40f425c27723ccec49985b8b5e14a737b6a7eb..fa6d6898f8722cc8e06a888a762a3edeb0474a6e 100644
--- a/drivers/power/supply/ingenic-battery.c
+++ b/drivers/power/supply/ingenic-battery.c
@@ -79,8 +79,10 @@ static int ingenic_battery_set_scale(struct ingenic_battery *bat)
dev_err(bat->dev, "Unable to read channel avail scale\n");
return ret;
}
- if (ret != IIO_AVAIL_LIST || scale_type != IIO_VAL_FRACTIONAL_LOG2)
- return -EINVAL;
+ if (ret != IIO_AVAIL_LIST || scale_type != IIO_VAL_FRACTIONAL_LOG2) {
+ ret = -EINVAL;
+ goto out;
+ }
max_mV = bat->info->voltage_max_design_uv / 1000;
@@ -99,7 +101,8 @@ static int ingenic_battery_set_scale(struct ingenic_battery *bat)
if (best_idx < 0) {
dev_err(bat->dev, "Unable to find matching voltage scale\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
/* Only set scale if there is more than one (fractional) entry */
@@ -109,10 +112,13 @@ static int ingenic_battery_set_scale(struct ingenic_battery *bat)
scale_raw[best_idx + 1],
IIO_CHAN_INFO_SCALE);
if (ret)
- return ret;
+ goto out;
}
- return 0;
+ ret = 0;
+out:
+ kfree(scale_raw);
+ return ret;
}
static enum power_supply_property ingenic_battery_properties[] = {
--
2.46.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH 7/7] power: supply: ingenic-battery: free scale buffer after use
2024-10-03 17:34 ` [PATCH 7/7] power: supply: ingenic-battery: free scale buffer after use Matteo Martelli
@ 2024-10-04 21:55 ` kernel test robot
2024-10-04 23:38 ` kernel test robot
1 sibling, 0 replies; 13+ messages in thread
From: kernel test robot @ 2024-10-04 21:55 UTC (permalink / raw)
To: Matteo Martelli, Jonathan Cameron, Lars-Peter Clausen,
Michael Hennerich, Alisa-Dariana Roman, Christian Eggers,
Peter Rosin, Paul Cercueil, Sebastian Reichel
Cc: oe-kbuild-all, linux-iio, linux-kernel, linux-mips, linux-pm,
Matteo Martelli
Hi Matteo,
kernel test robot noticed the following build errors:
[auto build test ERROR on fec496684388685647652ab4213454fbabdab099]
url: https://github.com/intel-lab-lkp/linux/commits/Matteo-Martelli/iio-core-add-read_avail_release_resource-callback-to-fix-race/20241004-013654
base: fec496684388685647652ab4213454fbabdab099
patch link: https://lore.kernel.org/r/20241003-iio-read-avail-release-v1-7-c70cc7d9c2e0%40gmail.com
patch subject: [PATCH 7/7] power: supply: ingenic-battery: free scale buffer after use
config: m68k-allmodconfig (https://download.01.org/0day-ci/archive/20241005/202410050547.Pybj1FLp-lkp@intel.com/config)
compiler: m68k-linux-gcc (GCC) 14.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20241005/202410050547.Pybj1FLp-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202410050547.Pybj1FLp-lkp@intel.com/
All errors (new ones prefixed by >>):
drivers/power/supply/ingenic-battery.c: In function 'ingenic_battery_set_scale':
>> drivers/power/supply/ingenic-battery.c:120:9: error: implicit declaration of function 'kfree'; did you mean 'kvfree'? [-Wimplicit-function-declaration]
120 | kfree(scale_raw);
| ^~~~~
| kvfree
vim +120 drivers/power/supply/ingenic-battery.c
59
60 /* Set the most appropriate IIO channel voltage reference scale
61 * based on the battery's max voltage.
62 */
63 static int ingenic_battery_set_scale(struct ingenic_battery *bat)
64 {
65 const int *scale_raw;
66 int scale_len, scale_type, best_idx = -1, best_mV, max_raw, i, ret;
67 u64 max_mV;
68
69 ret = iio_read_max_channel_raw(bat->channel, &max_raw);
70 if (ret) {
71 dev_err(bat->dev, "Unable to read max raw channel value\n");
72 return ret;
73 }
74
75 ret = iio_read_avail_channel_attribute(bat->channel, &scale_raw,
76 &scale_type, &scale_len,
77 IIO_CHAN_INFO_SCALE);
78 if (ret < 0) {
79 dev_err(bat->dev, "Unable to read channel avail scale\n");
80 return ret;
81 }
82 if (ret != IIO_AVAIL_LIST || scale_type != IIO_VAL_FRACTIONAL_LOG2) {
83 ret = -EINVAL;
84 goto out;
85 }
86
87 max_mV = bat->info->voltage_max_design_uv / 1000;
88
89 for (i = 0; i < scale_len; i += 2) {
90 u64 scale_mV = (max_raw * scale_raw[i]) >> scale_raw[i + 1];
91
92 if (scale_mV < max_mV)
93 continue;
94
95 if (best_idx >= 0 && scale_mV > best_mV)
96 continue;
97
98 best_mV = scale_mV;
99 best_idx = i;
100 }
101
102 if (best_idx < 0) {
103 dev_err(bat->dev, "Unable to find matching voltage scale\n");
104 ret = -EINVAL;
105 goto out;
106 }
107
108 /* Only set scale if there is more than one (fractional) entry */
109 if (scale_len > 2) {
110 ret = iio_write_channel_attribute(bat->channel,
111 scale_raw[best_idx],
112 scale_raw[best_idx + 1],
113 IIO_CHAN_INFO_SCALE);
114 if (ret)
115 goto out;
116 }
117
118 ret = 0;
119 out:
> 120 kfree(scale_raw);
121 return ret;
122 }
123
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 7/7] power: supply: ingenic-battery: free scale buffer after use
2024-10-03 17:34 ` [PATCH 7/7] power: supply: ingenic-battery: free scale buffer after use Matteo Martelli
2024-10-04 21:55 ` kernel test robot
@ 2024-10-04 23:38 ` kernel test robot
1 sibling, 0 replies; 13+ messages in thread
From: kernel test robot @ 2024-10-04 23:38 UTC (permalink / raw)
To: Matteo Martelli, Jonathan Cameron, Lars-Peter Clausen,
Michael Hennerich, Alisa-Dariana Roman, Christian Eggers,
Peter Rosin, Paul Cercueil, Sebastian Reichel
Cc: llvm, oe-kbuild-all, linux-iio, linux-kernel, linux-mips,
linux-pm, Matteo Martelli
Hi Matteo,
kernel test robot noticed the following build errors:
[auto build test ERROR on fec496684388685647652ab4213454fbabdab099]
url: https://github.com/intel-lab-lkp/linux/commits/Matteo-Martelli/iio-core-add-read_avail_release_resource-callback-to-fix-race/20241004-013654
base: fec496684388685647652ab4213454fbabdab099
patch link: https://lore.kernel.org/r/20241003-iio-read-avail-release-v1-7-c70cc7d9c2e0%40gmail.com
patch subject: [PATCH 7/7] power: supply: ingenic-battery: free scale buffer after use
config: hexagon-allmodconfig (https://download.01.org/0day-ci/archive/20241005/202410050737.0PgqTuD1-lkp@intel.com/config)
compiler: clang version 20.0.0git (https://github.com/llvm/llvm-project fef3566a25ff0e34fb87339ba5e13eca17cec00f)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20241005/202410050737.0PgqTuD1-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202410050737.0PgqTuD1-lkp@intel.com/
All errors (new ones prefixed by >>):
>> drivers/power/supply/ingenic-battery.c:120:2: error: call to undeclared function 'kfree'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
120 | kfree(scale_raw);
| ^
1 error generated.
vim +/kfree +120 drivers/power/supply/ingenic-battery.c
59
60 /* Set the most appropriate IIO channel voltage reference scale
61 * based on the battery's max voltage.
62 */
63 static int ingenic_battery_set_scale(struct ingenic_battery *bat)
64 {
65 const int *scale_raw;
66 int scale_len, scale_type, best_idx = -1, best_mV, max_raw, i, ret;
67 u64 max_mV;
68
69 ret = iio_read_max_channel_raw(bat->channel, &max_raw);
70 if (ret) {
71 dev_err(bat->dev, "Unable to read max raw channel value\n");
72 return ret;
73 }
74
75 ret = iio_read_avail_channel_attribute(bat->channel, &scale_raw,
76 &scale_type, &scale_len,
77 IIO_CHAN_INFO_SCALE);
78 if (ret < 0) {
79 dev_err(bat->dev, "Unable to read channel avail scale\n");
80 return ret;
81 }
82 if (ret != IIO_AVAIL_LIST || scale_type != IIO_VAL_FRACTIONAL_LOG2) {
83 ret = -EINVAL;
84 goto out;
85 }
86
87 max_mV = bat->info->voltage_max_design_uv / 1000;
88
89 for (i = 0; i < scale_len; i += 2) {
90 u64 scale_mV = (max_raw * scale_raw[i]) >> scale_raw[i + 1];
91
92 if (scale_mV < max_mV)
93 continue;
94
95 if (best_idx >= 0 && scale_mV > best_mV)
96 continue;
97
98 best_mV = scale_mV;
99 best_idx = i;
100 }
101
102 if (best_idx < 0) {
103 dev_err(bat->dev, "Unable to find matching voltage scale\n");
104 ret = -EINVAL;
105 goto out;
106 }
107
108 /* Only set scale if there is more than one (fractional) entry */
109 if (scale_len > 2) {
110 ret = iio_write_channel_attribute(bat->channel,
111 scale_raw[best_idx],
112 scale_raw[best_idx + 1],
113 IIO_CHAN_INFO_SCALE);
114 if (ret)
115 goto out;
116 }
117
118 ret = 0;
119 out:
> 120 kfree(scale_raw);
121 return ret;
122 }
123
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 4/7] iio: as73211: copy/release available integration times to fix race
2024-10-03 17:34 ` [PATCH 4/7] iio: as73211: copy/release available integration times " Matteo Martelli
@ 2024-10-06 14:18 ` Jonathan Cameron
0 siblings, 0 replies; 13+ messages in thread
From: Jonathan Cameron @ 2024-10-06 14:18 UTC (permalink / raw)
To: Matteo Martelli
Cc: Lars-Peter Clausen, Michael Hennerich, Alisa-Dariana Roman,
Christian Eggers, Peter Rosin, Paul Cercueil, Sebastian Reichel,
linux-iio, linux-kernel, linux-mips, linux-pm
On Thu, 03 Oct 2024 19:34:09 +0200
Matteo Martelli <matteomartelli3@gmail.com> wrote:
> While available integration times are being printed to sysfs by iio core
> (iio_read_channel_info_avail), the sampling frequency might be changed.
> This could cause the buffer shared with iio core to be corrupted. To
> prevent it, make a copy of the integration times buffer and free it in
> the read_avail_release_resource callback.
>
> Signed-off-by: Matteo Martelli <matteomartelli3@gmail.com>
> ---
> drivers/iio/light/as73211.c | 23 ++++++++++++++++++++---
> 1 file changed, 20 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/iio/light/as73211.c b/drivers/iio/light/as73211.c
> index be0068081ebbbb37fdfb252b67a77b302ff725f6..520c898e0ff9c530b4fdd45589559f9014d7992c 100644
> --- a/drivers/iio/light/as73211.c
> +++ b/drivers/iio/light/as73211.c
> @@ -493,17 +493,33 @@ static int as73211_read_avail(struct iio_dev *indio_dev, struct iio_chan_spec co
> *type = IIO_VAL_INT;
> return IIO_AVAIL_LIST;
>
> - case IIO_CHAN_INFO_INT_TIME:
> + case IIO_CHAN_INFO_INT_TIME: {
> *length = ARRAY_SIZE(data->int_time_avail);
> - *vals = data->int_time_avail;
> *type = IIO_VAL_INT_PLUS_MICRO;
> - return IIO_AVAIL_LIST;
>
> + guard(mutex)(&data->mutex);
> +
> + *vals = kmemdup_array(data->int_time_avail, *length,
> + sizeof(int), GFP_KERNEL);
> + if (!*vals)
> + return -ENOMEM;
> +
> + return IIO_AVAIL_LIST;
> + }
> default:
> return -EINVAL;
> }
> }
>
> +static void as73211_read_avail_release_res(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan,
> + const int *vals, long mask)
> +{
> + if (mask == IIO_CHAN_INFO_INT_TIME)
> + kfree(vals);
> +}
> +
Trivial but one blank line is enough. If there is no other feedback on the
series I can tidy this up whilst applying.
> +
> static int _as73211_write_raw(struct iio_dev *indio_dev,
> struct iio_chan_spec const *chan __always_unused,
> int val, int val2, long mask)
> @@ -699,6 +715,7 @@ static irqreturn_t as73211_trigger_handler(int irq __always_unused, void *p)
> static const struct iio_info as73211_info = {
> .read_raw = as73211_read_raw,
> .read_avail = as73211_read_avail,
> + .read_avail_release_resource = as73211_read_avail_release_res,
> .write_raw = as73211_write_raw,
> };
>
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 6/7] iio: consumers: release available info buffer copied from producer
2024-10-03 17:34 ` [PATCH 6/7] iio: consumers: release available info buffer copied " Matteo Martelli
@ 2024-10-06 14:20 ` Jonathan Cameron
0 siblings, 0 replies; 13+ messages in thread
From: Jonathan Cameron @ 2024-10-06 14:20 UTC (permalink / raw)
To: Matteo Martelli
Cc: Lars-Peter Clausen, Michael Hennerich, Alisa-Dariana Roman,
Christian Eggers, Peter Rosin, Paul Cercueil, Sebastian Reichel,
linux-iio, linux-kernel, linux-mips, linux-pm
On Thu, 03 Oct 2024 19:34:11 +0200
Matteo Martelli <matteomartelli3@gmail.com> wrote:
> The iio_read_avail_channel_raw() inkern interface now allocates a copy
> of the available info buffer that must be freed after use. To do so,
> free the buffer in the consumers read_avail_relese_resource callback.
release
Otherwise fine.
J
>
> Signed-off-by: Matteo Martelli <matteomartelli3@gmail.com>
> ---
> drivers/iio/afe/iio-rescale.c | 8 ++++++++
> drivers/iio/dac/dpot-dac.c | 8 ++++++++
> drivers/iio/multiplexer/iio-mux.c | 8 ++++++++
> 3 files changed, 24 insertions(+)
>
> diff --git a/drivers/iio/afe/iio-rescale.c b/drivers/iio/afe/iio-rescale.c
> index 56e5913ab82d1c045c9ca27012008a4495502cbf..78bb86c291706748b4072a484532ad20c415ff9f 100644
> --- a/drivers/iio/afe/iio-rescale.c
> +++ b/drivers/iio/afe/iio-rescale.c
> @@ -249,9 +249,17 @@ static int rescale_read_avail(struct iio_dev *indio_dev,
> }
> }
>
> +static void rescale_read_avail_release_res(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan,
> + const int *vals, long mask)
> +{
> + kfree(vals);
> +}
> +
> static const struct iio_info rescale_info = {
> .read_raw = rescale_read_raw,
> .read_avail = rescale_read_avail,
> + .read_avail_release_resource = rescale_read_avail_release_res,
> };
>
> static ssize_t rescale_read_ext_info(struct iio_dev *indio_dev,
> diff --git a/drivers/iio/dac/dpot-dac.c b/drivers/iio/dac/dpot-dac.c
> index 7332064d0852d979620f90066fb027f6f68f8c95..beec76247acb5170b81058d28a71ed17c831c905 100644
> --- a/drivers/iio/dac/dpot-dac.c
> +++ b/drivers/iio/dac/dpot-dac.c
> @@ -108,6 +108,13 @@ static int dpot_dac_read_avail(struct iio_dev *indio_dev,
> return -EINVAL;
> }
>
> +static void dpot_dac_read_avail_release_res(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan,
> + const int *vals, long mask)
> +{
> + kfree(vals);
> +}
> +
> static int dpot_dac_write_raw(struct iio_dev *indio_dev,
> struct iio_chan_spec const *chan,
> int val, int val2, long mask)
> @@ -125,6 +132,7 @@ static int dpot_dac_write_raw(struct iio_dev *indio_dev,
> static const struct iio_info dpot_dac_info = {
> .read_raw = dpot_dac_read_raw,
> .read_avail = dpot_dac_read_avail,
> + .read_avail_release_resource = dpot_dac_read_avail_release_res,
> .write_raw = dpot_dac_write_raw,
> };
>
> diff --git a/drivers/iio/multiplexer/iio-mux.c b/drivers/iio/multiplexer/iio-mux.c
> index 2953403bef53bbe47a97a8ab1c475ed88d7f86d2..31345437784b01c5d6f8ea70263f4c2574388e7a 100644
> --- a/drivers/iio/multiplexer/iio-mux.c
> +++ b/drivers/iio/multiplexer/iio-mux.c
> @@ -142,6 +142,13 @@ static int mux_read_avail(struct iio_dev *indio_dev,
> return ret;
> }
>
> +static void mux_read_avail_release_res(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan,
> + const int *vals, long mask)
> +{
> + kfree(vals);
> +}
> +
> static int mux_write_raw(struct iio_dev *indio_dev,
> struct iio_chan_spec const *chan,
> int val, int val2, long mask)
> @@ -171,6 +178,7 @@ static int mux_write_raw(struct iio_dev *indio_dev,
> static const struct iio_info mux_info = {
> .read_raw = mux_read_raw,
> .read_avail = mux_read_avail,
> + .read_avail_release_resource = mux_read_avail_release_res,
> .write_raw = mux_write_raw,
> };
>
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 0/7] iio: fix possible race condition during access of available info lists
2024-10-03 17:34 [PATCH 0/7] iio: fix possible race condition during access of available info lists Matteo Martelli
` (6 preceding siblings ...)
2024-10-03 17:34 ` [PATCH 7/7] power: supply: ingenic-battery: free scale buffer after use Matteo Martelli
@ 2024-10-06 14:23 ` Jonathan Cameron
7 siblings, 0 replies; 13+ messages in thread
From: Jonathan Cameron @ 2024-10-06 14:23 UTC (permalink / raw)
To: Matteo Martelli
Cc: Lars-Peter Clausen, Michael Hennerich, Alisa-Dariana Roman,
Christian Eggers, Peter Rosin, Paul Cercueil, Sebastian Reichel,
linux-iio, linux-kernel, linux-mips, linux-pm
On Thu, 03 Oct 2024 19:34:05 +0200
Matteo Martelli <matteomartelli3@gmail.com> wrote:
> Some iio drivers currently share an available info list buffer that
> might be changed while iio core prints it to sysfs. This could cause the
> buffer shared with iio core to be corrupted. However, note that I was
> able to trigger the race condition only by adding a delay between each
> sysfs_emit_at calls in the iio_format_list() to force the concurrent
> access to the shared available list buffer.
>
> This patch set extends the iio APIs and fixes some affected drivers.
Thanks for tidying these up. My comments are very minor but
as this is changing how a core bit of infrastructure works I'd like
them to sit on the list another week anyway.
There is just enough here that I'd prefer a v2 though if you don't
get time I can probably tidy it up whilst applying.
The build bot issue is presumably a missing include.
Thanks,
Jonathan
>
> Summary:
> - Patch 1: iio core: introduce a iio info release callback to let
> drivers share a copy of their available info list and later free it.
>
> - Patch 2: pac1921: handle the current scale available info via the
> read_avail+read_avail_release_resource APIs instead of using an ad-hoc
> ext_info attribute. The latter was used to avoid the risk of a race in
> the available list.
>
> - Patch 3,4: ad7192, as73211: fix the possible race in the drivers by
> copying/releasing the affected available lists.
>
> - Patch 5: inkern: make consumers copy and release the available info
> lists of their producers, necessary after patch 1.
>
> - Patch 6,7: iio-mux, iio-rescale, dpot-dac, ingenic-battery: adapt
> consumers to inkern API change by freeing the now copied available
> lists of their producers.
>
> Tested:
> - pac1921: could not reproduce the race condition with the new APIs,
> even with additional delays among the sysfs_emit_at calls during a
> shunt resistor write. No new issue found after the change.
>
> - iio-mux, iio-rescale, dpot-dac: tested with pac1921 as producer, which
> was adapted to produce a mock raw available info list.
> The tests did not cover the driver features but focused on assessing
> the function call sequence. For example the following traced function
> graph shows a read of the dpot mocked out voltage (with ftrace
> filters: pac1921* iio* dpot* kmemdup_array* kfree*):
>
> 3) | iio_read_channel_info_avail [industrialio]() {
> 3) | dpot_dac_read_avail [dpot_dac]() {
> 3) | iio_read_avail_channel_raw [industrialio]() {
> 3) | iio_channel_read_avail [industrialio]() {
> 3) | pac1921_read_avail [pac1921]() {
> 3) 5.208 us | kmemdup_array();
> 3) + 11.459 us | }
> 3) 3.167 us | kmemdup_array();
> 3) | pac1921_read_avail_release_res [pac1921]() {
> 3) 1.709 us | kfree();
> 3) 4.458 us | }
> 3) + 25.750 us | }
> 3) + 31.792 us | }
> 3) + 35.000 us | }
> 3) + 37.083 us | iio_format_list [industrialio]();
> 3) | dpot_dac_read_avail_release_res [dpot_dac]() {
> 3) 1.583 us | kfree();
> 3) 4.250 us | }
> 3) + 84.292 us | }
>
> - ingenic-battery: also tested with mock available info produced by the
> pac1921 driver. Following the traced graph part that should correspond
> to the ingenic_battery_set_scale() flow (which is not traceable with
> the additional ingenic* ftrace filter for some reason):
>
> 2) | ingenic_battery_probe [ingenic_battery]() {
> ...
> 2) | iio_read_max_channel_raw [industrialio]() {
> 2) | iio_channel_read_avail [industrialio]() {
> 2) | pac1921_read_avail [pac1921]() {
> 2) 4.333 us | kmemdup_array();
> 2) + 10.834 us | }
> 2) 3.500 us | kmemdup_array();
> 2) | pac1921_read_avail_release_res [pac1921]() {
> 2) 1.791 us | kfree();
> 2) 4.625 us | }
> 2) + 26.291 us | }
> 2) 1.583 us | kfree();
> 2) + 35.750 us | }
> 2) | iio_read_avail_channel_attribute [industrialio]() {
> 2) | iio_channel_read_avail [industrialio]() {
> 2) | pac1921_read_avail [pac1921]() {
> 2) 3.250 us | kmemdup_array();
> 2) 8.209 us | }
> 2) 3.458 us | kmemdup_array();
> 2) | pac1921_read_avail_release_res [pac1921]() {
> 2) 1.542 us | kfree();
> 2) 4.292 us | }
> 2) + 21.417 us | }
> 2) + 26.333 us | }
> 2) | iio_write_channel_attribute [industrialio]() {
> 2) 4.375 us | pac1921_write_raw [pac1921]();
> 2) 9.625 us | }
> 2) 1.666 us | kfree();
> 2) * 47810.08 us | }
>
> Not tested:
> - ad7192, as73211
>
> Link: https://lore.kernel.org/linux-iio/20240724-iio-pac1921-v4-0-723698e903a3@gmail.com/
>
> Signed-off-by: Matteo Martelli <matteomartelli3@gmail.com>
> ---
> Matteo Martelli (7):
> iio: core: add read_avail_release_resource callback to fix race
> iio: pac1921: use read_avail+release APIs instead of custom ext_info
> iio: ad7192: copy/release available filter frequencies to fix race
> iio: as73211: copy/release available integration times to fix race
> iio: inkern: copy/release available info from producer
> iio: consumers: release available info buffer copied from producer
> power: supply: ingenic-battery: free scale buffer after use
>
> drivers/iio/adc/ad7192.c | 22 +++++-
> drivers/iio/adc/pac1921.c | 128 ++++++++++++---------------------
> drivers/iio/afe/iio-rescale.c | 8 +++
> drivers/iio/dac/dpot-dac.c | 8 +++
> drivers/iio/industrialio-core.c | 14 +++-
> drivers/iio/inkern.c | 64 ++++++++++++-----
> drivers/iio/light/as73211.c | 23 +++++-
> drivers/iio/multiplexer/iio-mux.c | 8 +++
> drivers/power/supply/ingenic-battery.c | 16 +++--
> include/linux/iio/consumer.h | 4 +-
> include/linux/iio/iio.h | 4 ++
> 11 files changed, 185 insertions(+), 114 deletions(-)
> ---
> base-commit: fec496684388685647652ab4213454fbabdab099
> change-id: 20240802-iio-read-avail-release-cb3d2a1e1b98
>
> Best regards,
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2024-10-06 14:23 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-10-03 17:34 [PATCH 0/7] iio: fix possible race condition during access of available info lists Matteo Martelli
2024-10-03 17:34 ` [PATCH 1/7] iio: core: add read_avail_release_resource callback to fix race Matteo Martelli
2024-10-03 17:34 ` [PATCH 2/7] iio: pac1921: use read_avail+release APIs instead of custom ext_info Matteo Martelli
2024-10-03 17:34 ` [PATCH 3/7] iio: ad7192: copy/release available filter frequencies to fix race Matteo Martelli
2024-10-03 17:34 ` [PATCH 4/7] iio: as73211: copy/release available integration times " Matteo Martelli
2024-10-06 14:18 ` Jonathan Cameron
2024-10-03 17:34 ` [PATCH 5/7] iio: inkern: copy/release available info from producer Matteo Martelli
2024-10-03 17:34 ` [PATCH 6/7] iio: consumers: release available info buffer copied " Matteo Martelli
2024-10-06 14:20 ` Jonathan Cameron
2024-10-03 17:34 ` [PATCH 7/7] power: supply: ingenic-battery: free scale buffer after use Matteo Martelli
2024-10-04 21:55 ` kernel test robot
2024-10-04 23:38 ` kernel test robot
2024-10-06 14:23 ` [PATCH 0/7] iio: fix possible race condition during access of available info lists Jonathan Cameron
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).