[PATCH] drm/nouveau/iccsense: fix memory leak in nvkm_iccsense_oneinit

From: Muhammad Bilal

Date: Mon Aug 03 2026 - 17:50:40 EST


nvbios_iccsense_parse() allocates stbl.rail via kmalloc_objs() to hold
the per-entry power-rail table parsed out of the vbios ICCSENSE table
(drivers/gpu/drm/nouveau/nvkm/subdev/bios/iccsense.c). The only
consumer of that table, nvkm_iccsense_oneinit(), copies the fields it
needs into freshly allocated struct nvkm_iccsense_rail nodes but never
frees stbl.rail itself, on either the normal return path or the
-ENOMEM error path taken when a rail node allocation fails.

nvkm_iccsense_dtor() only walks and frees iccsense->rails (the copied
nodes) and iccsense->sensors -- it has no reference to the transient
stbl.rail array, so that allocation is unrecoverably leaked every time
oneinit() runs.

Observed with kmemleak on a KASAN build:

unreferenced object 0xffff888104cbe480 (size 96)
comm "(udev-worker)" pid 526
backtrace:
nvbios_iccsense_parse+0x217/0x740 [nouveau]
nvkm_iccsense_oneinit+0x140/0xdd0

Free stbl.rail once we're done consuming it, via a common exit path
that also covers the -ENOMEM case.

Note: ret is reset to 0 immediately before the loop rather than at
declaration time, since it is already in use a few lines earlier for
the unrelated nvbios_power_budget_header()/nvbios_power_budget_entry()
return codes. Returning it unreset from the done: label would leak
that unrelated (and commonly non-zero, e.g. on boards without a power
budget table) status code out of oneinit() on the success path.

Fixes: b71c0892631a ("drm/nouveau/iccsense: implement for ina209, ina219 and ina3221")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Muhammad Bilal <meatuni001@xxxxxxxxx>
---
drivers/gpu/drm/nouveau/nvkm/subdev/iccsense/base.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/iccsense/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/iccsense/base.c
index 3ccdbbe2fad0..6bfe4913dcb6 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/iccsense/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/iccsense/base.c
@@ -239,6 +239,7 @@ nvkm_iccsense_oneinit(struct nvkm_subdev *subdev)
return 0;

iccsense->data_valid = true;
+ ret = 0;
for (i = 0; i < stbl.nr_entry; ++i) {
struct pwr_rail_t *pwr_rail = &stbl.rail[i];
struct nvkm_iccsense_sensor *sensor;
@@ -280,8 +281,10 @@ nvkm_iccsense_oneinit(struct nvkm_subdev *subdev)
}

rail = kmalloc_obj(*rail);
- if (!rail)
- return -ENOMEM;
+ if (!rail) {
+ ret = -ENOMEM;
+ goto done;
+ }

rail->read = read;
rail->sensor = sensor;
@@ -291,7 +294,10 @@ nvkm_iccsense_oneinit(struct nvkm_subdev *subdev)
list_add_tail(&rail->head, &iccsense->rails);
}
}
- return 0;
+
+done:
+ kfree(stbl.rail);
+ return ret;
}

static int
--
2.55.0