KASAN: use-after-free Read in blk_mq_free_rqs
Original report of the bug: https://syzkaller.appspot.com/bug?id=36fe241584203cf394d44560a42e3430434f1213
Our system SyzScope detected 1 critical impact of control flow hijacking from this bug.
Fuzzer tested kernel version: 79c3ba32
Upstream patch: block: free sched's request pool in blk_cleanup_queue
Primitive 1: Control flow hijacking in blk_mq_free_rqs
Bug impact analysis:
The vulnerable object was accidentally freed in loop_remove.
static void loop_remove(struct loop_device *lo)
{
del_gendisk(lo->lo_disk);
blk_cleanup_queue(lo->lo_queue);
blk_mq_free_tag_set(&lo->tag_set);
put_disk(lo->lo_disk);
kfree(lo); // the object of type loop_device freed
}
Then, it was used in blk_mq_free_rqs and triggered a UAF read.
void blk_mq_free_rqs(struct blk_mq_tag_set *set, struct blk_mq_tags *tags,
unsigned int hctx_idx)
{
struct page *page;
if (tags->rqs && set->ops->exit_request) { // "set" now points to freed memory because its parent object "lo" was freed earlier. This line thus triggered a UAF read which was initially caught by syzbot/syzkaller
int i;
for (i = 0; i < tags->nr_tags; i++) {
struct request *rq = tags->static_rqs[i];
if (!rq)
continue;
set->ops->exit_request(set, rq, hctx_idx); // after our analysis, we realize that this line can trigger a direct control flow hijacking, which can lead to arbitrary code execution in kernel context
tags->static_rqs[i] = NULL;
}
}
...
}
As the code shown, attackers will first overwrite the vulnerable object (freed object) by heap spraying, and hijack the control flow when dereferencing the function pointer set->ops->exit_request().
Trace in high level:
|blk_mq_free_rqs block/blk-mq.c:2049 (Triggered the UAF read)
|None block/blk-mq.c:2057 (Triggered a new impact which we identify: Control flow hijacking)
Trace in detail(we confirm this trace can occur in practice):
--------------------------------------
0xffffffff825712f0
blk_mq_free_rqs block/blk-mq.c:2049 (Triggered the UAF read)
--------------------------------------
0xffffffff825712fd
blk_mq_free_rqs block/blk-mq.c:2049
--------------------------------------
0xffffffff82571308
blk_mq_free_rqs block/blk-mq.c:2049
--------------------------------------
0xffffffff8257130d
blk_mq_free_rqs block/blk-mq.c:2049
--------------------------------------
0xffffffff82571315
blk_mq_free_rqs block/blk-mq.c:2049
--------------------------------------
0xffffffff82571322
blk_mq_free_rqs block/blk-mq.c:2049
--------------------------------------
0xffffffff8257132a
blk_mq_free_rqs block/blk-mq.c:2049
--------------------------------------
0xffffffff8257133a
blk_mq_free_rqs block/blk-mq.c:2053
--------------------------------------
0xffffffff82571345
blk_mq_free_rqs block/blk-mq.c:2053
--------------------------------------
0xffffffff8257135d
blk_mq_free_rqs block/blk-mq.c:2053
--------------------------------------
0xffffffff8257136d
blk_mq_free_rqs block/blk-mq.c:2057
--------------------------------------
0xffffffff82571372
blk_mq_free_rqs block/blk-mq.c:2057
--------------------------------------
0xffffffff8257137b
blk_mq_free_rqs block/blk-mq.c:2057
--------------------------------------
0xffffffff8257138c
blk_mq_free_rqs block/blk-mq.c:2057(Triggered a new bug: Control flow hijacking)
--------------------------------------
Total 27 basic block