From 0a648b272c197b4bc12aabd2ace11a23dbb409cf Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Fri, 24 Aug 2018 23:08:52 -0500 Subject: [PATCH] ntoskrnl.exe/tests: Add basic tests for ZwLoadDriver()/ZwUnloadDriver(). Signed-off-by: Zebediah Figura Signed-off-by: Alexandre Julliard --- dlls/ntoskrnl.exe/tests/Makefile.in | 4 ++ dlls/ntoskrnl.exe/tests/driver.c | 44 ++++++++++++++++ dlls/ntoskrnl.exe/tests/driver.h | 1 + dlls/ntoskrnl.exe/tests/driver2.c | 45 ++++++++++++++++ dlls/ntoskrnl.exe/tests/driver2.spec | 1 + dlls/ntoskrnl.exe/tests/ntoskrnl.c | 77 ++++++++++++++++++++-------- 6 files changed, 151 insertions(+), 21 deletions(-) create mode 100644 dlls/ntoskrnl.exe/tests/driver2.c create mode 100644 dlls/ntoskrnl.exe/tests/driver2.spec diff --git a/dlls/ntoskrnl.exe/tests/Makefile.in b/dlls/ntoskrnl.exe/tests/Makefile.in index 6a427ca429f..fae11bb7031 100644 --- a/dlls/ntoskrnl.exe/tests/Makefile.in +++ b/dlls/ntoskrnl.exe/tests/Makefile.in @@ -3,8 +3,12 @@ IMPORTS = advapi32 driver_IMPORTS = winecrt0 ntoskrnl driver_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native +driver2_IMPORTS = winecrt0 ntoskrnl +driver2_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native SOURCES = \ driver.c \ driver.spec \ + driver2.c \ + driver2.spec \ ntoskrnl.c diff --git a/dlls/ntoskrnl.exe/tests/driver.c b/dlls/ntoskrnl.exe/tests/driver.c index cde78e5d780..d424396d4c1 100644 --- a/dlls/ntoskrnl.exe/tests/driver.c +++ b/dlls/ntoskrnl.exe/tests/driver.c @@ -187,6 +187,29 @@ static void test_init_funcs(void) ok(timer2.Header.SignalState == 0, "got: %u\n", timer2.Header.SignalState); } +static const WCHAR driver2_path[] = { + '\\','R','e','g','i','s','t','r','y', + '\\','M','a','c','h','i','n','e', + '\\','S','y','s','t','e','m', + '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t', + '\\','S','e','r','v','i','c','e','s', + '\\','W','i','n','e','T','e','s','t','D','r','i','v','e','r','2',0 +}; + +static void test_load_driver(void) +{ + UNICODE_STRING name; + NTSTATUS ret; + + RtlInitUnicodeString(&name, driver2_path); + + ret = ZwLoadDriver(&name); + ok(!ret, "got %#x\n", ret); + + ret = ZwUnloadDriver(&name); + ok(!ret, "got %#x\n", ret); +} + static NTSTATUS main_test(IRP *irp, IO_STACK_LOCATION *stack, ULONG_PTR *info) { ULONG length = stack->Parameters.DeviceIoControl.OutputBufferLength; @@ -213,6 +236,7 @@ static NTSTATUS main_test(IRP *irp, IO_STACK_LOCATION *stack, ULONG_PTR *info) test_currentprocess(); test_mdl_map(); test_init_funcs(); + test_load_driver(); /* print process report */ if (test_input->winetest_debug) @@ -245,6 +269,23 @@ static NTSTATUS test_basic_ioctl(IRP *irp, IO_STACK_LOCATION *stack, ULONG_PTR * return STATUS_SUCCESS; } +static NTSTATUS test_load_driver_ioctl(IRP *irp, IO_STACK_LOCATION *stack, ULONG_PTR *info) +{ + BOOL *load = irp->AssociatedIrp.SystemBuffer; + UNICODE_STRING name; + + if (!load) + return STATUS_ACCESS_VIOLATION; + + *info = 0; + + RtlInitUnicodeString(&name, driver2_path); + if (*load) + return ZwLoadDriver(&name); + else + return ZwUnloadDriver(&name); +} + static NTSTATUS WINAPI driver_Create(DEVICE_OBJECT *device, IRP *irp) { irp->IoStatus.Status = STATUS_SUCCESS; @@ -265,6 +306,9 @@ static NTSTATUS WINAPI driver_IoControl(DEVICE_OBJECT *device, IRP *irp) case IOCTL_WINETEST_MAIN_TEST: status = main_test(irp, stack, &irp->IoStatus.Information); break; + case IOCTL_WINETEST_LOAD_DRIVER: + status = test_load_driver_ioctl(irp, stack, &irp->IoStatus.Information); + break; default: break; } diff --git a/dlls/ntoskrnl.exe/tests/driver.h b/dlls/ntoskrnl.exe/tests/driver.h index b254d44c8d2..6a4179ed003 100644 --- a/dlls/ntoskrnl.exe/tests/driver.h +++ b/dlls/ntoskrnl.exe/tests/driver.h @@ -24,6 +24,7 @@ /* All custom IOCTLs need to have a function value >= 0x800. */ #define IOCTL_WINETEST_BASIC_IOCTL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_WINETEST_MAIN_TEST CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_WINETEST_LOAD_DRIVER CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS) static const char teststr[] = "Wine is not an emulator"; diff --git a/dlls/ntoskrnl.exe/tests/driver2.c b/dlls/ntoskrnl.exe/tests/driver2.c new file mode 100644 index 00000000000..c648ec60ffc --- /dev/null +++ b/dlls/ntoskrnl.exe/tests/driver2.c @@ -0,0 +1,45 @@ +/* + * Second driver loaded by driver.c + * + * Copyright 2018 Zebediah Figura + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" +#include "winternl.h" +#include "winioctl.h" +#include "ddk/wdm.h" + +#include "driver.h" + +static void WINAPI driver_Unload(DRIVER_OBJECT *driver) +{ + DbgPrint("unloading driver2\n"); +} + +NTSTATUS WINAPI DriverEntry(DRIVER_OBJECT *driver, UNICODE_STRING *registry) +{ + DbgPrint("loading driver2\n"); + + driver->DriverUnload = driver_Unload; + + return STATUS_SUCCESS; +} diff --git a/dlls/ntoskrnl.exe/tests/driver2.spec b/dlls/ntoskrnl.exe/tests/driver2.spec new file mode 100644 index 00000000000..ad33444716a --- /dev/null +++ b/dlls/ntoskrnl.exe/tests/driver2.spec @@ -0,0 +1 @@ +# nothing here yet diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c index 40de760dead..73f0e85a518 100644 --- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c @@ -30,9 +30,6 @@ #include "driver.h" -static const char driver_name[] = "WineTestDriver"; -static const char device_path[] = "\\\\.\\WineTestDriver"; - static HANDLE device; static BOOL (WINAPI *pRtlDosPathNameToNtPathName_U)( LPCWSTR, PUNICODE_STRING, PWSTR*, CURDIR* ); @@ -80,11 +77,9 @@ static void unload_driver(SC_HANDLE service) CloseServiceHandle(service); } -static SC_HANDLE load_driver(char *filename) +static SC_HANDLE load_driver(char *filename, const char *resname, const char *driver_name) { SC_HANDLE manager, service; - SERVICE_STATUS status; - BOOL ret; manager = OpenSCManagerA(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (!manager && GetLastError() == ERROR_ACCESS_DENIED) @@ -94,12 +89,11 @@ static SC_HANDLE load_driver(char *filename) } ok(!!manager, "OpenSCManager failed\n"); - /* before we start with the actual tests, make sure to terminate - * any old wine test drivers. */ + /* stop any old drivers running under this name */ service = OpenServiceA(manager, driver_name, SERVICE_ALL_ACCESS); if (service) unload_driver(service); - load_resource("driver.dll", filename); + load_resource(resname, filename); trace("Trying to load driver %s\n", filename); service = CreateServiceA(manager, driver_name, driver_name, @@ -107,7 +101,15 @@ static SC_HANDLE load_driver(char *filename) SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, filename, NULL, NULL, NULL, NULL, NULL); ok(!!service, "CreateService failed: %u\n", GetLastError()); + CloseServiceHandle(manager); + return service; +} + +static BOOL start_driver(HANDLE service) +{ + SERVICE_STATUS status; + BOOL ret; SetLastError(0xdeadbeef); ret = StartServiceA(service, 0, NULL); @@ -117,8 +119,7 @@ static SC_HANDLE load_driver(char *filename) skip("Failed to start service; probably your machine doesn't accept unsigned drivers.\n"); DeleteService(service); CloseServiceHandle(service); - DeleteFileA(filename); - return NULL; + return FALSE; } ok(ret, "StartService failed: %u\n", GetLastError()); @@ -134,10 +135,7 @@ static SC_HANDLE load_driver(char *filename) ok(status.dwCurrentState == SERVICE_RUNNING, "expected SERVICE_RUNNING, got %d\n", status.dwCurrentState); - device = CreateFileA(device_path, 0, 0, NULL, OPEN_EXISTING, 0, NULL); - ok(device != INVALID_HANDLE_VALUE, "failed to open device: %u\n", GetLastError()); - - return service; + return TRUE; } static void main_test(void) @@ -194,22 +192,59 @@ static void test_basic_ioctl(void) ok(!strcmp(buf, teststr), "got '%s'\n", buf); } +static void test_load_driver(SC_HANDLE service) +{ + SERVICE_STATUS status; + BOOL load, res; + DWORD sz; + + res = QueryServiceStatus(service, &status); + ok(res, "QueryServiceStatusEx failed: %u\n", GetLastError()); + ok(status.dwCurrentState == SERVICE_STOPPED, "got state %#x\n", status.dwCurrentState); + + load = TRUE; + res = DeviceIoControl(device, IOCTL_WINETEST_LOAD_DRIVER, &load, sizeof(load), NULL, 0, &sz, NULL); + ok(res, "DeviceIoControl failed: %u\n", GetLastError()); + + res = QueryServiceStatus(service, &status); + ok(res, "QueryServiceStatusEx failed: %u\n", GetLastError()); + ok(status.dwCurrentState == SERVICE_RUNNING, "got state %#x\n", status.dwCurrentState); + + load = FALSE; + res = DeviceIoControl(device, IOCTL_WINETEST_LOAD_DRIVER, &load, sizeof(load), NULL, 0, &sz, NULL); + ok(res, "DeviceIoControl failed: %u\n", GetLastError()); + + res = QueryServiceStatus(service, &status); + ok(res, "QueryServiceStatusEx failed: %u\n", GetLastError()); + ok(status.dwCurrentState == SERVICE_STOPPED, "got state %#x\n", status.dwCurrentState); +} + START_TEST(ntoskrnl) { - char filename[MAX_PATH]; - SC_HANDLE service; - BOOL ret; + char filename[MAX_PATH], filename2[MAX_PATH]; + SC_HANDLE service, service2; HMODULE hntdll = GetModuleHandleA("ntdll.dll"); pRtlDosPathNameToNtPathName_U = (void *)GetProcAddress(hntdll, "RtlDosPathNameToNtPathName_U"); - if (!(service = load_driver(filename))) + if (!(service = load_driver(filename, "driver.dll", "WineTestDriver"))) return; + if (!start_driver(service)) + { + DeleteFileA(filename); + return; + } + service2 = load_driver(filename2, "driver2.dll", "WineTestDriver2"); + + device = CreateFileA("\\\\.\\WineTestDriver", 0, 0, NULL, OPEN_EXISTING, 0, NULL); + ok(device != INVALID_HANDLE_VALUE, "failed to open device: %u\n", GetLastError()); test_basic_ioctl(); main_test(); + test_load_driver(service2); + unload_driver(service2); unload_driver(service); - ret = DeleteFileA(filename); - ok(ret, "DeleteFile failed: %u\n", GetLastError()); + ok(DeleteFileA(filename), "DeleteFile failed: %u\n", GetLastError()); + ok(DeleteFileA(filename2), "DeleteFile failed: %u\n", GetLastError()); }