Showing posts with label Object Manager. Show all posts
Showing posts with label Object Manager. Show all posts

Friday, June 17, 2016

Caching and file object reference in Windows.

This is how the last reference to a file object backing cached file data is being released by the kernel. In that case this was a network filesystem

19 nt!IofCallDriver
1a mup!MupiCallUncProvider
1b mup!MupStateMachine
1c mup!MupClose
1d nt!IofCallDriver
1e nt!IopDeleteFilec
1f nt!ObpRemoveObjectRoutine
20 nt!ObfDereferenceObjectWithTag
21 nt!ObfDereferenceObject
22 nt!CcDeleteSharedCacheMap
23 nt!CcWriteBehind
24 nt!CcWorkerThread
25 nt!ExpWorkerThread
26 nt!PspSystemThreadStartup
27 nt!KiThreadStartup

Friday, June 10, 2016

How handles are closed on process termination in Windows

Just for curiosity. A call stack when handles are closed on process termination

00 nt!ObpDecrementHandleCount
01 nt!ObpCloseHandleTableEntry
02 nt!ExSweepHandleTable
03 nt!ObKillProcess
04 nt!PspExitThread
05 nt!PsExitSpecialApc
06 nt!KiDeliverApc
07 nt!KiServiceExit
08 ntdll!KiFastSystemCallRet
09 ntdll!ZwWaitForWorkViaWorkerFactory
0a ntdll!TppWorkerThread
0b KERNEL32!BaseThreadInitThunk
0c ntdll!__RtlUserThreadStart
0d ntdll!_RtlUserThreadStart

Friday, February 5, 2016

