mtd: slram: remove failed entries from the device list

register_device() links a new slram_mtdlist entry before allocating all
of the state needed by the entry. If a later allocation, memremap(), or
mtd_device_register() fails, the partially initialized entry remains on
the global list. A later cleanup can then dereference or free invalid
state from that failed entry.

Unwind the partially initialized entry and clear the list tail on each
failure path after the entry has been linked.

Fixes: 1da177e4c3 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Signed-off-by: Ruoyu Wang <ruoyuw560@gmail.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
This commit is contained in:
Ruoyu Wang
2026-06-09 16:45:27 +08:00
committed by Miquel Raynal
parent 72de4a7c8e
commit 36f1648644

View File

@@ -129,6 +129,7 @@ static int slram_write(struct mtd_info *mtd, loff_t to, size_t len,
static int register_device(char *name, unsigned long start, unsigned long length)
{
slram_mtd_list_t **curmtd;
int ret = -ENOMEM;
curmtd = &slram_mtdlist;
while (*curmtd) {
@@ -155,14 +156,15 @@ static int register_device(char *name, unsigned long start, unsigned long length
if (!(*curmtd)->mtdinfo) {
E("slram: Cannot allocate new MTD device.\n");
return(-ENOMEM);
goto err_free_list;
}
if (!(((slram_priv_t *)(*curmtd)->mtdinfo->priv)->start =
memremap(start, length,
MEMREMAP_WB | MEMREMAP_WT | MEMREMAP_WC))) {
E("slram: memremap failed\n");
return -EIO;
ret = -EIO;
goto err_free_priv;
}
((slram_priv_t *)(*curmtd)->mtdinfo->priv)->end =
((slram_priv_t *)(*curmtd)->mtdinfo->priv)->start + length;
@@ -183,10 +185,8 @@ static int register_device(char *name, unsigned long start, unsigned long length
if (mtd_device_register((*curmtd)->mtdinfo, NULL, 0)) {
E("slram: Failed to register new device\n");
memunmap(((slram_priv_t *)(*curmtd)->mtdinfo->priv)->start);
kfree((*curmtd)->mtdinfo->priv);
kfree((*curmtd)->mtdinfo);
return(-EAGAIN);
ret = -EAGAIN;
goto err_unmap;
}
T("slram: Registered device %s from %luKiB to %luKiB\n", name,
(start / 1024), ((start + length) / 1024));
@@ -194,6 +194,16 @@ static int register_device(char *name, unsigned long start, unsigned long length
((slram_priv_t *)(*curmtd)->mtdinfo->priv)->start,
((slram_priv_t *)(*curmtd)->mtdinfo->priv)->end);
return(0);
err_unmap:
memunmap(((slram_priv_t *)(*curmtd)->mtdinfo->priv)->start);
err_free_priv:
kfree((*curmtd)->mtdinfo->priv);
err_free_list:
kfree((*curmtd)->mtdinfo);
kfree(*curmtd);
*curmtd = NULL;
return ret;
}
static void unregister_devices(void)