Takashi Iwai 756990
From 7c2c69e010431b0157c9454adcdd2305809bf9fb Mon Sep 17 00:00:00 2001
Takashi Iwai 756990
From: Li Jinlin <lijinlin3@huawei.com>
Takashi Iwai 756990
Date: Tue, 14 Sep 2021 12:26:05 +0800
Takashi Iwai 756990
Subject: [PATCH] blk-cgroup: fix UAF by grabbing blkcg lock before destroying blkg pd
Takashi Iwai 756990
Git-commit: 858560b27645e7e97aca37ee8f232cccd658fbd2
Takashi Iwai 756990
Patch-mainline: v5.15-rc2
Takashi Iwai 756990
References: stable-5.14.9
Takashi Iwai 756990
Takashi Iwai 756990
[ Upstream commit 858560b27645e7e97aca37ee8f232cccd658fbd2 ]
Takashi Iwai 756990
Takashi Iwai 756990
KASAN reports a use-after-free report when doing fuzz test:
Takashi Iwai 756990
Takashi Iwai 756990
[693354.104835] ==================================================================
Takashi Iwai 756990
[693354.105094] BUG: KASAN: use-after-free in bfq_io_set_weight_legacy+0xd3/0x160
Takashi Iwai 756990
[693354.105336] Read of size 4 at addr ffff888be0a35664 by task sh/1453338
Takashi Iwai 756990
Takashi Iwai 756990
[693354.105607] CPU: 41 PID: 1453338 Comm: sh Kdump: loaded Not tainted 4.18.0-147
Takashi Iwai 756990
[693354.105610] Hardware name: Huawei 2288H V5/BC11SPSCB0, BIOS 0.81 07/02/2018
Takashi Iwai 756990
[693354.105612] Call Trace:
Takashi Iwai 756990
[693354.105621]  dump_stack+0xf1/0x19b
Takashi Iwai 756990
[693354.105626]  ? show_regs_print_info+0x5/0x5
Takashi Iwai 756990
[693354.105634]  ? printk+0x9c/0xc3
Takashi Iwai 756990
[693354.105638]  ? cpumask_weight+0x1f/0x1f
Takashi Iwai 756990
[693354.105648]  print_address_description+0x70/0x360
Takashi Iwai 756990
[693354.105654]  kasan_report+0x1b2/0x330
Takashi Iwai 756990
[693354.105659]  ? bfq_io_set_weight_legacy+0xd3/0x160
Takashi Iwai 756990
[693354.105665]  ? bfq_io_set_weight_legacy+0xd3/0x160
Takashi Iwai 756990
[693354.105670]  bfq_io_set_weight_legacy+0xd3/0x160
Takashi Iwai 756990
[693354.105675]  ? bfq_cpd_init+0x20/0x20
Takashi Iwai 756990
[693354.105683]  cgroup_file_write+0x3aa/0x510
Takashi Iwai 756990
[693354.105693]  ? ___slab_alloc+0x507/0x540
Takashi Iwai 756990
[693354.105698]  ? cgroup_file_poll+0x60/0x60
Takashi Iwai 756990
[693354.105702]  ? 0xffffffff89600000
Takashi Iwai 756990
[693354.105708]  ? usercopy_abort+0x90/0x90
Takashi Iwai 756990
[693354.105716]  ? mutex_lock+0xef/0x180
Takashi Iwai 756990
[693354.105726]  kernfs_fop_write+0x1ab/0x280
Takashi Iwai 756990
[693354.105732]  ? cgroup_file_poll+0x60/0x60
Takashi Iwai 756990
[693354.105738]  vfs_write+0xe7/0x230
Takashi Iwai 756990
[693354.105744]  ksys_write+0xb0/0x140
Takashi Iwai 756990
[693354.105749]  ? __ia32_sys_read+0x50/0x50
Takashi Iwai 756990
[693354.105760]  do_syscall_64+0x112/0x370
Takashi Iwai 756990
[693354.105766]  ? syscall_return_slowpath+0x260/0x260
Takashi Iwai 756990
[693354.105772]  ? do_page_fault+0x9b/0x270
Takashi Iwai 756990
[693354.105779]  ? prepare_exit_to_usermode+0xf9/0x1a0
Takashi Iwai 756990
[693354.105784]  ? enter_from_user_mode+0x30/0x30
Takashi Iwai 756990
[693354.105793]  entry_SYSCALL_64_after_hwframe+0x65/0xca
Takashi Iwai 756990
Takashi Iwai 756990
[693354.105875] Allocated by task 1453337:
Takashi Iwai 756990
[693354.106001]  kasan_kmalloc+0xa0/0xd0
Takashi Iwai 756990
[693354.106006]  kmem_cache_alloc_node_trace+0x108/0x220
Takashi Iwai 756990
[693354.106010]  bfq_pd_alloc+0x96/0x120
Takashi Iwai 756990
[693354.106015]  blkcg_activate_policy+0x1b7/0x2b0
Takashi Iwai 756990
[693354.106020]  bfq_create_group_hierarchy+0x1e/0x80
Takashi Iwai 756990
[693354.106026]  bfq_init_queue+0x678/0x8c0
Takashi Iwai 756990
[693354.106031]  blk_mq_init_sched+0x1f8/0x460
Takashi Iwai 756990
[693354.106037]  elevator_switch_mq+0xe1/0x240
Takashi Iwai 756990
[693354.106041]  elevator_switch+0x25/0x40
Takashi Iwai 756990
[693354.106045]  elv_iosched_store+0x1a1/0x230
Takashi Iwai 756990
[693354.106049]  queue_attr_store+0x78/0xb0
Takashi Iwai 756990
[693354.106053]  kernfs_fop_write+0x1ab/0x280
Takashi Iwai 756990
[693354.106056]  vfs_write+0xe7/0x230
Takashi Iwai 756990
[693354.106060]  ksys_write+0xb0/0x140
Takashi Iwai 756990
[693354.106064]  do_syscall_64+0x112/0x370
Takashi Iwai 756990
[693354.106069]  entry_SYSCALL_64_after_hwframe+0x65/0xca
Takashi Iwai 756990
Takashi Iwai 756990
[693354.106114] Freed by task 1453336:
Takashi Iwai 756990
[693354.106225]  __kasan_slab_free+0x130/0x180
Takashi Iwai 756990
[693354.106229]  kfree+0x90/0x1b0
Takashi Iwai 756990
[693354.106233]  blkcg_deactivate_policy+0x12c/0x220
Takashi Iwai 756990
[693354.106238]  bfq_exit_queue+0xf5/0x110
Takashi Iwai 756990
[693354.106241]  blk_mq_exit_sched+0x104/0x130
Takashi Iwai 756990
[693354.106245]  __elevator_exit+0x45/0x60
Takashi Iwai 756990
[693354.106249]  elevator_switch_mq+0xd6/0x240
Takashi Iwai 756990
[693354.106253]  elevator_switch+0x25/0x40
Takashi Iwai 756990
[693354.106257]  elv_iosched_store+0x1a1/0x230
Takashi Iwai 756990
[693354.106261]  queue_attr_store+0x78/0xb0
Takashi Iwai 756990
[693354.106264]  kernfs_fop_write+0x1ab/0x280
Takashi Iwai 756990
[693354.106268]  vfs_write+0xe7/0x230
Takashi Iwai 756990
[693354.106271]  ksys_write+0xb0/0x140
Takashi Iwai 756990
[693354.106275]  do_syscall_64+0x112/0x370
Takashi Iwai 756990
[693354.106280]  entry_SYSCALL_64_after_hwframe+0x65/0xca
Takashi Iwai 756990
Takashi Iwai 756990
[693354.106329] The buggy address belongs to the object at ffff888be0a35580
Takashi Iwai 756990
                 which belongs to the cache kmalloc-1k of size 1024
