提交 fb9a380f 编写于 作者: Y Yu Kuai 提交者: Zheng Zengkai

blk-mq: fix potential uaf for 'queue_hw_ctx'

hulk inclusion
category: bugfix
bugzilla: 186389, https://gitee.com/openeuler/kernel/issues/I4Y43S
CVE: NA

--------------------------------

blk_mq_realloc_hw_ctxs() will free the 'queue_hw_ctx'(e.g. undate
submit_queues through configfs for null_blk), while it might still be
used from other context(e.g. switch elevator to none):

t1					t2
elevator_switch
 blk_mq_unquiesce_queue
  blk_mq_run_hw_queues
   queue_for_each_hw_ctx
    // assembly code for hctx = (q)->queue_hw_ctx[i]
    mov    0x48(%rbp),%rdx -> read old queue_hw_ctx

					__blk_mq_update_nr_hw_queues
					 blk_mq_realloc_hw_ctxs
					  hctxs = q->queue_hw_ctx
					  q->queue_hw_ctx = new_hctxs
					  kfree(hctxs)
    movslq %ebx,%rax
    mov    (%rdx,%rax,8),%rdi ->uaf

Sicne the queue is freezed in __blk_mq_update_nr_hw_queues(), fix the
problem by protecting 'queue_hw_ctx' through rcu where it can be accessed
without grabbing 'q_usage_counter'.
Signed-off-by: NYu Kuai <yukuai3@huawei.com>
Reviewed-by: NMing Lei <ming.lei@redhat.com>
Signed-off-by: NZhang Wensheng <zhangwensheng5@huawei.com>
Reviewed-by: NJason Yan <yanaijie@huawei.com>
Signed-off-by: NZheng Zengkai <zhengzengkai@huawei.com>
上级 2bb95412
...@@ -3280,7 +3280,15 @@ static void blk_mq_realloc_hw_ctxs(struct blk_mq_tag_set *set, ...@@ -3280,7 +3280,15 @@ static void blk_mq_realloc_hw_ctxs(struct blk_mq_tag_set *set,
if (hctxs) if (hctxs)
memcpy(new_hctxs, hctxs, q->nr_hw_queues * memcpy(new_hctxs, hctxs, q->nr_hw_queues *
sizeof(*hctxs)); sizeof(*hctxs));
q->queue_hw_ctx = new_hctxs;
rcu_assign_pointer(q->queue_hw_ctx, new_hctxs);
/*
* Make sure reading the old queue_hw_ctx from other
* context concurrently won't trigger uaf. and when
* it is in start up time, no need to sync rcu.
*/
if (hctxs)
synchronize_rcu();
kfree(hctxs); kfree(hctxs);
hctxs = new_hctxs; hctxs = new_hctxs;
} }
......
...@@ -612,9 +612,20 @@ static inline void *blk_mq_rq_to_pdu(struct request *rq) ...@@ -612,9 +612,20 @@ static inline void *blk_mq_rq_to_pdu(struct request *rq)
return rq + 1; return rq + 1;
} }
static inline struct blk_mq_hw_ctx *queue_hctx(struct request_queue *q, int id)
{
struct blk_mq_hw_ctx *hctx;
rcu_read_lock();
hctx = *(rcu_dereference(q->queue_hw_ctx) + id);
rcu_read_unlock();
return hctx;
}
#define queue_for_each_hw_ctx(q, hctx, i) \ #define queue_for_each_hw_ctx(q, hctx, i) \
for ((i) = 0; (i) < (q)->nr_hw_queues && \ for ((i) = 0; (i) < (q)->nr_hw_queues && \
({ hctx = (q)->queue_hw_ctx[i]; 1; }); (i)++) ({ hctx = queue_hctx((q), i); 1; }); (i)++)
#define hctx_for_each_ctx(hctx, ctx, i) \ #define hctx_for_each_ctx(hctx, ctx, i) \
for ((i) = 0; (i) < (hctx)->nr_ctx && \ for ((i) = 0; (i) < (hctx)->nr_ctx && \
......
...@@ -421,7 +421,7 @@ struct request_queue { ...@@ -421,7 +421,7 @@ struct request_queue {
unsigned int queue_depth; unsigned int queue_depth;
/* hw dispatch queues */ /* hw dispatch queues */
struct blk_mq_hw_ctx **queue_hw_ctx; struct blk_mq_hw_ctx __rcu **queue_hw_ctx;
unsigned int nr_hw_queues; unsigned int nr_hw_queues;
struct backing_dev_info *backing_dev_info; struct backing_dev_info *backing_dev_info;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册