From: Bernhard Übelacker bernhardu@mailbox.org
https://gitlab.winehq.org/wine/wine/-/merge_requests/3007#note_36196 https://testbot.winehq.org/JobDetails.pl?Key=133935 --- dlls/ntoskrnl.exe/tests/driver.c | 48 ++++++++++++++++++++++++++++++ dlls/ntoskrnl.exe/tests/driver.h | 4 +++ dlls/ntoskrnl.exe/tests/ntoskrnl.c | 47 +++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+)
diff --git a/dlls/ntoskrnl.exe/tests/driver.c b/dlls/ntoskrnl.exe/tests/driver.c index a80bef78fab..7ac06126a66 100644 --- a/dlls/ntoskrnl.exe/tests/driver.c +++ b/dlls/ntoskrnl.exe/tests/driver.c @@ -2501,6 +2501,48 @@ static NTSTATUS test_load_driver_ioctl(IRP *irp, IO_STACK_LOCATION *stack, ULONG return ZwUnloadDriver(&name); }
+static NTSTATUS empty_ioctl(IRP *irp, IO_STACK_LOCATION *stack) +{ + ULONG code = stack->Parameters.DeviceIoControl.IoControlCode; + const void *input_buffer, *output_buffer; + + input_buffer = irp->AssociatedIrp.SystemBuffer; + output_buffer = irp->AssociatedIrp.SystemBuffer; + + if (code == IOCTL_WINETEST_EMPTY_NEITHER) + { + input_buffer = stack->Parameters.DeviceIoControl.Type3InputBuffer; + output_buffer = irp->UserBuffer; + } + else if (code == IOCTL_WINETEST_EMPTY_IN_DIRECT) + { + if (irp->MdlAddress) + input_buffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority); + else + input_buffer = NULL; + input_buffer = irp->MdlAddress; + } + else if (code == IOCTL_WINETEST_EMPTY_OUT_DIRECT) + { + if (irp->MdlAddress) + output_buffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority); + else + output_buffer = NULL; + output_buffer = irp->MdlAddress; + } + + if (input_buffer) + return STATUS_INVALID_PARAMETER_1; + if (stack->Parameters.DeviceIoControl.InputBufferLength) + return STATUS_INVALID_PARAMETER_2; + if (output_buffer) + return STATUS_INVALID_PARAMETER_3; + if (stack->Parameters.DeviceIoControl.OutputBufferLength) + return STATUS_INVALID_PARAMETER_4; + + return STATUS_END_OF_FILE; +} + static NTSTATUS completion_ioctl(DEVICE_OBJECT *device, IRP *irp, IO_STACK_LOCATION *stack) { if (device == upper_device) @@ -2617,6 +2659,12 @@ static NTSTATUS WINAPI driver_IoControl(DEVICE_OBJECT *device, IRP *irp) break; case IOCTL_WINETEST_COMPLETION: return completion_ioctl(device, irp, stack); + case IOCTL_WINETEST_EMPTY_BUFFERED: + case IOCTL_WINETEST_EMPTY_IN_DIRECT: + case IOCTL_WINETEST_EMPTY_OUT_DIRECT: + case IOCTL_WINETEST_EMPTY_NEITHER: + status = empty_ioctl(irp, stack); + break; default: break; } diff --git a/dlls/ntoskrnl.exe/tests/driver.h b/dlls/ntoskrnl.exe/tests/driver.h index 34dfdca476c..160391c990b 100644 --- a/dlls/ntoskrnl.exe/tests/driver.h +++ b/dlls/ntoskrnl.exe/tests/driver.h @@ -36,6 +36,10 @@ #define IOCTL_WINETEST_RETURN_STATUS_DIRECT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80a, METHOD_OUT_DIRECT, FILE_ANY_ACCESS) #define IOCTL_WINETEST_RETURN_STATUS_NEITHER CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80a, METHOD_NEITHER, FILE_ANY_ACCESS) #define IOCTL_WINETEST_COMPLETION CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80c, METHOD_NEITHER, FILE_ANY_ACCESS) +#define IOCTL_WINETEST_EMPTY_BUFFERED CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80d, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_WINETEST_EMPTY_IN_DIRECT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80d, METHOD_IN_DIRECT, FILE_ANY_ACCESS) +#define IOCTL_WINETEST_EMPTY_OUT_DIRECT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80d, METHOD_OUT_DIRECT, FILE_ANY_ACCESS) +#define IOCTL_WINETEST_EMPTY_NEITHER CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80d, METHOD_NEITHER, FILE_ANY_ACCESS)
#define IOCTL_WINETEST_BUS_MAIN CTL_CODE(FILE_DEVICE_BUS_EXTENDER, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_WINETEST_BUS_REGISTER_IFACE CTL_CODE(FILE_DEVICE_BUS_EXTENDER, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS) diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c index 859dab4b3a9..63c7c5bb2b6 100644 --- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c @@ -1148,6 +1148,52 @@ static void test_blocking_irp(void) CloseHandle(file); }
+static void test_ioctl_buffers(void) +{ + IO_STATUS_BLOCK io; + NTSTATUS status; + unsigned int j; + + static const struct + { + void *in; + ULONG in_size; + void *out; + ULONG out_size; + NTSTATUS buffered_status, direct_status, neither_status; + } + param_tests[] = + { + {NULL, 0, NULL, 0, STATUS_END_OF_FILE, STATUS_END_OF_FILE, STATUS_END_OF_FILE}, + {NULL, 4, NULL, 0, STATUS_END_OF_FILE, STATUS_END_OF_FILE, STATUS_INVALID_PARAMETER_2}, + {(void *)16, 0, NULL, 0, STATUS_END_OF_FILE, STATUS_END_OF_FILE, STATUS_INVALID_PARAMETER_1}, + {(void *)16, 4, NULL, 0, STATUS_ACCESS_VIOLATION, STATUS_ACCESS_VIOLATION, STATUS_INVALID_PARAMETER_1}, + {NULL, 0, NULL, 4, STATUS_END_OF_FILE, STATUS_ACCESS_VIOLATION, STATUS_INVALID_PARAMETER_4}, + {NULL, 0, (void *)16, 0, STATUS_END_OF_FILE, STATUS_END_OF_FILE, STATUS_INVALID_PARAMETER_3}, + {NULL, 0, (void *)16, 4, STATUS_ACCESS_VIOLATION, STATUS_ACCESS_VIOLATION, STATUS_INVALID_PARAMETER_3}, + }; + + for (j = 0; j < ARRAY_SIZE(param_tests); ++j) + { + winetest_push_context("test %u", j); + + status = NtDeviceIoControlFile(device, NULL, NULL, NULL, &io, IOCTL_WINETEST_EMPTY_BUFFERED, + param_tests[j].in, param_tests[j].in_size, param_tests[j].out, param_tests[j].out_size); + ok(status == param_tests[j].buffered_status, "got %#lx\n", status); + status = NtDeviceIoControlFile(device, NULL, NULL, NULL, &io, IOCTL_WINETEST_EMPTY_IN_DIRECT, + param_tests[j].in, param_tests[j].in_size, param_tests[j].out, param_tests[j].out_size); + ok(status == param_tests[j].direct_status, "got %#lx\n", status); + status = NtDeviceIoControlFile(device, NULL, NULL, NULL, &io, IOCTL_WINETEST_EMPTY_OUT_DIRECT, + param_tests[j].in, param_tests[j].in_size, param_tests[j].out, param_tests[j].out_size); + ok(status == param_tests[j].direct_status, "got %#lx\n", status); + status = NtDeviceIoControlFile(device, NULL, NULL, NULL, &io, IOCTL_WINETEST_EMPTY_NEITHER, + param_tests[j].in, param_tests[j].in_size, param_tests[j].out, param_tests[j].out_size); + ok(status == param_tests[j].neither_status, "got %#lx\n", status); + + winetest_pop_context(); + } +} + static void test_driver3(struct testsign_context *ctx) { WCHAR filename[MAX_PATH]; @@ -1954,6 +2000,7 @@ START_TEST(ntoskrnl) test_return_status(); test_object_info(); test_blocking_irp(); + test_ioctl_buffers();
/* We need a separate ioctl to call IoDetachDevice(); calling it in the * driver unload routine causes a live-lock. */