question on paged and non-paged pools

Hi,

I noticed the regions of non-paged and paged pool seem to overlap as seen in
the following windbg output:

kd> dd MmNonPagedPoolStart l1
8054fa58 80db0000
kd> dd MmNonPagedPoolEnd l1
80546760 ffbe0000
kd> dd MmPagedPoolStart l1
80546764 e1000000
kd> dd MmPagedPoolEnd l1
8054fa54 edbfffff

The paged pool region e1000000-edbfffff lies in the non-paged pool region
80db0000-ffbe0000. Aren’t these two regions supposed to be non-overlapping?

Another related question, I ran ‘lmi’ command in windbg and it dumps start
and end addresses of system modules (as in snip below).

start end module name
f7e8b000 f7ed9a00 srv (pdb symbols) srv.sys
f7fca000 f7ff4280 mrxdav (pdb symbols) mrxdav.sys
f7ff5000 f8008520 hgfs (no symbols)
f8149000 f8169380 afd (pdb symbols) afd.sys
f82aa000 f82bf380 dump_atapi (pdb symbols) dump_atapi.sys

All these address ranges seem to lie in the non-paged pool region. Does it
mean all drivers images are loaded in non-paged pool region?

Thanks
Chandra

Non-paged pool resides in non-pageable system area, and, AFAIK, the lowest possible address of this area is 0xEB000000. Therefore, non-paged pool just cannot start at 0x80db0000. Are you sure there is no mistake in your observations???

Does it mean all drivers images are loaded in non-paged pool region?

Well, drivers are supposed to be non-pageable by their very definition (apart from the section that is marked as pageable). In fact, you can load a driver with ZwSetSytemInformation() so that it is pageable, but this is not really a driver but just a kernel-mode module that cannot participate in any device stack (PDRIVER_OBJECT that its DriverEntry() receives is NULL)

Anton Bassov

Nonpaged pool has 2 parts:

  • the primary pool which is the identity-mapped pages, allocation is
    trivial.
  • expansion pool which is some address space range, allocation needs a)
    allocate a physical page b) allocate a PTE in this address space and set it to
    point to the page.

So, you have MmNonPagedPoolStart as start of primary pool, which then ends
and gives the space for paged pool. MmPagedPoolEnd is probably the expansion
pool end.


Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com

“chandra97 97” wrote in message news:xxxxx@ntdev…
> Hi,
>
> I noticed the regions of non-paged and paged pool seem to overlap as seen in
> the following windbg output:
>
> kd> dd MmNonPagedPoolStart l1
> 8054fa58 80db0000
> kd> dd MmNonPagedPoolEnd l1
> 80546760 ffbe0000
> kd> dd MmPagedPoolStart l1
> 80546764 e1000000
> kd> dd MmPagedPoolEnd l1
> 8054fa54 edbfffff
>
> The paged pool region e1000000-edbfffff lies in the non-paged pool region
> 80db0000-ffbe0000. Aren’t these two regions supposed to be non-overlapping?
>
> Another related question, I ran ‘lmi’ command in windbg and it dumps start
> and end addresses of system modules (as in snip below).
>
> start end module name
> f7e8b000 f7ed9a00 srv (pdb symbols) srv.sys
> f7fca000 f7ff4280 mrxdav (pdb symbols) mrxdav.sys
> f7ff5000 f8008520 hgfs (no symbols)
> f8149000 f8169380 afd (pdb symbols) afd.sys
> f82aa000 f82bf380 dump_atapi (pdb symbols) dump_atapi.sys
>
>
> All these address ranges seem to lie in the non-paged pool region. Does it
> mean all drivers images are loaded in non-paged pool region?
>
> Thanks
> Chandra
>

Ok. Here is another related question.

I wanted to dump in memory PE image of a driver. I already know its base
address (BaseAddress) and size (SizeOfImage). I use the code below for this.
Everything works find up until call to MmUnlockPages().

