Skip to content

Commit 1ba0403

Browse files
YuKuai-huaweiaxboe
authored andcommitted
block, bfq: fix uaf for accessing waker_bfqq after splitting
After commit 42c306e ("block, bfq: don't break merge chain in bfq_split_bfqq()"), if the current procress is the last holder of bfqq, the bfqq can be freed after bfq_split_bfqq(). Hence recored the bfqq and then access bfqq->waker_bfqq may trigger UAF. What's more, the waker_bfqq may in the merge chain of bfqq, hence just recored waker_bfqq is still not safe. Fix the problem by adding a helper bfq_waker_bfqq() to check if bfqq->waker_bfqq is in the merge chain, and current procress is the only holder. Fixes: 42c306e ("block, bfq: don't break merge chain in bfq_split_bfqq()") Signed-off-by: Yu Kuai <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jens Axboe <[email protected]>
1 parent 29390bb commit 1ba0403

File tree

1 file changed

+28
-3
lines changed

1 file changed

+28
-3
lines changed

Diff for: block/bfq-iosched.c

+28-3
Original file line numberDiff line numberDiff line change
@@ -6825,6 +6825,31 @@ static void bfq_prepare_request(struct request *rq)
68256825
rq->elv.priv[0] = rq->elv.priv[1] = NULL;
68266826
}
68276827

6828+
static struct bfq_queue *bfq_waker_bfqq(struct bfq_queue *bfqq)
6829+
{
6830+
struct bfq_queue *new_bfqq = bfqq->new_bfqq;
6831+
struct bfq_queue *waker_bfqq = bfqq->waker_bfqq;
6832+
6833+
if (!waker_bfqq)
6834+
return NULL;
6835+
6836+
while (new_bfqq) {
6837+
if (new_bfqq == waker_bfqq) {
6838+
/*
6839+
* If waker_bfqq is in the merge chain, and current
6840+
* is the only procress.
6841+
*/
6842+
if (bfqq_process_refs(waker_bfqq) == 1)
6843+
return NULL;
6844+
break;
6845+
}
6846+
6847+
new_bfqq = new_bfqq->new_bfqq;
6848+
}
6849+
6850+
return waker_bfqq;
6851+
}
6852+
68286853
/*
68296854
* If needed, init rq, allocate bfq data structures associated with
68306855
* rq, and increment reference counters in the destination bfq_queue
@@ -6886,7 +6911,7 @@ static struct bfq_queue *bfq_init_rq(struct request *rq)
68866911
/* If the queue was seeky for too long, break it apart. */
68876912
if (bfq_bfqq_coop(bfqq) && bfq_bfqq_split_coop(bfqq) &&
68886913
!bic->bfqq_data[a_idx].stably_merged) {
6889-
struct bfq_queue *old_bfqq = bfqq;
6914+
struct bfq_queue *waker_bfqq = bfq_waker_bfqq(bfqq);
68906915

68916916
/* Update bic before losing reference to bfqq */
68926917
if (bfq_bfqq_in_large_burst(bfqq))
@@ -6906,7 +6931,7 @@ static struct bfq_queue *bfq_init_rq(struct request *rq)
69066931
bfqq_already_existing = true;
69076932

69086933
if (!bfqq_already_existing) {
6909-
bfqq->waker_bfqq = old_bfqq->waker_bfqq;
6934+
bfqq->waker_bfqq = waker_bfqq;
69106935
bfqq->tentative_waker_bfqq = NULL;
69116936

69126937
/*
@@ -6916,7 +6941,7 @@ static struct bfq_queue *bfq_init_rq(struct request *rq)
69166941
* woken_list of the waker. See
69176942
* bfq_check_waker for details.
69186943
*/
6919-
if (bfqq->waker_bfqq)
6944+
if (waker_bfqq)
69206945
hlist_add_head(&bfqq->woken_list_node,
69216946
&bfqq->waker_bfqq->woken_list);
69226947
}

0 commit comments

Comments
 (0)