Index: modules/rostests/kmtests/CMakeLists.txt =================================================================== --- modules/rostests/kmtests/CMakeLists.txt (revision 56722) +++ modules/rostests/kmtests/CMakeLists.txt (working copy) @@ -24,6 +24,7 @@ example/Example.c example/KernelType.c + ntos_ex/ExCallback.c ntos_ex/ExDoubleList.c ntos_ex/ExFastMutex.c ntos_ex/ExHardError.c @@ -50,6 +51,7 @@ ntos_ob/ObReference.c ntos_ob/ObType.c ntos_ob/ObTypes.c + ntos_ps/PsNotify.c ${COMMON_SOURCE} kmtest_drv/kmtest_drv.rc) Index: modules/rostests/kmtests/include/kmt_test.h =================================================================== --- modules/rostests/kmtests/include/kmt_test.h (revision 56730) +++ modules/rostests/kmtests/include/kmt_test.h (working copy) @@ -173,6 +173,20 @@ #define MILLISECOND (1000 * MICROSECOND) #define SECOND (1000 * MILLISECOND) +#define KmtInvalidPointer ((PVOID)0x0123456789ABCDEFULL) + +#define KmtStartSeh() \ + ExceptionStatus = STATUS_SUCCESS; \ + _SEH2_TRY \ + { +#define KmtEndSeh(ExpectedStatus) \ + } \ + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) \ + { \ + ExceptionStatus = _SEH2_GetExceptionCode(); \ + } _SEH2_END; \ + ok_eq_hex(ExceptionStatus, ExpectedStatus) + #if defined KMT_DEFINE_TEST_FUNCTIONS #if defined KMT_KERNEL_MODE Index: modules/rostests/kmtests/kmtest_drv/testlist.c =================================================================== --- modules/rostests/kmtests/kmtest_drv/testlist.c (revision 56722) +++ modules/rostests/kmtests/kmtest_drv/testlist.c (working copy) @@ -8,6 +8,7 @@ #include KMT_TESTFUNC Test_Example; +KMT_TESTFUNC Test_ExCallback; KMT_TESTFUNC Test_ExDoubleList; KMT_TESTFUNC Test_ExFastMutex; KMT_TESTFUNC Test_ExHardError; @@ -37,6 +38,7 @@ KMT_TESTFUNC Test_ObTypeClean; KMT_TESTFUNC Test_ObTypeNoClean; KMT_TESTFUNC Test_ObTypes; +KMT_TESTFUNC Test_PsNotify; KMT_TESTFUNC Test_RtlAvlTree; KMT_TESTFUNC Test_RtlException; KMT_TESTFUNC Test_RtlMemory; @@ -44,6 +46,7 @@ const KMT_TEST TestList[] = { + { "ExCallback", Test_ExCallback }, { "ExDoubleList", Test_ExDoubleList }, { "ExFastMutex", Test_ExFastMutex }, { "ExHardError", Test_ExHardError }, @@ -74,6 +77,7 @@ { "-ObTypeClean", Test_ObTypeClean }, { "-ObTypeNoClean", Test_ObTypeNoClean }, { "ObTypes", Test_ObTypes }, + { "PsNotify", Test_PsNotify }, { "RtlAvlTreeKM", Test_RtlAvlTree }, { "RtlExceptionKM", Test_RtlException }, { "RtlMemoryKM", Test_RtlMemory }, Index: modules/rostests/kmtests/ntos_ex/ExCallback.c =================================================================== --- modules/rostests/kmtests/ntos_ex/ExCallback.c (revision 0) +++ modules/rostests/kmtests/ntos_ex/ExCallback.c (working copy) @@ -0,0 +1,154 @@ +/* + * PROJECT: ReactOS kernel-mode tests + * LICENSE: GPLv2+ - See COPYING in the top level directory + * PURPOSE: Kernel-Mode Test Suite Executive Callback test + * PROGRAMMER: Thomas Faber + */ + +#include + +//#define NDEBUG +#include + +static +PEX_CALLBACK_ROUTINE_BLOCK +(NTAPI +*ExAllocateCallBack)( + IN PEX_CALLBACK_FUNCTION Function, + IN PVOID Context +) +//= (PVOID)0x809af1f4 // 2003 sp1 x86 +//= (PVOID)0x80a7f04a // 2003 sp1 x86 checked +; + +static +VOID +(NTAPI +*ExFreeCallBack)( + IN PEX_CALLBACK_ROUTINE_BLOCK CallbackBlock +) +//= (PVOID)0x80918bb5 // 2003 sp1 x86 +//= (PVOID)0x80a355f0 // 2003 sp1 x86 checked +; + +static INT CallbackArgument1; +static INT CallbackArgument2; + +static +NTSTATUS +NTAPI +ExCallbackFunction( + IN PVOID CallbackContext, + IN PVOID Argument1 OPTIONAL, + IN PVOID Argument2 OPTIONAL) +{ + ok(0, "\n"); + return STATUS_SUCCESS; +} + +static +VOID +TestPrivateFunctions(VOID) +{ + UNICODE_STRING ExAllocateCallBackName = RTL_CONSTANT_STRING(L"ExAllocateCallBack"); + UNICODE_STRING ExFreeCallBackName = RTL_CONSTANT_STRING(L"ExFreeCallBack"); + PEX_CALLBACK_ROUTINE_BLOCK CallbackBlock; + INT CallbackContext; + + if (!ExAllocateCallBack) + ExAllocateCallBack = MmGetSystemRoutineAddress(&ExAllocateCallBackName); + if (!ExFreeCallBack) + ExFreeCallBack = MmGetSystemRoutineAddress(&ExFreeCallBackName); + + if (skip(ExAllocateCallBack && ExFreeCallBack, "ExAllocateCallBack and/or ExFreeCallBack unavailable\n")) + return; + + CallbackBlock = ExAllocateCallBack(ExCallbackFunction, &CallbackContext); + ok(CallbackBlock != NULL, "CallbackBlock = NULL\n"); + + if (skip(CallbackBlock != NULL, "Allocating callback failed\n")) + return; + + ok_eq_pointer(CallbackBlock->Function, ExCallbackFunction); + ok_eq_pointer(CallbackBlock->Context, &CallbackContext); + ok_eq_hex(KmtGetPoolTag(CallbackBlock), 'brbC'); + + ExFreeCallBack(CallbackBlock); +} + +static +VOID +NTAPI +CallbackFunction( + IN PVOID CallbackContext, + IN PVOID Argument1, + IN PVOID Argument2) +{ + INT *InvocationCount = CallbackContext; + + ok_irql(PASSIVE_LEVEL); + + (*InvocationCount)++; + ok_eq_pointer(Argument1, &CallbackArgument1); + ok_eq_pointer(Argument2, &CallbackArgument2); +} + +START_TEST(ExCallback) +{ + NTSTATUS Status; + PCALLBACK_OBJECT CallbackObject; + OBJECT_ATTRIBUTES ObjectAttributes; + UNICODE_STRING CallbackName = RTL_CONSTANT_STRING(L"\\Callback\\KmtestExCallbackTestCallback"); + PVOID CallbackRegistration; + INT InvocationCount = 0; + + TestPrivateFunctions(); + + /* TODO: Parameter tests */ + /* TODO: Test the three predefined callbacks */ + /* TODO: Test opening an existing callback */ + /* TODO: Test AllowMultipleCallbacks */ + /* TODO: Test calling multiple callbacks */ + /* TODO: Test registering the same function twice */ + /* TODO: Test callback object fields */ + InitializeObjectAttributes(&ObjectAttributes, + &CallbackName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + + CallbackObject = KmtInvalidPointer; + Status = ExCreateCallback(&CallbackObject, + &ObjectAttributes, + TRUE, + TRUE); + ok_eq_hex(Status, STATUS_SUCCESS); + ok(CallbackObject != NULL && CallbackObject != KmtInvalidPointer, + "CallbackObject = %p", CallbackObject); + + if (skip(NT_SUCCESS(Status), "Creating callback failed\n")) + return; + + CallbackRegistration = ExRegisterCallback(CallbackObject, + CallbackFunction, + &InvocationCount); + ok(CallbackRegistration != NULL, "CallbackRegistration = NULL\n"); + + if (!skip(CallbackRegistration != NULL, "Registering callback failed\n")) + { + ok_eq_hex(KmtGetPoolTag(CallbackRegistration), 'eRBC'); + ok_eq_int(InvocationCount, 0); + ExNotifyCallback(CallbackObject, + &CallbackArgument1, + &CallbackArgument2); + ok_eq_int(InvocationCount, 1); + ExNotifyCallback(CallbackObject, + &CallbackArgument1, + &CallbackArgument2); + ok_eq_int(InvocationCount, 2); + + ExUnregisterCallback(CallbackRegistration); + } + + ObDereferenceObject(CallbackObject); +} Index: modules/rostests/kmtests/ntos_ps/PsNotify.c =================================================================== --- modules/rostests/kmtests/ntos_ps/PsNotify.c (revision 0) +++ modules/rostests/kmtests/ntos_ps/PsNotify.c (working copy) @@ -0,0 +1,168 @@ +/* + * PROJECT: ReactOS kernel-mode tests + * LICENSE: GPLv2+ - See COPYING in the top level directory + * PURPOSE: Kernel-Mode Test Suite Process Notification Routines test + * PROGRAMMER: Thomas Faber + */ + +#include + +//#define NDEBUG +#include + +static +VOID +NTAPI +CreateProcessNotifyRoutine( + IN HANDLE ParentId, + IN HANDLE ProcessId, + IN BOOLEAN Create) +{ + ok_irql(PASSIVE_LEVEL); + if (!Create) + ok_eq_pointer(ProcessId, PsGetCurrentProcessId()); + else + ok(ProcessId != PsGetCurrentProcessId(), + "ProcessId %p equals current\n", ProcessId); + DPRINT("%s(%p, %p, %d)\n", __FUNCTION__, ParentId, ProcessId, Create); +} + +static +VOID +TestNotifyCreateProcess(VOID) +{ + NTSTATUS Status; + LARGE_INTEGER Interval; + + Status = PsSetCreateProcessNotifyRoutine(NULL, TRUE); + ok_eq_hex(Status, STATUS_PROCEDURE_NOT_FOUND); + + Status = PsSetCreateProcessNotifyRoutine(NULL, FALSE); + ok_eq_hex(Status, STATUS_SUCCESS); + + Status = PsSetCreateProcessNotifyRoutine(NULL, TRUE); + ok_eq_hex(Status, STATUS_SUCCESS); + + Status = PsSetCreateProcessNotifyRoutine(CreateProcessNotifyRoutine, TRUE); + ok_eq_hex(Status, STATUS_PROCEDURE_NOT_FOUND); + + Status = PsSetCreateProcessNotifyRoutine(CreateProcessNotifyRoutine, FALSE); + ok_eq_hex(Status, STATUS_SUCCESS); + + DPRINT1("Process\n"); + Interval.QuadPart = -5 * SECOND; + (VOID)KeDelayExecutionThread(KernelMode, FALSE, &Interval); + + Status = PsSetCreateProcessNotifyRoutine(CreateProcessNotifyRoutine, TRUE); + ok_eq_hex(Status, STATUS_SUCCESS); + + /* TODO: register the same routine twice */ + /* TODO: register so many notifications that it fails */ +} + +static +VOID +NTAPI +CreateThreadNotifyRoutine( + IN HANDLE ProcessId, + IN HANDLE ThreadId, + IN BOOLEAN Create) +{ + ok_irql(PASSIVE_LEVEL); + if (!Create) + { + ok_eq_pointer(ProcessId, PsGetCurrentProcessId()); + ok_eq_pointer(ThreadId, PsGetCurrentThreadId()); + } + else + { + ok(ThreadId != PsGetCurrentThreadId(), + "ThreadId %p equals current\n", ThreadId); + } + DPRINT("%s(%p, %p, %d)\n", __FUNCTION__, ProcessId, ThreadId, Create); +} + +static +VOID +TestNotifyCreateThread(VOID) +{ + NTSTATUS Status; + LARGE_INTEGER Interval; + + Status = PsRemoveCreateThreadNotifyRoutine(NULL); + ok_eq_hex(Status, STATUS_PROCEDURE_NOT_FOUND); + + Status = PsSetCreateThreadNotifyRoutine(NULL); + ok_eq_hex(Status, STATUS_SUCCESS); + + Status = PsRemoveCreateThreadNotifyRoutine(NULL); + ok_eq_hex(Status, STATUS_SUCCESS); + + Status = PsRemoveCreateThreadNotifyRoutine(CreateThreadNotifyRoutine); + ok_eq_hex(Status, STATUS_PROCEDURE_NOT_FOUND); + + Status = PsSetCreateThreadNotifyRoutine(CreateThreadNotifyRoutine); + ok_eq_hex(Status, STATUS_SUCCESS); + + DPRINT1("Thread\n"); + Interval.QuadPart = -5 * SECOND; + (VOID)KeDelayExecutionThread(KernelMode, FALSE, &Interval); + + Status = PsRemoveCreateThreadNotifyRoutine(CreateThreadNotifyRoutine); + ok_eq_hex(Status, STATUS_SUCCESS); + + /* TODO: register the same routine twice */ + /* TODO: register so many notifications that it fails */ +} + +static +VOID +NTAPI +LoadImageNotifyRoutine( + IN PUNICODE_STRING FullImageName OPTIONAL, + IN HANDLE ProcessId, + IN PIMAGE_INFO ImageInfo) +{ + ok_irql(PASSIVE_LEVEL); + DPRINT("%s('%wZ', %p, %p)\n", __FUNCTION__, FullImageName, ProcessId, ImageInfo); +} + +static +VOID +TestNotifyLoadImage(VOID) +{ + NTSTATUS Status; + LARGE_INTEGER Interval; + + Status = PsRemoveLoadImageNotifyRoutine(NULL); + ok_eq_hex(Status, STATUS_PROCEDURE_NOT_FOUND); + + Status = PsSetLoadImageNotifyRoutine(NULL); + ok_eq_hex(Status, STATUS_SUCCESS); + + Status = PsRemoveLoadImageNotifyRoutine(NULL); + ok_eq_hex(Status, STATUS_SUCCESS); + + Status = PsRemoveLoadImageNotifyRoutine(LoadImageNotifyRoutine); + ok_eq_hex(Status, STATUS_PROCEDURE_NOT_FOUND); + + Status = PsSetLoadImageNotifyRoutine(LoadImageNotifyRoutine); + ok_eq_hex(Status, STATUS_SUCCESS); + + DPRINT1("Load\n"); + Interval.QuadPart = -5 * SECOND; + (VOID)KeDelayExecutionThread(KernelMode, FALSE, &Interval); + + Status = PsRemoveLoadImageNotifyRoutine(LoadImageNotifyRoutine); + ok_eq_hex(Status, STATUS_SUCCESS); + + /* TODO: register the same routine twice */ + /* TODO: register so many notifications that it fails */ +} + +START_TEST(PsNotify) +{ + TestNotifyCreateProcess(); + TestNotifyCreateThread(); + TestNotifyLoadImage(); +} Index: ntoskrnl/ex/callback.c =================================================================== --- ntoskrnl/ex/callback.c (revision 56722) +++ ntoskrnl/ex/callback.c (working copy) @@ -59,7 +59,7 @@ /* Allocate a callback */ CallbackBlock = ExAllocatePoolWithTag(PagedPool, sizeof(EX_CALLBACK_ROUTINE_BLOCK), - 'CbRb'); + TAG_CALLBACK_ROUTINE_BLOCK); if (CallbackBlock) { /* Initialize it */ @@ -77,7 +77,7 @@ ExFreeCallBack(IN PEX_CALLBACK_ROUTINE_BLOCK CallbackBlock) { /* Just free it from memory */ - ExFreePoolWithTag(CallbackBlock, CALLBACK_TAG); + ExFreePoolWithTag(CallbackBlock, TAG_CALLBACK_ROUTINE_BLOCK); } VOID @@ -124,7 +124,7 @@ EX_FAST_REF OldValue; ULONG_PTR Count; PEX_CALLBACK_ROUTINE_BLOCK CallbackBlock; - + /* Acquire a reference */ OldValue = ExAcquireFastReference(&CallBack->RoutineBlock); Count = ExGetCountFastReference(OldValue); @@ -140,10 +140,10 @@ ASSERT(FALSE); return NULL; } - + /* Get the callback block */ CallbackBlock = ExGetObjectFastReference(OldValue); - + /* Check if this is the last reference */ if (Count == 1) { @@ -567,7 +567,7 @@ /* Allocate memory for the structure */ CallbackRegistration = ExAllocatePoolWithTag(NonPagedPool, sizeof(CALLBACK_REGISTRATION), - CALLBACK_TAG); + TAG_CALLBACK_REGISTRATION); if (!CallbackRegistration) { /* Dereference and fail */ @@ -602,7 +602,7 @@ KeReleaseSpinLock(&CallbackObject->Lock, OldIrql); /* Free the registration */ - ExFreePoolWithTag(CallbackRegistration, CALLBACK_TAG); + ExFreePoolWithTag(CallbackRegistration, TAG_CALLBACK_REGISTRATION); CallbackRegistration = NULL; /* Dereference the object */ @@ -676,7 +676,7 @@ KeReleaseSpinLock(&CallbackObject->Lock, OldIrql); /* Delete this registration */ - ExFreePoolWithTag(CallbackRegistration, CALLBACK_TAG); + ExFreePoolWithTag(CallbackRegistration, TAG_CALLBACK_REGISTRATION); /* Remove the reference */ ObDereferenceObject(CallbackObject); Index: ntoskrnl/include/internal/tag.h =================================================================== --- ntoskrnl/include/internal/tag.h (revision 56722) +++ ntoskrnl/include/internal/tag.h (working copy) @@ -5,8 +5,9 @@ #define TAG_BCB ' BCB' #define TAG_IBCB 'BCBi' -/* formely located in include/callback.h */ -#define CALLBACK_TAG 'KBLC' +/* Executive Callbacks */ +#define TAG_CALLBACK_ROUTINE_BLOCK 'brbC' +#define TAG_CALLBACK_REGISTRATION 'eRBC' /* formely located in dbg/dbgkobj.c */ #define TAG_DEBUG_EVENT 'EgbD' Index: ntoskrnl/ntoskrnl.spec =================================================================== --- ntoskrnl/ntoskrnl.spec (revision 56722) +++ ntoskrnl/ntoskrnl.spec (working copy) @@ -64,6 +64,7 @@ @ stdcall ExAcquireSharedStarveExclusive(ptr long) @ stdcall ExAcquireSharedWaitForExclusive(ptr long) @ stdcall ExAllocateCacheAwareRundownProtection(long long) +@ stdcall ExAllocateCallBack(ptr ptr) @ stdcall ExAllocateFromPagedLookasideList(ptr) ExiAllocateFromPagedLookasideList @ stdcall ExAllocatePool(long long) @ stdcall ExAllocatePoolWithQuota(long long) @@ -85,6 +86,7 @@ @ extern ExEventObjectType _ExEventObjectType @ stdcall ExExtendZone(ptr ptr long) @ stdcall ExFreeCacheAwareRundownProtection(ptr) +@ stdcall ExFreeCallBack(ptr) @ stdcall ExFreePool(ptr) @ stdcall ExFreePoolWithTag(ptr long) @ stdcall ExFreeToPagedLookasideList(ptr ptr) ExiFreeToPagedLookasideList