On Fri, 2026-10-23 at 16:31 +0100, Peter Maydell wrote: > 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]>
Reviewed-by: Alistair Francis <[email protected]> Alistair > --- > 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)
