Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MmAllocateContiguousMemory inconsistencies #3

Open
daniel-dron opened this issue May 25, 2023 · 1 comment
Open

MmAllocateContiguousMemory inconsistencies #3

daniel-dron opened this issue May 25, 2023 · 1 comment

Comments

@daniel-dron
Copy link

daniel-dron commented May 25, 2023

When allocating 2 MB of memory of the large page using MmAllocateContiguousMemory there's a few things that might go wrong:

  1. The base physical address is not aligned to 2MB
  2. The returned virtual address is not part of a large page

I confirmed both this statements on windows 10 22h2:

  1.  constexpr auto pg_align { 0x200000 };
     void* pg = MmAllocateContiguousMemory(
         0x200000,
         { .QuadPart = static_cast< LONGLONG >( MAXUINT64 ) }
     );
    
     if ( pg && ( reinterpret_cast< uintptr_t >( pg ) & ( pg_align - 1 ) ) ==
         0 )
         LOG( "aligned virtual address: %p", pg );
     else
         LOG( "unaligned virtual address: %p (%p)", pg );
    
     if ( const auto pg_phys { MmGetPhysicalAddress( pg ).QuadPart };
         pg_phys && ( ( pg_phys ) & ( pg_align - 1 ) ) == 0 )
         LOG( "aligned physical address: %p\n", pg_phys );
     else
         LOG( "unaligned physical address: %p\n", pg_phys );
    

The result looks like the following:
aligned virtual address: FFFFA478F8E00000 unaligned physical address: 0000000285044000

While this is not a direct problem to our case, it's still might be usefull to know that windows also aknowledges this problem.

    kd> !vtop 0x001ad000 0xFFFFA478F8E00000
    Amd64VtoP: Virt ffffa478f8e00000, pagedir 00000000001ad000
    Amd64VtoP: PML4E 00000000001ada40
    Amd64VtoP: PDPE 000000000ef36f18
    Amd64VtoP: PDE 0000000007330e38
    Amd64VtoP: PTE 00000001a05e8000
    Amd64VtoP: Mapped phys 0000000285044000
    Virtual address ffffa478f8e00000 translates to physical address 285044000.

As you can see, it is not actually a large page even tho we allocated 2MB


From point 1 we can see the physical address is not aligned to 2MB. Why is this a problem?
When constructing the PD entry for a large page, the pfn is the physical address shifted >> 21. If the physical address is not aligned to 2MB this will clear a few bits. Thus, this pfn no longer represents the original physical address, but now represents a physical address that is lower than the original.

This will result in a VA mapping where the base address is actually mapping a physical address that was not originally encompassed in the pages returned by the call to MmAllocateContiguousMemory

To visualize this I made this quick graph:

Can you confirm that this MmAllocateContiguousMemory behaviour also happens on your vms and local machine? According to windows internals, allocating 2MB of contiguous memory should yield an allocation that is aligned to 2mb boundaries, yet in practice that doesn't look like it's the case here.

This might be a problem if windows allocates a page that encompasses that little rogue region that we mapped in the new PD. That means that it may be modified in the future without our permission.

@Xyrem
Copy link
Owner

Xyrem commented May 30, 2023

Hey dude, apologies for the late reply; was out all week.
I've just tested on a machine with Windows 11 22H2, and everything seems aligned. However, on my VM which runs on Win 10 22H2 it seems that the physical address is not aligned... Though my VM runs on 4GB ram, I think this issue could be related to the amount of RAM available to the system. I'll look into it later when I am available, though if you do create a fix for it; a PR would be welcome :)

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

No branches or pull requests

2 participants