Skip to content

clk: imx: fix NULL pointer deref in imx_unregister_hw_clocks() error path - #49

Open
ngocthang2710 wants to merge 1 commit into
nxp-imx:lf-6.18.yfrom
ngocthang2710:fix/clk-imx-unregister-null-deref
Open

clk: imx: fix NULL pointer deref in imx_unregister_hw_clocks() error path#49
ngocthang2710 wants to merge 1 commit into
nxp-imx:lf-6.18.yfrom
ngocthang2710:fix/clk-imx-unregister-null-deref

Conversation

@ngocthang2710

@ngocthang2710 ngocthang2710 commented Aug 1, 2026

Copy link
Copy Markdown

Summary

imx_unregister_hw_clocks() unconditionally calls clk_hw_unregister() for
every entry in the hws[] array up to count, including entries that were
never populated because the calling probe function returned early on error
before filling the whole array. Those unfilled entries are still NULL, so
clk_hw_unregister(NULL) dereferences a NULL pointer and crashes.

How it was found

Reproduced on FRDM-IMX91 (i.MX91, standalone U-Boot/kernel build,
imx91_11x11_frdm_defconfig + imx91-11x11-frdm.dtb) when
imx93_clocks_probe() (shared clock driver for i.MX91/i.MX93) jumps to the
unregister_hws error path after devm_of_iomap() fails on the
"fsl,imx93-anatop" node:

WARNING: CPU: 0 PID: 1 at drivers/clk/imx/clk-imx93.c:339 imx93_clocks_probe+0x5bc/0x5d8
...
Unable to handle kernel NULL pointer dereference ... clk_hw_unregister+0xc/0x20
Kernel panic - not syncing: Attempted to kill init!

imx_unregister_hw_clocks(clks, IMX93_CLK_END) walks past the ~10 clocks
actually registered before the failure and hits NULL entries, turning a
recoverable probe failure into a full kernel panic.

Fix

Skip entries that are NULL or an error pointer before unregistering.

Test plan

  • Booted on FRDM-IMX91 hardware: before the fix, imx93_clocks_probe()
    failure escalates to a kernel panic (Attempted to kill init!).
    After the fix, the probe fails gracefully (error -22), boot
    continues normally, and the kernel reaches the expected
    VFS: Unable to mount root fs stop point (no rootfs attached in this
    test setup).

Update: root cause of the underlying imx93_clocks_probe() failure identified

An earlier version of this description speculated the devm_of_iomap()
failure on the anatop node was related to TRDC access configuration in ATF.
That hypothesis has since been disproven by elimination testing and is
retracted so it doesn't mislead anyone investigating further:

Components (SPL / BL31+OP-TEE / kernel) Result
standalone-built / standalone-built / lf-6.18.y fails
standalone-built / extracted from NXP's official imx-boot-imx91frdm-sd.bin-flash_singleboot / lf-6.18.y fails identically
extracted from NXP's official image / extracted from NXP's official image / lf-6.18.y fails identically
extracted from NXP's official image / extracted from NXP's official image / lf-6.12.y no failure, boots to login

Swapping SPL and then BL31+OP-TEE for NXP's own known-good binaries (from
their validated FRDM release) did not change the outcome at all — same
crash, same offsets. The only change that fixed it was switching the kernel
branch from lf-6.18.y to lf-6.12.y. Since imx93_clocks_probe() runs
entirely in kernel space, well after firmware hand-off, this rules out
SPL/ATF/OP-TEE/TRDC and points to a lf-6.18.y-specific regression in the
imx93-ccm driver or its interaction with the FRDM-IMX91 DT on that branch.
This PR's NULL-check fix remains correct and worth keeping regardless (any
early probe failure elsewhere would hit the same crash), but it does not
address that separate lf-6.18.y regression, which needs its own
investigation/issue.

…path

imx_unregister_hw_clocks() unconditionally calls clk_hw_unregister()
for every entry in the hws[] array up to count, including entries that
were never populated because the calling probe function (e.g.
imx93_clocks_probe()) returned early on error before filling the whole
array. Those unfilled entries are still NULL/zeroed, so
clk_hw_unregister(NULL) dereferences a NULL pointer and crashes.

Reproduced on FRDM-IMX91 (i.MX91) when imx93_clocks_probe() jumps to
the unregister_hws error path after devm_of_iomap() fails on the
"fsl,imx93-anatop" node (WARN_ON at clk-imx93.c:339): the subsequent
imx_unregister_hw_clocks(clks, IMX93_CLK_END) call walks past the ~10
clocks actually registered and hits NULL entries, turning a recoverable
probe failure into a full kernel panic ("Attempted to kill init!").

Skip entries that are NULL or an error pointer before unregistering.

Signed-off-by: ThangNN99 <ngocthang2710.1999@gmail.com>
@ngocthang2710

Copy link
Copy Markdown
Author

