hw/ufs: Reject zero-depth MCQ queues
Reject SQATTR.SIZE and CQATTR.SIZE values that produce zero-entry MCQ queues. Such queues can later trigger a divide-by-zero while advancing queue pointers. Fixes: 5c079578d2e ("hw/ufs: Add support MCQ of UFSHCI 4.0") Cc: qemu-stable@nongnu.org Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com>
Jeuk Kim committed
May 6, 2026 at 13:50 UTC
4a909c00b9e18478e67a792c7f7cfae62cb6c865
2 files changed
+18
-2
hw/ufs/trace-events
+2
@@ -40,10 +40,12 @@ ufs_err_mcq_db_wr_invalid_sqid(uint8_t qid) "invalid mcq sqid %"PRIu8""
40
ufs_err_mcq_db_wr_invalid_db(uint8_t qid, uint32_t db) "invalid mcq doorbell sqid %"PRIu8", db %"PRIu32""
41
ufs_err_mcq_create_sq_invalid_sqid(uint8_t qid) "invalid mcq sqid %"PRIu8""
42
ufs_err_mcq_create_sq_invalid_cqid(uint8_t qid) "invalid mcq cqid %"PRIu8""
43
+ufs_err_mcq_create_sq_invalid_size(uint8_t qid) "invalid mcq sq size for sqid %"PRIu8""
44
ufs_err_mcq_create_sq_already_exists(uint8_t qid) "mcq sqid %"PRIu8 "already exists"
45
ufs_err_mcq_delete_sq_invalid_sqid(uint8_t qid) "invalid mcq sqid %"PRIu8""
46
ufs_err_mcq_delete_sq_not_exists(uint8_t qid) "mcq sqid %"PRIu8 "not exists"
47
ufs_err_mcq_create_cq_invalid_cqid(uint8_t qid) "invalid mcq cqid %"PRIu8""
48
+ufs_err_mcq_create_cq_invalid_size(uint8_t qid) "invalid mcq cq size for cqid %"PRIu8""
49
ufs_err_mcq_create_cq_already_exists(uint8_t qid) "mcq cqid %"PRIu8 "already exists"
50
ufs_err_mcq_delete_cq_invalid_cqid(uint8_t qid) "invalid mcq cqid %"PRIu8""
51
ufs_err_mcq_delete_cq_not_exists(uint8_t qid) "mcq cqid %"PRIu8 "not exists"
hw/ufs/ufs.c
+16
-2
@@ -506,6 +506,8 @@ static bool ufs_mcq_create_sq(UfsHc *u, uint8_t qid, uint32_t attr)
506
UfsMcqReg *reg = &u->mcq_reg[qid];
507
UfsSq *sq;
508
uint8_t cqid = FIELD_EX32(attr, SQATTR, CQID);
509
+ uint16_t qsize =
510
+ ((FIELD_EX32(attr, SQATTR, SIZE) + 1) << 2) / sizeof(UfsSqEntry);
511
512
if (qid >= u->params.mcq_maxq) {
513
trace_ufs_err_mcq_create_sq_invalid_sqid(qid);
@@ -527,12 +529,17 @@ static bool ufs_mcq_create_sq(UfsHc *u, uint8_t qid, uint32_t attr)
529
return false;
530
}
531
532
+ if (!qsize) {
533
+ trace_ufs_err_mcq_create_sq_invalid_size(qid);
534
+ return false;
535
+ }
536
+
537
sq = g_malloc0(sizeof(*sq));
538
sq->u = u;
539
sq->sqid = qid;
540
sq->cq = u->cq[cqid];
541
sq->addr = ((uint64_t)reg->squba << 32) | reg->sqlba;
535
- sq->size = ((FIELD_EX32(attr, SQATTR, SIZE) + 1) << 2) / sizeof(UfsSqEntry);
542
+ sq->size = qsize;
543
544
sq->bh = qemu_bh_new_guarded(ufs_mcq_process_sq, sq,
545
&DEVICE(u)->mem_reentrancy_guard);
@@ -576,6 +583,8 @@ static bool ufs_mcq_create_cq(UfsHc *u, uint8_t qid, uint32_t attr)
583
{
584
UfsMcqReg *reg = &u->mcq_reg[qid];
585
UfsCq *cq;
586
+ uint16_t qsize =
587
+ ((FIELD_EX32(attr, CQATTR, SIZE) + 1) << 2) / sizeof(UfsCqEntry);
588
589
if (qid >= u->params.mcq_maxq) {
590
trace_ufs_err_mcq_create_cq_invalid_cqid(qid);
@@ -587,11 +596,16 @@ static bool ufs_mcq_create_cq(UfsHc *u, uint8_t qid, uint32_t attr)
596
return false;
597
}
598
599
+ if (!qsize) {
600
+ trace_ufs_err_mcq_create_cq_invalid_size(qid);
601
+ return false;
602
+ }
603
+
604
cq = g_malloc0(sizeof(*cq));
605
cq->u = u;
606
cq->cqid = qid;
607
cq->addr = ((uint64_t)reg->cquba << 32) | reg->cqlba;
594
- cq->size = ((FIELD_EX32(attr, CQATTR, SIZE) + 1) << 2) / sizeof(UfsCqEntry);
608
+ cq->size = qsize;
609
610
cq->bh = qemu_bh_new_guarded(ufs_mcq_process_cq, cq,
611
&DEVICE(u)->mem_reentrancy_guard);