Skip to content

Add LA57 (5-level paging) support for Linux & Windows Intel layers#1991

Open
ricardojrdez wants to merge 4 commits into
volatilityfoundation:developfrom
ricardojrdez:feature/la57-paging
Open

Add LA57 (5-level paging) support for Linux & Windows Intel layers#1991
ricardojrdez wants to merge 4 commits into
volatilityfoundation:developfrom
ricardojrdez:feature/la57-paging

Conversation

@ricardojrdez

Copy link
Copy Markdown

Five-level paging (LA57) widens the linear address space to 57 bits by adding a fifth page map level (PML5). The existing Intel32e layer is hardwired to 48-bit virtual addresses and a 4-entry page-table walk, so on LA57 images the 48-bit address_mask truncates canonical kernel pointers and the page walk treats the PML5 as a PML4. The visible symptom is that physical scanning (psscan) works while virtual list-following (pslist, check_syscall, ...) silently returns nothing.

Add Intel32e_LA57 with _maxvirtaddr=57 and a 5-entry _structure; all derived values (maximum_address, address_mask, canonicalization, translation walk) follow from those two constants. Add the matching WindowsIntel32e_LA57 (transition-PFN workaround) and LinuxIntel32e_LA57 (_maxphyaddr=52, as 5-level kernels always use a 52-bit physical mask).

Detect LA57 at runtime in the Linux automagic: read __pgtable_l5_enabled from the physical layer in the banner stacker, and use NUMBER(pgtable_l5_enabled) in the VMCOREINFO stacker. Detection is runtime, not build-time, since a CONFIG_X86_5LEVEL kernel still boots in 4-level mode on non-LA57 hardware.

Add synthetic-page-table unit tests in test/layers/test_intel.py covering the 5-level walk (4K/2M/1G), 57-bit canonicalization, the pointer-masking regression, and the Windows/Linux entry variants.

Validated against a real LA57 LiME capture (Ubuntu 24.04, 6.8.0-117, Diamorphine rootkit): pslist now lists processes, hidden_modules reveals the rootkit and check_syscall recovers the hijacked entries.

Ricardo J. Rodríguez and others added 4 commits June 7, 2026 19:19
Five-level paging (LA57) widens the linear address space to 57 bits by
adding a fifth page map level (PML5). The existing Intel32e layer is
hardwired to 48-bit virtual addresses and a 4-entry page-table walk, so
on LA57 images the 48-bit address_mask truncates canonical kernel
pointers and the page walk treats the PML5 as a PML4. The visible symptom
is that physical scanning (psscan) works while virtual list-following
(pslist, check_syscall, ...) silently returns nothing.

Add Intel32e_LA57 with _maxvirtaddr=57 and a 5-entry _structure; all
derived values (maximum_address, address_mask, canonicalization,
translation walk) follow from those two constants. Add the matching
WindowsIntel32e_LA57 (transition-PFN workaround) and LinuxIntel32e_LA57
(_maxphyaddr=52, as 5-level kernels always use a 52-bit physical mask).

Detect LA57 at runtime in the Linux automagic: read __pgtable_l5_enabled
from the physical layer in the banner stacker, and use
NUMBER(pgtable_l5_enabled) in the VMCOREINFO stacker. Detection is
runtime, not build-time, since a CONFIG_X86_5LEVEL kernel still boots in
4-level mode on non-LA57 hardware.

Add synthetic-page-table unit tests in test/layers/test_intel.py
covering the 5-level walk (4K/2M/1G), 57-bit canonicalization, the
pointer-masking regression, and the Windows/Linux entry variants.

Validated against a real LA57 LiME capture (Ubuntu 24.04, 6.8.0-117,
Diamorphine rootkit): pslist now lists processes, hidden_modules reveals
the rootkit and check_syscall recovers the hijacked entries.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add WindowsIntel32e_LA57 selection to the Windows automagic. A
self-referential PML5 is indistinguishable from a PML4 during the DTB
scan, so the 64-bit choice is refined by reading CR4 from the x64 Low
Stub (_PROCESSOR_START_BLOCK->...->SpecialRegisters->Cr4): bit 12 (LA57)
is the authoritative runtime indicator of 5-level paging. The new
_la57_from_low_stub helper validates the stub's CR3 against the
discovered DTB before trusting its CR4, and returns None when no Low
Stub is present so 4-level behaviour is unchanged.

Replace hardwired 48-bit constants that broke on LA57:
- pdbscan: optimized scan start derived from _maxvirtaddr
  (0x1F0 << (maxvirtaddr - 9)); kernel hint/base masked with
  vlayer.address_mask instead of 0xFFFFFFFFFFFF.
- modules.get_kernel_space_start: the 64-bit MmSystemRangeStart fallback
  default is derived from the layer (0xFFFF800000000000 for 4-level,
  0xFF00000000000000 for LA57) instead of being hardcoded.

Add new CR4 Low Stub constants and synthetic-stub unit tests in
test/automagic/test_windows.py.

Note: detection still relies on the Low Stub, which is absent on some
virtualized snapshots; a probe-based fallback for that case is left for
a follow-up (no Windows LA57 image was available to validate it).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
With 5-level paging now supported, resolve the FIXME in
_intel_vmemmap_start: for the !CONFIG_DYNAMIC_MEMORY_LAYOUT SPARSEMEM
case, use __VMEMMAP_BASE_L5 (0xFFD4000000000000) when the layer is LA57
instead of raising "5-level paging is not yet supported".

KASLR kernels (>= 4.9) keep using the vmemmap_base symbol, so this
branch only affects non-KASLR 5-level kernels. The surrounding page ->
physical machinery (canonicalize + page objects) was validated on a real
LA57 capture via linux.pagecache.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Build a synthetic Windows physical image with a self-referential x64 DTB
and an x64 Low Stub, then drive the real WindowsIntelStacker.stack() to
confirm it selects WindowsIntel32e_LA57 iff CR4.LA57 is set, and falls
back to WindowsIntel32e when the bit is clear or no Low Stub is present.

This exercises the self-referential scan path plus the CR4 refinement
end-to-end, complementing the existing _la57_from_low_stub unit tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@ikelos

ikelos commented Jun 7, 2026

Copy link
Copy Markdown
Member

#1939 might also be related. My concern is that it only supports linux at the moment, and it will need carefully checking to ensure it's extensible enough to support Windows if/when windows eventually moves to 5-level paging.

@ricardojrdez

ricardojrdez commented Jun 8, 2026

Copy link
Copy Markdown
Author

I've already extended to Windows in a related commit. For testing I used a synthetic dump as Windows is not yet supporting LA57

@ricardojrdez ricardojrdez reopened this Jun 8, 2026
@ricardojrdez ricardojrdez changed the title Add LA57 (5-level paging) support for Linux Intel layers Add LA57 (5-level paging) support for Linuz & Windows Intel layers Jun 8, 2026
@ricardojrdez ricardojrdez changed the title Add LA57 (5-level paging) support for Linuz & Windows Intel layers Add LA57 (5-level paging) support for Linux & Windows Intel layers Jun 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants