[PATCH RFC] nbd: fix resource leak when device is abandoned

"syzbot" <[email protected]>
Newsgroups dev.linux.lists.syzbot
Message-ID <[email protected]>
When a user-space process configures an NBD device via netlink but exits
without explicitly disconnecting it or opening the block device, the NBD
device and its request queue are leaked. The leaked request queues hold
dynamically registered lock classes. When this happens repeatedly, it
exhausts the MAX_LOCKDEP_KEYS limit and triggers a lockdep BUG.

The leak occurs because the initial configuration reference (config_refs)
is set to 1 during configuration. If the process exits, the sockets are
closed and the recv_work threads exit, but the initial reference is never
dropped unless the device is explicitly disconnected or the
NBD_CFLAG_DESTROY_ON_DISCONNECT flag was set. As a result, the device is
considered in use and skipped during subsequent device allocations, leading
to unbounded creation of new devices and request queues.

Fix this by scheduling disconnect_work to tear down the device when all
sockets are closed and the disk has no openers, even if
NBD_DESTROY_ON_DISCONNECT is not set. This ensures the initial
configuration reference is dropped, allowing the device configuration to be
freed and the device to become eligible for reuse, preventing the resource
leak and the lockdep crash.

Fixes: e46c7287b1c2 ("nbd: add a basic netlink interface")
Assisted-by: Gemini:gemini-3.1-pro-preview Gemini:gemini-3-flash-preview syzbot
Reported-by: [email protected]
Closes: https://syzkaller.appspot.com/bug?extid=6279b273d888c2017726
Link: https://syzkaller.appspot.com/ai_job?id=f2b193da-12d6-456c-8401-8680f8682836
To: "Jens Axboe" <[email protected]>
To: "Josef Bacik" <[email protected]>
To: <[email protected]>
To: <[email protected]>
Cc: <[email protected]>

---
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index fe63f3c55..d31c8e5e3 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -124,6 +124,7 @@ struct nbd_device {
 	struct gendisk *disk;
 	struct workqueue_struct *recv_workq;
 	struct work_struct remove_work;
+	struct work_struct disconnect_work;
 
 	struct list_head list;
 	struct task_struct *task_setup;
@@ -322,7 +323,15 @@ static void nbd_mark_nsock_dead(struct nbd_device *nbd, struct nbd_sock *nsock,
 				set_bit(NBD_RT_DISCONNECTED,
 					&nbd->config->runtime_flags);
 				dev_info(nbd_to_dev(nbd),
-					"Disconnected due to user request.\n");
+					 "Disconnected due to user request.\n");
+			}
+			if (test_bit(NBD_DESTROY_ON_DISCONNECT, &nbd->flags) ||
+			    disk_openers(nbd->disk) == 0) {
+				if (refcount_inc_not_zero(&nbd->refs)) {
+					if (!queue_work(system_wq,
+							&nbd->disconnect_work))
+						nbd_put(nbd);
+				}
 			}
 		}
 	}
@@ -1904,6 +1913,8 @@ static const struct blk_mq_ops nbd_mq_ops = {
 	.timeout	= nbd_xmit_timeout,
 };
 
+static void nbd_disconnect_work(struct work_struct *work);
+
 static struct nbd_device *nbd_dev_add(int index, unsigned int refs)
 {
 	struct queue_limits lim = {
@@ -1928,6 +1939,7 @@ static struct nbd_device *nbd_dev_add(int index, unsigned int refs)
 	nbd->tag_set.flags = BLK_MQ_F_BLOCKING;
 	nbd->tag_set.driver_data = nbd;
 	INIT_WORK(&nbd->remove_work, nbd_dev_remove_work);
+	INIT_WORK(&nbd->disconnect_work, nbd_disconnect_work);
 	nbd->backend = NULL;
 
 	err = blk_mq_alloc_tag_set(&nbd->tag_set);
@@ -2272,6 +2284,14 @@ static void nbd_disconnect_and_put(struct nbd_device *nbd)
 		nbd_config_put(nbd);
 }
 
+static void nbd_disconnect_work(struct work_struct *work)
+{
+	struct nbd_device *nbd =
+		container_of(work, struct nbd_device, disconnect_work);
+	nbd_disconnect_and_put(nbd);
+	nbd_put(nbd);
+}
+
 static int nbd_genl_disconnect(struct sk_buff *skb, struct genl_info *info)
 {
 	struct nbd_device *nbd;


base-commit: e7ae89a0c97ce2b68b0983cd01eda67cf373517d
-- 
This is an AI-generated patch subject to moderation.
Reply with '#syz upstream' to Sign-off the patch as a human author
and send it to the upstream kernel mailing lists.
Reply with '#syz reject' to reject it ('#syz unreject' to undo).

See https://goo.gle/syzbot-ai-patches for information about AI-generated patches.
You can comment on the patch as usual, syzbot will try to address
the comments and send a new version of the patch if necessary.
syzbot engineers can be reached at [email protected].
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.