Unsafe use of FltGetFileNameInformationUnsafe

  FltGetFileNameInformationUnsafe name is spot on. It is very unsafe and dangerous function but not in the way mentioned in WDK. The documentation misses yet another dangerous case when it should not be used. This case is related to file system isolation filters( for more information on such filters follow this link https://www.osronline.com/article.cfm?article=560 ). I would state this additional condition as

  - A filter driver must not use FltGetFileNameInformationUnsafe for file objects it never observed. A filter observed a file object if it was called at least once with this file object for any operation and it never received IRP_MJ_CLOSE for this file object or observed a failed IRP_MJ_CREATE. This condition guaranties that a file object is initialized by a filter of file system driver that is beneath a filter calling FltGetFileNameInformationUnsafe . 

  When the above condition is violated by any file system filter a filter might call an underlying file system with a file object this file system never initialized as the file object was initialized by a file system filter that is above a filter that has called FltGetFileNameInformationUnsafe . At first glance it seems that in that case an upper filter must isolate the underlying filters from such file object. This is true, but there is a degenerate case when a filter can gain access to file objects that it should never see. This is a case of a process creation callback when a file object for executable file is provided as a parameter to a callback and this file object might have been initialized by a file system filter above one that registered this callback. Below is a call stack from the system where Microsoft Windows Defender file system minifilter used FltGetFileNameInformationUnsafe from a process creation callback to query a file name for a file object initialized by a file system filter attached to MiniFilter Manager ( aka fltmgr.sys )


Ntfs!NtfsCommonQueryInformation+0xa7
Ntfs!NtfsFsdDispatchSwitch+0xd3
Ntfs!NtfsFsdDispatchWait+0x47
nt!IovCallDriver+0x3cd
fltmgr!FltpQueryInformationFile+0x10e
fltmgr!QueryStandardLinkInformation+0x4d
fltmgr!FltpSetStreamListStandardInformationFlags+0x7a
fltmgr!FltpGetFileNameInformation+0x796
fltmgr!FltGetFileNameInformationUnsafe+0x71
WdFilter!MpGetImageNormalizedName+0x51
WdFilter!MpCreateProcessNotifyRoutineEx+0x77
nt!PspInsertThread+0x7a7
nt!NtCreateUserProcess+0x806
nt!KiSystemServiceCopyEnd+0x13

As a result NTFS crashed when it received an IRP with a file object initialized by a file system filter attached to the top of the drivers stack. The obvious solution is to use the old good ObQueryNameString as it has been done for the last 25 years by the kernel itself, for example in NtQueryVirtualMemory when processing a memory region supported by a mapped file. In that case an IRP is created and sent from the very top of a drivers stack so an isolation filter has a chance to intercept this IRP and complete it.

Thursday, October 15, 2015

When are object callbacks being called?


The object callbacks registered with ObRegisterCallbacks are called from ObpCreateHandle, e.g.

01 ffffd000`98d1c4b0 fffff802`9eaa8b96 nt!ObpCallPreOperationCallbacks+0x16a
02 ffffd000`98d1c540 fffff802`9eb0e6cd nt!ObpCreateHandle+0xa76
03 ffffd000`98d1c780 fffff802`9eb0fde4 nt!PsOpenProcess+0x5cd
04 ffffd000`98d1cac0 fffff802`9e7df863 nt!NtOpenProcess+0x24
05 ffffd000`98d1cb00 00007ffc`1113375a nt!KiSystemServiceCopyEnd+0x13
06 00000062`ae57e3d8 00007ffc`0e5e59f4 ntdll!NtOpenProcess+0xa

Tuesday, May 5, 2015

Getting an object type on Windows 10 Technical Preview Build 10074

   Windows 10 Technical Preview Build 10074 came with a surprise. A bit of history - Windows 7 introduced a new way for retrieving an object type by object address, the object type pointer Type in OBJECT_HEADER was replaced with the TypeIndex which is an index in ObTypeIndexTable, this saved 3 ( 32 bit) or 7 (on 64 bit) bytes compared to a pointer. Windows 10 Build 10074 added a new feature, the TypeIndex value is not an index but a result of a binary operation between an index in ObTypeIndexTable, the second lowest byte of the object address and a value from ObHeaderCookie. The actual reason of this is not yet clear for me but it looks like an attempt to reduce an inter CPU cache coherency traffic by spreading the ObTypeIndexTable to contain copies of the object types and multiplexing access based on the object address. The exported ObGetObjectType function can be used to retrieve an object type address. Lets take a look on ObGetObjectType.

nt!ObGetObjectType:
lea         rax,[rcx-30h]
movzx   ecx,byte ptr [rcx-18h]
shr        rax,8
movzx   eax,al
xor        rax,rcx
movzx   ecx,byte ptr [nt!ObHeaderCookie (fffff802`eae3d42c)]
xor        rax,rcx
lea         rcx,[nt!ObTypeIndexTable (fffff802`eae3d8e0)]
mov       rax,qword ptr [rcx+rax*8]
ret

which can be written in C as ( where XOR(a,b) is a^b )

POBJECT_TYPE
ObGetObjectType( __in PVOID Object )
{
POBJECT_HEADER   Header = GET_OBJECT_HEADER( Object );
UCHAR    Index = XOR( Header->TypeIndex, (UCHAR)(Header>>8) );
       UCHAR    Cookie= *(PUCHAR)ObHeaderCookie;

        return  ObTypeIndexTable[ XOR(Index, Cookie) ];
}

Monday, March 24, 2014

Windows Object Manager, Paged Pool and elevated IRQL

Surprisingly Windows 8 Object Manager allocates some objects from the Paged Pool, that means that ObReferenceObject and ObDereferenceObject can't be safely called at DISPATCH_LEVEL as the actual maximum IRQL becomes APC_LEVEL if an object is allocated from the paged pool, for example a token object might be from the paged pool, as !pool command shows

1: kd> !pool ffffc00002b73770
Pool page ffffc00002b73770 region is Paged pool
.....
*ffffc00002b73740 size:  8c0 previous size:  1c0  (Allocated) *Toke
Pooltag Toke : Token objects, Binary : nt!se

The object itself ( a pretty large pointer count, but nevertheless this is a valid object )

1: kd> !object ffffc00002b737a0
Object: ffffc00002b737a0  Type: (ffffe00000153db0) Token
    ObjectHeader: ffffc00002b73770 (new version)
    HandleCount: 33  PointerCount: 131067

Driver Verifier was active and cleared the valid bit from a PTE mapping the paged pool's page on which the object was allocated

1: kd> !pte ffffc00002b737a0
                                           VA ffffc00002b737a0
PXE at FFFFF6FB7DBEDC00    PPE at FFFFF6FB7DB80000    PDE at FFFFF6FB700000A8    PTE at FFFFF6E000015B98
contains 000000000134F863  contains 0000000001DCE863  contains 00000001257C2863  contains FB40000129FE9882
pfn 134f      ---DA--KWEV  pfn 1dce      ---DA--KWEV  pfn 1257c2    ---DA--KWEV  not valid
                                                                                  Transition: 129fe9
                                                                                  Protect: 4 - ReadWrite

the PTE was marked as invalid though the physical page actually contains valid data and has not been reused and swapped out, the valid bit will be brought back by the page fault handler when processing a page fault ( this is called a soft page fault when there is no IO from backing store ), but calling ObDereferenceObject and providing this object at DISPATCH_LEVEL would crash the system

TRAP_FRAME:  ffffd000201fc800 -- (.trap 0xffffd000201fc800)
NOTE: The trap frame does not contain all registers.
Some register values may be zeroed or incorrect.
rax=0000000000000005 rbx=0000000000000000 rcx=ffffc00002b737a0
rdx=0000000000000005 rsi=0000000000000000 rdi=0000000000000000
rip=fffff803b20565a3 rsp=ffffd000201fc990 rbp=fffff800017bf594
 r8=0000000000000007  r9=fffff800017debac r10=0000000000000000
r11=ffffd000201fcc70 r12=0000000000000000 r13=0000000000000000
r14=0000000000000000 r15=0000000000000000
iopl=0         nv up ei ng nz na po nc
nt!ObfDereferenceObject+0x23:
fffff803`b20565a3 f0480fc15ed0    lock xadd qword ptr [rsi-30h],rbx ds:ffffffff`ffffffd0=????????????????
Resetting default scope

LAST_CONTROL_TRANSFER:  from fffff803b21f10ea to fffff803b216f890

STACK_TEXT:  
 nt!DbgBreakPointWithStatus
nt!KiBugCheckDebugBreak+0x12
nt!KeBugCheck2+0x8ab
nt!KeBugCheckEx+0x104
nt!KiBugCheckDispatch+0x69
nt!KiPageFault+0x23a
nt!ObfDereferenceObject+0x23
<here is an offending driver ))))>