[PATCH] fix: mtd: mtd_device_parse_register: fix refcount imbalance on add_mtd_device failure and multi-call scenarios

WenTao Liang vulab at iscas.ac.cn
Fri Jun 26 08:13:49 PDT 2026


add_mtd_device initializes mtd->refcnt via kref_init unconditionally. The
  cleanup in the out label only calls del_mtd_device when
  device_is_registered is true. When add_mtd_device fails before
  device_register, the refcnt is left at 1 (leak). Conversely, when
  CONFIG_MTD_PARTITIONED_MASTER is disabled and the device was already
  registered by a prior call, the error path incorrectly calls
  del_mtd_device without a matching add_mtd_device in this invocation,
  causing a refcount underflow.

Track whether add_mtd_device succeeded in this invocation with a
  registered flag, and only call del_mtd_device on error when registered is
  true.

Cc: stable at vger.kernel.org
Fixes: 1c4c215cbdcb ("mtd: add new API for handling MTD registration")
Signed-off-by: WenTao Liang <vulab at iscas.ac.cn>
---
 drivers/mtd/mtdcore.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 576537774628..59d8a6c61f55 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -1108,6 +1108,7 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
 			      int nr_parts)
 {
 	int ret, err;
+	bool registered = false;
 
 	mtd_set_dev_defaults(mtd);
 
@@ -1119,6 +1120,7 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
 		ret = add_mtd_device(mtd);
 		if (ret)
 			goto out;
+		registered = true;
 	}
 
 	if (IS_REACHABLE(CONFIG_MTD_VIRT_CONCAT)) {
@@ -1136,9 +1138,11 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
 		ret = 0;
 	else if (nr_parts)
 		ret = add_mtd_partitions(mtd, parts, nr_parts);
-	else if (!device_is_registered(&mtd->dev))
+	else if (!device_is_registered(&mtd->dev)) {
 		ret = add_mtd_device(mtd);
-	else
+		if (!ret)
+			registered = true;
+	} else
 		ret = 0;
 
 	if (ret)
@@ -1170,7 +1174,7 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
 		nvmem_unregister(mtd->otp_factory_nvmem);
 	}
 
-	if (ret && device_is_registered(&mtd->dev)) {
+	if (ret && registered) {
 		err = del_mtd_device(mtd);
 		if (err)
 			pr_err("Error when deleting MTD device (%d)\n", err);
-- 
2.39.5 (Apple Git-154)




More information about the linux-mtd mailing list