Este artículo está dirigido a aquellos que acaban de comenzar a desarrollar controladores de kernel para Windows. ¿Por centésima vez ves el odiado IRQL_NOT_LESS_OR_EQUAL y esta triste carita sonriente? Entonces, por favor, ve debajo del gato.
, , IRQL , , Windows.
, , - PID-.
KSPIN_LOCK SharedDataLock;
NTSTATUS SomeFunction(_In_ HANDLE ProcessId)
{
KIRQL OriginalIrql;
NTSTATUS status = STATUS_UNSUCCESSFUL;
// lock shared data access
KeAcquireSpinLock(&SharedDataLock, &OriginalIrql);
// some code, which works with shared data
PVOID data = GetProcessSharedData(ProcessId);
NT_ASSERT("GetProcessSharedData() must always return shared data.", data);
PEPROCESS Process = NULL;
// next we need to get process image name
status = PsLookupProcessByProcessId(
ProcessId,
&Process
);
if ( !NT_SUCCESS( status ) )
{
goto LOCK_RELEASE;
}
PUNICODE_STRING ProcessImage = NULL;
status = GetProcessImagename(Process, &ProcessImage);
if ( !NT_SUCCESS( status ) )
{
goto PROCESS_LINK_DEREF;
}
// generate some event for our log
GenerateEvent( ProcessImage, data );
PROCESS_LINK_DEREF:
ObDereferenceObject(Process);
LOCK_RELEASE: // release lock
KeReleaseSpinLock(&SharedDataLock, OriginalIrql);
return status;
}
, , , . , .
?
PsLookupProcessByProcessId()
– : IRQL <= APC_LEVEL.
, BSOD IRQL_NOT_LESS_OR_EQUAL.
, . , , IRQL , .
, — :
KSPIN_LOCK SharedDataLock;
VOID SetIrql(_In_ KIRQL Irql)
{
if ( KeGetCurrentIrql() > Irql )
KeLowerIrql(Irql);
else if ( KeGetCurrentIrql() < Irql )
KzRaiseIrql(Irql);
}
NTSTATUS SomeFunction(_In_ HANDLE ProcessId)
{
KIRQL OriginalIrql;
NTSTATUS status = STATUS_UNSUCCESSFUL;
// lock shared data access
KeAcquireSpinLock(&SharedDataLock, &OriginalIrql);
// some code, which works with shared data
PVOID data = GetProcessSharedData(ProcessId);
NT_ASSERT("GetProcessSharedData() must always return shared data.", data);
SetIrql(APC_LEVEL);
PEPROCESS Process = NULL;
// next we need to get process image name
status = PsLookupProcessByProcessId(
ProcessId,
&Process
);
SetIrql(DISPATCH_LEVEL);
if ( !NT_SUCCESS( status ) )
{
goto LOCK_RELEASE;
}
PUNICODE_STRING ProcessImage = NULL;
status = GetProcessImagename(Process, &ProcessImage);
if ( !NT_SUCCESS( status ) )
{
goto PROCESS_LINK_DEREF;
}
// generate some event for our log
GenerateEvent( ProcessImage, data );
PROCESS_LINK_DEREF:
ObDereferenceObject(Process);
LOCK_RELEASE:
// release lock
KeReleaseSpinLock(&SharedDataLock, OriginalIrql);
return status;
}
, . , . , , 1 1000 , , , .
, :
« IRQL , , !»
:
- IRQL = APC_LEVEL, . IRQL DISPATCH_LEVEL, APC_LEVEL, .
, , :
KSPIN_LOCK SharedDataLock;
_IRQL_requires_max_(APC_LEVEL)
NTSTATUS SomeFunction(_In_ HANDLE ProcessId)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
PEPROCESS Process = NULL;
// next we need to get process image name
status = PsLookupProcessByProcessId(
ProcessId,
&Process
);
if ( !NT_SUCCESS( status ) )
{
goto EXIT_ROUTINE;
}
PUNICODE_STRING ProcessImage = NULL;
status = GetProcessImagename(Process, &ProcessImage);
if ( !NT_SUCCESS( status ) )
{
goto PROCESS_LINK_DEREF;
}
// lock shared data access
KeAcquireSpinLock(&SharedDataLock, &OriginalIrql);
// some code, which works with shared data
PVOID data = GetProcessSharedData(ProcessId);
NT_ASSERT("GetProcessSharedData() must always return shared data.", data);
// generate some event for our log
GenerateEvent( ProcessImage, data );
// release lock
KeReleaseSpinLock(&SharedDataLock, OriginalIrql);
PROCESS_LINK_DEREF:
ObDereferenceObject(Process);
EXIT_ROUTINE:
return status;
}
SetIrql() 2- , , .. , .
, SAL, :
Microsoft whitepaper( ) , :
MSDN Managing Hardware Priorities
, - - - Api, IRQL, WorkItem’. , .