[PATCH v2 2/2] ACPI: IORT: validate RMR node array extents
Pengpeng Hou
pengpeng at iscas.ac.cn
Thu Aug 13 09:05:40 PDT 2026
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 <pengpeng at iscas.ac.cn>
---
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 <linux/iommu.h>
#include <linux/kernel.h>
#include <linux/list.h>
+#include <linux/overflow.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -962,6 +963,48 @@ void acpi_configure_pmsi_domain(struct device *dev)
}
#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 = (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 = 0;
int i;
+ 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;
}
+ 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 = (struct acpi_iort_rmr *)node->node_data;
if (!rmr->rmr_offset || !rmr->rmr_count)
return;
--
2.50.1 (Apple Git-155)
More information about the linux-arm-kernel
mailing list