mappedBuffer = NULL;
if (( Buffer = ExAllocatePool(PagedPool, SizeOfImage )) != NULL )
{
if (( mdl = IoAllocateMdl ((PVOID)BaseAddress, SizeOfImage,
FALSE, FALSE, NULL)) != NULL )
{
__try
{
MmProbeAndLockPages ( mdl, KernelMode, IoReadAccess );

pagesLocked = TRUE;

mappedBuffer = MmMapLockedPagesSpecifyCache(
mdl,
KernelMode,
MmCached,
NULL,
FALSE,
NormalPagePriority);

if(mappedBuffer)
{
RtlCopyMemory( Buffer, mappedBuffer, SizeOfImage );
}
else
{
ExFreePool(Buffer);
Buffer = NULL;
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}

if(mappedBuffer)
{
MmUnmapLockedPages(mappedBuffer, mdl);
mappedBuffer = NULL;
}

if(pagesLocked)
{
MmUnlockPages(mdl);
pagesLocked = FALSE;
}
IoFreeMdl(mdl);
return Buffer;
}
}

Calling into MmUnlockPages() gives a bugcheck:

PFN_LIST_CORRUPT (4e)
Typically caused by drivers passing bad memory descriptor lists (ie: calling
MmUnlockPages twice with the same list, etc). If a kernel debugger is
available get the stack trace.
Arguments:
Arg1: 00000007, A driver has unlocked a page more times than it locked it
Arg2: 00000651, page frame number
Arg3: 000064db, current share count
Arg4: 00000000, 0

I check mdl->MdlFlags at every step in debug session all the way starting
from IoAllocateMdl(). Here is what I find.

After call to IoAllocateMdl
mdl->MdlFlags = 0

After call to MmProbeAndLockPages()
mdl->MdlFlags = MDL_PAGES_LOCKED

The above change in values of MdlFlags along with the code below seem to
contradict bugcheck description that “A driver has unlocked a page more
times than it locked it”. MmProbeAndLockPages() was called only *once* and
so was MmUnlockPages(). In all documentation relating to these calls I find
that a successful call to MmProbeAndLockPages() must be complimented by a
call to MmUnlockPages(). BTW, I also verified other fields of MDL structure
and they seem to look ok at every step. This code is not in a complicated
path where mdl gets passed below to a lower driver etc. This code simply
gets called to serve a IOCTL from a user app in a synchronous manner.
My primary objective is to obtain a dump of in memory PE image of a driver
and this is obviously not working. What is the reason for this bugcheck? Any
other good solution(s) for getting in memory PE image dump of a driver?

Thanks
Chandra

On 6/12/07, Maxim S. Shatskih wrote:
>
> Nonpaged pool has 2 parts:
>
> - the primary pool which is the identity-mapped pages, allocation is
> trivial.
> - expansion pool which is some address space range, allocation needs
> a)
> allocate a physical page b) allocate a PTE in this address space and set
> it to
> point to the page.
>
> So, you have MmNonPagedPoolStart as start of primary pool, which then
> ends
> and gives the space for paged pool. MmPagedPoolEnd is probably the
> expansion
> pool end.
>
> –
> Maxim Shatskih, Windows DDK MVP
> StorageCraft Corporation
> xxxxx@storagecraft.com
> http://www.storagecraft.com
>
> “chandra97 97” wrote in message news:xxxxx@ntdev…
> > Hi,
> >
> > I noticed the regions of non-paged and paged pool seem to overlap as
> seen in
> > the following windbg output:
> >
> > kd> dd MmNonPagedPoolStart l1
> > 8054fa58 80db0000
> > kd> dd MmNonPagedPoolEnd l1
> > 80546760 ffbe0000
> > kd> dd MmPagedPoolStart l1
> > 80546764 e1000000
> > kd> dd MmPagedPoolEnd l1
> > 8054fa54 edbfffff
> >
> > The paged pool region e1000000-edbfffff lies in the non-paged pool
> region
> > 80db0000-ffbe0000. Aren’t these two regions supposed to be
> non-overlapping?
> >
> > Another related question, I ran ‘lmi’ command in windbg and it dumps
> start
> > and end addresses of system modules (as in snip below).
> >
> > start end module name
> > f7e8b000 f7ed9a00 srv (pdb symbols) srv.sys
> > f7fca000 f7ff4280 mrxdav (pdb symbols) mrxdav.sys
> > f7ff5000 f8008520 hgfs (no symbols)
> > f8149000 f8169380 afd (pdb symbols) afd.sys
> > f82aa000 f82bf380 dump_atapi (pdb symbols) dump_atapi.sys
> >
> >
> > All these address ranges seem to lie in the non-paged pool region. Does
> it
> > mean all drivers images are loaded in non-paged pool region?
> >
> > Thanks
> > Chandra
> >
>
>
> —
> Questions? First check the Kernel Driver FAQ at
> http://www.osronline.com/article.cfm?id=256
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>

chandra97 97 wrote:

Ok. Here is another related question.

I wanted to dump in memory PE image of a driver. I already know its
base address (BaseAddress) and size (SizeOfImage). I use the code
below for this. Everything works find up until call to MmUnlockPages().

If you know the base address and size of image, why do you probe, lock,
and map the pages at all? If this is in an ioctl handler, as you say,
then you can survive a page fault, should any page of the driver happen
to be swapped out.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

If I just use the base address and size of image, and don’t probe, lock,
and map the pages, I get Bug Check 0x50 (PAGE_FAULT_IN_NONPAGED_AREA) while
getting dump of PE images for some of the drivers. From this it seems for
some drivers not all pages in their PE image are in non-paged pool. That led
me to this arduous path to probe, lock and map of the pages.

Chandra

