MmProbeAndLockPages question...

Hello,

I am observing a behaviour where MmProbeAndLockPages is changing the virtual -> physical mapping of an already resident memory page. I am wondering if this is expected and why does it need to do that?

This is causing me an issue in following scenario

  1. I patch a read-only page (backed by a .sys file) by taking a writable reference to it using MmMapIoSpace.
  2. I lock the page using MmProbeAndLockPages function.
  3. At this point the virtual->physical mapping of the page that I patched changes.
  4. I unpatch the modification done in (1) using the same writable reference. However, this restore happens on a completely different page since MmProbeAndLockPages has changed the mapping underneath.
  5. I tried taking the writable reference twice (once during patch and once during the unpatch) and that solved this specific issue.
  6. However, next time, the same page is loaded, it contains my patch since the restore had happened on a completely different page. It looks to me that the original page where I patched is still on standby list and is soft faulted in subsequently.

Can experts on the list shade some light on this observed behaviour?

Thanks.
-Prasad

I think the actual problem here lies with MmMapIoSpace(), rather than MmProbeAndLockPages().

The thing is, the term “resident” is, probably, a bit of a misnomer here, because, IIRC, the only thing MmMapIoSpace() does is updating the PTE, without doing anything in relation to the structures that deal with PFN database.This is why it is named this way - this function allows you to map just anything, including non-RAM ranges like device BARs ( as well as the reserved and even non - existent ranges), to the kernel virtual address.

Once MM page-related structures are not updated by MmMapIoSpace(), MM does not really think of your target page as of resident one, which explains the behavior that you observe when calling MmProbeAndLockPages()…

Anton Bassov

Thanks Anton for the quick response!

However, I am calling MmProbeAndLockPages on the original address. AFAIK, MmMapIoSpace is just creating an alias PTE entry (with write bit enabled) pointing to the same page right?

There is another behaviour that I am confused about. I thought that the address returned by MmGetPhysicalAddress should match with the address returned by the !pte command on the same virtual address. However, I see that, they don’t match?

Here is the relevant windbg output with my comments

Below is the virtual address (0x9e152a2e) that I am patching. As you can see this is a read only PTE and hence I cannot write to it from this virtual address.

1: kd> !pte 0x9e152a2e
VA 9e152a2e
PDE at C0602780 PTE at C04F0A90
contains 000000002B2CA863 contains 000000007CF41121
pfn 2b2ca —DA–KWEV pfn 7cf41 -G–A–KREV

This is an alias address (0x9c526a2e) that I took using MmMapIoSpace. As you can see that this is a writable PTE entry and hence I can patch through this virtual address. Both are pointing to same PFN #7cf41

1: kd> !pte 0x9c526a2e
VA 9c526a2e
PDE at C0602710 PTE at C04E2930
contains 0000000024DAC863 contains 000000007CF41963
pfn 24dac —DA–KWEV pfn 7cf41 -G-DA–KWEV

After patching, I see that the PTE entries are still pointing to the same page.

I called MmGetPhysicalAddress on the original virtual address (0x9e152a2e) and it reported me 7cf8b000. This address did not match with the PFN reported by !pte. After that I call MmProbeAndLockPages and then again call MmGetPhysicalAddress on the same virtual address and it reports me a different physical address 7cf3f000.

Thanks.
-Prasad

> 1. I patch a read-only page (backed by a .sys file) by taking a writable reference to it using

MmMapIoSpace.
2. I lock the page using MmProbeAndLockPages function.

Strange sequence.

MmMapIoSpace wants a physical address. From where do you obtain it?

The correct sequence should be:

MmProbeAndLockPages
look at physical address in the MDL tail
MmMapIoSpace


Maxim S. Shatskih
Microsoft MVP on File System And Storage
xxxxx@storagecraft.com
http://www.storagecraft.com

