[PATCH 01/58] mtd: clear OTP provider pointers after unregistering them
James Hilliard
james.hilliard1 at gmail.com
Sat Nov 7 02:15:58 PST 2026
If factory OTP discovery or registration fails after user OTP was
registered, mtd_otp_nvmem_add() unregisters the user provider but leaves
its pointer set. mtd_device_parse_register() then unregisters it again
while unwinding the error, accessing a freed provider or dropping a
reference still owned by a consumer.
The same stale pointer survives when the factory OTP error is
-EOPNOTSUPP, which mtd_otp_nvmem_add() treats as success. In that case
mtd_device_unregister() can release the provider a second time later.
Centralize removal of the OTP providers and clear each pointer after
unregistering it so subsequent cleanup cannot repeat the put.
Fixes: e0489f6e221f ("mtd: core: fix error path for nvmem provider")
Cc: stable at vger.kernel.org
Signed-off-by: James Hilliard <james.hilliard1 at gmail.com>
---
drivers/mtd/mtdcore.c | 19 ++++++++++++-------
1 file changed, 12 insertions(+), 7 deletions(-)
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 8efa2d88556e..558a605ba749 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -1016,6 +1016,14 @@ static int mtd_nvmem_fact_otp_reg_read(void *priv, unsigned int offset,
return retlen == bytes ? 0 : -EIO;
}
+static void mtd_otp_nvmem_remove(struct mtd_info *mtd)
+{
+ nvmem_unregister(mtd->otp_user_nvmem);
+ mtd->otp_user_nvmem = NULL;
+ nvmem_unregister(mtd->otp_factory_nvmem);
+ mtd->otp_factory_nvmem = NULL;
+}
+
static int mtd_otp_nvmem_add(struct mtd_info *mtd)
{
struct device *dev = mtd->dev.parent;
@@ -1082,7 +1090,7 @@ static int mtd_otp_nvmem_add(struct mtd_info *mtd)
return 0;
err:
- nvmem_unregister(mtd->otp_user_nvmem);
+ mtd_otp_nvmem_remove(mtd);
/* Don't report error if OTP is not supported. */
if (err == -EOPNOTSUPP)
return 0;
@@ -1180,10 +1188,8 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
}
out:
- if (ret) {
- nvmem_unregister(mtd->otp_user_nvmem);
- nvmem_unregister(mtd->otp_factory_nvmem);
- }
+ if (ret)
+ mtd_otp_nvmem_remove(mtd);
if (ret && device_is_registered(&mtd->dev)) {
err = del_mtd_device(mtd);
@@ -1210,8 +1216,7 @@ int mtd_device_unregister(struct mtd_info *master)
memset(&master->reboot_notifier, 0, sizeof(master->reboot_notifier));
}
- nvmem_unregister(master->otp_user_nvmem);
- nvmem_unregister(master->otp_factory_nvmem);
+ mtd_otp_nvmem_remove(master);
if (IS_REACHABLE(CONFIG_MTD_VIRT_CONCAT)) {
err = mtd_virt_concat_destroy(master);
--
2.53.0
More information about the linux-mtd
mailing list