[PATCH 2/3] firmware: arm_scmi: Fix bound iterators returning too many items

Geert Uytterhoeven
2026-03-23T16:56:21Z

When using a bound-iterator with an upper bound, commands are sent, and
responses are received, until the upper bound is reached. However, it
is up to the SCMI provider implementation to decide how many rates are
returned in response to a single CLOCK_DESCRIBE_RATES command. If the
last response contains rates beyond the specified upper bound, they are
still passed up for further processing. This may lead to buffer
overflows in unprepared callsites.

While the imprecise bound handling may have been intentional (it was
mentioned in the commit message introducing the code), it is still
confusing for users, and may cause hard to debug crashes. Fix this by
strictly enforcing the upper bound.

Note that this may cause an increase in the number of
CLOCK_DESCRIBE_RATES commands issued, as retrieving the last rate may no
longer be done inadvertentently, but require its own command.

Fixes: 13289addf5a52e1f ("firmware: arm_scmi: Add bound iterators support")
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
This caused random "kernel BUG at drivers/base/devres.c:135!" crashes
during boot on R-Car X5H, as lazy clock rate discovery does not handle
correctly receiving more rates than expected.

Example for a clock with 8 rates, which are all returned in response to
a single CLOCK_DESCRIBE_RATES command:

scmi_clock_describe_rates_get_lazy: Grabbing rates 0..2
iter_clk_describe_update_state: Returned 8 remaining 0
iter_clk_describe_update_state: Allocating 8 rates
iter_clk_describe_process_response: rates[0] = 33333333
iter_clk_describe_process_response: rates[1] = 66666666
iter_clk_describe_process_response: rates[2] = 133333333
iter_clk_describe_process_response: rates[3] = 266666666
iter_clk_describe_process_response: rates[4] = 355555555
iter_clk_describe_process_response: rates[5] = 533333333
iter_clk_describe_process_response: rates[6] = 711111111
iter_clk_describe_process_response: rates[7] = 1066666666
^^^^^^^^^^
Rates [3] to [7] are received, despite being outside the bound.

scmi_clock_describe_rates_get_lazy: Grabbing rates 7..7
iter_clk_describe_update_state: Returned 1 remaining 0
iter_clk_describe_process_response: rates[8] = 1066666666
^ ^^^^^^^^^^
Out of bounds access! ------------------------+ |
Same value as [7] ---------------------------------+
---
drivers/firmware/arm_scmi/driver.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index 2a9183686203b4e7..03fd7caa8b42a12c 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -1820,6 +1820,7 @@ static int __scmi_iterator_run(void *iter, unsigned int *start, unsigned int *en
const struct scmi_protocol_handle *ph;
struct scmi_iterator_state *st;
struct scmi_iterator *i;
+ unsigned int n;

if (!iter)
return -EINVAL;
@@ -1852,13 +1853,17 @@ static int __scmi_iterator_run(void *iter, unsigned int *start, unsigned int *en
return -EINVAL;
}

- for (st->loop_idx = 0; st->loop_idx < st->num_returned; st->loop_idx++) {
+ if (end)
+ n = min(st->num_returned, *end - st->desc_index + 1);
+ else
+ n = st->num_returned;
+ for (st->loop_idx = 0; st->loop_idx < n; st->loop_idx++) {
ret = iops->process_response(ph, i->resp, st, i->priv);
if (ret)
return ret;
}

- st->desc_index += st->num_returned;
+ st->desc_index += n;
ph->xops->reset_rx_to_maxsz(ph, i->t);
/*
* check for both returned and remaining to avoid infinite
--
2.43.0