XTLDR exposes PML table memory to the kernel as LoaderFree #25
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
There is a critical memory management bug in the XTLDR. When the bootloader constructs the page tables and enables paging before handing off control to the kernel, it fails to explicitly reserve the physical frame containing the top-level PML table. As a result, the physical address residing in the CR3 register is passed to the kernel as LoaderFree (Type 2). When the kernel's memory manager begins allocating memory and zeroes out a newly requested page via RTL::Memory::ZeroMemory, it inadvertently overwrites the active PML table. This instantly destroys the entire virtual memory address space, leading to a system freeze and subsequent Double/Triple Faults due to the CPU being unable to read the IDT or stack.
Problem analysis:
The active CR3 register points to physical address 0x7CE0D000:
A physical memory dump of this exact address confirms the PML4 has been completely zeroed out:
Code analysis:
The
Xtos::RunBootSequencefunction in the xtos_o module, exhibits an architectural flaw:At the time
InitializeLoaderBlockis executed, the memory for the PML4 table has not yet been reserved, which is why XTLDR marks it as free. To diagnose the issue, I added custom diagnostic code to theXtos::GetMemoryDescriptorListfunction:With these additional logs, I was able to analyze the memory map being passed to the kernel and noticed that the address used by the PML4 table is explicitly marked as LoaderFree:
The physical address of the PML4 table from the CR3 register is 0x7CE0D000. Dividing this by the page size (4096 bytes) gives us the PFN: 0x7CE0D000 / 4096 = 0x7CE0D. Mathematically, this frame (our PML4) falls within the bounds of descriptor 14, i.e.,
0x7BFFC < 0x7CE0D < 0x7CE0E. Consequently, the kernel assumes it has every right to overwrite this area.In contrast, a log read from inside
XtLdrProtocol->Memory.BuildPageMapshows what the bootloader does a fraction of a second later:To expose this bug, I had to force XTLDR to log mappings that do not have a virtual address set. It then becomes apparent that at this stage, the bootloader finally reserves frames from the free pool and marks them as Type=20 (LoaderMemoryData), subsequently building the paging tree within them. However, this updated data never makes it to the kernel.
I need to vent about how unbelievably fucked up the xtos_o module is right now. It is an absolute clusterfuck of bad memory management architecture and desperately needs a complete rewrite from the ground up.
21b3b269a7