@samitouri / QOSamiQemu / commits / 4a909c00b9

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);