Takashi Iwai 756990
[693354.106736] The buggy address is located 228 bytes inside of
Takashi Iwai 756990
                 1024-byte region [ffff888be0a35580, ffff888be0a35980)
Takashi Iwai 756990
[693354.107114] The buggy address belongs to the page:
Takashi Iwai 756990
[693354.107273] page:ffffea002f828c00 count:1 mapcount:0 mapping:ffff888107c17080 index:0x0 compound_mapcount: 0
Takashi Iwai 756990
[693354.107606] flags: 0x17ffffc0008100(slab|head)
Takashi Iwai 756990
[693354.107760] raw: 0017ffffc0008100 ffffea002fcbc808 ffffea0030bd3a08 ffff888107c17080
Takashi Iwai 756990
[693354.108020] raw: 0000000000000000 00000000001c001c 00000001ffffffff 0000000000000000
Takashi Iwai 756990
[693354.108278] page dumped because: kasan: bad access detected
Takashi Iwai 756990
Takashi Iwai 756990
[693354.108511] Memory state around the buggy address:
Takashi Iwai 756990
[693354.108671]  ffff888be0a35500: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
Takashi Iwai 756990
[693354.116396]  ffff888be0a35580: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
Takashi Iwai 756990
[693354.124473] >ffff888be0a35600: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
Takashi Iwai 756990
[693354.132421]                                                        ^
Takashi Iwai 756990
[693354.140284]  ffff888be0a35680: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
Takashi Iwai 756990
[693354.147912]  ffff888be0a35700: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
Takashi Iwai 756990
[693354.155281] ==================================================================
Takashi Iwai 756990
Takashi Iwai 756990
blkgs are protected by both queue and blkcg locks and holding
Takashi Iwai 756990
either should stabilize them. However, the path of destroying
Takashi Iwai 756990
blkg policy data is only protected by queue lock in
Takashi Iwai 756990
blkcg_activate_policy()/blkcg_deactivate_policy(). Other tasks
Takashi Iwai 756990
can get the blkg policy data before the blkg policy data is
Takashi Iwai 756990
destroyed, and use it after destroyed, which will result in a
Takashi Iwai 756990
use-after-free.
Takashi Iwai 756990
Takashi Iwai 756990
CPU0                             CPU1
Takashi Iwai 756990
blkcg_deactivate_policy
Takashi Iwai 756990
  spin_lock_irq(&q->queue_lock)
