[PATCH mt76 v3] wifi: mt76: mt7915: fix thermal zone use-after-free and cooling device leak
From: Ryan Leung via B4 Relay
Date: Sun Sep 06 2026 - 17:42:21 EST
From: Ryan Leung <untilscour@xxxxxxxxxxxxxx>
The thermal zone registered against the parent device is never torn
down when the phy is unregistered, so it can still be dereferenced
by the thermal core after the phy is freed. The thermal zone and
cooling device are also left registered if a later hwmon
registration step fails during init, leaking both.
Unregister the thermal zone alongside the cooling device on both the
regular unregister path and the init failure path. Also clear
phy->tzone and phy->cdev after unregistering so that a future caller
invoking the function twice doesn't unregister already-freed objects.
While at it, include the band index in the thermal zone registration
warning to help identify which band failed on multi-band chips.
Fixes: 313f1a27ebcb ("wifi: mt76: mt7915: add thermal zone device registration")
Signed-off-by: Ryan Leung <untilscour@xxxxxxxxxxxxxx>
---
Changes in v3:
- Clear phy->tzone/phy->cdev in mt7915_unregister_thermal() after
unregistering, making it idempotent.
- Link to v2: https://patch.msgid.link/20260810-mt7915-unregister-thermal-v2-1-2a0f51adf56f@xxxxxxxxxxxxxx
Changes in v2:
- Unwind cdev/tzone registration in mt7915_thermal_init() on hwmon registration failure.
- Link to v1: https://patch.msgid.link/20260810-mt7915-unregister-thermal-v1-1-c6d57b4cb368@xxxxxxxxxxxxxx
---
drivers/net/wireless/mediatek/mt76/mt7915/init.c | 17 ++++++++++++++---
1 file changed, 14 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c
index ca46a203aa48..e5285d1a1f9d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c
@@ -200,11 +200,17 @@ static void mt7915_unregister_thermal(struct mt7915_phy *phy)
{
struct wiphy *wiphy = phy->mt76->hw->wiphy;
+ if (phy->tzone) {
+ devm_thermal_of_zone_unregister(phy->dev->mt76.dev, phy->tzone);
+ phy->tzone = NULL;
+ }
+
if (!phy->cdev)
return;
sysfs_remove_link(&wiphy->dev.kobj, "cooling_device");
thermal_cooling_device_unregister(phy->cdev);
+ phy->cdev = NULL;
}
static int mt7915_thermal_init(struct mt7915_phy *phy)
@@ -213,6 +219,7 @@ static int mt7915_thermal_init(struct mt7915_phy *phy)
struct thermal_cooling_device *cdev;
struct device *hwmon;
const char *name;
+ int ret;
name = devm_kasprintf(&wiphy->dev, GFP_KERNEL, "mt7915_%s",
wiphy_name(wiphy));
@@ -238,8 +245,8 @@ static int mt7915_thermal_init(struct mt7915_phy *phy)
if (IS_ERR(phy->tzone)) {
if (PTR_ERR(phy->tzone) != -ENODEV)
dev_warn(phy->dev->mt76.dev,
- "failed to register thermal zone: %ld\n",
- PTR_ERR(phy->tzone));
+ "failed to register thermal zone %d: %ld\n",
+ phy->mt76->band_idx, PTR_ERR(phy->tzone));
phy->tzone = NULL;
}
@@ -248,7 +255,11 @@ static int mt7915_thermal_init(struct mt7915_phy *phy)
hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev, name, phy,
mt7915_hwmon_groups);
- return PTR_ERR_OR_ZERO(hwmon);
+ ret = PTR_ERR_OR_ZERO(hwmon);
+ if (ret)
+ mt7915_unregister_thermal(phy);
+
+ return ret;
}
static void mt7915_led_set_config(struct led_classdev *led_cdev,
---
base-commit: 1b60ed34f712e9f606d80951f1586f4274ebadf1
change-id: 20260809-mt7915-unregister-thermal-82e805c618a6
Best regards,
--
Ryan Leung <untilscour@xxxxxxxxxxxxxx>