[PATCH] mtd: rfd_ftl: quiesce requests before freeing mappings

Sung Byeongchan tjdqudcks0424 at naver.com
Sat Nov 7 01:35:46 PST 2026


rfd_ftl_remove_dev() frees the sector map, header cache and block array
before del_mtd_blktrans_dev() stops new requests and drains the blk-mq
queue. A block read admitted before that late barrier can consequently use
the freed sector map in rfd_ftl_readsect().

The issue reproduced as the same rfd_ftl_readsect() Oops in three of three
fresh KASAN boots using the production MTD BLKPG add/delete and RFD block
read paths. Normal, close-before-delete and wrong-partition controls were
clean in nine of nine boots.

Save the three allocation pointers while the enclosing partition is live,
quiesce and drain through the blktrans core, then free only the saved
pointers. This also avoids dereferencing the partition after core teardown
may release its final reference.

The fixed kernel completed 32 natural delete/read cycles in each of three
fresh boots without Oops or KASAN. All fixed controls and following-valid
operations also passed.

The demonstrated impact is a local or delegated kernel invalid read and
crash with administrative setup and deletion. Information disclosure,
controlled write, RCE and LPE were not demonstrated.

Fixes: d056f8cd2fc2 ("mtd: rfd_ftl: fix use-after-free")
Link: https://lore.kernel.org/r/20210807214538.14484-5-sean@mess.org
Assisted-by: OpenAI Codex

Signed-off-by: Sung Byeongchan <tjdqudcks0424 at naver.com>
---
 drivers/mtd/rfd_ftl.c |    9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/drivers/mtd/rfd_ftl.c b/drivers/mtd/rfd_ftl.c
index 9f7efdab6e908..0f7b3fb27ece8 100644
--- a/drivers/mtd/rfd_ftl.c
+++ b/drivers/mtd/rfd_ftl.c
@@ -792,6 +792,9 @@ static void rfd_ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
 static void rfd_ftl_remove_dev(struct mtd_blktrans_dev *dev)
 {
 	struct partition *part = container_of(dev, struct partition, mbd);
+	u_long *sector_map = part->sector_map;
+	u16 *header_cache = part->header_cache;
+	struct block *blocks = part->blocks;
 	int i;
 
 	for (i=0; i<part->total_blocks; i++) {
@@ -799,10 +802,10 @@ static void rfd_ftl_remove_dev(struct mtd_blktrans_dev *dev)
 			part->mbd.mtd->name, i, part->blocks[i].erases);
 	}
 
-	vfree(part->sector_map);
-	kfree(part->header_cache);
-	kfree(part->blocks);
 	del_mtd_blktrans_dev(&part->mbd);
+	vfree(sector_map);
+	kfree(header_cache);
+	kfree(blocks);
 }
 
 static struct mtd_blktrans_ops rfd_ftl_tr = {

base-commit: d48723711bae9b8cdc56719c448ba42fef28cbee
-- 
2.43.0



More information about the linux-mtd mailing list