MmProbeAndLockPages Bugchecks with PAGE_FAULT_IN_NONPAGED_AREA

Hi All,

I have a WDM driver that is attempting to read a page of memory from the driver TSDDD.dll. Before reading the memory I’m using MmProbeAndLockPages to make sure that the page stays in memory while I read it. First I use IoAllocateMdl to create an MDL for the page I try to read. I’ve verified that the MDL is not null. When I call MmProbeAndLockPages the machine bugchecks, and when I analyze the crash dump the error I get is PAGE_FAULT_IN_NONPAGED_AREA. In the stack backtrace I can see the calls that caused the bugcheck were: nt!MmProbeAndLockPages > nt!KiTrap0E > MmAccessFault.

When I load up the crash dump and enumerate drivers with “lm t n” the driver TSDDD.dll shows up in the list at address 0x978a0000 (this is the same address that windbg reports to have caused the PAGE_FAULT_IN_NONPAGED_AREA). If I use “dd 978a0000” all words of data that I get back are “???”. And finally, if I use the command “!pte 978a0000”, the page table entry for the address is 0x00000000.

So there’s a few things that I’m trying to get answered here. First, does anyone have an idea of why MmProbeAndLockPages would be bugchecking on me? I have the call within try/except blocks, but it looks like the call isn’t bugchecking because of any documented failure modes (i.e. access violation). Secondly, is there any safe way for me to know when a driver can’t be accessed?

My first thought is that the driver TSDDD.dll is somehow marked as nonpageable, but for some reason it’s not actually in memory. So when I try to page it in using MmProbeAndLockPages, the OS detects a page fault on what it thinks is a nonpageable region of memory, causing the bugcheck I’m seeing.

If anyone could give me insight as to why this is happening and what I can do to prevent this from crashing I would appreciate it. Thanks.

-Jeff

>First, does anyone have an idea of why MmProbeAndLockPages would be

bugchecking on me? I have the call within >try/except blocks, but it looks
like the call isn’t bugchecking because of any documented failure modes
(i.e. access violation).

MmProbeAndLockPages will only raise if the requestor mode is user or the bad
virtual address is a user virtual address. For a bad kernel virtual address
with a requestor mode of kernel the system is going to crash, errors of this
type cannot be caught in a try/except. I just looked and the docs don’t make
this very clear unfortunately.

Based on the information that you have provided, I’d say that the address
you’re trying to lock was in a discardable section. For example, if you put
your DriverEntry in an INIT section then after it is run then it will
possibly be removed from memory and the virtual address will no longer map
to anything. Resource sections are also often marked as discardable, for
example:

0: kd> !dh ntfs

File Type: EXECUTABLE IMAGE
FILE HEADER VALUES
14C machine (i386)
7 number of sections
48025BE5 time date stamp Sun Apr 13 15:15:49 2008

SECTION HEADER #6
.rsrc name
3E0 virtual size
88A00 virtual address
400 size of raw data
88A00 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
42000040 flags
Initialized Data
Discardable *****************
(no align specified)
Read Only

0: kd> !pte ntfs+88A00
VA f846da00
PDE at 00000000C0603E10 PTE at 00000000C07C2368
contains 0000000001030963 contains 0000000000000000
pfn 1030 -G-DA–KWEV

0: kd> dc ntfs+88A00
f846da00 ??? ??? ??? ??? ???
f846da10 ??? ??? ??? ??? ???
f846da20 ??? ??? ??? ??? ???
f846da30 ??? ??? ??? ??? ???
f846da40 ??? ??? ??? ??? ???
f846da50 ??? ??? ??? ??? ???
f846da60 ??? ??? ??? ??? ???
f846da70 ??? ??? ??? ??? ???

To confirm my theory, you could run !dh tsddd and figure out if the address
that you have falls in the range of a discardable section.

In terms of fixing it, you’re not expected to be poking around in other
people’s images so you’ll need to do some extra work to avoid crashing. You
could always just go with checking the on disk image, which would be much
safer.

-scott


Scott Noone
Consulting Associate
OSR Open Systems Resources, Inc.
http://www.osronline.com

wrote in message news:xxxxx@ntdev…
> Hi All,
>
> I have a WDM driver that is attempting to read a page of memory from the
> driver TSDDD.dll. Before reading the memory I’m using MmProbeAndLockPages
> to make sure that the page stays in memory while I read it. First I use
> IoAllocateMdl to create an MDL for the page I try to read. I’ve verified
> that the MDL is not null. When I call MmProbeAndLockPages the machine
> bugchecks, and when I analyze the crash dump the error I get is
> PAGE_FAULT_IN_NONPAGED_AREA. In the stack backtrace I can see the calls
> that caused the bugcheck were: nt!MmProbeAndLockPages > nt!KiTrap0E >
> MmAccessFault.
>
> When I load up the crash dump and enumerate drivers with “lm t n” the
> driver TSDDD.dll shows up in the list at address 0x978a0000 (this is the
> same address that windbg reports to have caused the
> PAGE_FAULT_IN_NONPAGED_AREA). If I use “dd 978a0000” all words of data
> that I get back are “???”. And finally, if I use the command “!pte
> 978a0000”, the page table entry for the address is 0x00000000.
>
> So there’s a few things that I’m trying to get answered here. First, does
> anyone have an idea of why MmProbeAndLockPages would be bugchecking on me?
> I have the call within try/except blocks, but it looks like the call isn’t
> bugchecking because of any documented failure modes (i.e. access
> violation). Secondly, is there any safe way for me to know when a driver
> can’t be accessed?
>
> My first thought is that the driver TSDDD.dll is somehow marked as
> nonpageable, but for some reason it’s not actually in memory. So when I
> try to page it in using MmProbeAndLockPages, the OS detects a page fault
> on what it thinks is a nonpageable region of memory, causing the bugcheck
> I’m seeing.
>
> If anyone could give me insight as to why this is happening and what I can
> do to prevent this from crashing I would appreciate it. Thanks.
>
> -Jeff
>
>

