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
}