* [PATCH 0/2] EDAC: fsl_ddr: probe failure and remove lifetime fixes
@ 2026-07-19 19:40 Rosen Penev
2026-07-19 19:40 ` [PATCH 1/2] EDAC: fsl_ddr: restore MC error registers on probe failure Rosen Penev
2026-07-19 19:40 ` [PATCH 2/2] EDAC: fsl_ddr: manage mci lifetime via devres to fix remove UAF Rosen Penev
0 siblings, 2 replies; 3+ messages in thread
From: Rosen Penev @ 2026-07-19 19:40 UTC (permalink / raw)
To: linux-edac
Cc: Frank Li, Borislav Petkov, Tony Luck, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, York Sun,
open list:EDAC-FSL_DDR, open list,
open list:CLANG/LLVM BUILD SUPPORT:Keyword:b(?i:clang|llvm)b
This series fixes two lifetime/error-path issues in the FSL DDR EDAC
driver (drivers/edac/fsl_ddr_edac.c):
* Patch 1: On probe failure, fsl_mc_err_probe() leaves the memory
controller hardware configured to generate interrupts (DISABLE cleared,
INT_EN set) while no handler is registered, which can trigger an
unhandled interrupt storm on the shared IRQ line. Restore the MC error
registers in both error paths.
* Patch 2: The devm-requested IRQ passes mci as context, but
fsl_mc_err_remove() frees mci via edac_mc_free() before devres tears
down the IRQ, leaving a use-after-free window for the shared interrupt
handler. Manage mci lifetime through devres so it is freed only after
the IRQ is released.
Both patches are build-tested for arm64 (defconfig + CONFIG_EDAC_FSL_DDR)
with LLVM=1.
Rosen Penev (2):
EDAC: fsl_ddr: restore MC error registers on probe failure
EDAC: fsl_ddr: manage mci lifetime via devres to fix remove UAF
drivers/edac/fsl_ddr_edac.c | 42 +++++++++++++++++++++++--------------
1 file changed, 26 insertions(+), 16 deletions(-)
--
2.55.0
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH 1/2] EDAC: fsl_ddr: restore MC error registers on probe failure
2026-07-19 19:40 [PATCH 0/2] EDAC: fsl_ddr: probe failure and remove lifetime fixes Rosen Penev
@ 2026-07-19 19:40 ` Rosen Penev
2026-07-19 19:40 ` [PATCH 2/2] EDAC: fsl_ddr: manage mci lifetime via devres to fix remove UAF Rosen Penev
1 sibling, 0 replies; 3+ messages in thread
From: Rosen Penev @ 2026-07-19 19:40 UTC (permalink / raw)
To: linux-edac
Cc: Frank Li, Borislav Petkov, Tony Luck, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, York Sun,
open list:EDAC-FSL_DDR, open list,
open list:CLANG/LLVM BUILD SUPPORT:Keyword:b(?i:clang|llvm)b
fsl_mc_err_probe() clears FSL_MC_ERR_DISABLE and, in EDAC_OPSTATE_INT
mode, sets FSL_MC_ERR_INT_EN to enable error reporting. If a later
initialization step fails and jumps to the err/err2 labels, the cleanup
only frees driver memory and does not restore these hardware registers.
This leaves the memory controller configured to generate interrupts while
no handler is successfully registered, which can cause an unhandled
interrupt storm on the shared IRQ line. Restore FSL_MC_ERR_DISABLE,
FSL_MC_ERR_INT_EN and the SBE threshold in both error paths.
Initialize the orig_ddr_err_disable/orig_ddr_err_sbe save fields up front
so the error paths are safe even when they are reached before the INT
block populates them.
Built for arm64 (defconfig + CONFIG_EDAC_FSL_DDR) with LLVM=1;
drivers/edac/fsl_ddr_edac.o compiles cleanly.
Fixes: ea2eb9a8b620 ("EDAC, fsl-ddr: Separate FSL DDR driver from MPC85xx")
Assisted-by: opencode:hy3-free
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
drivers/edac/fsl_ddr_edac.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/edac/fsl_ddr_edac.c b/drivers/edac/fsl_ddr_edac.c
index b27dff96aeb6..b1e6e177b088 100644
--- a/drivers/edac/fsl_ddr_edac.c
+++ b/drivers/edac/fsl_ddr_edac.c
@@ -518,6 +518,8 @@ int fsl_mc_err_probe(struct platform_device *op)
pdata = mci->pvt_info;
pdata->name = "fsl_mc_err";
+ pdata->orig_ddr_err_disable = 0;
+ pdata->orig_ddr_err_sbe = 0;
mci->pdev = &op->dev;
pdata->edac_idx = edac_mc_idx++;
dev_set_drvdata(mci->pdev, mci);
@@ -645,7 +647,11 @@ int fsl_mc_err_probe(struct platform_device *op)
err2:
edac_mc_del_mc(&op->dev);
+ ddr_out32(pdata, FSL_MC_ERR_INT_EN, 0);
err:
+ ddr_out32(pdata, FSL_MC_ERR_DISABLE,
+ pdata->orig_ddr_err_disable);
+ ddr_out32(pdata, FSL_MC_ERR_SBE, pdata->orig_ddr_err_sbe);
devres_release_group(&op->dev, fsl_mc_err_probe);
edac_mc_free(mci);
return res;
--
2.55.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH 2/2] EDAC: fsl_ddr: manage mci lifetime via devres to fix remove UAF
2026-07-19 19:40 [PATCH 0/2] EDAC: fsl_ddr: probe failure and remove lifetime fixes Rosen Penev
2026-07-19 19:40 ` [PATCH 1/2] EDAC: fsl_ddr: restore MC error registers on probe failure Rosen Penev
@ 2026-07-19 19:40 ` Rosen Penev
1 sibling, 0 replies; 3+ messages in thread
From: Rosen Penev @ 2026-07-19 19:40 UTC (permalink / raw)
To: linux-edac
Cc: Frank Li, Borislav Petkov, Tony Luck, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, York Sun,
open list:EDAC-FSL_DDR, open list,
open list:CLANG/LLVM BUILD SUPPORT:Keyword:b(?i:clang|llvm)b
fsl_mc_err_probe() requests the shared interrupt with devm_request_irq(),
passing mci as the handler context. At removal fsl_mc_err_remove() calls
edac_mc_free(mci) explicitly, but the devm-requested IRQ is only torn
down by devres afterwards. Between edac_mc_free() and the IRQ release,
another device sharing the line can fire and fsl_mc_isr() will
dereference the freed mci and its pdata.
Register an edac_mc_free() callback via devm_add_action_or_reset() right
after edac_mc_alloc(), so mci is owned by devres and freed only after the
devm IRQ is released (devres runs actions in LIFO order). Drop the
explicit edac_mc_free() from both the probe error paths and
fsl_mc_err_remove(); edac_mc_del_mc() is still called explicitly at
remove time so the edac device is unregistered before the deferred free.
This also lets the now-redundant devres group open/release/remove calls
be removed.
Built for arm64 (defconfig + CONFIG_EDAC_FSL_DDR) with LLVM=1;
drivers/edac/fsl_ddr_edac.o compiles cleanly and passes checkpatch --strict.
Fixes: ea2eb9a8b620 ("EDAC, fsl-ddr: Separate FSL DDR driver from MPC85xx")
Assisted-by: opencode:hy3-free
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
drivers/edac/fsl_ddr_edac.c | 36 ++++++++++++++++++++----------------
1 file changed, 20 insertions(+), 16 deletions(-)
diff --git a/drivers/edac/fsl_ddr_edac.c b/drivers/edac/fsl_ddr_edac.c
index b1e6e177b088..cdd129bc42c7 100644
--- a/drivers/edac/fsl_ddr_edac.c
+++ b/drivers/edac/fsl_ddr_edac.c
@@ -490,6 +490,13 @@ static void fsl_ddr_init_csrows(struct mem_ctl_info *mci)
}
}
+static void fsl_mc_edac_free(void *data)
+{
+ struct mem_ctl_info *mci = data;
+
+ edac_mc_free(mci);
+}
+
int fsl_mc_err_probe(struct platform_device *op)
{
struct mem_ctl_info *mci;
@@ -500,9 +507,6 @@ int fsl_mc_err_probe(struct platform_device *op)
u32 sdram_ctl;
int res;
- if (!devres_open_group(&op->dev, fsl_mc_err_probe, GFP_KERNEL))
- return -ENOMEM;
-
layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
layers[0].size = 4;
layers[0].is_virt_csrow = true;
@@ -511,10 +515,17 @@ int fsl_mc_err_probe(struct platform_device *op)
layers[1].is_virt_csrow = false;
mci = edac_mc_alloc(edac_mc_idx, ARRAY_SIZE(layers), layers,
sizeof(*pdata));
- if (!mci) {
- devres_release_group(&op->dev, fsl_mc_err_probe);
+ if (!mci)
return -ENOMEM;
- }
+
+ /*
+ * Manage mci lifetime via devres so it is freed only after the
+ * devm-requested IRQ is released, avoiding a use-after-free of mci
+ * (and its pdata) in the shared interrupt handler during removal.
+ */
+ res = devm_add_action_or_reset(&op->dev, fsl_mc_edac_free, mci);
+ if (res)
+ return res;
pdata = mci->pvt_info;
pdata->name = "fsl_mc_err";
@@ -558,10 +569,8 @@ int fsl_mc_err_probe(struct platform_device *op)
if (pdata->flag == TYPE_IMX9) {
pdata->inject_vbase = devm_platform_ioremap_resource_byname(op, "inject");
- if (IS_ERR(pdata->inject_vbase)) {
- res = -ENOMEM;
- goto err;
- }
+ if (IS_ERR(pdata->inject_vbase))
+ return -ENOMEM;
}
if (pdata->flag == TYPE_IMX9) {
@@ -575,8 +584,7 @@ int fsl_mc_err_probe(struct platform_device *op)
if ((sdram_ctl & ecc_en_mask) != ecc_en_mask) {
/* no ECC */
pr_warn("%s: No ECC DIMMs discovered\n", __func__);
- res = -ENODEV;
- goto err;
+ return -ENODEV;
}
edac_dbg(3, "init mci\n");
@@ -639,7 +647,6 @@ int fsl_mc_err_probe(struct platform_device *op)
pdata->irq);
}
- devres_remove_group(&op->dev, fsl_mc_err_probe);
edac_dbg(3, "success\n");
pr_info(EDAC_MOD_STR " MC err registered\n");
@@ -652,8 +659,6 @@ int fsl_mc_err_probe(struct platform_device *op)
ddr_out32(pdata, FSL_MC_ERR_DISABLE,
pdata->orig_ddr_err_disable);
ddr_out32(pdata, FSL_MC_ERR_SBE, pdata->orig_ddr_err_sbe);
- devres_release_group(&op->dev, fsl_mc_err_probe);
- edac_mc_free(mci);
return res;
}
@@ -674,5 +679,4 @@ void fsl_mc_err_remove(struct platform_device *op)
edac_mc_del_mc(&op->dev);
- edac_mc_free(mci);
}
--
2.55.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-07-19 19:40 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-19 19:40 [PATCH 0/2] EDAC: fsl_ddr: probe failure and remove lifetime fixes Rosen Penev
2026-07-19 19:40 ` [PATCH 1/2] EDAC: fsl_ddr: restore MC error registers on probe failure Rosen Penev
2026-07-19 19:40 ` [PATCH 2/2] EDAC: fsl_ddr: manage mci lifetime via devres to fix remove UAF Rosen Penev
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox