Proximity-domain association compares only ProximityDomainLo (ignores ProximityDomainHi and x2APIC entries): NUMA domains >= 256 silently dropped or organized under the wrong socket
Summary
The memory-to-CPU association compares a u32 domain against the CPU entry's single Lo byte, ignoring Hi[3] and never handling Type-2 x2APIC entries: domains >=256 never match ('not found', ranges silently ignored) or collide with an unrelated socket's low byte (pages queued under the wrong NUMA domain). Downstream bounded - correctness/silent-NUMA-misdirection gap, no memory safety. full-domain-compare + x2APIC case fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-5651 Β· 2 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | file | 1.9 KB | β raw | |
| verdict.json | file | 2.4 KB | view raw |
DF-5651 β SRAT proximity-domain association compares only the low byte (ProximityDomainLo), ignoring ProximityDomainHi and x2APIC entries
What
sys/platform/pc64/acpica/acpi_srat.c:112-113 and :124-125 associate a
MEMORY affinity entry with a CPU affinity entry by comparing the memory
entry's full 32-bit ProximityDomain (packed u32@+2) against the CPU
entry's one-byte ProximityDomainLo (packed u8@+2):
if (cpu == NULL ||
mem->mem.ProximityDomain != cpu->cpu.ProximityDomainLo) { /* :113 */
The rev-1 CPU entry's upper three domain bytes (ProximityDomainHi[3],
actbl3.h:377, packed @+9) are never consulted, and rev-2+ x2APIC CPU
entries (ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY, Type 2, 32-bit domain +
32-bit APIC ID) are not handled at all (:118-120 dispatches only
Type 0).
Effect (correctness/perf, no memory-safety impact)
- Any proximity domain >= 256 can never match a rev-1 CPU entry whose low
byte happens to differ β the range prints "(not found)"
(acpi_srat.c:140) and
vm_numa_organize()is never called for it. - Worse, a domain like 0x0100 collides with Lo=0x00 of an unrelated socket β memory is organized under the wrong chip's page-color domain (vm_page.c:546-547), cross-node memory placement for the machine's life.
- On systems whose firmware only emits x2APIC CPU entries (legal since ACPI 4.0, required for APIC IDs > 255), no CPU entry ever matches and no SRAT memory range is ever organized β the NUMA code silently no-ops.
No memory corruption, leak, or privilege boundary is crossed: physid
derived from the matched ApicId (u8) is bounded (mod
cpu_topology_phys_ids, vm_page.c:547). Filed as Info (correctness gap /
silent NUMA misdirection), untested on hardware that exposes it.
Suggested fix
Compare the CPU entry's full 20-bit domain
(ProximityDomainHi[3]<<8 | ProximityDomainLo) against
mem->mem.ProximityDomain, and handle Type-2 x2APIC entries' 32-bit
domain/APIC ID.
Fix verification
not_testableInfo-severity correctness gap; no fix build warranted (single-socket QEMU rig has cpu_topology_phys_ids==1 so vm_numa_organize is a no-op and misdirection is unobservable).
Confirmed kernel references
Detail
Evidence (decisive lines)
README.md cites acpi_srat.c:112-113,124-125 (Lo-only compare), :118-120 (Type-0-only dispatch), actbl3.h:377 (ProximityDomainHi), vm_page.c:534-547 (bounded downstream use).
PoC changes
No PoC authored (Info; single-socket rig cannot manifest NUMA misdirection).
Verified recommended fix
Compare full 20-bit domain (Hi[3]<<8|Lo) and handle ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY entries' 32-bit domain and APIC ID.
Verdict
Static-analysis finding (Info severity, no security impact): the memory-to-CPU affinity association compares the 32-bit memory ProximityDomain against the CPU entry's single ProximityDomainLo byte (acpi_srat.c:113,124-125), ignoring ProximityDomainHi[3] (actbl3.h:377) and the Type-2 x2APIC entries entirely (:118-120). Domains >= 256 either never match (range dropped, '(not found)', vm_numa_organize never called) or collide with an unrelated socket's low byte (pages organized under the wrong NUMA domain, vm_page.c:546-547). Downstream values are bounded (ApicId u8, physid mod cpu_topology_phys_ids), so this is a correctness/silent-NUMA-misdirection gap, not memory corruption. Not verified on the guest: the QEMU rig is single-socket (cpu_topology_phys_ids == 1, vm_numa_organize early-returns at vm_page.c:534) so no observable NUMA placement exists to misdirect.
No comments yet.