[PATCH] ACPI: processor: validate CPU mapping entries

From: Jiale Yao

Date: Fri Oct 16 2026 - 10:27:00 EST


CPU physical ID lookup walks MADT subtables directly and also accepts
records returned by _MAT. Both paths can pass a truncated typed record
to a CPU-specific mapper, and the MADT walker can be stalled or moved
outside the table by an invalid length.

Validate generic record bounds and the minimum size required by each
supported CPU record before dispatching it on both provider paths.

Signed-off-by: Jiale Yao <yaojiale02@xxxxxxx>
---
drivers/acpi/processor_core.c | 48 ++++++++++++++++++++++++++++++++++-
1 file changed, 47 insertions(+), 1 deletion(-)

diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index 3bf076c150fa..4d5ff53f27ab 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -157,6 +157,47 @@ static int map_core_pic_id(struct acpi_subtable_header *entry,
return -EINVAL;
}

+static bool madt_cpu_entry_is_valid(struct acpi_subtable_header *entry,
+ unsigned long end)
+{
+ unsigned long start = (unsigned long)entry;
+ size_t length, min_length;
+
+ if (start >= end || end - start < sizeof(*entry))
+ return false;
+
+ length = entry->length;
+ if (length < sizeof(*entry) || length > end - start)
+ return false;
+
+ switch (entry->type) {
+ case ACPI_MADT_TYPE_LOCAL_APIC:
+ min_length = sizeof(struct acpi_madt_local_apic);
+ break;
+ case ACPI_MADT_TYPE_LOCAL_X2APIC:
+ min_length = sizeof(struct acpi_madt_local_x2apic);
+ break;
+ case ACPI_MADT_TYPE_LOCAL_SAPIC:
+ min_length = sizeof(struct acpi_madt_local_sapic);
+ break;
+ case ACPI_MADT_TYPE_GENERIC_INTERRUPT:
+ min_length = offsetofend(struct acpi_madt_generic_interrupt,
+ arm_mpidr);
+ break;
+ case ACPI_MADT_TYPE_RINTC:
+ min_length = offsetofend(struct acpi_madt_rintc, uid);
+ break;
+ case ACPI_MADT_TYPE_CORE_PIC:
+ min_length = sizeof(struct acpi_madt_core_pic);
+ break;
+ default:
+ min_length = sizeof(*entry);
+ break;
+ }
+
+ return length >= min_length;
+}
+
static phys_cpuid_t map_madt_entry(struct acpi_table_madt *madt,
int type, u32 acpi_id)
{
@@ -172,7 +213,8 @@ static phys_cpuid_t map_madt_entry(struct acpi_table_madt *madt,
/* Parse all entries looking for a match. */

entry += sizeof(struct acpi_table_madt);
- while (entry + sizeof(struct acpi_subtable_header) < madt_end) {
+ while (madt_cpu_entry_is_valid((struct acpi_subtable_header *)entry,
+ madt_end)) {
struct acpi_subtable_header *header =
(struct acpi_subtable_header *)entry;
if (header->type == ACPI_MADT_TYPE_LOCAL_APIC) {
@@ -251,6 +293,10 @@ static phys_cpuid_t map_mat_entry(acpi_handle handle, int type, u32 acpi_id)
}

header = (struct acpi_subtable_header *)obj->buffer.pointer;
+ if (!madt_cpu_entry_is_valid(header,
+ (unsigned long)header + obj->buffer.length))
+ goto exit;
+
if (header->type == ACPI_MADT_TYPE_LOCAL_APIC)
map_lapic_id(header, acpi_id, &phys_id);
else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC)
--
2.34.1