On 6/12/07, Tim Roberts wrote:
>
> chandra97 97 wrote:
> > Ok. Here is another related question.
> >
> > I wanted to dump in memory PE image of a driver. I already know its
> > base address (BaseAddress) and size (SizeOfImage). I use the code
> > below for this. Everything works find up until call to MmUnlockPages().
>
> If you know the base address and size of image, why do you probe, lock,
> and map the pages at all? If this is in an ioctl handler, as you say,
> then you can survive a page fault, should any page of the driver happen
> to be swapped out.
>
> –
> Tim Roberts, xxxxx@probo.com
> Providenza & Boekelheide, Inc.
>
>
> —
> Questions? First check the Kernel Driver FAQ at
> http://www.osronline.com/article.cfm?id=256
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>

> I wanted to dump in memory PE image of a driver.

If you want to dump in memory PE image of a driver, why do you need MDL here, in the first place??? Please note that driver image has been already mapped into the system address space, so that it can be accessed directly (once it resides in non-pageable system area, it can be accessed directly at any IRQL). The fact that it resides in non-pageable system area is of crucial importance here - you are trying to unlock non-pageable memory (once MDL describes memory that is unpageable anyway, apparently, your call to MmProbeAndLockPages() does not have any effects in terms of page reference count). Do you still need any explanations of the reason why you bugcheck???

In any case, be carefull when you deal with a driver image - it may have its own quirks. For example, names of imported functions may go to the .INIT section, together with it DriverEntry(), which gets discarded from RAM after driver has been loaded (because after IAT has been filled, they are not needed any more, and non-paged memory is considered a precious recource that should not be wasted). Therefore, you should be really carefull when accessing calculated pointers that you have obtained via its PE header - such pointer may point right to the middle of nowhere…

Anton Bassov

>Please note that driver image has been already mapped into the system
address space, so that it can be accessed directly (once it resides in
non-pageable system area, it can be accessed directly at any IRQL)
I too first thought that since the image has already been mapped into system
address space in it can be read directly. But, like I mentioned previously
for some of the drivers I get bugcheck 0x50 (PAGE_FAULT_IN_NONPAGED_AREA) on
a direct memory read in the driver image space whose base address and size
are known.

The fact that it resides in non-pageable system area is of crucial
importance here - you are trying to unlock non-pageable memory (once MDL
describes memory that is unpageable anyway, apparently, your call to
MmProbeAndLockPages() does not have any effects in terms of page reference
count). Do you still need any explanations of the reason why you
bugcheck???
Are you referring to bugcheck 4E (PFN_LIST_CORRUPT)? As you say
MmProbeAndLockPages() does not increment the reference count on a
non-pageable memory region. I thought so too earlier and then instead of
using MmProbeAndLockPages(), I used MmBuildMdlForNonPagedPool() which fills
in/updates MDL for a non-paged list of pages as in the code below. Even this
didn’t work. For some drivers there was bugcheck 0x50 again on stepping over
RtlCopyMemory(). FYI, in this bugcheck on using MmBuildMdlForNonPagedPool,
pMDL->MdlFlags was set to 0x12(MDL_PAGES_LOCKED|MDL_PARTIAL)

pMDL = IoAllocateMdl(
BaseAddress,
Size,
FALSE,
TRUE,
NULL);
if(!pMDL)
{
//return error
}
else
{
MmBuildMdlForNonPagedPool(pMDL);

startVa = MmGetSystemAddressForMdlSafe(
pMDL,
NormalPagePriority);
if(!startVa)
{
//return error
}
else
{
RtlCopyMemory(OutputBuffer, startVa, Size);

status = STATUS_SUCCESS;
}
}

