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