I am calling MmGetPhysicalAddress on the original readonly virtual address and then getting a writable virtual address to it using MmMapIoSpace. Agreed that I should probably be calling MmProbeAndLockPages before calling MmGetPhysicalAddress. However, for my experiment, I know that my virtual address is mapped and resident.

I have two mysteries at the moment.

  1. The PFN returned by !pte VA is not matching with MmGetPhysicalAddress(VA).
  2. After calling MmProbeAndLockPages, MmGetPhysicalAddress(VA) returns a different value while !pte VA continues to show the same value.

Thanks.
-Prasad

> I am calling MmGetPhysicalAddress on the original readonly virtual address …

…which does not give you an ownership of the target physical page…

… and then getting a writable virtual address to it using MmMapIoSpace.

…which means that the target physical page may get re-purposed meanwhile. Certainly, the address that you get with MmMapIoSpace(0 is going to be valid until you unmap it, so that you are guaranteed to be using the same physical page. However, its actual application may change meanwhile, because you don’t own it, at least as far as MM is concerned. Judging from your description, this is exactly what is happening - there is nothing particularly “mysterious” here.

As Max pointed out already, you have to call MmProbeAndLockPages() in order to get the ownership of the physical pages that correspond to a given virtual address/range. If you do it this way they will become “immutable” in a sense that they don’t get re-purposed until you call MmUnlockPages(). At this point you are already in a position to safely map and modify the target pages

Anton Bassov

Thanks Anton and Max for the clarification! Yes, I understand now that I need to call MmProbeAndLock before calling MmGetPhysicalAddress/MmMapIoSpace.

However, I don’t see, how it helps understand the two potential mysteries that I raised in my earlier post.

I know, that, in my example, the page is not getting repurposed for some other application. The !pte VA is reporting me the same PFN before and after MmProbeAndLock. However, MmGetPhysicalAddress is returning me different physical address before and after MmProbeAndLock.

Thanks.
-Prasad

> However, I don’t see, how it helps understand the two potential mysteries that I

raised in my earlier post.

Well, I am afraid we are already not in a position to help you here - you are the only one in the entire Universe who can potentially handle this part…

I know, that, in my example, the page is not getting repurposed for some other application.

First of all, you are simply not in a position to say so unless you happen to be the target page’s owner, and this ownership gets granted to you only by your call to MmProbeAndLockPages() .
The only thing that MmGetPhysicalAddress() does is checking the contents of the PTE - it does not oblige MM to maintain the status quo. In fact, the correspondence between the physical address that MmGetPhysicalAddress() returns and the target virtual one may theoretically be already broken by the time MmGetPhysicalAddress() returns contro, unless you own the physical pages in the target range (i.e. have previously called MmProbeAndLockPages())

However, MmGetPhysicalAddress is returning me different physical address before
and after MmProbeAndLock.

…which clearly indicates that your target page has been re-purposed in between your first call to
MmGetPhysicalAddress() and the one to MmProbeAndLockPages(). Is it so terribly complex to understand???



BTW, what are you trying to do? Are you just gathering some material for your new book about the undocumented features of NT? If this is the case, please don’t forget to mention me in the “References” section

Anton Bassov

Hello,

I completely understand and agree that I should be calling MmProbeAndLockPages. The reason, I thought that the page is not repurposed is because !pte is not showing me any change. However, as per MmGetPhysicalAddress call, it is reporting that the VA-PA mapping is changed and this mapping (before and after) doesn’t not match with !pte is reporting.

Anyways, sincere thanks for all your help! I will MmProbeAndLockPages and see if it helps me.

On the ironical mode comment: No, I am neither writing any book nor am I gathering any material for the book.

I have a simple requirement of getting to know when any kernel mode driver “loads” or “unloads” from the system. The PsSetLoadImageNotifyRoutine routine allows me to register a callback that gets called when any image in “mapped” into memory. I can use SystemModeImage filter to figure the kernel images. However, I do not have an equivalent callback when the image is “unmapped”. Further there is no explicit hook when the driver is “loaded” or “unloaded”.

My question came up in the context of solving this issue.

Thanks.
-Prasad

>I am calling MmGetPhysicalAddress on the original readonly virtual address

As you can understand, this is just plain volatile, and is not protected against any races in the Mm.

MDLs (well, also common buffers, but they are separate from this) are the only ways in Windows to reliably work with physical memory.

Agreed that I should probably be calling MmProbeAndLockPages before calling
MmGetPhysicalAddress.

Just forget about the very existence of the MmGetPhysicalAddress API. I wonder why MS will not remove it from the OS at all.

Use:
MmProbeAndLockPages
then parse the MDL tail

However, for my experiment, I know that my virtual address is mapped and resident.

It can become unmapped and nonresident a microsecond after.

  1. The PFN returned by !pte VA is not matching with MmGetPhysicalAddress(VA).

Yes, a good indication that MmGetPhysicalAddress is unreliable.


Maxim S. Shatskih
Microsoft MVP on File System And Storage
xxxxx@storagecraft.com
http://www.storagecraft.com

Be prepared that hooking the read-only pageable memory by aliasing can drive Mm crazy.

For instance, the hook will disappear after the next discard/page fault/inpage sequence.


Maxim S. Shatskih
Microsoft MVP on File System And Storage
xxxxx@storagecraft.com
http://www.storagecraft.com

wrote in message news:xxxxx@ntdev…
> Hello,
>
> I completely understand and agree that I should be calling MmProbeAndLockPages. The reason, I thought that the page is not repurposed is because !pte is not showing me any change. However, as per MmGetPhysicalAddress call, it is reporting that the VA-PA mapping is changed and this mapping (before and after) doesn’t not match with !pte is reporting.
>
> Anyways, sincere thanks for all your help! I will MmProbeAndLockPages and see if it helps me.
>
> On the ironical mode comment: No, I am neither writing any book nor am I gathering any material for the book.
>
> I have a simple requirement of getting to know when any kernel mode driver “loads” or “unloads” from the system. The PsSetLoadImageNotifyRoutine routine allows me to register a callback that gets called when any image in “mapped” into memory. I can use SystemModeImage filter to figure the kernel images. However, I do not have an equivalent callback when the image is “unmapped”. Further there is no explicit hook when the driver is “loaded” or “unloaded”.
>
> My question came up in the context of solving this issue.
>
> Thanks.
> -Prasad
>
>

>Be prepared that hooking the read-only pageable memory by aliasing can drive Mm crazy.

For instance, the hook will disappear after the next discard/page fault/inpage sequence.

Is this because, MM is not aware of the modification through an alias address and hence it doesn’t copy the block to the page file and does a page discard and then during page-in, it’s fetched from the backing file?

I don’t intend the keep the hook for long time and the physical page will be locked. However, yes, there is no guarantee on the virtual address being valid and hence the case you mention may happen.
Would using MmSetAddressRangeModified on the original virtual address would help here? Also, would it help if I use MmMapLockedPagesSpecifyCache on the locked MDL instead of using MmMapIoSpace and then use the address returned by that to write to the page?

Thanks.
-Prasad

> Is this because, MM is not aware of the modification through an alias address

Surely.

Would using MmSetAddressRangeModified on the original virtual address would help here?

I don’t know whether it will work for the read-only PE section.

Also, would it help if I use MmMapLockedPagesSpecifyCache on the locked MDL

Wow! how could I forget it? this is exactly the correct way to do the aliasing, even does not require meddling with MDL tails.


Maxim S. Shatskih
Microsoft MVP on File System And Storage
xxxxx@storagecraft.com
http://www.storagecraft.com

MmSetAddressRangeModified did not help. However, using MmProbeAndLockPages and MmMapLockedPagesSpecifyCache did solve my problem.

Thanks a lot Max and Anton for all your help!

Thanks.
-Prasad