[PATCH] irqchip/riscv-aplic: Validate translated source IDs

Pengpeng Hou posted 1 patch 6 days, 23 hours ago
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(-)
[PATCH] irqchip/riscv-aplic: Validate translated source IDs
Posted by Pengpeng Hou 6 days, 23 hours ago
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@iscas.ac.cn>
---
 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