From: Maciej W. Rozycki Date: Thu, 31 Mar 2022 07:10:55 +0000 (+0100) Subject: x86/PCI: Add PIRQ routing table range checks X-Git-Tag: microblaze-v5.20~237^2~4 X-Git-Url: http://git.monstr.eu/?a=commitdiff_plain;h=5d64089aa4a5bd3d7e00e3d6ddf4943dd34627b3;p=linux-2.6-microblaze.git x86/PCI: Add PIRQ routing table range checks Verify that the PCI IRQ Routing Table header as well as individual slot entries are all wholly contained within the BIOS memory area. Do not even call the checksum calculator if the header would overrun the area and then bail out early if any slot would. Signed-off-by: Maciej W. Rozycki Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/r/alpine.DEB.2.21.2203301735510.22465@angie.orcam.me.uk --- diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c index 4b0e008aeb30..ef97b260a556 100644 --- a/arch/x86/pci/irq.c +++ b/arch/x86/pci/irq.c @@ -68,7 +68,8 @@ void (*pcibios_disable_irq)(struct pci_dev *dev) = pirq_disable_irq; * and perform checksum verification. */ -static inline struct irq_routing_table *pirq_check_routing_table(u8 *addr) +static inline struct irq_routing_table *pirq_check_routing_table(u8 *addr, + u8 *limit) { struct irq_routing_table *rt; int i; @@ -78,7 +79,8 @@ static inline struct irq_routing_table *pirq_check_routing_table(u8 *addr) if (rt->signature != PIRQ_SIGNATURE || rt->version != PIRQ_VERSION || rt->size % 16 || - rt->size < sizeof(struct irq_routing_table)) + rt->size < sizeof(struct irq_routing_table) || + (limit && rt->size > limit - addr)) return NULL; sum = 0; for (i = 0; i < rt->size; i++) @@ -99,17 +101,22 @@ static inline struct irq_routing_table *pirq_check_routing_table(u8 *addr) static struct irq_routing_table * __init pirq_find_routing_table(void) { + u8 * const bios_start = (u8 *)__va(0xf0000); + u8 * const bios_end = (u8 *)__va(0x100000); u8 *addr; struct irq_routing_table *rt; if (pirq_table_addr) { - rt = pirq_check_routing_table((u8 *) __va(pirq_table_addr)); + rt = pirq_check_routing_table((u8 *)__va(pirq_table_addr), + NULL); if (rt) return rt; printk(KERN_WARNING "PCI: PIRQ table NOT found at pirqaddr\n"); } - for (addr = (u8 *) __va(0xf0000); addr < (u8 *) __va(0x100000); addr += 16) { - rt = pirq_check_routing_table(addr); + for (addr = bios_start; + addr < bios_end - sizeof(struct irq_routing_table); + addr += 16) { + rt = pirq_check_routing_table(addr, bios_end); if (rt) return rt; }