mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
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: 98f7060b9e ("xen/arm/irq: add handling for IRQs in the eSPI range")
Signed-off-by: Mykola Kvach <mykola_kvach@epam.com>
Reviewed-by: Michal Orzel <michal.orzel@amd.com>
This commit is contained in:
1 parent
22f8ddd1c6
commit
bfa8367d3b
1 file changed
+25
-3
+25
-3
@@ -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) )
|
||||
|
||||