[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