Please take a look at blk_mq_clear_rq_mapping():
//drv_tags points to set->tags[] which is shared in host wide
struct blk_mq_tags *drv_tags = set->tags[hctx_idx];
...
//tags points to sched_tags
list_for_each_entry(page, &tags->page_list, lru) {
unsigned long start = (unsigned long)page_address(page);
unsigned long end = start + order_to_size(page->private);
int i;
/* clear drv_tags->rq[i] in case it is from this sched tags*/
for (i = 0; i < set->queue_depth; i++) {
struct request *rq = drv_tags->rqs[i];
unsigned long rq_addr = (unsigned long)rq;
if (rq_addr >= start && rq_addr < end) {
WARN_ON_ONCE(refcount_read(&rq->ref) != 0);
cmpxchg(&drv_tags->rqs[i], rq, NULL);
}
}
}
So we do clear tags->rq[] instead of sched_tag->rq[].
After switching elevator, tags->rq[tag] still point to the request
that is just freed.
No.
3) nbd server send a reply with random tag directly:
recv_work
nbd_read_stat
blk_mq_tag_to_rq(tags, tag)
rq = tags->rq[tag] -> rq is freed
Usually, nbd will get tag and send a request to server first, and then
handle the reply. However, if the request is skipped, such uaf problem
can be triggered.
When or how is such reply with random tag replied to nbd client? Is it
possible for nbd client to detect such un-expected/bad situation?
What if blk_mq_tag_to_rq() is just called before/when we clear tags->rq[]?