Takashi Iwai 756990
                                 bfq_io_set_weight_legacy
Takashi Iwai 756990
                                   spin_lock_irq(&blkcg->lock)
Takashi Iwai 756990
                                   blkg_to_bfqg(blkg)
Takashi Iwai 756990
                                     pd_to_bfqg(blkg->pd[pol->plid])
Takashi Iwai 756990
                                     ^^^^^^blkg->pd[pol->plid] != NULL
Takashi Iwai 756990
                                           bfqg != NULL
Takashi Iwai 756990
  pol->pd_free_fn(blkg->pd[pol->plid])
Takashi Iwai 756990
    pd_to_bfqg(blkg->pd[pol->plid])
Takashi Iwai 756990
    bfqg_put(bfqg)
Takashi Iwai 756990
      kfree(bfqg)
Takashi Iwai 756990
  blkg->pd[pol->plid] = NULL
Takashi Iwai 756990
  spin_unlock_irq(q->queue_lock);
Takashi Iwai 756990
                                   bfq_group_set_weight(bfqg, val, 0)
Takashi Iwai 756990
                                     bfqg->entity.new_weight
Takashi Iwai 756990
                                     ^^^^^^trigger uaf here
Takashi Iwai 756990
                                   spin_unlock_irq(&blkcg->lock);
