From patchwork Mon Jul 26 05:02:46 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Isaku Yamahata X-Patchwork-Id: 59891 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 5083BB6EFE for ; Mon, 26 Jul 2010 15:04:47 +1000 (EST) Received: from localhost ([127.0.0.1]:46627 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OdFro-0007F3-0c for incoming@patchwork.ozlabs.org; Mon, 26 Jul 2010 01:04:44 -0400 Received: from [140.186.70.92] (port=58171 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OdFmt-0004wv-47 for qemu-devel@nongnu.org; Mon, 26 Jul 2010 00:59:49 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.69) (envelope-from ) id 1OdFmi-0004Lr-QL for qemu-devel@nongnu.org; Mon, 26 Jul 2010 00:59:38 -0400 Received: from mail.valinux.co.jp ([210.128.90.3]:50977) by eggs.gnu.org with esmtp (Exim 4.69) (envelope-from ) id 1OdFmi-0004Ky-C0 for qemu-devel@nongnu.org; Mon, 26 Jul 2010 00:59:28 -0400 Received: from ps.local.valinux.co.jp (vagw.valinux.co.jp [210.128.90.14]) by mail.valinux.co.jp (Postfix) with SMTP id A77D6107935; Mon, 26 Jul 2010 13:59:23 +0900 (JST) Received: (nullmailer pid 1702 invoked by uid 1000); Mon, 26 Jul 2010 05:02:46 -0000 From: Isaku Yamahata To: seabios@seabios.org Date: Mon, 26 Jul 2010 14:02:46 +0900 Message-Id: <467b97ca8eab5336ed7fa6fae93db3695a04e8dd.1280120278.git.yamahata@valinux.co.jp> X-Mailer: git-send-email 1.7.1.1 In-Reply-To: References: In-Reply-To: References: X-Virus-Scanned: clamav-milter 0.95.2 at va-mail.local.valinux.co.jp X-Virus-Status: Clean X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 3) Cc: yamahata@valinux.co.jp, cam@cs.ualberta.ca, qemu-devel@nongnu.org, mst@redhat.com Subject: [Qemu-devel] [PATCH 2/2] seabios: pciinit: fix overflow when bar allocation. X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org When allocating bar, overflow can occur. So add overflow check and don't allocate bar if overflowed. Overflow check is ugly, but necessary. Another suggested way is to change related variables u64 from u32 thus overflow can't occur because the related value are all u32 addressable. Anyway even with u64, it is necessary to the resulted value > max_u32. Signed-off-by: Isaku Yamahata --- src/pciinit.c | 48 ++++++++++++++++++++++++++++++++++-------------- 1 files changed, 34 insertions(+), 14 deletions(-) diff --git a/src/pciinit.c b/src/pciinit.c index f75e552..9be895c 100644 --- a/src/pciinit.c +++ b/src/pciinit.c @@ -49,6 +49,12 @@ static void pci_set_io_region_addr(u16 bdf, int region_num, u32 addr) dprintf(1, "region %d: 0x%08x\n", region_num, addr); } +static inline int pci_bar_overflow(u32 addr, u32 size) +{ + return (ALIGN(addr, size) < addr) || + (ALIGN(addr, size) + size < ALIGN(addr, size)); +} + /* * return value * 0: 32bit BAR @@ -78,7 +84,8 @@ static int pci_bios_allocate_region(u16 bdf, int region_num) if (val != 0) { if (val & PCI_BASE_ADDRESS_SPACE_IO) { paddr = &pci_bios_io_addr; - if (ALIGN(*paddr, size) + size >= 64 * 1024) { + if (pci_bar_overflow(*paddr, size) || + ALIGN(*paddr, size) + size >= 64 * 1024) { dprintf(1, "io region of (bdf 0x%x bar %d) can't be mapped.\n", bdf, region_num); @@ -90,7 +97,8 @@ static int pci_bios_allocate_region(u16 bdf, int region_num) /* If pci_bios_prefmem_addr == 0, keep old behaviour */ pci_bios_prefmem_addr != 0) { paddr = &pci_bios_prefmem_addr; - if (ALIGN(*paddr, size) + size >= BUILD_PCIPREFMEM_END) { + if (pci_bar_overflow(*paddr, size) || + ALIGN(*paddr, size) + size >= BUILD_PCIPREFMEM_END) { dprintf(1, "prefmem region of (bdf 0x%x bar %d) can't be mapped. " "decrease BUILD_PCIMEM_SIZE and recompile. size %x\n", @@ -99,7 +107,8 @@ static int pci_bios_allocate_region(u16 bdf, int region_num) } } else { paddr = &pci_bios_mem_addr; - if (ALIGN(*paddr, size) + size >= BUILD_PCIMEM_END) { + if (pci_bar_overflow(*paddr, size) || + ALIGN(*paddr, size) + size >= BUILD_PCIMEM_END) { dprintf(1, "mem region of (bdf 0x%x bar %d) can't be mapped. " "increase BUILD_PCIMEM_SIZE and recompile. size %x\n", @@ -152,6 +161,12 @@ static const struct pci_device_id pci_isa_bridge_tbl[] = { PCI_DEVICE_END }; +static inline int pci_addr_overflow(u32 old, u32 base, u32 addr, u32 end) +{ + /* if without overflow, old <= base <= addr <= end */ + return (old > base) || (base > addr) || (addr > end); +} + #define PCI_IO_ALIGN 4096 #define PCI_IO_SHIFT 8 #define PCI_MEMORY_ALIGN (1UL << 20) @@ -184,36 +199,41 @@ static void pci_bios_init_device_bridge(u16 bdf, void *arg) pci_bios_init_device_in_bus(secbus); } - pci_bios_io_addr = ALIGN(pci_bios_io_addr, PCI_IO_ALIGN); - pci_bios_mem_addr = ALIGN(pci_bios_mem_addr, PCI_MEMORY_ALIGN); - pci_bios_prefmem_addr = - ALIGN(pci_bios_prefmem_addr, PCI_PREF_MEMORY_ALIGN); - - u32 io_end = pci_bios_io_addr; - if (io_end == io_base) { + u32 io_end = ALIGN(pci_bios_io_addr, PCI_IO_ALIGN); + if (pci_addr_overflow(io_old, io_base, pci_bios_io_addr, io_end) || + io_end == io_base) { pci_bios_io_addr = io_old; io_base = 0xffff; io_end = 1; + } else { + pci_bios_io_addr = io_end; } pci_config_writeb(bdf, PCI_IO_BASE, io_base >> PCI_IO_SHIFT); pci_config_writew(bdf, PCI_IO_BASE_UPPER16, 0); pci_config_writeb(bdf, PCI_IO_LIMIT, (io_end - 1) >> PCI_IO_SHIFT); pci_config_writew(bdf, PCI_IO_LIMIT_UPPER16, 0); - u32 mem_end = pci_bios_mem_addr; - if (mem_end == mem_base) { + u32 mem_end = ALIGN(pci_bios_mem_addr, PCI_MEMORY_ALIGN); + if (pci_addr_overflow(mem_old, mem_base, pci_bios_mem_addr, mem_end) || + mem_end == mem_base) { pci_bios_mem_addr = mem_old; mem_base = 0xffffffff; mem_end = 1; + } else { + pci_bios_io_addr = mem_end; } pci_config_writew(bdf, PCI_MEMORY_BASE, mem_base >> PCI_MEMORY_SHIFT); pci_config_writew(bdf, PCI_MEMORY_LIMIT, (mem_end -1) >> PCI_MEMORY_SHIFT); - u32 prefmem_end = pci_bios_prefmem_addr; - if (prefmem_end == prefmem_base) { + u32 prefmem_end = ALIGN(pci_bios_prefmem_addr, PCI_PREF_MEMORY_ALIGN); + if (pci_addr_overflow(prefmem_old, prefmem_base, + pci_bios_prefmem_addr, prefmem_end) || + prefmem_end == prefmem_base) { pci_bios_prefmem_addr = prefmem_old; prefmem_base = 0xffffffff; prefmem_end = 1; + } else { + pci_bios_prefmem_addr = prefmem_end; } pci_config_writew(bdf, PCI_PREF_MEMORY_BASE, prefmem_base >> PCI_PREF_MEMORY_SHIFT);