From nobody Tue Sep 29 02:02:56 2026 Received: from cstnet.cn (smtp21.cstnet.cn [159.226.251.21]) (using TLSv1.2 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C2CFD2F8E98; Thu, 13 Aug 2026 16:04:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=159.226.251.21 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786637057; cv=none; b=lUdMBE4maKekRL482NmlrFgDsfMh7k8ro2hS/OfSl3XqJ4f0dzxXMXWmxpQpuWrqp4fAMOphox+3BMc9r+1r2zzUR8ky5TybkWR9fJu8DLwLv/hlMWZKkCrVh7MKnUx2HINU22wH/fDVbnfAAdyXkdvEnWggv5CKSsku6ubaGuY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786637057; c=relaxed/simple; bh=2LtZ3cYUMI0i+nvTYSbTqG4og8sUeAQPXZ2li1ybIxc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=nIyfY13UYij/BPOWWE+0KTbL3dlBVhGj1mmRBblCO5VRj5nCvlw8KuYCoNgRCaQrx226gBnNFx5K4Eq0l2BJjPLUyHKCBCn4Oe11vOgJm4yp4jg5onq0P3hzyC/pyBARUDS3bE60xHIANYCGwM3T/hIg7TCPN4+H6z8urnrFXuY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iscas.ac.cn; spf=pass smtp.mailfrom=iscas.ac.cn; arc=none smtp.client-ip=159.226.251.21 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iscas.ac.cn Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=iscas.ac.cn Received: from localhost.localdomain (unknown [111.196.241.250]) by APP-01 (Coremail) with SMTP id qwCowABnPfH26n1qtTJ7BQ--.24293S2; Fri, 14 Aug 2026 00:04:06 +0800 (CST) From: Pengpeng Hou To: Lorenzo Pieralisi , Hanjun Guo Cc: Sudeep Holla , Catalin Marinas , Will Deacon , "Rafael J. Wysocki" , Len Brown , Robin Murphy , Shameer Kolothum , Joerg Roedel , linux-acpi@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Pengpeng Hou Subject: [PATCH v2 1/2] ACPI: IORT: validate table and node extents before traversal Date: Fri, 14 Aug 2026 00:04:06 +0800 Message-ID: <20260813160406.71911-1-pengpeng@iscas.ac.cn> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20260813160118.69153-1-pengpeng@iscas.ac.cn> References: <20260813160118.69153-1-pengpeng@iscas.ac.cn> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: qwCowABnPfH26n1qtTJ7BQ--.24293S2 X-Coremail-Antispam: 1UD129KBjvJXoW3XrW8Gw13Kry8Wr13CFy5CFg_yoW7Xw13pr 4DGFWYqrZ3JFsrW3yxtrZ5Cw45Aw4Ikr4UJr4rGayakwn5C345CFW2kr9I9F1rGF4kWw48 ZF1Y9FyjkFWDAr7anT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUU9Y14x267AKxVW8JVW5JwAFc2x0x2IEx4CE42xK8VAvwI8IcIk0 rVWrJVCq3wAFIxvE14AKwVWUJVWUGwA2ocxC64kIII0Yj41l84x0c7CEw4AK67xGY2AK02 1l84ACjcxK6xIIjxv20xvE14v26r4j6ryUM28EF7xvwVC0I7IYx2IY6xkF7I0E14v26F4j 6r4UJwA2z4x0Y4vEx4A2jsIE14v26r1j6r4UM28EF7xvwVC2z280aVCY1x0267AKxVW8JV W8Jr1le2I262IYc4CY6c8Ij28IcVAaY2xG8wAqx4xG64xvF2IEw4CE5I8CrVC2j2WlYx0E 2Ix0cI8IcVAFwI0_JF0_Jw1lYx0Ex4A2jsIE14v26r1j6r4UMcvjeVCFs4IE7xkEbVWUJV W8JwACjcxG0xvY0x0EwIxGrwACjI8F5VA0II8E6IAqYI8I648v4I1lFIxGxcIEc7CjxVA2 Y2ka0xkIwI1lc7CjxVAaw2AFwI0_Jw0_GFyl42xK82IYc2Ij64vIr41l4I8I3I0E4IkC6x 0Yz7v_Jr0_Gr1lx2IqxVAqx4xG67AKxVWUJVWUGwC20s026x8GjcxK67AKxVWUGVWUWwC2 zVAF1VAY17CE14v26r1q6r43MIIYrxkI7VAKI48JMIIF0xvE2Ix0cI8IcVAFwI0_Jr0_JF 4lIxAIcVC0I7IYx2IY6xkF7I0E14v26r4j6F4UMIIF0xvE42xK8VAvwI8IcIk0rVWUJVWU CwCI42IY6I8E87Iv67AKxVWUJVW8JwCI42IY6I8E87Iv6xkF7I0E14v26r4j6r4UJbIYCT nIWIevJa73UjIFyTuYvjfUoq2MUUUUU X-CM-SenderInfo: pshqw1xhqjqxpvfd2hldfou0/ Content-Type: text/plain; charset="utf-8" IORT walkers construct the first node from firmware node_offset and then read node fields after checking only whether the current pointer reached the table end. A bad root offset, truncated node header, or zero or oversized node length can therefore escape the table or prevent progress. Validate the root table and minimum node area before constructing the first pointer. Reuse a remaining-length check in each generic IORT node walk so every advertised node is contained before its fields are consumed. Fixes: 88ef16d888a0 ("ACPI: I/O Remapping Table (IORT) initial support") Assisted-by: Codex:gpt-5 Signed-off-by: Pengpeng Hou --- drivers/acpi/arm64/iort.c | 64 ++++++++++++++++++++++++++++++++++----- 1 file changed, 56 insertions(+), 8 deletions(-) diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index af7a9b2fd5bc..101d54eec544 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -148,6 +148,48 @@ typedef acpi_status (*iort_find_node_callback) /* Root pointer to the mapped IORT table */ static struct acpi_table_header *iort_table; =20 +static bool iort_table_valid(struct acpi_table_iort *iort) +{ + size_t node_bytes; + + if (!iort || iort->header.length < sizeof(*iort)) + return false; + + if (!iort->node_count) + return true; + + if (iort->node_offset < sizeof(*iort) || + iort->node_offset > iort->header.length - + sizeof(struct acpi_iort_node)) + return false; + + node_bytes =3D iort->header.length - iort->node_offset; + return iort->node_count <=3D + node_bytes / sizeof(struct acpi_iort_node); +} + +static bool iort_node_valid(struct acpi_iort_node *node, + struct acpi_iort_node *end) +{ + size_t remaining; + + if (WARN_TAINT(node >=3D end, TAINT_FIRMWARE_WORKAROUND, + "IORT node pointer overflows, bad table!\n")) + return false; + + remaining =3D (u8 *)end - (u8 *)node; + if (WARN_TAINT(remaining < sizeof(*node), TAINT_FIRMWARE_WORKAROUND, + "IORT node header is truncated, bad table!\n")) + return false; + + if (WARN_TAINT(node->length < sizeof(*node) || + node->length > remaining, TAINT_FIRMWARE_WORKAROUND, + "IORT node length overflows, bad table!\n")) + return false; + + return true; +} + static LIST_HEAD(iort_msi_chip_list); static DEFINE_SPINLOCK(iort_msi_chip_lock); =20 @@ -237,14 +279,16 @@ static struct acpi_iort_node *iort_scan_node(enum acp= i_iort_node_type type, =20 /* Get the first IORT node */ iort =3D (struct acpi_table_iort *)iort_table; + if (!iort_table_valid(iort) || !iort->node_count) + return NULL; + iort_node =3D ACPI_ADD_PTR(struct acpi_iort_node, iort, iort->node_offset); iort_end =3D ACPI_ADD_PTR(struct acpi_iort_node, iort_table, iort_table->length); =20 for (i =3D 0; i < iort->node_count; i++) { - if (WARN_TAINT(iort_node >=3D iort_end, TAINT_FIRMWARE_WORKAROUND, - "IORT node pointer overflows, bad table!\n")) + if (!iort_node_valid(iort_node, iort_end)) return NULL; =20 if (iort_node->type =3D=3D type && @@ -1168,6 +1212,8 @@ static void iort_find_rmrs(struct acpi_iort_node *iom= mu, struct device *dev, return; =20 iort =3D (struct acpi_table_iort *)iort_table; + if (!iort_table_valid(iort) || !iort->node_count) + return; =20 iort_node =3D ACPI_ADD_PTR(struct acpi_iort_node, iort, iort->node_offset); @@ -1175,8 +1221,7 @@ static void iort_find_rmrs(struct acpi_iort_node *iom= mu, struct device *dev, iort_table->length); =20 for (i =3D 0; i < iort->node_count; i++) { - if (WARN_TAINT(iort_node >=3D iort_end, TAINT_FIRMWARE_WORKAROUND, - "IORT node pointer overflows, bad table!\n")) + if (!iort_node_valid(iort_node, iort_end)) return; =20 if (iort_node->type =3D=3D ACPI_IORT_NODE_RMR) @@ -2054,6 +2099,8 @@ static void __init iort_init_platform_devices(void) * have different struct types */ iort =3D (struct acpi_table_iort *)iort_table; + if (!iort_table_valid(iort) || !iort->node_count) + return; =20 /* Get the first IORT node */ iort_node =3D ACPI_ADD_PTR(struct acpi_iort_node, iort, @@ -2062,10 +2109,8 @@ static void __init iort_init_platform_devices(void) iort_table->length); =20 for (i =3D 0; i < iort->node_count; i++) { - if (iort_node >=3D iort_end) { - pr_err("iort node pointer overflows, bad table\n"); + if (!iort_node_valid(iort_node, iort_end)) return; - } =20 iort_enable_acs(iort_node); =20 @@ -2132,12 +2177,14 @@ phys_addr_t __init acpi_iort_dma_get_max_cpu_addres= s(void) (struct acpi_table_header **)&iort); if (ACPI_FAILURE(status)) return limit; + if (!iort_table_valid(iort) || !iort->node_count) + goto out; =20 node =3D ACPI_ADD_PTR(struct acpi_iort_node, iort, iort->node_offset); end =3D ACPI_ADD_PTR(struct acpi_iort_node, iort, iort->header.length); =20 for (i =3D 0; i < iort->node_count; i++) { - if (node >=3D end) + if (!iort_node_valid(node, end)) break; =20 switch (node->type) { @@ -2162,6 +2209,7 @@ phys_addr_t __init acpi_iort_dma_get_max_cpu_address(= void) } node =3D ACPI_ADD_PTR(struct acpi_iort_node, node, node->length); } +out: acpi_put_table(&iort->header); return limit; } --=20 2.50.1 (Apple Git-155) From nobody Tue Sep 29 02:02:56 2026 Received: from cstnet.cn (smtp21.cstnet.cn [159.226.251.21]) (using TLSv1.2 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 11D5437F8C3; Thu, 13 Aug 2026 16:05:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=159.226.251.21 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786637152; cv=none; b=dqL5AWRDNtcdo9NF3R1N6arbRZ1EI9H3FhY5/elrf97Y+ZWUCI7OIJwot8zkJ4PeXiGFQ+Pi5/81F3x2wWhKjgI+7Z6nS7zvSje7GSBC5j8U7kAnZscGorosTAabW/YW80c0kb6uJwiHODj3GnEBSGufj+sCEcQ6t7HI8iOyzkw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786637152; c=relaxed/simple; bh=tiR2SAWoFJgNdFTsPEU90nhOLXG6ibnAMGSGwfmNFAA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=pVQ6WxsmtBPIUiA41ys6tR82tC7NVKv6bc4XtsK06oJzI4NmMYs2pqIb5W7DN3SdqfLT4v+yVQtXOWcRMsZygN/RhBdFBZuPMICYNyGhXSv6uZ9IQpIZjmoi2CbQhmMZVPqPA8Dv18QNw6i/HWF+ielXdtGTxSippaLcZmG95F4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iscas.ac.cn; spf=pass smtp.mailfrom=iscas.ac.cn; arc=none smtp.client-ip=159.226.251.21 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iscas.ac.cn Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=iscas.ac.cn Received: from localhost.localdomain (unknown [111.196.241.250]) by APP-01 (Coremail) with SMTP id qwCowAAX7O9V631qIEh7BQ--.56475S2; Fri, 14 Aug 2026 00:05:41 +0800 (CST) From: Pengpeng Hou To: Lorenzo Pieralisi , Hanjun Guo Cc: Sudeep Holla , Catalin Marinas , Will Deacon , "Rafael J. Wysocki" , Len Brown , Robin Murphy , Shameer Kolothum , Joerg Roedel , linux-acpi@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Pengpeng Hou Subject: [PATCH v2 2/2] ACPI: IORT: validate RMR node array extents Date: Fri, 14 Aug 2026 00:05:40 +0800 Message-ID: <20260813160540.72395-1-pengpeng@iscas.ac.cn> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20260813160118.69153-1-pengpeng@iscas.ac.cn> References: <20260813160118.69153-1-pengpeng@iscas.ac.cn> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: qwCowAAX7O9V631qIEh7BQ--.56475S2 X-Coremail-Antispam: 1UD129KBjvJXoWxJw1UGF15uFWkZF4xGrW7urg_yoW5CFykpF 4DGry5Aws5JF12grWSv3Z5AFWYqw1kGrWakrZa93yqyFn0yrnIya109FyY9F15JFW8ua1x Krs8tFW7CF1DZrJanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUU9F14x267AKxVW8JVW5JwAFc2x0x2IEx4CE42xK8VAvwI8IcIk0 rVWrJVCq3wAFIxvE14AKwVWUJVWUGwA2ocxC64kIII0Yj41l84x0c7CEw4AK67xGY2AK02 1l84ACjcxK6xIIjxv20xvE14v26r4j6ryUM28EF7xvwVC0I7IYx2IY6xkF7I0E14v26F4j 6r4UJwA2z4x0Y4vEx4A2jsIE14v26r1j6r4UM28EF7xvwVC2z280aVCY1x0267AKxVW8JV W8Jr1le2I262IYc4CY6c8Ij28IcVAaY2xG8wAqx4xG64xvF2IEw4CE5I8CrVC2j2WlYx0E 2Ix0cI8IcVAFwI0_JF0_Jw1lYx0Ex4A2jsIE14v26r1j6r4UMcvjeVCFs4IE7xkEbVWUJV W8JwACjcxG0xvY0x0EwIxGrwACjI8F5VA0II8E6IAqYI8I648v4I1lFIxGxcIEc7CjxVA2 Y2ka0xkIwI1lc7CjxVAaw2AFwI0_Jw0_GFyl42xK82IYc2Ij64vIr41l4I8I3I0E4IkC6x 0Yz7v_Jr0_Gr1lx2IqxVAqx4xG67AKxVWUJVWUGwC20s026x8GjcxK67AKxVWUGVWUWwC2 zVAF1VAY17CE14v26r1q6r43MIIYrxkI7VAKI48JMIIF0xvE2Ix0cI8IcVAFwI0_Jr0_JF 4lIxAIcVC0I7IYx2IY6xkF7I0E14v26F4j6r4UJwCI42IY6xAIw20EY4v20xvaj40_Jr0_ JF4lIxAIcVC2z280aVAFwI0_Jr0_Gr1lIxAIcVC2z280aVCY1x0267AKxVW8JVW8JrUvcS sGvfC2KfnxnUUI43ZEXa7VUbtxhJUUUUU== X-CM-SenderInfo: pshqw1xhqjqxpvfd2hldfou0/ Content-Type: text/plain; charset="utf-8" IORT RMR nodes carry offsets and counts for reserved-memory descriptors and ID mappings. iort_node_get_rmr_info() trusts both arrays and later loops over the firmware counts without proving that either array fits in the containing node. Require the fixed RMR payload, then validate each non-empty array with checked multiplication and subtraction-based bounds before constructing an element pointer. Keep the helpers under CONFIG_IOMMU_API with their users. Fixes: 491cf4a6735a ("ACPI/IORT: Add support to retrieve IORT RMR reserved = regions") Assisted-by: Codex:gpt-5 Signed-off-by: Pengpeng Hou --- drivers/acpi/arm64/iort.c | 53 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index 101d54eec544..17d904f4c1ee 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -962,6 +963,48 @@ void acpi_configure_pmsi_domain(struct device *dev) } =20 #ifdef CONFIG_IOMMU_API +static bool iort_node_array_valid(struct acpi_iort_node *node, u32 offset, + u32 count, size_t elem_size, + size_t min_offset, const char *name) +{ + size_t bytes; + + /* An empty array has no elements to access, regardless of its offset. */ + if (!count) + return true; + + if (!offset || offset < min_offset || offset > node->length) { + pr_err(FW_BUG "Invalid %s offset in IORT node %p\n", name, + node); + return false; + } + + if (check_mul_overflow(count, elem_size, &bytes) || + bytes > node->length - offset) { + pr_err(FW_BUG "Invalid %s array in IORT node %p\n", name, + node); + return false; + } + + return true; +} + +static bool iort_rmr_node_valid(struct acpi_iort_node *node) +{ + struct acpi_iort_rmr *rmr; + + if (node->length < sizeof(*node) + sizeof(*rmr)) { + pr_err(FW_BUG "Truncated RMR node in IORT table\n"); + return false; + } + + rmr =3D (struct acpi_iort_rmr *)node->node_data; + return iort_node_array_valid(node, rmr->rmr_offset, rmr->rmr_count, + sizeof(struct acpi_iort_rmr_desc), + sizeof(*node) + sizeof(*rmr), + "RMR descriptor"); +} + static void iort_rmr_free(struct device *dev, struct iommu_resv_region *region) { @@ -1152,12 +1195,22 @@ static void iort_node_get_rmr_info(struct acpi_iort= _node *node, u32 num_sids =3D 0; int i; =20 + if (!iort_rmr_node_valid(node)) + return; + if (!node->mapping_offset || !node->mapping_count) { pr_err(FW_BUG "Invalid ID mapping, skipping RMR node %p\n", node); return; } =20 + if (!iort_node_array_valid(node, node->mapping_offset, + node->mapping_count, + sizeof(struct acpi_iort_id_mapping), + sizeof(*node) + sizeof(*rmr), + "ID mapping")) + return; + rmr =3D (struct acpi_iort_rmr *)node->node_data; if (!rmr->rmr_offset || !rmr->rmr_count) return; --=20 2.50.1 (Apple Git-155)