[PATCH] thermal: tegra-bpmp: fix use-after-free in trip update work

Fan Wu posted 1 patch 2 weeks, 2 days ago
drivers/thermal/tegra/tegra-bpmp-thermal.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
[PATCH] thermal: tegra-bpmp: fix use-after-free in trip update work
Posted by Fan Wu 2 weeks, 2 days ago
Each thermal zone carries a work_struct that the BPMP thermal message
handler queues on the system workqueue whenever the firmware reports
a trip point crossing. The work handler tz_device_update_work_fn()
recovers the zone with container_of() and calls
thermal_zone_device_update() on its thermal zone device.

tegra_bpmp_thermal_remove() only unregisters the mrq handler with
tegra_bpmp_free_mrq(). That stops new trip messages from being
dispatched, but it does not drain work that was already queued. After
the remove callback returns, devm releases the zones, and a pending
trip update work can then run and dereference the freed zone.

Cancel the per-zone works after tegra_bpmp_free_mrq(), which
guarantees no new instance can be queued: mrq handlers are dispatched
under the same bpmp->lock that tegra_bpmp_free_mrq() holds.

This issue was found by an in-house static analysis tool.

Fixes: 7afebede62be ("thermal: Add Tegra BPMP thermal sensor driver")
Cc: stable@vger.kernel.org
Assisted-by: Codex:gpt-5.6
Co-developed-by: Song Li <songl@zju.edu.cn>
Signed-off-by: Song Li <songl@zju.edu.cn>
Signed-off-by: Fan Wu <fanwu01@zju.edu.cn>
---
 drivers/thermal/tegra/tegra-bpmp-thermal.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/thermal/tegra/tegra-bpmp-thermal.c b/drivers/thermal/tegra/tegra-bpmp-thermal.c
index 997d77ce30d..7ad46b34e17 100644
--- a/drivers/thermal/tegra/tegra-bpmp-thermal.c
+++ b/drivers/thermal/tegra/tegra-bpmp-thermal.c
@@ -303,8 +303,12 @@ static int tegra_bpmp_thermal_probe(struct platform_device *pdev)
 static void tegra_bpmp_thermal_remove(struct platform_device *pdev)
 {
 	struct tegra_bpmp_thermal *tegra = platform_get_drvdata(pdev);
+	unsigned int i;
 
 	tegra_bpmp_free_mrq(tegra->bpmp, MRQ_THERMAL, tegra);
+
+	for (i = 0; i < tegra->num_zones; ++i)
+		cancel_work_sync(&tegra->zones[i]->tz_device_update_work);
 }
 
 static const struct of_device_id tegra_bpmp_thermal_of_match[] = {