[PATCH v3 2/3] soc: qcom: apr: Fix theoretical use-after-free of GPR port on concurrent RX callback

From: Krzysztof Kozlowski

Date: Tue Nov 03 2026 - 10:26:36 EST


gpr_do_rx_callback(), executed from the RX workqueue, looks up the
destination port in the IDR under svcs_lock, but then drops the lock to
call port's callback.

Concurrently closing a graph calls gpr_free_port(), which frees the port
after removing it from IDR, thus a theoretical scenario (not reproduced)
is possible:

CPU0 (RX worker) CPU1 (teardown)
---------------- ---------------
gpr_do_rx_callback()
lock(svcs_lock)
svc = idr_find()
unlock(svcs_lock)
q6apm_graph_close()
gpr_free_port()
idr_remove()
kfree(port)
kfree(graph)
svc->callback(..., svc->priv) <- use-after-free

Reported-by: Sashiko <sashiko-bot@xxxxxxxxxx>
Closes: https://sashiko.dev/#/bug/linux-1ebe255f-a874-46dc-b7cc-455e7bce402f
Fixes: ec1471a898cc ("soc: qcom: apr: Add GPR support")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@xxxxxxxxxxxxxxxx>

---

Changes in v3:
1. New patch
---
drivers/soc/qcom/apr.c | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/drivers/soc/qcom/apr.c b/drivers/soc/qcom/apr.c
index e303562526d4..80056bd0686b 100644
--- a/drivers/soc/qcom/apr.c
+++ b/drivers/soc/qcom/apr.c
@@ -83,6 +83,13 @@ void gpr_free_port(gpr_port_t *port)
idr_remove(&gpr->svcs_idr, port->id);
spin_unlock_irqrestore(&gpr->svcs_lock, flags);

+ /*
+ * The port is no longer discoverable, but RX worker might have already
+ * looked it up and be calling its callback, so wait for
+ * gpr_do_rx_callback() to finish.
+ */
+ flush_workqueue(gpr->rxwq);
+
kfree(port);
}
EXPORT_SYMBOL_GPL(gpr_free_port);
--
2.53.0