[PATCH AUTOSEL 6.19-6.18] pinctrl: mediatek: make devm allocations safer and clearer in mtk_eint_do_init()
From: Sasha Levin <sashal@kernel.org>
Date: 2026-02-19 02:04:49
Also in:
linux-gpio, linux-mediatek, linux-patches, lkml, stable
Subsystem:
pin control subsystem, pin controller - mediatek, the rest · Maintainers:
Linus Walleij, Sean Wang, Linus Torvalds
From: Liang Jie <redacted>
[ Upstream commit 255b721c96046d4c57fa2268e4c72607868ce91f ]
mtk_eint_do_init() allocates several pointer arrays which are then
populated in a per-instance loop and freed on error. The arrays are
currently allocated with devm_kmalloc(), so their entries are left
uninitialised until the per-instance allocations succeed.
On a failure in the middle of the loop, the error path iterates over
the full nbase range and calls devm_kfree() on each element. For
indices which were never initialised, the corresponding array entries
contain stack garbage. If any of those happen to be non-zero,
devm_kfree() will pass them to devres_destroy(), which will WARN
because there is no matching devm_kmalloc() resource for such bogus
pointers.
Improve the robustness and readability by:
- Using devm_kcalloc() for the pointer arrays so that all entries
start as NULL, ensuring that only genuinely initialised elements
may be freed and preventing spurious WARN_ON()s in the error path.
- Switching the allocations to sizeof(*ptr) / sizeof(**ptr) forms,
avoiding hard-coded element types and making the code more resilient
to future type changes.
- Dropping the redundant NULL checks before devm_kfree(), as
devm_kfree() safely handles NULL pointers.
The functional behaviour in the successful initialisation path remains
unchanged, while the error handling becomes simpler and less
error-prone.
Reviewed-by: fanggeng <redacted>
Signed-off-by: Liang Jie <redacted>
Signed-off-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
So the buggy code is NOT in 6.12 or older LTS trees (as expected, since
it was added in 6.15). This fix is only relevant for 6.15+ stable trees.
### 7. Verification Summary
**Verification:**
- Read the current file (`mtk-eint.c` lines 520-622) — confirmed the
buggy `devm_kmalloc()` calls at lines 547, 551, 555 and the error path
at lines 598-606 that iterates over uninitialized entries.
- `git log` confirmed `3ef9f710efcb5` ("Add EINT support for multiple
addresses") introduced the multi-base code with `nbase`, the loop, and
the error path — landed in v6.15.
- `git tag --contains 3ef9f710efcb5` confirmed it's in `p-6.15`,
`p-6.16`, `p-6.17`.
- `git log --oneline v6.18.12` confirmed the buggy commit is present in
the 6.18.y stable tree.
- `git log --oneline v6.12` confirmed the buggy code is NOT in 6.12 or
older LTS trees (not applicable for those).
- Verified the error path: loop at line 599 iterates `0..nbase-1`, but
if allocation fails at index `k`, indices `k+1..nbase-1` have
uninitialized pointer entries — confirmed in pre-patch code.
- `devm_kfree(NULL)` is safe (no-op) — confirmed by kernel API
convention.
- The patch is self-contained; no other patches are needed as
dependencies.
### 8. Conclusion
This commit fixes a real bug: **use of uninitialized memory in the error
path** of `mtk_eint_do_init()`. When memory allocation fails partway
through a loop, the cleanup code passes uninitialized (garbage) pointer
values to `devm_kfree()`, which can trigger `WARN_ON()` in
`devres_destroy()` and potentially cause memory corruption.
The fix is small, surgical (3 `devm_kmalloc` → `devm_kcalloc` changes +
removal of now-redundant NULL checks), well-understood, reviewed by a
maintainer, and carries minimal risk. It only affects the error path —
the successful path is functionally unchanged. The buggy code exists in
stable trees 6.15+.
**YES**
drivers/pinctrl/mediatek/mtk-eint.c | 29 +++++++++++++++++------------
1 file changed, 17 insertions(+), 12 deletions(-)
diff --git a/drivers/pinctrl/mediatek/mtk-eint.c b/drivers/pinctrl/mediatek/mtk-eint.c
index c8c5097c11c4d..2a3c04eedc5f3 100644
--- a/drivers/pinctrl/mediatek/mtk-eint.c
+++ b/drivers/pinctrl/mediatek/mtk-eint.c@@ -544,24 +544,32 @@ int mtk_eint_do_init(struct mtk_eint *eint, struct mtk_eint_pin *eint_pin) } } - eint->pin_list = devm_kmalloc(eint->dev, eint->nbase * sizeof(u16 *), GFP_KERNEL); + eint->pin_list = devm_kcalloc(eint->dev, eint->nbase, + sizeof(*eint->pin_list), GFP_KERNEL); if (!eint->pin_list) goto err_pin_list; - eint->wake_mask = devm_kmalloc(eint->dev, eint->nbase * sizeof(u32 *), GFP_KERNEL); + eint->wake_mask = devm_kcalloc(eint->dev, eint->nbase, + sizeof(*eint->wake_mask), GFP_KERNEL); if (!eint->wake_mask) goto err_wake_mask; - eint->cur_mask = devm_kmalloc(eint->dev, eint->nbase * sizeof(u32 *), GFP_KERNEL); + eint->cur_mask = devm_kcalloc(eint->dev, eint->nbase, + sizeof(*eint->cur_mask), GFP_KERNEL); if (!eint->cur_mask) goto err_cur_mask; for (i = 0; i < eint->nbase; i++) { - eint->pin_list[i] = devm_kzalloc(eint->dev, eint->base_pin_num[i] * sizeof(u16), + eint->pin_list[i] = devm_kzalloc(eint->dev, + eint->base_pin_num[i] * sizeof(**eint->pin_list), GFP_KERNEL); port = DIV_ROUND_UP(eint->base_pin_num[i], 32); - eint->wake_mask[i] = devm_kzalloc(eint->dev, port * sizeof(u32), GFP_KERNEL); - eint->cur_mask[i] = devm_kzalloc(eint->dev, port * sizeof(u32), GFP_KERNEL); + eint->wake_mask[i] = devm_kzalloc(eint->dev, + port * sizeof(**eint->wake_mask), + GFP_KERNEL); + eint->cur_mask[i] = devm_kzalloc(eint->dev, + port * sizeof(**eint->cur_mask), + GFP_KERNEL); if (!eint->pin_list[i] || !eint->wake_mask[i] || !eint->cur_mask[i]) goto err_eint; }
@@ -597,12 +605,9 @@ int mtk_eint_do_init(struct mtk_eint *eint, struct mtk_eint_pin *eint_pin) err_eint: for (i = 0; i < eint->nbase; i++) { - if (eint->cur_mask[i]) - devm_kfree(eint->dev, eint->cur_mask[i]); - if (eint->wake_mask[i]) - devm_kfree(eint->dev, eint->wake_mask[i]); - if (eint->pin_list[i]) - devm_kfree(eint->dev, eint->pin_list[i]); + devm_kfree(eint->dev, eint->cur_mask[i]); + devm_kfree(eint->dev, eint->wake_mask[i]); + devm_kfree(eint->dev, eint->pin_list[i]); } devm_kfree(eint->dev, eint->cur_mask); err_cur_mask:
--
2.51.0