DF-5649 / fix.diff
--- a/sys/platform/pc64/acpica/acpi_srat.c +++ b/sys/platform/pc64/acpica/acpi_srat.c @@ -88,16 +88,37 @@ goto done; } + /* + * Validate every subtable entry before touching any field beyond + * the two-byte ACPI_SUBTABLE_HEADER, mirroring + * madt_iterate_entries() (acpi_madt.c). The entry Type/Length are + * firmware-supplied: Length == 0 wedges the walk in an infinite + * loop, and an entry extending past the table end makes the parser + * read beyond the mapped table. + */ cpu = NULL; for (mem = (srat_entry_t *)(srat + 1); - (char *)mem < (char *)srat + srat->Header.Length; + (char *)mem + sizeof(mem->head) <= + (char *)srat + srat->Header.Length; mem = (srat_entry_t *)((char *)mem + mem->head.Length)) { + if (mem->head.Length < sizeof(mem->head) || + (char *)mem + mem->head.Length > + (char *)srat + srat->Header.Length) { + kprintf("srat_probe: invalid SRAT entry len %u\n", + mem->head.Length); + break; + } /* * Mem scan memory affinity only */ if (mem->head.Type != ACPI_SRAT_TYPE_MEMORY_AFFINITY) continue; + if (mem->head.Length < sizeof(mem->mem)) { + kprintf("srat_probe: truncated memory affinity " + "entry len %u\n", mem->head.Length); + continue; + } if ((mem->mem.Flags & ACPI_SRAT_MEM_ENABLED) == 0) continue; @@ -111,13 +132,21 @@ */ if (cpu == NULL || mem->mem.ProximityDomain != cpu->cpu.ProximityDomainLo) { + cpu = NULL; for (cpu = (srat_entry_t *)(srat + 1); - (char *)cpu < (char *)srat + srat->Header.Length; + (char *)cpu + sizeof(cpu->head) <= + (char *)srat + srat->Header.Length; cpu = (srat_entry_t *)((char *)cpu + cpu->head.Length)) { + if (cpu->head.Length < sizeof(cpu->head) || + (char *)cpu + cpu->head.Length > + (char *)srat + srat->Header.Length) + break; if (cpu->head.Type != ACPI_SRAT_TYPE_CPU_AFFINITY) continue; + if (cpu->head.Length < sizeof(cpu->cpu)) + break; if ((cpu->cpu.Flags & ACPI_SRAT_CPU_USE_AFFINITY) == 0) continue; |