#include <ddk/ntddk.h>
#include "kmtest.h"
+#define NDEBUG
+#include <debug.h>
+
LONG successes;
LONG failures;
+LONG skipped;
tls_data glob_data;
/* PRIVATE FUNCTIONS ***********************************************************/
{
successes = 0;
failures = 0;
+ skipped = 0;
}
VOID
-FinishTest(LPSTR TestName)
+FinishTest(HANDLE KeyHandle, LPWSTR TestName)
{
- DbgPrint("Test %s finished with %d succeses and %d failures\n", TestName, successes, failures);
+ WCHAR KeyName[100];
+ LONG total = successes + failures;
+ UNICODE_STRING KeyNameU;
+
+ wcscpy(KeyName, TestName);
+ wcscat(KeyName, L"SuccessCount");
+ RtlInitUnicodeString(&KeyNameU, KeyName);
+
+ ZwSetValueKey(KeyHandle,
+ &KeyNameU,
+ 0,
+ REG_DWORD,
+ &successes,
+ sizeof(ULONG));
+
+ wcscpy(KeyName, TestName);
+ wcscat(KeyName, L"FailureCount");
+ RtlInitUnicodeString(&KeyNameU, KeyName);
+
+ ZwSetValueKey(KeyHandle,
+ &KeyNameU,
+ 0,
+ REG_DWORD,
+ &failures,
+ sizeof(ULONG));
+
+ wcscpy(KeyName, TestName);
+ wcscat(KeyName, L"TotalCount");
+ RtlInitUnicodeString(&KeyNameU, KeyName);
+
+ ZwSetValueKey(KeyHandle,
+ &KeyNameU,
+ 0,
+ REG_DWORD,
+ &total,
+ sizeof(ULONG));
+
+ wcscpy(KeyName, TestName);
+ wcscat(KeyName, L"SkipCount");
+ RtlInitUnicodeString(&KeyNameU, KeyName);
+
+ ZwSetValueKey(KeyHandle,
+ &KeyNameU,
+ 0,
+ REG_DWORD,
+ &skipped,
+ sizeof(ULONG));
+
+ DbgPrint("%S: %d test executed (0 marked as todo, %d failures), %d skipped.\n", TestName, total, failures, skipped);
}
void kmtest_set_location(const char* file, int line)
/* PUBLIC FUNCTIONS ***********************************************************/
+PWCHAR CreateLowerDeviceRegistryKey(PUNICODE_STRING RegistryPath, PWCHAR NewDriver);
+
/*
* Test Declarations
*/
-VOID NtoskrnlIoTests();
-VOID NtoskrnlObTest();
-VOID NtoskrnlExecutiveTests();
-VOID NtoskrnlPoolsTest();
+VOID RegisterDI_Test(HANDLE KeyHandle);
+VOID NtoskrnlIoMdlTest(HANDLE KeyHandle);
+VOID NtoskrnlIoIrpTest(HANDLE KeyHandle);
+VOID NtoskrnlObTest(HANDLE KeyHandle);
+VOID ExTimerTest(HANDLE KeyHandle);
+VOID PoolsTest(HANDLE KeyHandle);
+VOID PoolsCorruption(HANDLE KeyHandle);
+VOID KeStallTest(HANDLE KeyHandle);
+VOID DriverObjectTest(PDRIVER_OBJECT, int);
+VOID DeviceCreateDeleteTest(PDRIVER_OBJECT);
+VOID DeviceObjectTest(PDEVICE_OBJECT);
+BOOLEAN ZwLoadTest(PDRIVER_OBJECT, PUNICODE_STRING, PWCHAR);
+BOOLEAN ZwUnloadTest(PDRIVER_OBJECT, PUNICODE_STRING, PWCHAR);
+BOOLEAN DetachDeviceTest(PDEVICE_OBJECT);
+BOOLEAN AttachDeviceTest(PDEVICE_OBJECT, PWCHAR);
+VOID LowerDeviceKernelAPITest(PDEVICE_OBJECT, BOOLEAN);
+
+typedef enum {
+ TestStageExTimer = 0,
+ TestStageIoMdl,
+ TestStageIoDi,
+ TestStageIoIrp,
+ TestStageMmPoolTest,
+ TestStageMmPoolCorruption,
+ TestStageOb,
+ TestStageKeStall,
+ TestStageDrv,
+ TestStageMax
+} TEST_STAGE;
+
+/*
+ * KmtestDispatch
+ */
+NTSTATUS
+NTAPI
+KmtestDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
+
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ if (AttachDeviceObject)
+ {
+ IoSkipCurrentIrpStackLocation(Irp);
+ Status = IoCallDriver(AttachDeviceObject, Irp);
+ return Status;
+ }
+
+ Irp->IoStatus.Status = Status;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return Status;
+}
+
+/*
+ * KmtestCreateClose
+ */
+NTSTATUS
+NTAPI
+KmtestCreateClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ if (AttachDeviceObject)
+ {
+ IoSkipCurrentIrpStackLocation(Irp);
+ Status = IoCallDriver(AttachDeviceObject, Irp);
+ return Status;
+ }
+
+ /* Do DriverObject Test with Driver Initialized */
+ DriverObjectTest(DeviceObject->DriverObject, 1);
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information=0;
+
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_SUCCESS;
+}
+
+/*
+ * KmtestUnload
+ */
+VOID
+NTAPI
+KmtestUnload(IN PDRIVER_OBJECT DriverObject)
+{
+ UNICODE_STRING DosDeviceString;
+
+ if(AttachDeviceObject)
+ {
+ IoDetachDevice(AttachDeviceObject);
+ }
+
+ /* Do DriverObject Test for Unload */
+ DriverObjectTest(DriverObject, 2);
+
+ if (MainDeviceObject)
+ {
+ RtlInitUnicodeString(&DosDeviceString, L"\\DosDevices\\Kmtest");
+ IoDeleteSymbolicLink(&DosDeviceString);
+
+ IoDeleteDevice(MainDeviceObject);
+ }
+}
+
+static
+PKEY_VALUE_PARTIAL_INFORMATION
+NTAPI
+ReadRegistryValue(HANDLE KeyHandle, PWCHAR ValueName)
+{
+ NTSTATUS Status;
+ PKEY_VALUE_PARTIAL_INFORMATION InformationBuffer = NULL;
+ ULONG AllocatedLength = 0, RequiredLength = 0;
+ UNICODE_STRING ValueNameU;
+
+ RtlInitUnicodeString(&ValueNameU, ValueName);
+
+ Status = ZwQueryValueKey(KeyHandle,
+ &ValueNameU,
+ KeyValuePartialInformation,
+ NULL,
+ 0,
+ &RequiredLength);
+ if (Status == STATUS_BUFFER_TOO_SMALL || Status == STATUS_BUFFER_OVERFLOW)
+ {
+ InformationBuffer = ExAllocatePool(PagedPool, RequiredLength);
+ AllocatedLength = RequiredLength;
+ if (!InformationBuffer) return NULL;
+
+ Status = ZwQueryValueKey(KeyHandle,
+ &ValueNameU,
+ KeyValuePartialInformation,
+ InformationBuffer,
+ AllocatedLength,
+ &RequiredLength);
+ }
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to read %S (0x%x)\n", ValueName, Status);
+ if (InformationBuffer != NULL)
+ ExFreePool(InformationBuffer);
+ return NULL;
+ }
+
+ return InformationBuffer;
+}
+
+static
+VOID
+RunKernelModeTest(PDRIVER_OBJECT DriverObject,
+ PUNICODE_STRING RegistryPath,
+ HANDLE KeyHandle,
+ TEST_STAGE Stage)
+{
+ UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"CurrentStage");
+ PWCHAR LowerDriverRegPath;
+
+ DPRINT1("Running stage %d test...\n", Stage);
+
+ ZwSetValueKey(KeyHandle,
+ &KeyName,
+ 0,
+ REG_DWORD,
+ &Stage,
+ sizeof(ULONG));
+
+ switch (Stage)
+ {
+ case TestStageExTimer:
+ ExTimerTest(KeyHandle);
+ break;
+
+ case TestStageIoMdl:
+ NtoskrnlIoMdlTest(KeyHandle);
+ break;
+
+ case TestStageIoDi:
+ RegisterDI_Test(KeyHandle);
+ break;
+
+ case TestStageIoIrp:
+ NtoskrnlIoIrpTest(KeyHandle);
+ break;
+
+ case TestStageMmPoolTest:
+ PoolsTest(KeyHandle);
+ break;
+
+ case TestStageMmPoolCorruption:
+ PoolsCorruption(KeyHandle);
+ break;
+
+ case TestStageOb:
+ NtoskrnlObTest(KeyHandle);
+ break;
+
+ case TestStageKeStall:
+ KeStallTest(KeyHandle);
+ break;
+
+ case TestStageDrv:
+ /* Start the tests for the driver routines */
+ StartTest();
+
+ /* Do DriverObject Test for Driver Entry */
+ DriverObjectTest(DriverObject, 0);
+
+ /* Create and delete device, on return MainDeviceObject has been created */
+ DeviceCreateDeleteTest(DriverObject);
+
+ /* Make sure a device object was created */
+ if (MainDeviceObject)
+ {
+ LowerDriverRegPath = CreateLowerDeviceRegistryKey(RegistryPath, L"kmtestassist");
+
+ if (LowerDriverRegPath)
+ {
+ /* Load driver test and load the lower driver */
+ if (ZwLoadTest(DriverObject, RegistryPath, LowerDriverRegPath))
+ {
+ AttachDeviceTest(MainDeviceObject, L"kmtestassists");
+ if (AttachDeviceObject)
+ {
+ LowerDeviceKernelAPITest(MainDeviceObject, FALSE);
+ }
+
+ /* Unload lower driver without detaching from its device */
+ ZwUnloadTest(DriverObject, RegistryPath, LowerDriverRegPath);
+ LowerDeviceKernelAPITest(MainDeviceObject, TRUE);
+ }
+ else
+ {
+ DbgPrint("Failed to load kmtestassist driver\n");
+ }
+ }
+ }
+
+ FinishTest(KeyHandle, L"DriverTest");
+ break;
+
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+}
/*
* DriverEntry
DriverEntry(PDRIVER_OBJECT DriverObject,
PUNICODE_STRING RegistryPath)
{
- DbgPrint("\n===============================================\nKernel Mode Regression Test driver starting...\n");
- //NtoskrnlExecutiveTests();
- //NtoskrnlIoDeviceInterface();
- NtoskrnlIoTests();
- //NtoskrnlObTest();
- //NtoskrnlPoolsTest();
+ int i;
+ NTSTATUS Status;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ UNICODE_STRING ParameterKeyName = RTL_CONSTANT_STRING(L"Parameters");
+ PKEY_VALUE_PARTIAL_INFORMATION KeyInfo;
+ PULONG KeyValue;
+ TEST_STAGE CurrentStage;
+ HANDLE DriverKeyHandle, ParameterKeyHandle;
+
+ DbgPrint("\n===============================================\n");
+ DbgPrint("Kernel Mode Regression Driver Test starting...\n");
+ DbgPrint("===============================================\n");
+
+ InitializeObjectAttributes(&ObjectAttributes,
+ RegistryPath,
+ OBJ_CASE_INSENSITIVE,
+ 0,
+ NULL);
+
+ Status = ZwOpenKey(&DriverKeyHandle,
+ KEY_CREATE_SUB_KEY | KEY_ENUMERATE_SUB_KEYS,
+ &ObjectAttributes);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to open %wZ\n", RegistryPath);
+ return Status;
+ }
+
+ InitializeObjectAttributes(&ObjectAttributes,
+ &ParameterKeyName,
+ OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
+ DriverKeyHandle,
+ NULL);
+ Status = ZwCreateKey(&ParameterKeyHandle,
+ KEY_SET_VALUE | KEY_QUERY_VALUE,
+ &ObjectAttributes,
+ 0,
+ NULL,
+ REG_OPTION_NON_VOLATILE,
+ NULL);
+ ZwClose(DriverKeyHandle);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to create %wZ\\%wZ\n", RegistryPath, &ParameterKeyName);
+ return Status;
+ }
+
+ KeyInfo = ReadRegistryValue(ParameterKeyHandle, L"CurrentStage");
+ if (KeyInfo)
+ {
+ if (KeyInfo->DataLength != sizeof(ULONG))
+ {
+ DPRINT1("Invalid data length for CurrentStage: %d\n", KeyInfo->DataLength);
+ ExFreePool(KeyInfo);
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ KeyValue = (PULONG)KeyInfo->Data;
+
+ if ((*KeyValue) + 1 < TestStageMax)
+ {
+ DPRINT1("Resuming testing after a crash at stage %d\n", (*KeyValue));
+
+ CurrentStage = (TEST_STAGE)((*KeyValue) + 1);
+ }
+ else
+ {
+ DPRINT1("Testing was completed on a previous boot\n");
+ ExFreePool(KeyInfo);
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ ExFreePool(KeyInfo);
+ }
+ else
+ {
+ DPRINT1("Starting a fresh test\n");
+ CurrentStage = (TEST_STAGE)0;
+ }
+
+ /* Run the tests */
+ while (CurrentStage < TestStageMax)
+ {
+ RunKernelModeTest(DriverObject,
+ RegistryPath,
+ ParameterKeyHandle,
+ CurrentStage);
+ CurrentStage++;
+ }
+
+ DPRINT1("Testing is complete!\n");
+ ZwClose(ParameterKeyHandle);
+
+ /* Set all MajorFunctions to NULL to verify that kernel fixes them */
+ for (i = 1; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
+ DriverObject->MajorFunction[i] = NULL;
+
+ /* Set necessary routines */
+ DriverObject->DriverUnload = KmtestUnload;
+ DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = KmtestDispatch;
+ DriverObject->MajorFunction[IRP_MJ_CREATE] = KmtestCreateClose;
+ DriverObject->MajorFunction[IRP_MJ_CLOSE] = KmtestCreateClose;
return STATUS_SUCCESS;
}