mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-28 19:14:35 -04:00
ACPI: processor: validate MADT IOAPIC entry bounds
The IOAPIC hotplug lookup parses both MADT and _MAT records directly.
The MADT walk previously used a subtable's declared length to advance
the cursor after only locating a generic header. The _MAT path likewise
passed a generic header to the IOAPIC helper.
Validate that a current record has a complete generic header, that its
declared length is contained in the available record range, and that a
typed IOAPIC record contains the full fixed IOAPIC body before reading
its fields. Use the same relation for both MADT and _MAT provider
paths.
Fixes: ecf5636dcd ("ACPI: Add interfaces to parse IOAPIC ID for IOAPIC hotplug")
Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
Link: https://patch.msgid.link/20260715083253.22831-1-pengpeng@iscas.ac.cn
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
committed by
Rafael J. Wysocki
parent
1590cf0329
commit
2c50ffdc73
@@ -336,11 +336,26 @@ int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id)
|
||||
EXPORT_SYMBOL_GPL(acpi_get_cpuid);
|
||||
|
||||
#ifdef CONFIG_ACPI_HOTPLUG_IOAPIC
|
||||
static int get_ioapic_id(struct acpi_subtable_header *entry, u32 gsi_base,
|
||||
static bool madt_entry_is_valid(struct acpi_subtable_header *entry,
|
||||
unsigned long end)
|
||||
{
|
||||
unsigned long start = (unsigned long)entry;
|
||||
|
||||
if (start >= end || end - start < sizeof(*entry))
|
||||
return false;
|
||||
|
||||
return entry->length >= sizeof(*entry) && entry->length <= end - start;
|
||||
}
|
||||
|
||||
static int get_ioapic_id(struct acpi_subtable_header *entry,
|
||||
const unsigned long end, u32 gsi_base,
|
||||
u64 *phys_addr, int *ioapic_id)
|
||||
{
|
||||
struct acpi_madt_io_apic *ioapic = (struct acpi_madt_io_apic *)entry;
|
||||
|
||||
if (!madt_entry_is_valid(entry, end) || BAD_MADT_ENTRY(ioapic, end))
|
||||
return 0;
|
||||
|
||||
if (ioapic->global_irq_base != gsi_base)
|
||||
return 0;
|
||||
|
||||
@@ -361,17 +376,19 @@ static int parse_madt_ioapic_entry(u32 gsi_base, u64 *phys_addr)
|
||||
return apic_id;
|
||||
|
||||
entry = (unsigned long)madt;
|
||||
if (madt->header.length < sizeof(*madt))
|
||||
return apic_id;
|
||||
madt_end = entry + madt->header.length;
|
||||
|
||||
/* Parse all entries looking for a match. */
|
||||
entry += sizeof(struct acpi_table_madt);
|
||||
while (entry + sizeof(struct acpi_subtable_header) < madt_end) {
|
||||
while (madt_entry_is_valid((struct acpi_subtable_header *)entry,
|
||||
madt_end)) {
|
||||
hdr = (struct acpi_subtable_header *)entry;
|
||||
if (hdr->type == ACPI_MADT_TYPE_IO_APIC &&
|
||||
get_ioapic_id(hdr, gsi_base, phys_addr, &apic_id))
|
||||
get_ioapic_id(hdr, madt_end, gsi_base, phys_addr, &apic_id))
|
||||
break;
|
||||
else
|
||||
entry += hdr->length;
|
||||
entry += hdr->length;
|
||||
}
|
||||
|
||||
return apic_id;
|
||||
@@ -398,7 +415,9 @@ static int parse_mat_ioapic_entry(acpi_handle handle, u32 gsi_base,
|
||||
|
||||
header = (struct acpi_subtable_header *)obj->buffer.pointer;
|
||||
if (header->type == ACPI_MADT_TYPE_IO_APIC)
|
||||
get_ioapic_id(header, gsi_base, phys_addr, &apic_id);
|
||||
get_ioapic_id(header,
|
||||
(unsigned long)header + obj->buffer.length,
|
||||
gsi_base, phys_addr, &apic_id);
|
||||
|
||||
exit:
|
||||
kfree(buffer.pointer);
|
||||
|
||||
Reference in New Issue
Block a user