hw/ufs: Guard MCQ CQ accesses against missing queues
A guest can ring an MCQ CQ doorbell before the completion queue exists. The CQ head write path then dereferences a NULL CQ through ufs_mcq_cq_full(). Ignore CQ head updates for missing CQs, and make ufs_mcq_cq_full() handle a missing CQ defensively. Fixes: f78762a3cc8 ("hw/ufs: Fix mcq completion queue wraparound") Reported-by: Rayhan Ramdhany Hanaputra <hanaputrarayhan@gmail.com> Cc: qemu-stable@nongnu.org Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com>
Jeuk Kim committed
Mar 16, 2026 at 14:39 UTC
283d921e771e8a98a5c3d1eed1ed791b89ba47a8
2 files changed
+12
-1
hw/ufs/ufs.c
+4
@@ -817,6 +817,10 @@ static void ufs_write_mcq_op_reg(UfsHc *u, hwaddr offset, uint32_t data,
817
case offsetof(UfsMcqOpReg, cq.hp): {
818
UfsCq *cq = u->cq[qid];
819
820
+ if (!cq) {
821
+ break;
822
+ }
823
+
824
if (ufs_mcq_cq_full(u, qid) && !QTAILQ_EMPTY(&cq->req_list)) {
825
/* Enqueueing to CQ was blocked because it was full */
826
qemu_bh_schedule(cq->bh);
hw/ufs/ufs.h
+8
-1
@@ -203,7 +203,14 @@ static inline bool ufs_mcq_cq_empty(UfsHc *u, uint32_t qid)
203
static inline bool ufs_mcq_cq_full(UfsHc *u, uint32_t qid)
204
{
205
uint32_t tail = ufs_mcq_cq_tail(u, qid);
206
- uint16_t cq_size = u->cq[qid]->size;
206
+ UfsCq *cq = u->cq[qid];
207
+ uint16_t cq_size;
208
+
209
+ if (!cq) {
210
+ return false;
211
+ }
212
+
213
+ cq_size = cq->size;
214
215
tail = (tail + sizeof(UfsCqEntry)) % (sizeof(UfsCqEntry) * cq_size);
216
return tail == ufs_mcq_cq_head(u, qid);