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: [email protected] Fixes: e8e4994313b7 ("cadence_gem: Add support for screening") Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4363 Signed-off-by: Peter Maydell <[email protected]> --- hw/net/cadence_gem.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index 39e3620ef5b..9a94b3b8ca4 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) -- 2.43.0
