Signed-off-by: Zebediah Figura z.figura12@gmail.com --- In theory, we could just keep the section mapped for the driver's entire lifetime, and store the "failures" variable directly in the section. In practice, Windows panics when I try this. I suspect the reason is that memory mapped in one process (i.e. the system process) can't be safely accessed in another process (i.e. a user context), even if the section handle is created with OBJ_KERNEL_HANDLE.
dlls/ntoskrnl.exe/tests/driver.c | 7 +----- dlls/ntoskrnl.exe/tests/driver.h | 1 + dlls/ntoskrnl.exe/tests/driver_netio.c | 6 +---- dlls/ntoskrnl.exe/tests/ntoskrnl.c | 33 +++++++++++++------------- dlls/ntoskrnl.exe/tests/utils.h | 30 +++++++++++++++++++++++ 5 files changed, 49 insertions(+), 28 deletions(-)
diff --git a/dlls/ntoskrnl.exe/tests/driver.c b/dlls/ntoskrnl.exe/tests/driver.c index c5e0bdf754f..6d46314216b 100644 --- a/dlls/ntoskrnl.exe/tests/driver.c +++ b/dlls/ntoskrnl.exe/tests/driver.c @@ -1770,7 +1770,6 @@ static PIO_WORKITEM main_test_work_item; static void WINAPI main_test_task(DEVICE_OBJECT *device, void *context) { IRP *irp = context; - void *buffer = irp->AssociatedIrp.SystemBuffer;
IoFreeWorkItem(main_test_work_item); main_test_work_item = NULL; @@ -1784,9 +1783,8 @@ static void WINAPI main_test_task(DEVICE_OBJECT *device, void *context)
winetest_cleanup();
- *((LONG *)buffer) = failures; irp->IoStatus.Status = STATUS_SUCCESS; - irp->IoStatus.Information = sizeof(failures); + irp->IoStatus.Information = 0; IoCompleteRequest(irp, IO_NO_INCREMENT); }
@@ -2105,15 +2103,12 @@ static void test_permanence(void)
static NTSTATUS main_test(DEVICE_OBJECT *device, IRP *irp, IO_STACK_LOCATION *stack) { - ULONG length = stack->Parameters.DeviceIoControl.OutputBufferLength; void *buffer = irp->AssociatedIrp.SystemBuffer; struct main_test_input *test_input = (struct main_test_input *)buffer; NTSTATUS status;
if (!buffer) return STATUS_ACCESS_VIOLATION; - if (length < sizeof(failures)) - return STATUS_BUFFER_TOO_SMALL;
if ((status = winetest_init())) return status; diff --git a/dlls/ntoskrnl.exe/tests/driver.h b/dlls/ntoskrnl.exe/tests/driver.h index cdf706b9830..397dd528e84 100644 --- a/dlls/ntoskrnl.exe/tests/driver.h +++ b/dlls/ntoskrnl.exe/tests/driver.h @@ -43,6 +43,7 @@ struct test_data int running_under_wine; int winetest_report_success; int winetest_debug; + int successes, failures, skipped, todo_successes, todo_failures; };
struct main_test_input diff --git a/dlls/ntoskrnl.exe/tests/driver_netio.c b/dlls/ntoskrnl.exe/tests/driver_netio.c index 55b5688ff53..ec8161d2424 100644 --- a/dlls/ntoskrnl.exe/tests/driver_netio.c +++ b/dlls/ntoskrnl.exe/tests/driver_netio.c @@ -465,14 +465,11 @@ static void test_wsk_connect_socket(void)
static NTSTATUS main_test(DEVICE_OBJECT *device, IRP *irp, IO_STACK_LOCATION *stack) { - ULONG length = stack->Parameters.DeviceIoControl.OutputBufferLength; void *buffer = irp->AssociatedIrp.SystemBuffer; NTSTATUS status;
if (!buffer) return STATUS_ACCESS_VIOLATION; - if (length < sizeof(failures)) - return STATUS_BUFFER_TOO_SMALL;
if ((status = winetest_init())) return status; @@ -484,8 +481,7 @@ static NTSTATUS main_test(DEVICE_OBJECT *device, IRP *irp, IO_STACK_LOCATION *st
winetest_cleanup();
- *((LONG *)buffer) = failures; - irp->IoStatus.Information = sizeof(failures); + irp->IoStatus.Information = 0; return STATUS_SUCCESS; }
diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c index 92cbfa6a329..d0320fbb2b4 100644 --- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c @@ -47,6 +47,8 @@ static const GUID GUID_NULL;
static HANDLE device;
+static struct test_data *test_data; + static BOOL (WINAPI *pRtlDosPathNameToNtPathName_U)(const WCHAR *, UNICODE_STRING *, WCHAR **, CURDIR *); static BOOL (WINAPI *pRtlFreeUnicodeString)(UNICODE_STRING *); static BOOL (WINAPI *pCancelIoEx)(HANDLE, OVERLAPPED *); @@ -369,10 +371,9 @@ static ULONG64 modified_value; static void main_test(void) { struct main_test_input *test_input; - DWORD written, read; - LONG new_failures; char buffer[512]; HANDLE okfile; + DWORD size; BOOL res;
/* Create a temporary file that the driver will write ok/trace output to. */ @@ -387,17 +388,16 @@ static void main_test(void) test_input->modified_value = &modified_value; modified_value = 0;
- res = DeviceIoControl(device, IOCTL_WINETEST_MAIN_TEST, test_input, sizeof(*test_input), - &new_failures, sizeof(new_failures), &written, NULL); + res = DeviceIoControl(device, IOCTL_WINETEST_MAIN_TEST, test_input, sizeof(*test_input), NULL, 0, &size, NULL); ok(res, "DeviceIoControl failed: %u\n", GetLastError()); - ok(written == sizeof(new_failures), "got size %x\n", written); + ok(!size, "got size %u\n", size);
- /* Print the ok/trace output and then add to our failure count. */ do { - ReadFile(okfile, buffer, sizeof(buffer), &read, NULL); - printf("%.*s", read, buffer); - } while (read == sizeof(buffer)); - winetest_add_failures(new_failures); + ReadFile(okfile, buffer, sizeof(buffer), &size, NULL); + printf("%.*s", size, buffer); + } while (size == sizeof(buffer)); + + winetest_add_failures(InterlockedExchange(&test_data->failures, 0));
heap_free(test_input); CloseHandle(okfile); @@ -1193,7 +1193,6 @@ START_TEST(ntoskrnl) WCHAR filename[MAX_PATH], filename2[MAX_PATH]; struct testsign_context ctx; SC_HANDLE service, service2; - struct test_data *data; BOOL ret, is_wow64; HANDLE mapping; DWORD written; @@ -1216,12 +1215,12 @@ START_TEST(ntoskrnl) return;
mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, - 0, sizeof(*data), "Global\winetest_ntoskrnl_section"); + 0, sizeof(*test_data), "Global\winetest_ntoskrnl_section"); ok(!!mapping, "got error %u\n", GetLastError()); - data = MapViewOfFile(mapping, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 1024); - data->running_under_wine = !strcmp(winetest_platform, "wine"); - data->winetest_report_success = winetest_report_success; - data->winetest_debug = winetest_debug; + test_data = MapViewOfFile(mapping, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 1024); + test_data->running_under_wine = !strcmp(winetest_platform, "wine"); + test_data->winetest_report_success = winetest_report_success; + test_data->winetest_debug = winetest_debug;
subtest("driver"); if (!(service = load_driver(&ctx, filename, L"driver.dll", L"WineTestDriver"))) @@ -1271,6 +1270,6 @@ START_TEST(ntoskrnl)
out: testsign_cleanup(&ctx); - UnmapViewOfFile(data); + UnmapViewOfFile(test_data); CloseHandle(mapping); } diff --git a/dlls/ntoskrnl.exe/tests/utils.h b/dlls/ntoskrnl.exe/tests/utils.h index f743e88097a..60a5e4d1255 100644 --- a/dlls/ntoskrnl.exe/tests/utils.h +++ b/dlls/ntoskrnl.exe/tests/utils.h @@ -88,6 +88,13 @@ static inline NTSTATUS winetest_init(void)
static inline void winetest_cleanup(void) { + struct test_data *data; + SIZE_T size = sizeof(*data); + OBJECT_ATTRIBUTES attr; + UNICODE_STRING string; + void *addr = NULL; + HANDLE section; + if (winetest_debug) { kprintf("%04x:ntoskrnl: %d tests executed (%d marked as todo, %d %s), %d skipped.\n", @@ -95,6 +102,29 @@ static inline void winetest_cleanup(void) todo_successes, failures + todo_failures, (failures + todo_failures != 1) ? "failures" : "failure", skipped ); } + + RtlInitUnicodeString(&string, L"\BaseNamedObjects\winetest_ntoskrnl_section"); + /* OBJ_KERNEL_HANDLE is necessary for the file to be accessible from system threads */ + InitializeObjectAttributes(&attr, &string, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, NULL); + + if (!ZwOpenSection(§ion, SECTION_MAP_READ | SECTION_MAP_WRITE, &attr)) + { + if (!ZwMapViewOfSection(section, NtCurrentProcess(), &addr, + 0, 0, NULL, &size, ViewUnmap, 0, PAGE_READWRITE)) + { + data = addr; + + InterlockedExchangeAdd(&data->successes, successes); + InterlockedExchangeAdd(&data->failures, failures); + InterlockedExchangeAdd(&data->skipped, skipped); + InterlockedExchangeAdd(&data->todo_successes, todo_successes); + InterlockedExchangeAdd(&data->todo_failures, todo_failures); + + ZwUnmapViewOfSection(NtCurrentProcess(), addr); + } + ZwClose(section); + } + ZwClose(okfile); }