mirror of
https://github.com/nxp-imx/linux-imx.git
synced 2025-07-07 18:05:21 +02:00
block, bfq: fix uaf for accessing waker_bfqq after splitting
[ Upstream commit1ba0403ac6
] After commit42c306ed72
("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:42c306ed72
("block, bfq: don't break merge chain in bfq_split_bfqq()") Signed-off-by: Yu Kuai <yukuai3@huawei.com> Link: https://lore.kernel.org/r/20240909134154.954924-2-yukuai1@huaweicloud.com Signed-off-by: Jens Axboe <axboe@kernel.dk> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
0c9b52bfee
commit
0780451f03
|
@ -6823,6 +6823,31 @@ static void bfq_prepare_request(struct request *rq)
|
||||||
rq->elv.priv[0] = rq->elv.priv[1] = NULL;
|
rq->elv.priv[0] = rq->elv.priv[1] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct bfq_queue *bfq_waker_bfqq(struct bfq_queue *bfqq)
|
||||||
|
{
|
||||||
|
struct bfq_queue *new_bfqq = bfqq->new_bfqq;
|
||||||
|
struct bfq_queue *waker_bfqq = bfqq->waker_bfqq;
|
||||||
|
|
||||||
|
if (!waker_bfqq)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
while (new_bfqq) {
|
||||||
|
if (new_bfqq == waker_bfqq) {
|
||||||
|
/*
|
||||||
|
* If waker_bfqq is in the merge chain, and current
|
||||||
|
* is the only procress.
|
||||||
|
*/
|
||||||
|
if (bfqq_process_refs(waker_bfqq) == 1)
|
||||||
|
return NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_bfqq = new_bfqq->new_bfqq;
|
||||||
|
}
|
||||||
|
|
||||||
|
return waker_bfqq;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If needed, init rq, allocate bfq data structures associated with
|
* If needed, init rq, allocate bfq data structures associated with
|
||||||
* rq, and increment reference counters in the destination bfq_queue
|
* rq, and increment reference counters in the destination bfq_queue
|
||||||
|
@ -6884,7 +6909,7 @@ static struct bfq_queue *bfq_init_rq(struct request *rq)
|
||||||
/* If the queue was seeky for too long, break it apart. */
|
/* If the queue was seeky for too long, break it apart. */
|
||||||
if (bfq_bfqq_coop(bfqq) && bfq_bfqq_split_coop(bfqq) &&
|
if (bfq_bfqq_coop(bfqq) && bfq_bfqq_split_coop(bfqq) &&
|
||||||
!bic->bfqq_data[a_idx].stably_merged) {
|
!bic->bfqq_data[a_idx].stably_merged) {
|
||||||
struct bfq_queue *old_bfqq = bfqq;
|
struct bfq_queue *waker_bfqq = bfq_waker_bfqq(bfqq);
|
||||||
|
|
||||||
/* Update bic before losing reference to bfqq */
|
/* Update bic before losing reference to bfqq */
|
||||||
if (bfq_bfqq_in_large_burst(bfqq))
|
if (bfq_bfqq_in_large_burst(bfqq))
|
||||||
|
@ -6904,7 +6929,7 @@ static struct bfq_queue *bfq_init_rq(struct request *rq)
|
||||||
bfqq_already_existing = true;
|
bfqq_already_existing = true;
|
||||||
|
|
||||||
if (!bfqq_already_existing) {
|
if (!bfqq_already_existing) {
|
||||||
bfqq->waker_bfqq = old_bfqq->waker_bfqq;
|
bfqq->waker_bfqq = waker_bfqq;
|
||||||
bfqq->tentative_waker_bfqq = NULL;
|
bfqq->tentative_waker_bfqq = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -6914,7 +6939,7 @@ static struct bfq_queue *bfq_init_rq(struct request *rq)
|
||||||
* woken_list of the waker. See
|
* woken_list of the waker. See
|
||||||
* bfq_check_waker for details.
|
* bfq_check_waker for details.
|
||||||
*/
|
*/
|
||||||
if (bfqq->waker_bfqq)
|
if (waker_bfqq)
|
||||||
hlist_add_head(&bfqq->woken_list_node,
|
hlist_add_head(&bfqq->woken_list_node,
|
||||||
&bfqq->waker_bfqq->woken_list);
|
&bfqq->waker_bfqq->woken_list);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user