]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
nbd: defer config unlock in nbd_genl_connect
authorZheng Qixing <zhengqixing@huawei.com>
Mon, 10 Nov 2025 12:49:20 +0000 (20:49 +0800)
committerJens Axboe <axboe@kernel.dk>
Tue, 11 Nov 2025 14:50:15 +0000 (07:50 -0700)
There is one use-after-free warning when running NBD_CMD_CONNECT and
NBD_CLEAR_SOCK:

nbd_genl_connect
  nbd_alloc_and_init_config // config_refs=1
  nbd_start_device // config_refs=2
  set NBD_RT_HAS_CONFIG_REF open nbd // config_refs=3
  recv_work done // config_refs=2
NBD_CLEAR_SOCK // config_refs=1
close nbd // config_refs=0
  refcount_inc -> uaf

------------[ cut here ]------------
refcount_t: addition on 0; use-after-free.
WARNING: CPU: 24 PID: 1014 at lib/refcount.c:25 refcount_warn_saturate+0x12e/0x290
 nbd_genl_connect+0x16d0/0x1ab0
 genl_family_rcv_msg_doit+0x1f3/0x310
 genl_rcv_msg+0x44a/0x790

The issue can be easily reproduced by adding a small delay before
refcount_inc(&nbd->config_refs) in nbd_genl_connect():

        mutex_unlock(&nbd->config_lock);
        if (!ret) {
                set_bit(NBD_RT_HAS_CONFIG_REF, &config->runtime_flags);
+               printk("before sleep\n");
+               mdelay(5 * 1000);
+               printk("after sleep\n");
                refcount_inc(&nbd->config_refs);
                nbd_connect_reply(info, nbd->index);
        }

Fixes: e46c7287b1c2 ("nbd: add a basic netlink interface")
Signed-off-by: Zheng Qixing <zhengqixing@huawei.com>
Reviewed-by: Yu Kuai <yukuai@fnnas.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
drivers/block/nbd.c

index 0df7b33af67775d9345e726b7a3028e5da40b9d0..bbbafb6e2b33c3cf4debe94dd3be19ef8b6ed7d4 100644 (file)
@@ -2235,12 +2235,13 @@ again:
 
        ret = nbd_start_device(nbd);
 out:
-       mutex_unlock(&nbd->config_lock);
        if (!ret) {
                set_bit(NBD_RT_HAS_CONFIG_REF, &config->runtime_flags);
                refcount_inc(&nbd->config_refs);
                nbd_connect_reply(info, nbd->index);
        }
+       mutex_unlock(&nbd->config_lock);
+
        nbd_config_put(nbd);
        if (put_dev)
                nbd_put(nbd);