From: Ye Bin yebin10@huawei.com
hulk inclusion category: bugfix bugzilla: 185875 CVE: NA
-----------------------------------------------
We got issue as follows: [ 833.786542] nbd: failed to add new device [ 833.791613] ================================================================== [ 833.794918] BUG: KASAN: use-after-free in blk_mq_free_rqs+0x558/0x6c0 [ 833.798108] Read of size 8 at addr ffff800109b7c288 by task kworker/0:3/113 [ 833.804216] CPU: 0 PID: 113 Comm: kworker/0:3 Kdump: loaded Not tainted 4.19.90 #1 [ 833.807635] Hardware name: QEMU KVM Virtual Machine, BIOS 0.0.0 02/06/2015 [ 833.811798] Workqueue: events __blk_release_queue [ 833.815035] Call trace: [ 833.817964] dump_backtrace+0x0/0x3c0 [ 833.821070] show_stack+0x28/0x38 [ 833.824091] dump_stack+0xfc/0x154 [ 833.827042] print_address_description+0x68/0x278 [ 833.830147] kasan_report+0x204/0x330 [ 833.833121] __asan_report_load8_noabort+0x30/0x40 [ 833.836180] blk_mq_free_rqs+0x558/0x6c0 [ 833.839089] blk_mq_sched_tags_teardown+0xf4/0x1c0 [ 833.842035] blk_mq_exit_sched+0x1b8/0x260 [ 833.844878] elevator_exit+0x114/0x148 [ 833.847634] blk_exit_queue+0x68/0xe8 [ 833.850352] __blk_release_queue+0xd0/0x408 [ 833.853113] process_one_work+0x55c/0x10d0 [ 833.855864] worker_thread+0x3d4/0xe30 [ 833.858558] kthread+0x2c8/0x348 [ 833.861139] ret_from_fork+0x10/0x18 [ 833.863714] [ 833.866000] Allocated by task 186531: [ 833.868467] kasan_kmalloc+0xe0/0x190 [ 833.870936] kmem_cache_alloc_trace+0x104/0x218 [ 833.873483] nbd_dev_add+0x54/0x760 [nbd] [ 833.875988] nbd_genl_connect+0x3c4/0x1348 [nbd] [ 833.878591] genl_family_rcv_msg+0x798/0xa10 [ 833.881113] genl_rcv_msg+0xc0/0x170 [ 833.883489] netlink_rcv_skb+0x1b4/0x370 [ 833.885897] genl_rcv+0x40/0x58 [ 833.888225] netlink_unicast+0x4bc/0x660 [ 833.890661] netlink_sendmsg+0x880/0xa60 [ 833.893112] sock_sendmsg+0xb8/0x110 [ 833.895513] ____sys_sendmsg+0x570/0x698 [ 833.897927] ___sys_sendmsg+0x108/0x188 [ 833.900350] __sys_sendmsg+0xe8/0x198 [ 833.900360] __arm64_sys_sendmsg+0x78/0xa8 [ 833.906911] el0_svc_common+0x10c/0x330 [ 833.909289] el0_svc_handler+0x60/0xd0 [ 833.911660] el0_svc+0x8/0x1b0 [ 833.913963] [ 833.916117] Freed by task 186531: [ 833.918445] __kasan_slab_free+0x120/0x228 [ 833.920860] kasan_slab_free+0x10/0x18 [ 833.923193] kfree+0x80/0x1f0 [ 833.925392] nbd_dev_add+0xf0/0x760 [nbd] [ 833.927686] nbd_genl_connect+0x3c4/0x1348 [nbd] [ 833.929989] genl_family_rcv_msg+0x798/0xa10 [ 833.932231] genl_rcv_msg+0xc0/0x170 [ 833.934335] netlink_rcv_skb+0x1b4/0x370 [ 833.936444] genl_rcv+0x40/0x58 [ 833.938460] netlink_unicast+0x4bc/0x660 [ 833.940570] netlink_sendmsg+0x880/0xa60 [ 833.942682] sock_sendmsg+0xb8/0x110 [ 833.944745] ____sys_sendmsg+0x570/0x698 [ 833.946849] ___sys_sendmsg+0x108/0x188 [ 833.948924] __sys_sendmsg+0xe8/0x198 [ 833.950980] __arm64_sys_sendmsg+0x78/0xa8 [ 833.953059] el0_svc_common+0x10c/0x330 [ 833.955121] el0_svc_handler+0x60/0xd0 [ 833.957143] el0_svc+0x8/0x1b0 [ 833.959088] [ 833.960846] The buggy address belongs to the object at ffff800109b7c280 [ 833.960846] which belongs to the cache kmalloc-512 of size 512 [ 833.965502] The buggy address is located 8 bytes inside of [ 833.965502] 512-byte region [ffff800109b7c280, ffff800109b7c480) [ 833.970108] The buggy address belongs to the page: [ 833.972390] page:ffff7e000426df00 count:1 mapcount:0 mapping:ffff8000c0003800 index:0x0 compound_mapcount: 0 [ 833.975269] flags: 0x7ffff0000008100(slab|head) [ 833.977640] raw: 07ffff0000008100 ffff7e00035d1600 0000000200000002 ffff8000c0003800 [ 833.980426] raw: 0000000000000000 00000000000c000c 00000001ffffffff 0000000000000000 [ 833.983212] page dumped because: kasan: bad access detected [ 833.985778] [ 833.987935] Memory state around the buggy address: [ 833.990448] ffff800109b7c180: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 833.993265] ffff800109b7c200: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 833.996097] >ffff800109b7c280: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 833.998930] ^ [ 834.001384] ffff800109b7c300: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 834.004329] ffff800109b7c380: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 834.007264] ==================================================================
As 98fd847a495f commit add check "disk->first_minor", if failed will free tags and finally call put_disk will free request_queue. blk_mq_free_tag_set blk_mq_free_map_and_requests blk_mq_free_rqs
put_disk: __blk_release_queue blk_exit_queue elevator_exit blk_mq_exit_sched blk_mq_sched_tags_teardown blk_mq_free_rqs -->will trigger UAF To address this issue, just move 'disk->first_minor' check at the first in nbd_dev_add.
Fixes:98fd847a495f("nbd: add sanity check for first_minor") Signed-off-by: Ye Bin yebin10@huawei.com Reviewed-by: Yu Kuai yukuai3@huawei.com Reviewed-by: Jason Yan yanaijie@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/block/nbd.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-)
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 775cbb4c1bbcd..a35189098581b 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -1702,6 +1702,15 @@ static int nbd_dev_add(int index) struct gendisk *disk; struct request_queue *q; int err = -ENOMEM; + int first_minor = index << part_shift; + + /* + * Too big index can cause duplicate creation of sysfs files/links, + * because MKDEV() expect that the max first minor is MINORMASK, or + * index << part_shift can overflow. + */ + if (first_minor < index || first_minor > MINORMASK) + return -EINVAL;
nbd = kzalloc(sizeof(struct nbd_device), GFP_KERNEL); if (!nbd) @@ -1765,18 +1774,7 @@ static int nbd_dev_add(int index) refcount_set(&nbd->refs, 1); INIT_LIST_HEAD(&nbd->list); disk->major = NBD_MAJOR; - - /* - * Too big index can cause duplicate creation of sysfs files/links, - * because MKDEV() expect that the max first minor is MINORMASK, or - * index << part_shift can overflow. - */ - disk->first_minor = index << part_shift; - if (disk->first_minor < index || disk->first_minor > MINORMASK) { - err = -EINVAL; - goto out_free_tags; - } - + disk->first_minor = first_minor; disk->fops = &nbd_fops; disk->private_data = nbd; sprintf(disk->disk_name, "nbd%d", index);