Thanks, Scott. I tried using the !lh command and got the following output:

0: kd> !dh 978a0000
Can’t read file header: error == 0

So I can’t get any header information since it’s not in memory. I also saw that the help for this command mentioned the !lmi command, so I tried that as well with the following output:

0: kd> !lmi tsddd
Loaded Module Info: [tsddd]
Cannot read Image header @ 978a0000
Load Report: no symbols loaded

I understand that it’s normally not expected for a driver to read other drivers’ memory, but it still seems very strange to me that TSDDD.dll shows up in the loaded module list as well as in the list returned by EnumDeviceDrivers provided by Psapi. Is there a way either in my driver or in WinDbg that I can check an address to find out if it’s nonpaged? I already know that the PTE for this page indicates that it’s not valid and that MmIsAddressValid returns FALSE. If I were able to tell that this was a nonpageable address (which I believe it is because of the bugcheck), I could at least know not to try paging it in. I don’t see any Mmxxx functions that would accomplish this, so maybe this information is none of my business. If I can’t tell whether a page is nonpageable, then I would have to just rely on MmIsAddressValid, and skip reading any page where MmIsAddressValid returns FALSE. But this would be somewhat limiting, because I know that it’s possible for some driver sections to get paged to disk. Thanks.

-Jeff

I’m not really up on the architecture of terminal server, but could this memory only be mapped in session space?

mm

xxxxx@gmail.com wrote:

Thanks, Scott. I tried using the !lh command and got the following output:

0: kd> !dh 978a0000
Can’t read file header: error == 0

So I can’t get any header information since it’s not in memory. I also saw that the help for this command mentioned the !lmi command, so I tried that as well with the following output:

I understand that it’s normally not expected for a driver to read other drivers’ memory, but it still seems very strange to me that TSDDD.dll shows up in the loaded module list as well as in the list returned by EnumDeviceDrivers provided by Psapi.

Why is it strange? The driver is still around, it’s just that parts of
it are no longer needed, and thus are not wasting memory. Tsddd is part
of terminal services, which puts EXTREME demands on memory.

Is there a way either in my driver or in WinDbg that I can check an address to find out if it’s nonpaged?

The issue is not paged vs non-paged. The issue is present vs
non-present. Many drivers have sections that are discarded after
initialization.

Non-paged means it cannot be removed from memory.

If I can’t tell whether a page is nonpageable,

Again, that’s the wrong word. “Not present” is what you mean.

…then I would have to just rely on MmIsAddressValid, and skip reading any page where MmIsAddressValid returns FALSE. But this would be somewhat limiting, because I know that it’s possible for some driver sections to get paged to disk.

Right. There’s no general purpose way to accomplish what you’re
asking. You would have to use try/except wrappers.


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

Martin nailed it, I hadn’t recognized this as a terminal services related
module. You’re not going to get valid results unless you’re running in a
session that has that image mapped in it.

You can demonstrate this in the debugger:

0: kd> * Check that we have the module loaded
0: kd> lm mtsddd
start end module name
a2f40000 a2f49000 TSDDD (deferred)
0: kd> * Try to dump the memory
0: kd> dc tsddd l4
a2f40000 ??? ??? ??? ??? ???
0: kd> * Not mapped…
0: kd> !pte tsddd
VA a2f40000
PDE at 00000000C06028B8 PTE at 00000000C0517A00
contains 000000000941C863 contains 0000000000000000
pfn 941c —DA–KWEV

0: kd> * Check the current session
0: kd> !session
Sessions on machine: 4
Valid Sessions: 0 1 2 3
Current Session 2
0: kd> * Switch sessions to a session that does have it mapped (you just
have to know which session or try all)
0: kd> !session -s 0
Sessions on machine: 4
Using session 0
0: kd> * Find a process in the session to switch to
0: kd> !sprocess
Dumping Session 0

_MM_SESSION_SPACE 93454000
_MMSESSION 93454d00
PROCESS 93acad40 SessionId: 0 Cid: 0188 Peb: 7ffde000 ParentCid: 0174
DirBase: 3fece060 ObjectTable: 8b27afc0 HandleCount: 493.
Image: csrss.exe


0: kd> * Switch to that process
0: kd> .process /i 93acad40
You need to continue execution (press ‘g’ ) for the context
to be switched. When the debugger breaks in again, you will be in
the new process context.
0: kd> g
Break instruction exception - code 80000003 (first chance)
nt!RtlpBreakWithStatusInstruction:
826bf394 cc int 3
0: kd> * Image is mapped into this session, so we get valid results
0: kd> dc tsddd l4
a2f40000 00905a4d 00000003 00000004 0000ffff MZ…
0: kd> !pte tsddd
VA a2f40000
PDE at 00000000C06028B8 PTE at 00000000C0517A00
contains 0000000013109863 contains 0000000013A71221
pfn 13109 —DA–KWEV pfn 13a71 C—A–KREV

-scott


Scott Noone
Consulting Associate
OSR Open Systems Resources, Inc.
http://www.osronline.com

wrote in message news:xxxxx@ntdev…
> I’m not really up on the architecture of terminal server, but could this
> memory only be mapped in session space?
>
> mm
>