FltGetRequestorProcessId woes

Hi driver gurus J

I just got a crash from a customer. IRQL_NOT_LESS_OR_EQUAL L I have been
so careful to make sure I know the current IRQL and double check each API
called to make sure it’s legal. This customer sent me a WinDbg output
(apparently not a novice!) which shows the following:

The machine he’s on is: Windows Server 2003 Kernel Version 3790 (Service
Pack 2) MP (4 procs) Free x86 compatible

CURRENT_IRQL: 2
FAULTING_IP:
nt!PsGetProcessId+8
80852234 8b8094000000 mov eax,dword ptr [eax+94h]
DEFAULT_BUCKET_ID: DRIVER_FAULT
BUGCHECK_STR: 0xA
PROCESS_NAME: FileSightSvc.ex
TRAP_FRAME: f789ec00 – (.trap 0xfffffffff789ec00)
ErrCode = 00000000
eax=00000030 ebx=8a568434 ecx=8a78c048 edx=ffffffff esi=85f24008
edi=85f24040
eip=80852234 esp=f789ec74 ebp=f789ec74 iopl=0 nv up ei pl nz na pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010206
nt!PsGetProcessId+0x8:
80852234 8b8094000000 mov eax,dword ptr [eax+94h] ds:0023:000000c4=???
Resetting default scope
LAST_CONTROL_TRANSFER: from 80852234 to 80836df5
STACK_TEXT:
f789ec00 80852234 badb0d00 ffffffff f789ec58 nt!KiTrap0E+0x2a7
f789ec74 f7303359 00000030 f789edc4 b7562061 nt!PsGetProcessId+0x8
f789ec80 b7562061 8a568434 8a56848c 8a568434
fltmgr!FltGetRequestorProcessId+0x17
WARNING: Stack unwind information not available. Following frames may be
wrong.

So the CURRENT_IRQL is DISPATCH_LEVEL, but it crashed in
FltGetRequestorProcessId which is legal at IRQL <= DISPATCH_LEVEL.

What am I doing wrong?

Thanks for any input.

Doug

It isn’t as if PsGetProcessId is a heavy-weight function:

nt!PsGetProcessId:

8086ca32 8bff mov edi,edi

8086ca34 55 push ebp

8086ca35 8bec mov ebp,esp

8086ca37 8b4508 mov eax,dword ptr [ebp+8]

8086ca3a 8b8094000000 mov eax,dword ptr [eax+94h]

8086ca40 5d pop ebp

8086ca41 c20400 ret 4

(this from a Server 2003 system I happened to have open in the debugger
anyway.)

PsGetProcessId takes the EPROCESS and pulls a field from it (see
http://msdn.microsoft.com/en-us/library/aa906762.aspx for the argument
list.) That field is the process ID.

EBP+8 is the EPROCESS - you might want to look at this. EAX+94h is the
field in the EPROCESS (from “dt nt!_EPROCESS”):

+0x094 UniqueProcessId : Ptr32 Void

So, the only reasonable conclusion here is that what you have is not a
valid EPROCESS (I like the fact EAX is 0x30. What do you see when you
type “!process”?

Jumping up one level, we can examine FltGetRequestorProcessId:

kd> uf FltGetRequestorProcessId

fltmgr!FltGetRequestorProcessId:

f7242342 8bff mov edi,edi

f7242344 55 push ebp

f7242345 8bec mov ebp,esp

f7242347 ff7508 push dword ptr [ebp+8]

f724234a e8cbffffff call fltmgr!FltGetRequestorProcess
(f724231a)

f724234f 85c0 test eax,eax

f7242351 7408 je fltmgr!FltGetRequestorProcessId+0x19
(f724235b)

fltmgr!FltGetRequestorProcessId+0x11:

f7242353 50 push eax

f7242354 e88d060000 call fltmgr!PsGetProcessId (f72429e6)

f7242359 eb02 jmp fltmgr!FltGetRequestorProcessId+0x1b
(f724235d)

fltmgr!FltGetRequestorProcessId+0x19:

f724235b 33c0 xor eax,eax

fltmgr!FltGetRequestorProcessId+0x1b:

f724235d 5d pop ebp

f724235e c20400 ret 4

This isn’t exactly rocket science either but leads us to
FltGetRequestorProcess:

kd> uf FltGetRequestorProcess

fltmgr!FltGetRequestorProcess:

f724231a 8bff mov edi,edi

f724231c 55 push ebp

f724231d 8bec mov ebp,esp

f724231f 8b4508 mov eax,dword ptr [ebp+8]

f7242322 f60001 test byte ptr [eax],1

f7242325 740b je fltmgr!FltGetRequestorProcess+0x18
(f7242332)

fltmgr!FltGetRequestorProcess+0xd:

f7242327 ff70c4 push dword ptr [eax-3Ch]

f724232a ff15fc3124f7 call dword ptr
[fltmgr!_imp__IoGetRequestorProcess (f72431fc)]

f7242330 eb06 jmp fltmgr!FltGetRequestorProcess+0x1e
(f7242338)

fltmgr!FltGetRequestorProcess+0x18:

f7242332 ff15383224f7 call dword ptr
[fltmgr!_imp__IoGetCurrentProcess (f7243238)]

fltmgr!FltGetRequestorProcess+0x1e:

f7242338 5d pop ebp

f7242339 c20400 ret 4

It either comes from the IRP (IoGetRequestorProcess) or it is the
current process. MY guess is that it comes from the IRP in this case -
pull it off the stack (2nd parameter of the function called by
IopfCallDriver generally, unless it’s been overwritten) and look at the
IRP - I bet you will find that it doesn’t contain a valid thread
pointer. If that’s the case, everything is going to come unraveled
(they check for NULL, but if it isn’t NULL, the check won’t fall into
the “so just get the current process” path.)

Truthfully, this doesn’t look like a bug in your filter from this
information - you don’t control the IRP and you didn’t set up the
fields. It is filter manager’s responsibility to handle this (if it
can) or the caller’s responsibility to not hand filter manager an
improperly set-up IRP or the I/O Manager’s to not return something that
isn’t a valid EPROCESS pointer. It’s going to take a bit more digging
to figure out who should have handled this particular case (and how it
should have been handled - the problem with mitigation is that it
doesn’t eliminate the bug, it just makes it less likely to be observed.
That isn’t necessarily a good thing.)

My suggestion to the filter team would be to broaden the validity check
so that the Irp->Tail.Overlay.Thread needs to be a valid kernel address
(maybe this already happens in the checked build?) Since this is a
union, it is possible someone used it (e.g., in a device queue) but
didn’t initialize it back to zero. That still won’t fix the problem if
it IS inside the kernel address range, though, and ultimately it is the
caller that needs to either zero down that field or set it to the
current thread. Ah, but that probably isn’t documented so we can blame
the documentation team for the problem. :wink:

So this points back again to the IRP in question - find it, dump it and
see what is in that field. But I don’t see anything here that says it
is a bug in your driver’s logic.

Tony

OSR

As an alternative you can get this information from the Thread member in the callback data structure. At least you can manually check if that member is not NULL.

//Daniel