[PATCH] irqchip/riscv-aplic: Validate translated source IDs
From: Pengpeng Hou
Date: Sat Jul 18 2026 - 00:33:48 EST
APLIC source IDs are in the range 1..riscv,num-sources. Device Tree
interrupt specifiers contain a source ID directly, while ACPI specifiers
contain a GSI that must first be translated by subtracting gsi_base.
The shared helper currently checks only whether the raw specifier is zero.
An ACPI GSI equal to gsi_base therefore becomes source ID zero, a GSI below
gsi_base underflows, and either firmware interface can provide a source ID
above the configured count. These values later reach d->hwirq - 1 register
and saved-state indexing.
Pass the configured source count to the shared helper and validate the
translated ID before returning it. This covers both direct and MSI modes.
Fixes: 2333df5ae51e ("irqchip: Add RISC-V advanced PLIC driver for direct-mode")
Signed-off-by: Pengpeng Hou <pengpeng@xxxxxxxxxxx>
---
drivers/irqchip/irq-riscv-aplic-direct.c | 6 ++++--
drivers/irqchip/irq-riscv-aplic-main.c | 8 +++++---
drivers/irqchip/irq-riscv-aplic-main.h | 3 ++-
drivers/irqchip/irq-riscv-aplic-msi.c | 3 ++-
4 files changed, 13 insertions(+), 7 deletions(-)
diff --git a/drivers/irqchip/irq-riscv-aplic-direct.c b/drivers/irqchip/irq-riscv-aplic-direct.c
index 5a9650225dd80..eb46d9a219e10 100644
--- a/drivers/irqchip/irq-riscv-aplic-direct.c
+++ b/drivers/irqchip/irq-riscv-aplic-direct.c
@@ -97,7 +97,8 @@ static int aplic_direct_irqdomain_translate(struct irq_domain *d, struct irq_fws
{
struct aplic_priv *priv = d->host_data;
- return aplic_irqdomain_translate(fwspec, priv->gsi_base, hwirq, type);
+ return aplic_irqdomain_translate(fwspec, priv->gsi_base, priv->nr_irqs,
+ hwirq, type);
}
static int aplic_direct_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
@@ -110,7 +111,8 @@ static int aplic_direct_irqdomain_alloc(struct irq_domain *domain, unsigned int
unsigned int type;
int i, ret;
- ret = aplic_irqdomain_translate(fwspec, priv->gsi_base, &hwirq, &type);
+ ret = aplic_irqdomain_translate(fwspec, priv->gsi_base, priv->nr_irqs,
+ &hwirq, &type);
if (ret)
return ret;
diff --git a/drivers/irqchip/irq-riscv-aplic-main.c b/drivers/irqchip/irq-riscv-aplic-main.c
index d9afb6ae98cf5..2284dbaea449d 100644
--- a/drivers/irqchip/irq-riscv-aplic-main.c
+++ b/drivers/irqchip/irq-riscv-aplic-main.c
@@ -235,15 +235,17 @@ int aplic_irq_set_type(struct irq_data *d, unsigned int type)
}
int aplic_irqdomain_translate(struct irq_fwspec *fwspec, u32 gsi_base,
- unsigned long *hwirq, unsigned int *type)
+ u32 nr_irqs, unsigned long *hwirq,
+ unsigned int *type)
{
if (WARN_ON(fwspec->param_count < 2))
return -EINVAL;
- if (WARN_ON(!fwspec->param[0]))
- return -EINVAL;
/* For DT, gsi_base is always zero. */
*hwirq = fwspec->param[0] - gsi_base;
+ if (WARN_ON(!*hwirq || *hwirq > nr_irqs))
+ return -EINVAL;
+
*type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
WARN_ON(*type == IRQ_TYPE_NONE);
diff --git a/drivers/irqchip/irq-riscv-aplic-main.h b/drivers/irqchip/irq-riscv-aplic-main.h
index 2d8ad7138541a..8d4010e7149be 100644
--- a/drivers/irqchip/irq-riscv-aplic-main.h
+++ b/drivers/irqchip/irq-riscv-aplic-main.h
@@ -55,7 +55,8 @@ void aplic_irq_unmask(struct irq_data *d);
void aplic_irq_mask(struct irq_data *d);
int aplic_irq_set_type(struct irq_data *d, unsigned int type);
int aplic_irqdomain_translate(struct irq_fwspec *fwspec, u32 gsi_base,
- unsigned long *hwirq, unsigned int *type);
+ u32 nr_irqs, unsigned long *hwirq,
+ unsigned int *type);
void aplic_init_hw_global(struct aplic_priv *priv, bool msi_mode);
int aplic_setup_priv(struct aplic_priv *priv, struct device *dev, void __iomem *regs);
void aplic_direct_restore_states(struct aplic_priv *priv);
diff --git a/drivers/irqchip/irq-riscv-aplic-msi.c b/drivers/irqchip/irq-riscv-aplic-msi.c
index fb8d1838609fb..665840e2c3919 100644
--- a/drivers/irqchip/irq-riscv-aplic-msi.c
+++ b/drivers/irqchip/irq-riscv-aplic-msi.c
@@ -140,7 +140,8 @@ static int aplic_msi_translate(struct irq_domain *d, struct irq_fwspec *fwspec,
struct msi_domain_info *info = d->host_data;
struct aplic_priv *priv = info->data;
- return aplic_irqdomain_translate(fwspec, priv->gsi_base, hwirq, type);
+ return aplic_irqdomain_translate(fwspec, priv->gsi_base, priv->nr_irqs,
+ hwirq, type);
}
static const struct msi_domain_template aplic_msi_template = {
--
2.43.0