@MrVan @Anson-Huang could you please take a look when you have a chance? This fixes a NULL pointer deref crash in the shared clk_hw_unregister() error path that I hit while bringing up a standalone build on FRDM-IMX91 (imx93_clocks_probe() failing on the anatop iomap). Thanks!

@ngocthang2710

Copy link
Copy Markdown
Author

Correction for @MrVan @Anson-Huang: I initially speculated the root imx93_clocks_probe() failure was TRDC-related in ATF. I've since disproven that by swapping in NXP's own official BL31+OP-TEE binaries (extracted from imx-boot-imx91frdm-sd.bin-flash_singleboot) — same crash, identical offsets. The only thing that fixed the underlying probe failure was switching the kernel branch from lf-6.18.y to lf-6.12.y, so this looks like a lf-6.18.y-specific regression unrelated to firmware. Updated the PR description with the full elimination table. This PR's NULL-check fix still stands on its own regardless of that root cause.

@ngocthang2710

Copy link
Copy Markdown
Author

Separate finding: lf-6.18.y regression report (issues are disabled on this repo, posting here instead)

Since this repo has Issues disabled, filing the full root-cause writeup for the underlying imx93_clocks_probe() failure here instead of a separate issue.

Summary: on FRDM-IMX91, imx93-ccm fails to probe on lf-6.18.y, cascading into every peripheral depending on it (USB, I2C, MMC/eMMC, ADC, watchdog, thermal) being stuck in deferred probe forever — the board never reaches a usable rootfs mount. The identical driver/DT/firmware works fine on lf-6.12.y.

platform 4c100000.usb: deferred probe pending: platform: supplier 44450000.clock-controller not ready
platform 44340000.i2c: deferred probe pending: platform: supplier 44450000.clock-controller not ready
platform 42850000.mmc: deferred probe pending: platform: supplier 44450000.clock-controller not ready
platform 42860000.mmc: deferred probe pending: platform: supplier 44450000.clock-controller not ready
platform 44530000.adc: deferred probe pending: platform: supplier 44450000.clock-controller not ready
platform 42490000.watchdog: deferred probe pending: platform: supplier 44450000.clock-controller not ready

(full deferred-probe list and elimination table already in the PR description above)

Environment: linux-imx lf-6.18.y (fails) vs lf-6.12.y (works), imx_v8_defconfig, imx91-11x11-frdm.dtb, uboot-imx lf_v2026.04 (imx91_11x11_frdm_defconfig), imx-atf lf_v2.14.

Flagging in case anyone tracking lf-6.18.y FRDM-IMX91 support wants to reproduce — happy to provide more detail (full dmesg, .config) if useful.

@ngocthang2710

Copy link
Copy Markdown
Author

Follow-up: pinpointed the architectural change behind the lf-6.18.y regression

Dug further into this (comparing lf-6.12.y, which works, against lf-6.18.y, which doesn't):

  • lf-6.12.y: i.MX91 has its own dedicated clock driver, drivers/clk/imx/clk-imx91.c. The anatop node in imx91.dtsi is anatop@44480000 with compatible = "fsl,imx91-anatop", "syscon";.
  • lf-6.18.y: clk-imx91.c no longer exists — i.MX91 has been merged into the shared clk-imx93.c driver (imx93_clocks_probe(), matched via "fsl,imx91-ccm" in the of_match table). The anatop node moved into the new shared imx91_93_common.dtsi as clock-controller@44480000 with compatible = "fsl,imx93-anatop"; (no "syscon" fallback), to line up with what the shared driver's of_find_compatible_node(NULL, NULL, "fsl,imx93-anatop") call looks for.

I initially suspected a compatible-string mismatch from this refactor (i.e. that imx91.dtsi's &clk { compatible = "fsl,imx91-ccm"; }; override wasn't taking effect), but that's ruled out too — I decompiled both the dtb I built from lf-6.18.y source and the factory NXP dtb (from the LF_v6.6.36-2.1.0 FRDM release package) with dtc, and both correctly show compatible = "fsl,imx91-ccm"; on the clock-controller node. So the driver is getting PLAT_IMX91 as expected, and the dts-side compatible for anatop matches what the driver searches for. The devm_of_iomap() failure still happens anyway.

So the regression looks like it's specifically in the driver-unification refactor itself (imx91 clock support folded into clk-imx93.c) rather than a simple dts typo — something in the old dedicated clk-imx91.c path isn't fully preserved by the shared driver for FRDM-IMX91, but I don't have the commit history to pin down which change (shallow-cloned --depth 1, no full git log between the branches). Hoping this narrower description is useful for whoever worked on that unification.

@ngocthang2710

Copy link
Copy Markdown
Author

Opened #50 with a working fix for the underlying imx93_clocks_probe() regression itself (restores the dedicated clk-imx91.c driver) — tested on hardware, boots to login now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant