All of lore.kernel.org
 help / color / mirror / Atom feed
From: Adarsh Das <adarshdas950@gmail.com>
To: linux-mtd@lists.infradead.org
Cc: joern@lazybastard.org, miquel.raynal@bootlin.com, richard@nod.at,
	vigneshr@ti.com, Adarsh Das <adarshdas950@gmail.com>,
	syzbot <syzbot+7cab6a19619f1b8efc00@syzkaller.appspotmail.com>
Subject: [PATCH mtd] mtd: block2mtd: defer device open on module param write
Date: Wed, 16 Sep 2026 00:16:59 +0530	[thread overview]
Message-ID: <20260915184659.6939-1-adarshdas950@gmail.com> (raw)

When you write to /sys/module/block2mtd/parameters/block2mtd, the kernel
holds a module parameter lock for the whole callback. block2mtd was
opening the block device path inside that callback. Opening by path can
walk the filesystem and take overlayfs locks.

syzbot found this can create a circular lock dependency with overlayfs
(ovl_create_object). I was able to reproduce it with their C repro and
lockdep.

In this patch I applied the fix of copying the parameter string,
returning from the callback, then calling
block2mtd_setup2() from a work item so the device open happens after
the parameter lock is released.

Reported-by: syzbot <syzbot+7cab6a19619f1b8efc00@syzkaller.appspotmail.com>
Link: https://syzkaller.appspot.com/bug?id=3e420300f6b231aa906425cbb4bd55dd64f42da4
Tested-by: Adarsh Das <adarshdas950@gmail.com>
Signed-off-by: Adarsh Das <adarshdas950@gmail.com>
---
 drivers/mtd/devices/block2mtd.c | 53 ++++++++++++++++++++++++++++++---
 1 file changed, 49 insertions(+), 4 deletions(-)

diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c
index 03e80b2c4f5a..35ce306ed8fb 100644
--- a/drivers/mtd/devices/block2mtd.c
+++ b/drivers/mtd/devices/block2mtd.c
@@ -18,6 +18,7 @@
 
 #include <linux/module.h>
 #include <linux/delay.h>
+#include <linux/workqueue.h>
 #include <linux/fs.h>
 #include <linux/blkdev.h>
 #include <linux/backing-dev.h>
@@ -33,6 +34,8 @@
 
 /* Maximum number of comma-separated items in the 'block2mtd=' parameter */
 #define BLOCK2MTD_PARAM_MAX_COUNT 3
+/* 80 for device, 12 for erase size, 80 for label, 8 for timeout */
+#define BLOCK2MTD_PARAM_MAXLEN (80 + 12 + 80 + 8)
 
 /* Info for the block device */
 struct block2mtd_dev {
@@ -405,8 +408,7 @@ static char block2mtd_paramline[80 + 12];
 
 static int block2mtd_setup2(const char *val)
 {
-	/* 80 for device, 12 for erase size, 80 for name, 8 for timeout */
-	char buf[80 + 12 + 80 + 8];
+	char buf[BLOCK2MTD_PARAM_MAXLEN];
 	char *str = buf;
 	char *token[BLOCK2MTD_PARAM_MAX_COUNT];
 	char *name;
@@ -461,11 +463,54 @@ static int block2mtd_setup2(const char *val)
 	return 0;
 }
 
+struct block2mtd_deferred {
+	struct work_struct work;
+	char *val;
+};
+
+static void block2mtd_deferred_workfn(struct work_struct *work)
+{
+	struct block2mtd_deferred *req =
+		container_of(work, struct block2mtd_deferred, work);
+
+	block2mtd_setup2(req->val);
+	kfree(req->val);
+	kfree(req);
+	module_put(THIS_MODULE);
+}
+
+static int block2mtd_defer_setup2(const char *val)
+{
+	struct block2mtd_deferred *req;
+
+	if (strnlen(val, BLOCK2MTD_PARAM_MAXLEN) >= BLOCK2MTD_PARAM_MAXLEN)
+		return -EINVAL;
+
+	if (!try_module_get(THIS_MODULE))
+		return -ENODEV;
+
+	req = kmalloc_obj(struct block2mtd_deferred, GFP_KERNEL);
+	if (!req) {
+		module_put(THIS_MODULE);
+		return -ENOMEM;
+	}
+
+	req->val = kstrdup(val, GFP_KERNEL);
+	if (!req->val) {
+		kfree(req);
+		module_put(THIS_MODULE);
+		return -ENOMEM;
+	}
+
+	INIT_WORK(&req->work, block2mtd_deferred_workfn);
+	schedule_work(&req->work);
+	return 0;
+}
 
 static int block2mtd_setup(const char *val, const struct kernel_param *kp)
 {
 #ifdef MODULE
-	return block2mtd_setup2(val);
+	return block2mtd_defer_setup2(val);
 #else
 	/* If more parameters are later passed in via
 	   /sys/module/block2mtd/parameters/block2mtd
@@ -473,7 +518,7 @@ static int block2mtd_setup(const char *val, const struct kernel_param *kp)
 	   we can parse the argument now. */
 
 	if (block2mtd_init_called)
-		return block2mtd_setup2(val);
+		return block2mtd_defer_setup2(val);
 
 	/* During early boot stage, we only save the parameters
 	   here. We must parse them later: if the param passed
-- 
2.55.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

             reply	other threads:[~2026-09-15 18:47 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-15 18:46 Adarsh Das [this message]
2026-09-15 19:03 ` [PATCH mtd] mtd: block2mtd: defer device open on module param write sashiko-bot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260915184659.6939-1-adarshdas950@gmail.com \
    --to=adarshdas950@gmail.com \
    --cc=joern@lazybastard.org \
    --cc=linux-mtd@lists.infradead.org \
    --cc=miquel.raynal@bootlin.com \
    --cc=richard@nod.at \
    --cc=syzbot+7cab6a19619f1b8efc00@syzkaller.appspotmail.com \
    --cc=vigneshr@ti.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.