Commit b26d4302a8 for qemu.org
commit b26d4302a8978e1fe467b4d90a2e826f898f11d3
Author: Peter Maydell <peter.maydell@linaro.org>
Date: Fri Oct 23 16:31:06 2026 +0100
hw/net/cadence_gem: Check guest-provided queue numbers in screening registers
The Cadence GEM allows the guest to program "screening registers"
which control which queue received network data should be sent to.
The field for the queue number in these registers is 4 bits, but the
device might not actually have that many queues. We weren't checking
this, which meant the guest could program a value that caused us to
index off the end of various arrays.
Check against num_priority_queues, and treat out-of-range values
as if the screen didn't match (i.e. go to queue 0). (This is a
best guess at reasonable behaviour since I don't have access to
a datasheet for this device.)
Cc: qemu-stable@nongnu.org
Fixes: e8e4994313b7 ("cadence_gem: Add support for screening")
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4363
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Message-ID: <20261023153106.1710228-1-peter.maydell@linaro.org>
Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
index 39e3620ef5..9a94b3b8ca 100644
--- a/hw/net/cadence_gem.c
+++ b/hw/net/cadence_gem.c
@@ -854,6 +854,7 @@ static int get_queue_from_screen(CadenceGEMState *s, uint8_t *rxbuf_ptr,
uint32_t reg;
bool matched, mismatched;
int i, j;
+ int queue = 0; /* default to queue 0 if no match */
for (i = 0; i < s->num_type1_screeners; i++) {
reg = s->regs[R_SCREENING_TYPE1_REG0 + i];
@@ -881,7 +882,8 @@ static int get_queue_from_screen(CadenceGEMState *s, uint8_t *rxbuf_ptr,
}
if (matched && !mismatched) {
- return FIELD_EX32(reg, SCREENING_TYPE1_REG0, QUEUE_NUM);
+ queue = FIELD_EX32(reg, SCREENING_TYPE1_REG0, QUEUE_NUM);
+ goto out;
}
}
@@ -974,12 +976,23 @@ static int get_queue_from_screen(CadenceGEMState *s, uint8_t *rxbuf_ptr,
}
if (matched && !mismatched) {
- return FIELD_EX32(reg, SCREENING_TYPE2_REG0, QUEUE_NUM);
+ queue = FIELD_EX32(reg, SCREENING_TYPE2_REG0, QUEUE_NUM);
+ break;
}
}
- /* We made it here, assume it's queue 0 */
- return 0;
+out:
+ if (queue >= s->num_priority_queues) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "Screening register selected out of range queue %d\n",
+ queue);
+ /*
+ * This is a best guess at reasonable behaviour in the absence
+ * of a datasheet to confirm it.
+ */
+ queue = 0;
+ }
+ return queue;
}
static uint32_t gem_get_queue_base_addr(CadenceGEMState *s, bool tx, int q)