{"id":2234884,"url":"http://patchwork.ozlabs.org/api/1.2/patches/2234884/?format=json","web_url":"http://patchwork.ozlabs.org/project/linux-pci/patch/20260508082128.3344255-3-kanie@linux.alibaba.com/","project":{"id":28,"url":"http://patchwork.ozlabs.org/api/1.2/projects/28/?format=json","name":"Linux PCI development","link_name":"linux-pci","list_id":"linux-pci.vger.kernel.org","list_email":"linux-pci@vger.kernel.org","web_url":null,"scm_url":null,"webscm_url":null,"list_archive_url":"","list_archive_url_format":"","commit_url_format":""},"msgid":"<20260508082128.3344255-3-kanie@linux.alibaba.com>","list_archive_url":null,"date":"2026-05-08T08:21:28","name":"[v12,2/2] PCI: Check ROM header and data structure addr before accessing","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"c427a4bcdcfd350c12cdf2eebde32127433c97e8","submitter":{"id":89531,"url":"http://patchwork.ozlabs.org/api/1.2/people/89531/?format=json","name":"Guixin Liu","email":"kanie@linux.alibaba.com"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/linux-pci/patch/20260508082128.3344255-3-kanie@linux.alibaba.com/mbox/","series":[{"id":503346,"url":"http://patchwork.ozlabs.org/api/1.2/series/503346/?format=json","web_url":"http://patchwork.ozlabs.org/project/linux-pci/list/?series=503346","date":"2026-05-08T08:21:26","name":"PCI: Fix crash when access broken ROM","version":12,"mbox":"http://patchwork.ozlabs.org/series/503346/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2234884/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2234884/checks/","tags":{},"related":[],"headers":{"Return-Path":"\n <linux-pci+bounces-54240-incoming=patchwork.ozlabs.org@vger.kernel.org>","X-Original-To":["incoming@patchwork.ozlabs.org","linux-pci@vger.kernel.org"],"Delivered-To":"patchwork-incoming@legolas.ozlabs.org","Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (1024-bit key;\n unprotected) header.d=linux.alibaba.com header.i=@linux.alibaba.com\n header.a=rsa-sha256 header.s=default header.b=x11/5k0G;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=2600:3c04:e001:36c::12fc:5321; helo=tor.lore.kernel.org;\n envelope-from=linux-pci+bounces-54240-incoming=patchwork.ozlabs.org@vger.kernel.org;\n receiver=patchwork.ozlabs.org)","smtp.subspace.kernel.org;\n\tdkim=pass (1024-bit key) header.d=linux.alibaba.com\n header.i=@linux.alibaba.com header.b=\"x11/5k0G\"","smtp.subspace.kernel.org;\n arc=none smtp.client-ip=115.124.30.133","smtp.subspace.kernel.org;\n dmarc=pass (p=none dis=none) header.from=linux.alibaba.com","smtp.subspace.kernel.org;\n spf=pass smtp.mailfrom=linux.alibaba.com"],"Received":["from tor.lore.kernel.org (tor.lore.kernel.org\n [IPv6:2600:3c04:e001:36c::12fc:5321])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4gBhwV4QcLz1yJq\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 08 May 2026 18:23:54 +1000 (AEST)","from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby tor.lore.kernel.org (Postfix) with ESMTP id 9421B30514BA\n\tfor <incoming@patchwork.ozlabs.org>; Fri,  8 May 2026 08:21:55 +0000 (UTC)","from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id 2D70237F75E;\n\tFri,  8 May 2026 08:21:54 +0000 (UTC)","from out30-133.freemail.mail.aliyun.com\n (out30-133.freemail.mail.aliyun.com [115.124.30.133])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id 37050221F39\n\tfor <linux-pci@vger.kernel.org>; Fri,  8 May 2026 08:21:46 +0000 (UTC)","from localhost(mailfrom:kanie@linux.alibaba.com\n fp:SMTPD_---0X2Wne7b_1778228499 cluster:ay36)\n          by smtp.aliyun-inc.com;\n          Fri, 08 May 2026 16:21:44 +0800"],"ARC-Seal":"i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1778228512; cv=none;\n b=IDzeMAVT6hs1h8i9qT0MbA6FuZJALhv1i1/xE6BsJ+lDUcXH7bEHN3ekh6ZelEgHMvIs5zzgSlZByScBWqpQvZ6oRbU76zZj1ofOe2sUbu2XfiQ1KETxJQ8AA90y8FBgSXDeDAr7SXIN6G+1YPDaqrAxZr4QgZ4GRtOGOeaRcoY=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1778228512; c=relaxed/simple;\n\tbh=V3h4GANUuWozhDK+uvj1J1Ryvja7twnUcXsVZFRh0dE=;\n\th=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:\n\t MIME-Version;\n b=n/RofQC/CpjBuNxpQzmcjL39t/jBnxwzr3LhHQyuGEUjeq3djHetCjLE0fYYxncZRSYZr1dUcsW1dn27dcPZ/2D1xiFgT7GlFqg40OOhh8wcl5ytezgZTGYfPZweCL+Yk3RG4QOov8djzVEFxZrRqvKDXmq07kKOyndtrY+nzkg=","ARC-Authentication-Results":"i=1; smtp.subspace.kernel.org;\n dmarc=pass (p=none dis=none) header.from=linux.alibaba.com;\n spf=pass smtp.mailfrom=linux.alibaba.com;\n dkim=pass (1024-bit key) header.d=linux.alibaba.com\n header.i=@linux.alibaba.com header.b=x11/5k0G;\n arc=none smtp.client-ip=115.124.30.133","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=linux.alibaba.com; s=default;\n\tt=1778228504; h=From:To:Subject:Date:Message-ID:MIME-Version;\n\tbh=mcMIv8qaWKZuq2oCWwsjDndEyMqehlPDhIppWbr0hL8=;\n\tb=x11/5k0GaivZU1q7GgDoK8gM6gZNfoiK789qXKNj97V2OZLAvuvP8Th1ciLjU26KjSzYBeuADbyz0P3Iwv4ed8WvjqAsHFWAK+RfPG728IcK3rkmyyvuT3WE66S5rpvld+VvtDwYy7locewdgw5d7q8YJ3WFZkCsSYQxY1N9OFw=","X-Alimail-AntiSpam":"\n AC=PASS;BC=-1|-1;BR=01201311R441e4;CH=green;DM=||false|;DS=||;FP=0|-1|-1|-1|0|-1|-1|-1;HT=maildocker-contentspam033037026112;MF=kanie@linux.alibaba.com;NM=1;PH=DS;RN=7;SR=0;TI=SMTPD_---0X2Wne7b_1778228499;","From":"Guixin Liu <kanie@linux.alibaba.com>","To":"Bjorn Helgaas <bhelgaas@google.com>,\n Andy Shevchenko <andriy.shevchenko@intel.com>,\n =?utf-8?q?Ilpo_J=C3=A4rvinen?= <ilpo.jarvinen@linux.intel.com>, =?utf-8?q?K?=\n\t=?utf-8?q?rzysztof_Wilczy=C5=84ski?= <kwilczynski@kernel.org>","Cc":"linux-pci@vger.kernel.org,\n\txlpang@linux.alibaba.com,\n\toliver.yang@linux.alibaba.com","Subject":"[PATCH v12 2/2] PCI: Check ROM header and data structure addr before\n accessing","Date":"Fri,  8 May 2026 16:21:28 +0800","Message-ID":"<20260508082128.3344255-3-kanie@linux.alibaba.com>","X-Mailer":"git-send-email 2.43.7","In-Reply-To":"<20260508082128.3344255-1-kanie@linux.alibaba.com>","References":"<20260508082128.3344255-1-kanie@linux.alibaba.com>","Precedence":"bulk","X-Mailing-List":"linux-pci@vger.kernel.org","List-Id":"<linux-pci.vger.kernel.org>","List-Subscribe":"<mailto:linux-pci+subscribe@vger.kernel.org>","List-Unsubscribe":"<mailto:linux-pci+unsubscribe@vger.kernel.org>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit"},"content":"We meet a crash when running stress-ng on x86_64 machine:\n\n  BUG: unable to handle page fault for address: ffa0000007f40000\n  RIP: 0010:pci_get_rom_size+0x52/0x220\n  Call Trace:\n  <TASK>\n    pci_map_rom+0x80/0x130\n    pci_read_rom+0x4b/0xe0\n    kernfs_file_read_iter+0x96/0x180\n    vfs_read+0x1b1/0x300\n\nOur analysis reveals that the ROM space's start address is\n0xffa0000007f30000, and size is 0x10000. Because of broken ROM\nspace, before calling readl(pds), the pds's value is\n0xffa0000007f3ffff, which is already pointed to the ROM space\nend, invoking readl() would read 4 bytes therefore cause an\nout-of-bounds access and trigger a crash.\nFix this by adding image header and data structure checking.\n\nWe also found another crash on arm64 machine:\n\n  Unable to handle kernel paging request at virtual address\nffff8000dd1393ff\n  Mem abort info:\n  ESR = 0x0000000096000021\n  EC = 0x25: DABT (current EL), IL = 32 bits\n  SET = 0, FnV = 0\n  EA = 0, S1PTW = 0\n  FSC = 0x21: alignment fault\n\nThe call trace is the same with x86_64, but the crash reason is\nthat the data structure addr is not aligned with 4, and arm64\nmachine report \"alignment fault\". Fix this by adding alignment\nchecking.\n\nFixes: 47b975d234ea (\"PCI: Avoid iterating through memory outside the resource window\")\nSuggested-by: Guanghui Feng <guanghuifeng@linux.alibaba.com>\nSigned-off-by: Guixin Liu <kanie@linux.alibaba.com>\nReviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>\n---\n drivers/pci/rom.c | 128 +++++++++++++++++++++++++++++++++++++++-------\n 1 file changed, 110 insertions(+), 18 deletions(-)","diff":"diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c\nindex d4a141bd148b..9744f1a2923a 100644\n--- a/drivers/pci/rom.c\n+++ b/drivers/pci/rom.c\n@@ -6,9 +6,12 @@\n  * (C) Copyright 2004 Silicon Graphics, Inc. Jesse Barnes <jbarnes@sgi.com>\n  */\n \n+#include <linux/align.h>\n #include <linux/bits.h>\n #include <linux/kernel.h>\n #include <linux/export.h>\n+#include <linux/io.h>\n+#include <linux/overflow.h>\n #include <linux/pci.h>\n #include <linux/sizes.h>\n #include <linux/slab.h>\n@@ -27,6 +30,16 @@\n #define PCI_ROM_DATA_STRUCT_SIGNATURE\t\t0x52494350\n #define PCI_ROM_DATA_STRUCT_LEN\t\t\t0x0A\n \n+/*\n+ * Per PCI Local Bus Spec 2.x / PCI Firmware Spec r3.3 sec 5.1.3\n+ * Table 5-2, a conformant PCI Data Structure is at least 24 bytes\n+ * (0x18), large enough to cover every fixed field this driver\n+ * reads (up to the Indicator byte at offset 0x15).  Reject smaller\n+ * device-claimed lengths so the follow-up readers in\n+ * pci_get_rom_size() cannot escape the mapped ROM window.\n+ */\n+#define PCI_ROM_DATA_STRUCT_MIN_LEN\t\t0x18\n+\n /**\n  * pci_enable_rom - enable ROM decoding for a PCI device\n  * @pdev: PCI device to enable\n@@ -84,6 +97,95 @@ void pci_disable_rom(struct pci_dev *pdev)\n }\n EXPORT_SYMBOL_GPL(pci_disable_rom);\n \n+static bool pci_rom_is_header_valid(struct pci_dev *pdev,\n+\t\t\t\t    void __iomem *image,\n+\t\t\t\t    void __iomem *rom,\n+\t\t\t\t    size_t size,\n+\t\t\t\t    bool expect_valid)\n+{\n+\tunsigned long rom_end = (unsigned long)rom + size - 1;\n+\tunsigned long header_end;\n+\tu16 signature;\n+\n+\t/*\n+\t * Per PCI Firmware Specification r3.3, sec 5.1, each image must\n+\t * start on a 512-byte boundary and must contain the PCI Expansion\n+\t * ROM header.  Because @rom is page-aligned (returned by ioremap()),\n+\t * checking 512-byte alignment of @image is equivalent to enforcing\n+\t * the spec's sector-aligned layout within the ROM.  This also\n+\t * satisfies the natural-alignment requirement of readw() on archs\n+\t * such as arm64 that disallow unaligned IOMEM access.\n+\t */\n+\tif (!IS_ALIGNED((unsigned long)image, PCI_ROM_IMAGE_SECTOR_SIZE))\n+\t\treturn false;\n+\n+\tif (check_add_overflow((unsigned long)image, PCI_ROM_HEADER_SIZE - 1,\n+\t\t\t\t&header_end))\n+\t\treturn false;\n+\n+\tif (image < rom || header_end > rom_end)\n+\t\treturn false;\n+\n+\t/* Standard PCI ROMs start out with these bytes 55 AA */\n+\tsignature = readw(image);\n+\tif (signature != PCI_ROM_IMAGE_SIGNATURE) {\n+\t\tif (expect_valid) {\n+\t\t\tpci_info(pdev, \"Invalid PCI ROM header signature: expecting %#06x, got %#06x\\n\",\n+\t\t\t\t PCI_ROM_IMAGE_SIGNATURE, signature);\n+\t\t} else {\n+\t\t\tpci_info(pdev, \"No more image in the PCI ROM\\n\");\n+\t\t}\n+\t\treturn false;\n+\t}\n+\n+\treturn true;\n+}\n+\n+static bool pci_rom_is_data_struct_valid(struct pci_dev *pdev,\n+\t\t\t\t\t void __iomem *pds,\n+\t\t\t\t\t void __iomem *rom,\n+\t\t\t\t\t size_t size)\n+{\n+\tunsigned long rom_end = (unsigned long)rom + size - 1;\n+\tunsigned long end;\n+\tu32 signature;\n+\tu16 data_len;\n+\n+\t/*\n+\t * Some CPU architectures require IOMEM access addresses to\n+\t * be aligned, for example arm64, so since we're about to\n+\t * call readl(), we check here for 4-byte alignment.\n+\t */\n+\tif (!IS_ALIGNED((unsigned long)pds, 4))\n+\t\treturn false;\n+\n+\tif (check_add_overflow((unsigned long)pds, PCI_ROM_DATA_STRUCT_LEN + 1,\n+\t\t\t\t&end))\n+\t\treturn false;\n+\n+\tif (pds < rom || end > rom_end)\n+\t\treturn false;\n+\n+\tsignature = readl(pds);\n+\tif (signature != PCI_ROM_DATA_STRUCT_SIGNATURE) {\n+\t\tpci_info(pdev, \"Invalid PCI ROM data signature: expecting %#010x, got %#010x\\n\",\n+\t\t\t PCI_ROM_DATA_STRUCT_SIGNATURE, signature);\n+\t\treturn false;\n+\t}\n+\n+\tdata_len = readw(pds + PCI_ROM_DATA_STRUCT_LEN);\n+\tif (data_len < PCI_ROM_DATA_STRUCT_MIN_LEN || data_len == U16_MAX)\n+\t\treturn false;\n+\n+\tif (check_add_overflow((unsigned long)pds, data_len - 1, &end))\n+\t\treturn false;\n+\n+\tif (end > rom_end)\n+\t\treturn false;\n+\n+\treturn true;\n+}\n+\n /**\n  * pci_get_rom_size - obtain the actual size of the ROM image\n  * @pdev: target PCI device\n@@ -99,38 +201,28 @@ static size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom,\n \t\t\t       size_t size)\n {\n \tvoid __iomem *image;\n-\tint last_image;\n \tunsigned int length;\n+\tbool last_image;\n \n \timage = rom;\n \tdo {\n \t\tvoid __iomem *pds;\n-\t\t/* Standard PCI ROMs start out with these bytes 55 AA */\n-\t\tif (readw(image) != PCI_ROM_IMAGE_SIGNATURE) {\n-\t\t\tpci_info(pdev, \"Invalid PCI ROM header signature: expecting %#06x, got %#06x\\n\",\n-\t\t\t\t PCI_ROM_IMAGE_SIGNATURE, readw(image));\n+\t\tif (!pci_rom_is_header_valid(pdev, image, rom, size, true))\n \t\t\tbreak;\n-\t\t}\n+\n \t\t/* Get the PCI data structure and check its \"PCIR\" signature */\n \t\tpds = image + readw(image + PCI_ROM_POINTER_TO_DATA_STRUCT);\n-\t\tif (readl(pds) != PCI_ROM_DATA_STRUCT_SIGNATURE) {\n-\t\t\tpci_info(pdev, \"Invalid PCI ROM data signature: expecting %#010x, got %#010x\\n\",\n-\t\t\t\t PCI_ROM_DATA_STRUCT_SIGNATURE, readl(pds));\n+\t\tif (!pci_rom_is_data_struct_valid(pdev, pds, rom, size))\n \t\t\tbreak;\n-\t\t}\n+\n \t\tlast_image = readb(pds + PCI_ROM_LAST_IMAGE_INDICATOR) &\n \t\t\t\t   PCI_ROM_LAST_IMAGE_INDICATOR_BIT;\n \t\tlength = readw(pds + PCI_ROM_IMAGE_LEN);\n \t\timage += length * PCI_ROM_IMAGE_SECTOR_SIZE;\n-\t\t/* Avoid iterating through memory outside the resource window */\n-\t\tif (image >= rom + size)\n+\n+\t\tif (!last_image &&\n+\t\t    !pci_rom_is_header_valid(pdev, image, rom, size, false))\n \t\t\tbreak;\n-\t\tif (!last_image) {\n-\t\t\tif (readw(image) != PCI_ROM_IMAGE_SIGNATURE) {\n-\t\t\t\tpci_info(pdev, \"No more image in the PCI ROM\\n\");\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t}\n \t} while (length && !last_image);\n \n \t/* never return a size larger than the PCI resource window */\n","prefixes":["v12","2/2"]}