For example, names of imported functions may go to the .INIT section,
together with it DriverEntry(), which gets discarded from RAM after driver
has been loaded (because after IAT has been filled
ok. I return the copied PE image buffer to a user program for analysis and
don’t do any IAT/EAT parsing in the driver iself.

Any other viable solutions to dumping in memory PE image of a driver? Sorry
if I’m wasting time.

Thanks in advance,
Chandra

On 6/12/07, xxxxx@hotmail.com wrote:
>
> > I wanted to dump in memory PE image of a driver.
>
> If you want to dump in memory PE image of a driver, why do you need MDL
> here, in the first place??? Please note that driver image has been already
> mapped into the system address space, so that it can be accessed directly
> (once it resides in non-pageable system area, it can be accessed directly
> at any IRQL). The fact that it resides in non-pageable system area is of
> crucial importance here - you are trying to unlock non-pageable memory (once
> MDL describes memory that is unpageable anyway, apparently, your call to
> MmProbeAndLockPages() does not have any effects in terms of page reference
> count). Do you still need any explanations of the reason why you
> bugcheck???
>
>
> In any case, be carefull when you deal with a driver image - it may have
> its own quirks. For example, names of imported functions may go to the
> .INIT section, together with it DriverEntry(), which gets discarded from RAM
> after driver has been loaded (because after IAT has been filled, they are
> not needed any more, and non-paged memory is considered a precious recource
> that should not be wasted). Therefore, you should be really carefull when
> accessing calculated pointers that you have obtained via its PE header -
> such pointer may point right to the middle of nowhere…
>
>
> Anton Bassov
>
> —
> Questions? First check the Kernel Driver FAQ at
> http://www.osronline.com/article.cfm?id=256
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>

OK, let me explain it…

As long as you are at IRQL<dispatch_level you should not worry about page faults. therefore>PAGE_FAULT_IN_NONPAGED_AREA has nothing to do with page fault in itself - this is one of the most
common error descriptions that you can see on BSOD. Please check OSR - you will find an article that describes BSOD messages, so that you will have a chance to see that disagnostic value of these messages is not that high.

In this particular case this is not a page fault but simply access violation. As I told you already,
the system discards some parts of the image after a driver gets loaded, and invalidates their corresponding VADs -the system does not want to waste unpageable memory. However, SizeOfImage stays the same, because it is based upon information in PE header, rather than upon loader’s and Memory Manager’s actions. In practice, it means that there may be memory holes in between BaseAddres and BaseAddress+SizeOfImage, so that you bluescreen when you try to access such a hole. This is why you bluescreen when you step over RtlCopyMemory() - you are just
trying to access invalid address.

What you have to do here is just to treat the target range on page-by-page basis, and copy one page after another. Before you access a page, call MmIsAddressValid() or MmGetPhysicalAddress(). If your call is unsuccessfull, it means the address is invalid(once driver is guaranteed to be always loaded in RAM, these calls must be successfull whenever you access a valid virtual address in between BaseAddres and BaseAddress+SizeOfImage). Therefore, if your call is unsuccessfull, just proceed to the next page, and that’s it - there is no need for MDLs here whatsoever…

Anton Bassov</dispatch_level>

And what if one of those pages which were discarded were reused as
normal pool that was allocatd to another driver? Your
MmIsAddessValid/GetPhysicalAddress call will succeed, but the contents
you see will be garbage.

d

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of
xxxxx@hotmail.com
Sent: Tuesday, June 12, 2007 9:51 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] question on paged and non-paged pools

OK, let me explain it…

As long as you are at IRQL<dispatch_level you should not worry about>page faults. Therefore,
PAGE_FAULT_IN_NONPAGED_AREA has nothing to do with page fault in itself
- this is one of the most
common error descriptions that you can see on BSOD. Please check OSR -
you will find an article that describes BSOD messages, so that you will
have a chance to see that disagnostic value of these messages is not
that high.

In this particular case this is not a page fault but simply access
violation. As I told you already,
the system discards some parts of the image after a driver gets loaded,
and invalidates their corresponding VADs -the system does not want to
waste unpageable memory. However, SizeOfImage stays the same, because it
is based upon information in PE header, rather than upon loader’s and
Memory Manager’s actions. In practice, it means that there may be memory
holes in between BaseAddres and BaseAddress+SizeOfImage, so that you
bluescreen when you try to access such a hole. This is why you
bluescreen when you step over RtlCopyMemory() - you are just
trying to access invalid address.

What you have to do here is just to treat the target range on
page-by-page basis, and copy one page after another. Before you access a
page, call MmIsAddressValid() or MmGetPhysicalAddress(). If your call is
unsuccessfull, it means the address is invalid(once driver is guaranteed
to be always loaded in RAM, these calls must be successfull whenever you
access a valid virtual address in between BaseAddres and
BaseAddress+SizeOfImage). Therefore, if your call is unsuccessfull, just
proceed to the next page, and that’s it - there is no need for MDLs here
whatsoever…

Anton Bassov


Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer</dispatch_level>

Doron,

And what if one of those pages which were discarded were reused as
normal pool that was allocatd to another driver?
Your MmIsAddessValid/GetPhysicalAddress call will succeed, but the contents
you see will be garbage.

How can something like that possibly happen??? The only thing the other driver can do is to re-use
*PHYSICAL* pages that were discarded (actually, it does not necessarily have to be a driver - the system may re-use these pages in any way it wishes, including backing up user address space of a process that may need them). At this point another lifetime will start for these pages - they will be accessible from the virtual address they are currently mapped to, but their previous virtual address
will become invalid (the system invalidates VADs when it unmaps pages from their virtual addresses - after all, this is the only reason why the OP crashes when he tries to access these addresses).

Therefore, if pages get discarded, MmIsAddessValid/GetPhysicalAddress just have no chance to return anything, apart from failure - the first thing they do is checking PDE and PTE that correspond to the virtual address that have been passed to them, and , unless both entries are valid, they return 0…

Anton Bassov