Takashi Iwai 756990
Takashi Iwai 756990
Fix by grabbing the matching blkcg lock before trying to
Takashi Iwai 756990
destroy blkg policy data.
Takashi Iwai 756990
Takashi Iwai 756990
Suggested-by: Tejun Heo <tj@kernel.org>
Takashi Iwai 756990
Signed-off-by: Li Jinlin <lijinlin3@huawei.com>
Takashi Iwai 756990
Acked-by: Tejun Heo <tj@kernel.org>
Takashi Iwai 756990
Link: https://lore.kernel.org/r/20210914042605.3260596-1-lijinlin3@huawei.com
Takashi Iwai 756990
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Takashi Iwai 756990
Signed-off-by: Sasha Levin <sashal@kernel.org>
Takashi Iwai 756990
Acked-by: Takashi Iwai <tiwai@suse.de>
Takashi Iwai 756990
Takashi Iwai 756990
---
Takashi Iwai 756990
 block/blk-cgroup.c | 8 ++++++++
Takashi Iwai 756990
 1 file changed, 8 insertions(+)
Takashi Iwai 756990
Takashi Iwai 756990
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
Takashi Iwai 756990
index 26446f97deee..28e11decbac5 100644
Takashi Iwai 756990
--- a/block/blk-cgroup.c
Takashi Iwai 756990
+++ b/block/blk-cgroup.c
Takashi Iwai 756990
@@ -1385,10 +1385,14 @@ int blkcg_activate_policy(struct request_queue *q,
Takashi Iwai 756990
 	/* alloc failed, nothing's initialized yet, free everything */
Takashi Iwai 756990
 	spin_lock_irq(&q->queue_lock);
Takashi Iwai 756990
 	list_for_each_entry(blkg, &q->blkg_list, q_node) {
Takashi Iwai 756990
+		struct blkcg *blkcg = blkg->blkcg;
Takashi Iwai 756990
+
Takashi Iwai 756990
+		spin_lock(&blkcg->lock);
Takashi Iwai 756990
 		if (blkg->pd[pol->plid]) {
Takashi Iwai 756990
 			pol->pd_free_fn(blkg->pd[pol->plid]);
Takashi Iwai 756990
 			blkg->pd[pol->plid] = NULL;
Takashi Iwai 756990
 		}
Takashi Iwai 756990
+		spin_unlock(&blkcg->lock);
Takashi Iwai 756990
 	}
Takashi Iwai 756990
 	spin_unlock_irq(&q->queue_lock);
Takashi Iwai 756990
 	ret = -ENOMEM;
Takashi Iwai 756990
@@ -1420,12 +1424,16 @@ void blkcg_deactivate_policy(struct request_queue *q,
Takashi Iwai 756990
 	__clear_bit(pol->plid, q->blkcg_pols);
Takashi Iwai 756990
 
Takashi Iwai 756990
 	list_for_each_entry(blkg, &q->blkg_list, q_node) {
Takashi Iwai 756990
+		struct blkcg *blkcg = blkg->blkcg;
Takashi Iwai 756990
+
Takashi Iwai 756990
+		spin_lock(&blkcg->lock);
Takashi Iwai 756990
 		if (blkg->pd[pol->plid]) {
Takashi Iwai 756990
 			if (pol->pd_offline_fn)
Takashi Iwai 756990
 				pol->pd_offline_fn(blkg->pd[pol->plid]);
Takashi Iwai 756990
 			pol->pd_free_fn(blkg->pd[pol->plid]);
Takashi Iwai 756990
 			blkg->pd[pol->plid] = NULL;
Takashi Iwai 756990
 		}
Takashi Iwai 756990
+		spin_unlock(&blkcg->lock);
Takashi Iwai 756990
 	}
Takashi Iwai 756990
 
Takashi Iwai 756990
 	spin_unlock_irq(&q->queue_lock);
Takashi Iwai 756990
-- 
Takashi Iwai 756990
2.26.2
Takashi Iwai 756990