Skip to content

Commit eee6be6

Browse files
ambarusgregkh
authored andcommitted
firmware: samsung: acpm: Fix cross-thread RX length corruption
[ Upstream commit f133bd4 ] Sashiko identified a cross-thread RX length corruption bug when reviewing the thermal addition to ACPM [1]. When multiple threads concurrently send IPC requests, the ACPM polling mechanism can encounter responses belonging to other threads. To drain the queue, the driver saves these concurrent responses into an internal cache (`rx_data->cmd`) to be retrieved later by the owning thread. Previously, the driver incorrectly used `xfer->rxcnt` (the expected receive length of the *current* polling thread) when copying data for *other* threads into this cache. If the threads expected responses of different lengths, this resulted in buffer underflows (leading to reads of uninitialized memory) or potential buffer overflows. Fix this by replacing the boolean `response` flag in `struct acpm_rx_data` with `rxcnt`, caching the exact expected receive length for each specific transaction during transfer preparation. Use this cached length when saving concurrent responses. Consequently, ensure that `xfer->rxcnt` is explicitly zeroed in driver helpers (e.g., `acpm_dvfs_set_xfer`) for fire-and-forget messages to prevent uninitialized stack garbage from being interpreted as a massive expected receive length. Cc: stable@vger.kernel.org Fixes: a88927b ("firmware: add Exynos ACPM protocol driver") Closes: https://sashiko.dev/#/patchset/20260420-acpm-tmu-v3-0-3dc8e93f0b26%40linaro.org [1] Reported-by: Titouan Ameline de Cadeville <titouan.ameline@gmail.com> Closes: https://lore.kernel.org/r/20260426210255.73674-1-titouan.ameline@gmail.com/ Signed-off-by: Tudor Ambarus <tudor.ambarus@linaro.org> Link: https://patch.msgid.link/20260505-acpm-fixes-sashiko-reports-v5-1-43b5ee7f1674@linaro.org Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org> Signed-off-by: Sasha Levin <sashal@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 02ac3ba commit eee6be6

1 file changed

Lines changed: 7 additions & 7 deletions

File tree

drivers/firmware/samsung/exynos-acpm.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -103,12 +103,12 @@ struct acpm_queue {
103103
*
104104
* @cmd: pointer to where the data shall be saved.
105105
* @n_cmd: number of 32-bit commands.
106-
* @response: true if the client expects the RX data.
106+
* @rxcnt: expected length of the response in 32-bit words.
107107
*/
108108
struct acpm_rx_data {
109109
u32 *cmd;
110110
size_t n_cmd;
111-
bool response;
111+
size_t rxcnt;
112112
};
113113

114114
#define ACPM_SEQNUM_MAX 64
@@ -196,7 +196,7 @@ static void acpm_get_saved_rx(struct acpm_chan *achan,
196196
const struct acpm_rx_data *rx_data = &achan->rx_data[tx_seqnum - 1];
197197
u32 rx_seqnum;
198198

199-
if (!rx_data->response)
199+
if (!rx_data->rxcnt)
200200
return;
201201

202202
rx_seqnum = FIELD_GET(ACPM_PROTOCOL_SEQNUM, rx_data->cmd[0]);
@@ -253,7 +253,7 @@ static int acpm_get_rx(struct acpm_chan *achan, const struct acpm_xfer *xfer)
253253
seqnum = rx_seqnum - 1;
254254
rx_data = &achan->rx_data[seqnum];
255255

256-
if (rx_data->response) {
256+
if (rx_data->rxcnt) {
257257
if (rx_seqnum == tx_seqnum) {
258258
__ioread32_copy(xfer->rxd, addr,
259259
xfer->rxlen / 4);
@@ -267,7 +267,7 @@ static int acpm_get_rx(struct acpm_chan *achan, const struct acpm_xfer *xfer)
267267
* after the response is copied to the request.
268268
*/
269269
__ioread32_copy(rx_data->cmd, addr,
270-
xfer->rxlen / 4);
270+
rx_data->rxcnt);
271271
}
272272
} else {
273273
clear_bit(seqnum, achan->bitmap_seqnum);
@@ -379,8 +379,8 @@ static void acpm_prepare_xfer(struct acpm_chan *achan,
379379
/* Clear data for upcoming responses */
380380
rx_data = &achan->rx_data[achan->seqnum - 1];
381381
memset(rx_data->cmd, 0, sizeof(*rx_data->cmd) * rx_data->n_cmd);
382-
if (xfer->rxd)
383-
rx_data->response = true;
382+
/* zero means no response expected */
383+
rx_data->rxcnt = xfer->rxlen / 4;
384384

385385
/* Flag the index based on seqnum. (seqnum: 1~63, bitmap: 0~62) */
386386
set_bit(achan->seqnum - 1, achan->bitmap_seqnum);

0 commit comments

Comments
 (0)