[PATCH v2 1/3] ACPI: RIMT: validate table and node extents before traversal

Pengpeng Hou pengpeng at iscas.ac.cn
Thu Aug 13 08:41:23 PDT 2026


RIMT walkers construct the first node from a firmware-provided offset and
advance by each node length.  Checking only whether the current pointer
reached the table end still permits a bad root offset, a truncated node
header, or a zero or oversized node length to be read.

Validate the root node area before constructing the first pointer.  Bound
traversal by num_nodes and require every complete node to fit in the table.

Fixes: 8f7729552582 ("ACPI: RISC-V: Add support for RIMT")
Assisted-by: Codex:gpt-5
Signed-off-by: Pengpeng Hou <pengpeng at iscas.ac.cn>
---
 drivers/acpi/riscv/rimt.c | 53 ++++++++++++++++++++++++++++++++++++---
 1 file changed, 50 insertions(+), 3 deletions(-)

diff --git a/drivers/acpi/riscv/rimt.c b/drivers/acpi/riscv/rimt.c
index e4538fa6c2c8..533e9aba6e97 100644
--- a/drivers/acpi/riscv/rimt.c
+++ b/drivers/acpi/riscv/rimt.c
@@ -31,6 +31,45 @@ static DEFINE_SPINLOCK(rimt_fwnode_lock);
 /* Root pointer to the mapped RIMT table */
 static struct acpi_table_header *rimt_table;
 
+static bool rimt_table_valid(void)
+{
+	struct acpi_table_rimt *rimt = (struct acpi_table_rimt *)rimt_table;
+	size_t node_bytes;
+
+	if (!rimt || rimt->header.length < sizeof(*rimt))
+		return false;
+
+	if (!rimt->num_nodes)
+		return true;
+
+	if (rimt->node_offset < sizeof(*rimt) ||
+	    rimt->node_offset > rimt->header.length -
+				 sizeof(struct acpi_rimt_node))
+		return false;
+
+	node_bytes = rimt->header.length - rimt->node_offset;
+	return rimt->num_nodes <=
+		node_bytes / sizeof(struct acpi_rimt_node);
+}
+
+static bool rimt_node_valid(struct acpi_rimt_node *node,
+			    struct acpi_rimt_node *end)
+{
+	size_t remaining;
+
+	if ((u8 *)node >= (u8 *)end)
+		return false;
+
+	remaining = (u8 *)end - (u8 *)node;
+	if (remaining < sizeof(*node) || node->length < sizeof(*node) ||
+	    node->length > remaining) {
+		pr_err(FW_BUG "Invalid RIMT node length\n");
+		return false;
+	}
+
+	return true;
+}
+
 /**
  * rimt_set_fwnode() - Create rimt_fwnode and use it to register
  *		       iommu data in the rimt_fwnode_list
@@ -153,19 +192,21 @@ static struct acpi_rimt_node *rimt_scan_node(enum acpi_rimt_node_type type,
 	struct acpi_table_rimt *rimt;
 	int i;
 
-	if (!rimt_table)
+	if (!rimt_table_valid())
 		return NULL;
 
 	/* Get the first RIMT node */
 	rimt = (struct acpi_table_rimt *)rimt_table;
+	if (!rimt->num_nodes)
+		return NULL;
+
 	rimt_node = ACPI_ADD_PTR(struct acpi_rimt_node, rimt,
 				 rimt->node_offset);
 	rimt_end = ACPI_ADD_PTR(struct acpi_rimt_node, rimt_table,
 				rimt_table->length);
 
 	for (i = 0; i < rimt->num_nodes; i++) {
-		if (WARN_TAINT(rimt_node >= rimt_end, TAINT_FIRMWARE_WORKAROUND,
-			       "RIMT node pointer overflows, bad table!\n"))
+		if (!rimt_node_valid(rimt_node, rimt_end))
 			return NULL;
 
 		if (rimt_node->type == type &&
@@ -525,4 +566,10 @@ void __init riscv_acpi_rimt_init(void)
 
 		return;
 	}
+
+	if (!rimt_table_valid()) {
+		pr_err(FW_BUG "Invalid RIMT table layout\n");
+		acpi_put_table(rimt_table);
+		rimt_table = NULL;
+	}
 }
-- 
2.50.1 (Apple Git-155)




More information about the linux-riscv mailing list