From bfa8367d3baf8c9b6a95438f9d6a3e7796119dad Mon Sep 17 00:00:00 2001 From: Mykola Kvach Date: Tue, 29 Sep 2026 18:54:11 +0200 Subject: [PATCH] xen/arm: validate IRQs before descriptor lookup GICv3 eSPI support makes nr_irqs span the architectural INTID namespace through ESPI_MAX_INTID, but descriptor storage is sparse. local_irq_desc[] and irq_desc[] cover INTIDs below NR_IRQS, while espi_desc[] covers eSPIs. INTIDs 1024 through 4095 have no backing descriptors. Validation based only on nr_irqs accepts an INTID in this gap. __irq_to_desc() then indexes beyond irq_desc[], and callers may lock or update unrelated Xen memory. Reject INTIDs that the GIC reports as unimplemented in setup_irq() before looking up a descriptor. irq_set_spi_type() can run before the implemented GIC line counts are available, so validate descriptor-backed ranges there before looking up a descriptor. Use the same descriptor range check in irq_set_spi_type() and the assertion in __irq_to_desc() to keep them in sync. Log the IRQ number when setup_irq() rejects an invalid line. Fixes: 98f7060b9ed5 ("xen/arm/irq: add handling for IRQs in the eSPI range") Signed-off-by: Mykola Kvach Reviewed-by: Michal Orzel --- xen/arch/arm/irq.c | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c index 73e58a5108..8d3517e761 100644 --- a/xen/arch/arm/irq.c +++ b/xen/arch/arm/irq.c @@ -85,6 +85,12 @@ static int __init init_espi_data(void) static DEFINE_PER_CPU(irq_desc_t[NR_LOCAL_IRQS], local_irq_desc); +static bool irq_has_desc(unsigned int irq) +{ + return irq < NR_IRQS || + (IS_ENABLED(CONFIG_GICV3_ESPI) && is_espi(irq)); +} + struct irq_desc *__irq_to_desc(unsigned int irq) { if ( irq < NR_LOCAL_IRQS ) @@ -95,6 +101,8 @@ struct irq_desc *__irq_to_desc(unsigned int irq) return espi_to_desc(irq); #endif + ASSERT(irq_has_desc(irq)); + return &irq_desc[irq-NR_LOCAL_IRQS]; } @@ -416,6 +424,12 @@ int setup_irq(unsigned int irq, unsigned int irqflags, struct irqaction *new) struct irq_desc *desc; bool disabled; + if ( !gic_is_valid_line(irq) ) + { + printk(XENLOG_ERR "Cannot set up IRQ %u: invalid GIC interrupt\n", irq); + return -EINVAL; + } + desc = irq_to_desc(irq); spin_lock_irqsave(&desc->lock, flags); @@ -647,13 +661,21 @@ static bool irq_validate_new_type(unsigned int curr, unsigned int new) int irq_set_spi_type(unsigned int spi, unsigned int type) { unsigned long flags; - struct irq_desc *desc = irq_to_desc(spi); + struct irq_desc *desc; int ret = -EBUSY; - /* This function should not be used for other than SPIs */ - if ( spi < NR_LOCAL_IRQS ) + /* + * This function should not be used for other than SPIs. + * + * The implemented GIC line counts are not available when early + * callers configure IRQ types. Check descriptor storage here; setup_irq() + * validates the implemented line before the interrupt is used. + */ + if ( spi < NR_LOCAL_IRQS || !irq_has_desc(spi) ) return -EINVAL; + desc = irq_to_desc(spi); + spin_lock_irqsave(&desc->lock, flags); if ( !irq_validate_new_type(desc->arch.type, type) )