ReactOS help
ReactOS _KPRCB struct
_KPRCB LockQueue
WDM.H will help us :)
typedef ULONG_PTR KSPIN_LOCK;
typedef KSPIN_LOCK *PKSPIN_LOCK;
//
// Define per processor lock queue structure.
//
// N.B. The lock field of the spin lock queue structure contains the address
// of the associated kernel spin lock, an owner bit, and a lock bit. Bit
// 0 of the spin lock address is the wait bit and bit 1 is the owner bit.
// The use of this field is such that the bits can be set and cleared
// noninterlocked, however, the back pointer must be preserved.
//
// The lock wait bit is set when a processor enqueues itself on the lock
// queue and it is not the only entry in the queue. The processor will
// spin on this bit waiting for the lock to be granted.
//
// The owner bit is set when the processor owns the respective lock.
//
// The next field of the spin lock queue structure is used to line the
// queued lock structures together in fifo order. It also can set set and
// cleared noninterlocked.
//
#define LOCK_QUEUE_WAIT 1
#define LOCK_QUEUE_WAIT_BIT 0
#define LOCK_QUEUE_OWNER 2
#define LOCK_QUEUE_OWNER_BIT 1
#if defined(_AMD64_)
#define LOCK_QUEUE_TIMER_LOCK_SHIFT 4
#define LOCK_QUEUE_TIMER_TABLE_LOCKS (1 << (8 - LOCK_QUEUE_TIMER_LOCK_SHIFT))
typedef ULONG64 KSPIN_LOCK_QUEUE_NUMBER;
#define LockQueueDispatcherLock 0
#define LockQueueExpansionLock 1
#define LockQueuePfnLock 2
#define LockQueueSystemSpaceLock 3
#define LockQueueVacbLock 4
#define LockQueueMasterLock 5
#define LockQueueNonPagedPoolLock 6
#define LockQueueIoCancelLock 7
#define LockQueueWorkQueueLock 8
#define LockQueueIoVpbLock 9
#define LockQueueIoDatabaseLock 10
#define LockQueueIoCompletionLock 11
#define LockQueueNtfsStructLock 12
#define LockQueueAfdWorkQueueLock 13
#define LockQueueBcbLock 14
#define LockQueueMmNonPagedPoolLock 15
#define LockQueueUnusedSpare16 16
#define LockQueueTimerTableLock 17
#define LockQueueMaximumLock (LockQueueTimerTableLock + LOCK_QUEUE_TIMER_TABLE_LOCKS)
#else
#define LOCK_QUEUE_TIMER_LOCK_SHIFT 4
#define LOCK_QUEUE_TIMER_TABLE_LOCKS (1 << (8 - LOCK_QUEUE_TIMER_LOCK_SHIFT))
typedef enum _KSPIN_LOCK_QUEUE_NUMBER {
LockQueueDispatcherLock,
LockQueueExpansionLock,
LockQueuePfnLock,
LockQueueSystemSpaceLock,
LockQueueVacbLock,
LockQueueMasterLock,
LockQueueNonPagedPoolLock,
LockQueueIoCancelLock,
LockQueueWorkQueueLock,
LockQueueIoVpbLock,
LockQueueIoDatabaseLock,
LockQueueIoCompletionLock,
LockQueueNtfsStructLock,
LockQueueAfdWorkQueueLock,
LockQueueBcbLock,
LockQueueMmNonPagedPoolLock,
LockQueueUnusedSpare16,
LockQueueTimerTableLock,
LockQueueMaximumLock = LockQueueTimerTableLock + LOCK_QUEUE_TIMER_TABLE_LOCKS
} KSPIN_LOCK_QUEUE_NUMBER, *PKSPIN_LOCK_QUEUE_NUMBER;
#endif
typedef struct _KSPIN_LOCK_QUEUE {
struct _KSPIN_LOCK_QUEUE * volatile Next;
PKSPIN_LOCK volatile Lock;
} KSPIN_LOCK_QUEUE, *PKSPIN_LOCK_QUEUE;
#if (NTDDI_VERSION >= NTDDI_WINXP)
_DECL_HAL_KE_IMPORT
KIRQL
FASTCALL
KeAcquireQueuedSpinLock (
__in KSPIN_LOCK_QUEUE_NUMBER Number
);
#endif
#if (NTDDI_VERSION >= NTDDI_WINXP)
_DECL_HAL_KE_IMPORT
VOID
FASTCALL
KeReleaseQueuedSpinLock (
__in KSPIN_LOCK_QUEUE_NUMBER Number,
__in KIRQL OldIrql
);
#endif
WinDBG _KPRCB and SpinLock analyze
kd> !smt
SMT Summary:
------------
KeActiveProcessors: *------------------------------- (00000001)
KiIdleSummary: -------------------------------- (00000000)
No PRCB Set Master SMT Set
0 ffdff120 Master *------------------------------- (00000001)
kd> !prcb
PRCB for Processor 0 at ffdff120:
Threads-- Current 81cab020 Next 00000000 Idle 80558e20
Number 0 SetMember 00000001
Interrupt Count -- 000f499b
Times -- Dpc 0000004e Interrupt 000001ec
Kernel 000e53f5 User 00000313
kd> dt nt!_KPRCB ffdff120
+0x000 MinorVersion : 1
+0x002 MajorVersion : 1
+0x004 CurrentThread : 0x81cab020 _KTHREAD
+0x008 NextThread : (null)
+0x00c IdleThread : 0x80558e20 _KTHREAD
+0x010 Number : 0 ''
+0x011 Reserved : 0 ''
+0x012 BuildType : 2
+0x014 SetMember : 1
+0x018 CpuType : 15 ''
+0x019 CpuID : 1 ''
+0x01a CpuStep : 0x408
+0x01c ProcessorState : _KPROCESSOR_STATE
+0x33c KernelReserved : [16] 0
+0x37c HalReserved : [16] 0
+0x3bc PrcbPad0 : [92] ""
+0x418 LockQueue : [16] _KSPIN_LOCK_QUEUE
+0x498 PrcbPad1 : [8] ""
+0x4a0 NpxThread : 0x81c779e8 _KTHREAD
+0x4a4 InterruptCount : 0xf499b
+0x4a8 KernelTime : 0xe53f5
+0x4ac UserTime : 0x313
+0x4b0 DpcTime : 0x4e
+0x4b4 DebugDpcTime : 0
+0x4b8 InterruptTime : 0x1ec
+0x4bc AdjustDpcThreshold : 0x14
+0x4c0 PageColor : 0
+0x4c4 SkipTick : 0
+0x4c8 MultiThreadSetBusy : 0 ''
+0x4c9 Spare2 : [3] ""
+0x4cc ParentNode : 0x805594e0 _KNODE
+0x4d0 MultiThreadProcessorSet : 1
+0x4d4 MultiThreadSetMaster : (null)
+0x4d8 ThreadStartCount : [2] 0
+0x4e0 CcFastReadNoWait : 0
+0x4e4 CcFastReadWait : 0
+0x4e8 CcFastReadNotPossible : 0
+0x4ec CcCopyReadNoWait : 0
+0x4f0 CcCopyReadWait : 0
+0x4f4 CcCopyReadNoWaitMiss : 0
+0x4f8 KeAlignmentFixupCount : 0
+0x4fc KeContextSwitches : 0x11d7ac
+0x500 KeDcacheFlushCount : 0
+0x504 KeExceptionDispatchCount : 0x73a
+0x508 KeFirstLevelTbFills : 0
+0x50c KeFloatingEmulationCount : 0
+0x510 KeIcacheFlushCount : 0
+0x514 KeSecondLevelTbFills : 0
+0x518 KeSystemCalls : 0x1bea47
+0x51c SpareCounter0 : [1] 0
+0x520 PPLookasideList : [16] _PP_LOOKASIDE_LIST
+0x5a0 PPNPagedLookasideList : [32] _PP_LOOKASIDE_LIST
+0x6a0 PPPagedLookasideList : [32] _PP_LOOKASIDE_LIST
+0x7a0 PacketBarrier : 0
+0x7a4 ReverseStall : 0
+0x7a8 IpiFrame : (null)
+0x7ac PrcbPad2 : [52] ""
+0x7e0 CurrentPacket : [3] (null)
+0x7ec TargetSet : 0
+0x7f0 WorkerRoutine : (null)
+0x7f4 IpiFrozen : 0
+0x7f8 PrcbPad3 : [40] ""
+0x820 RequestSummary : 0
+0x824 SignalDone : (null)
+0x828 PrcbPad4 : [56] ""
+0x860 DpcListHead : _LIST_ENTRY [ 0xffdff980 - 0xffdff980 ]
+0x868 DpcStack : 0xf8974000
+0x86c DpcCount : 0x907c
+0x870 DpcQueueDepth : 0
+0x874 DpcRoutineActive : 0
+0x878 DpcInterruptRequested : 0
+0x87c DpcLastCount : 0x907c
+0x880 DpcRequestRate : 0
+0x884 MaximumDpcQueueDepth : 1
+0x888 MinimumDpcRate : 3
+0x88c QuantumEnd : 0
+0x890 PrcbPad5 : [16] ""
+0x8a0 DpcLock : 0
+0x8a4 PrcbPad6 : [28] ""
+0x8c0 CallDpc : _KDPC
+0x8e0 ChainedInterruptList : (null)
+0x8e4 LookasideIrpFloat : 1431
+0x8e8 SpareFields0 : [6] 0
+0x900 VendorString : [13] "GenuineIntel"
+0x90d InitialApicId : 0 ''
+0x90e LogicalProcessorsPerPhysicalProcessor : 0x1 ''
+0x910 MHz : 0xbf0
+0x914 FeatureBits : 0x33fff
+0x918 UpdateSignature : _LARGE_INTEGER 0x17`00000000
+0x920 NpxSaveArea : _FX_SAVE_AREA
+0xb30 PowerState : _PROCESSOR_POWER_STATE
kd> dt nt!_KSPIN_LOCK_QUEUE ffdff120+0x418
+0x000 Next : (null)
+0x004 Lock : 0x80551434 -> 0 -> LockQueueDispatcherLock
kd> dt nt!_KSPIN_LOCK_QUEUE ffdff120+0x418+0x8
+0x000 Next : (null)
+0x004 Lock : 0x80551430 -> 0 -> LockQueueExpansionLock
kd> dt nt!_KSPIN_LOCK_QUEUE ffdff120+0x418+0x10
+0x000 Next : (null)
+0x004 Lock : 0x80551448 -> 0 -> LockQueuePfnLock
kd> dt nt!_KSPIN_LOCK_QUEUE ffdff120+0x418+0x18
+0x000 Next : (null)
+0x004 Lock : 0x8055144c -> 0 -> LockQueueSystemSpaceLock
kd> dt nt!_KSPIN_LOCK_QUEUE ffdff120+0x418+0x20
+0x000 Next : (null)
+0x004 Lock : 0x805513f8 -> 0 -> LockQueueVacbLock
kd> dt nt!_KSPIN_LOCK_QUEUE ffdff120+0x418+0x28
+0x000 Next : (null)
+0x004 Lock : 0x805513f0 -> 0 -> LockQueueMasterLock
kd> dt nt!_KSPIN_LOCK_QUEUE ffdff120+0x418+0x30
+0x000 Next : (null)
+0x004 Lock : 0x80551408 -> 0 -> LockQueueNonPagedPoolLock
kd> dt nt!_KSPIN_LOCK_QUEUE ffdff120+0x418+0x38
+0x000 Next : (null)
+0x004 Lock : 0x80551414 -> 0 -> LockQueueIoCancelLock
kd> dt nt!_KSPIN_LOCK_QUEUE ffdff120+0x418+0x40
+0x000 Next : (null)
+0x004 Lock : 0x805513f4 -> 0 -> LockQueueWorkQueueLock
kd> dt nt!_KSPIN_LOCK_QUEUE ffdff120+0x418+0x48
+0x000 Next : (null)
+0x004 Lock : 0x80551418 -> 0 -> LockQueueIoVpbLock
kd> dt nt!_KSPIN_LOCK_QUEUE ffdff120+0x418+0x50
+0x000 Next : (null)
+0x004 Lock : 0x8055141c -> 0 -> LockQueueIoDatabaseLock
kd> dt nt!_KSPIN_LOCK_QUEUE ffdff120+0x418+0x58
+0x000 Next : (null)
+0x004 Lock : 0x80551410 -> 0 -> LockQueueIoCompletionLock
kd> dt nt!_KSPIN_LOCK_QUEUE ffdff120+0x418+0x60
+0x000 Next : (null)
+0x004 Lock : 0x8055145c -> 0 -> LockQueueNtfsStructLock
kd> dt nt!_KSPIN_LOCK_QUEUE ffdff120+0x418+0x68
+0x000 Next : (null)
+0x004 Lock : 0x80551460 -> 0 -> LockQueueAfdWorkQueueLock
kd> dt nt!_KSPIN_LOCK_QUEUE ffdff120+0x418+0x70
+0x000 Next : (null)
+0x004 Lock : 0x80551404 -> 0 -> LockQueueBcbLock
kd> dt nt!_KSPIN_LOCK_QUEUE ffdff120+0x418+0x78
+0x000 Next : (null)
+0x004 Lock : (null) -> LockQueueMmNonPagedPoolLock
kd> dt nt!_KSPIN_LOCK_QUEUE ffdff120+0x418+0x80
+0x000 Next : (null)
+0x004 Lock : (null) -> LockQueueUnusedSpare16
For machine with 2 CPU
lkd> !smt
SMT Summary:
------------
KeActiveProcessors: **------------------------------ (00000003)
KiIdleSummary: *------------------------------- (00000001)
No PRCB Set Master SMT Set IAID
0 ffdff120 Master **------------------------------ (00000003) 00
1 f8704120 ffdff120 **------------------------------ (00000003) 01
lkd> dt nt!_KSPIN_LOCK_QUEUE ffdff120+0x418
+0x000 Next : (null)
+0x004 Lock : 0x80552880 -> 0 -> LockQueueDispatcherLock (CPU0)
lkd> dt nt!_KSPIN_LOCK_QUEUE f8704120+0x418
+0x000 Next : (null)
+0x004 Lock : 0x80552880 -> 0 -> LockQueueDispatcherLock (CPU1)
lkd> dt nt!_KSPIN_LOCK_QUEUE ffdff120+0x418+0x8
+0x000 Next : (null)
+0x004 Lock : 0x80552800 -> 0 -> LockQueueExpansionLock (CPU0)
lkd> dt nt!_KSPIN_LOCK_QUEUE f8704120+0x418+0x8
+0x000 Next : (null)
+0x004 Lock : 0x80552800 -> 0 -> LockQueueExpansionLock (CPU1)
SO, CPU0 and CPU1 using the same "GLOBAL" lock!
We are able now to secure read ANY memory on x86 arch.
Example
#if (NTDDI_VERSION >= NTDDI_WINXP)
_DECL_HAL_KE_IMPORT
KIRQL
FASTCALL
KeAcquireQueuedSpinLock (
__in KSPIN_LOCK_QUEUE_NUMBER Number
);
#endif
#if (NTDDI_VERSION >= NTDDI_WINXP)
_DECL_HAL_KE_IMPORT
VOID
FASTCALL
KeReleaseQueuedSpinLock (
__in KSPIN_LOCK_QUEUE_NUMBER Number,
__in KIRQL OldIrql
);
#endif
#include "i386.h"
BOOLEAN
I386IsAddressValidPae(PVOID VirtualAddress)
{
PPTE_PAE ptr;
ptr = PDEaddrPAE(VirtualAddress);
if( ptr->Present == 0 )
{
return FALSE;
}
if( ptr->LargePage != 0 )
{
return TRUE;
}
ptr = PTEaddrPAE(VirtualAddress);
if( ptr->Present == 0 )
{
return FALSE;
}
return TRUE;
}
BOOLEAN
I386IsAddressValid(PVOID VirtualAddress)
{
PPTE ptr;
ptr = PDEaddr(VirtualAddress);
if( ptr->Present == 0 )
{
return FALSE;
}
if( ptr->LargePage != 0 )
{
return TRUE;
}
ptr = PTEaddr(VirtualAddress);
if( ptr->Present == 0)
{
return FALSE;
}
return TRUE;
}
BOOLEAN
IsAddressValid(PVOID VirtualAddress)
{
ULONG cr4 = GetCR4();
if(cr4 & CR4_PAE)
{
return I386IsAddressValid(VirtualAddress);
}
else
{
return I386IsAddressValid(VirtualAddress);
}
}
/*
* Secure read of NonPaged memory
* Take care with memory mapped for devices eg. PCI, Video
*/
BOOLEAN
ReadULONG(PVOID VirtualAddress, PULONG Data)
{
BOOLEAN status = FALSE;
KIRQL oldIrql, oldIrql_2;
oldIrql = KeAcquireQueuedSpinLock( LockQueuePfnLock );
if( IsAddressValid( VirtualAddress ) )
{
// Read memory
// Shoule we also Acquire NonPagedPoolLock??
oldIrql_2 = KeAcquireQueuedSpinLock(LockQueueNonPagedPoolLock);
// NOW WE CAN READ MEMORY
*Data = *( (ULONG*) VirtualAddress );
status = TRUE;
KeReleaseQueuedSpinLock(LockQueueNonPagedPoolLock, oldIrql_2);
}
KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql);
return status;
}
Example of SpinLock implementation
// SpinLock in ecx register
VOID FASTCALL
KeAcquireSpinLock(IN PKSPIN_LOCK SpinLock)
{
label1:
; test and set SpinLock, in multiprocessor environment
; lock insures that the processor has exclusive use of
; any shared memory while the signal is asserted
lock bts dword ptr[ecx]
; SpinLock owned, wait
jc label2
; OK, acquired
ret
label2:
; was cleared?
test dword ptr[ecx], 1
; yes, SpinLock is free
jz label1
; no
jmp label2
}
// SpinLock in ecx register
VOID FASTCALL
KeReleaseSpinLock(IN PKSPIN_LOCK SpinLock)
{
lock and dword ptr[ecx], 0
ret
}