1 /* 2 * PROJECT: ReactOS kernel-mode tests 3 * LICENSE: LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+) 4 * PURPOSE: Kernel-Mode Test Suite user-mode support routines 5 * COPYRIGHT: Copyright 2011-2020 Thomas Faber <thomas.faber@reactos.org> 6 * Copyright 2013 Nikolay Borisov <nib9@aber.ac.uk> 7 * Copyright 2018 Serge Gautherie <reactos-git_serge_171003@gautherie.fr> 8 */ 9 10 #include <kmt_test.h> 11 12 #include "kmtest.h" 13 #include <kmt_public.h> 14 15 #include <assert.h> 16 #include <debug.h> 17 18 extern HANDLE KmtestHandle; 19 20 /** 21 * @name KmtUserCallbackThread 22 * 23 * Thread routine which awaits callback requests from kernel-mode 24 * 25 * @return Win32 error code 26 */ 27 DWORD 28 WINAPI 29 KmtUserCallbackThread( 30 PVOID Parameter) 31 { 32 DWORD Error = ERROR_SUCCESS; 33 /* TODO: RequestPacket? */ 34 KMT_CALLBACK_REQUEST_PACKET RequestPacket; 35 KMT_RESPONSE Response; 36 DWORD BytesReturned; 37 HANDLE LocalKmtHandle; 38 39 UNREFERENCED_PARAMETER(Parameter); 40 41 /* concurrent IoCtls on the same (non-overlapped) handle aren't possible, 42 * so open a separate one. 43 * For more info http://www.osronline.com/showthread.cfm?link=230782 */ 44 LocalKmtHandle = CreateFile(KMTEST_DEVICE_PATH, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); 45 if (LocalKmtHandle == INVALID_HANDLE_VALUE) 46 error_goto(Error, cleanup); 47 48 while (1) 49 { 50 if (!DeviceIoControl(LocalKmtHandle, IOCTL_KMTEST_USERMODE_AWAIT_REQ, NULL, 0, &RequestPacket, sizeof(RequestPacket), &BytesReturned, NULL)) 51 error_goto(Error, cleanup); 52 ASSERT(BytesReturned == sizeof(RequestPacket)); 53 54 switch (RequestPacket.OperationClass) 55 { 56 case QueryVirtualMemory: 57 { 58 SIZE_T InfoBufferSize = VirtualQuery(RequestPacket.Parameters, &Response.MemInfo, sizeof(Response.MemInfo)); 59 /* FIXME: an error is a valid result. That should go as a response to kernel mode instead of terminating the thread */ 60 if (InfoBufferSize == 0) 61 error_goto(Error, cleanup); 62 63 if (!DeviceIoControl(LocalKmtHandle, IOCTL_KMTEST_USERMODE_SEND_RESPONSE, &RequestPacket.RequestId, sizeof(RequestPacket.RequestId), &Response, sizeof(Response), &BytesReturned, NULL)) 64 error_goto(Error, cleanup); 65 ASSERT(BytesReturned == 0); 66 67 break; 68 } 69 default: 70 DPRINT1("Unrecognized user-mode callback request\n"); 71 break; 72 } 73 } 74 75 cleanup: 76 if (LocalKmtHandle != INVALID_HANDLE_VALUE) 77 CloseHandle(LocalKmtHandle); 78 79 DPRINT("Callback handler dying! Error code %lu", Error); 80 return Error; 81 } 82 83 84 /** 85 * @name KmtRunKernelTest 86 * 87 * Run the specified kernel-mode test part 88 * 89 * @param TestName 90 * Name of the test to run 91 * 92 * @return Win32 error code as returned by DeviceIoControl 93 */ 94 DWORD 95 KmtRunKernelTest( 96 IN PCSTR TestName) 97 { 98 HANDLE CallbackThread; 99 DWORD Error = ERROR_SUCCESS; 100 DWORD BytesRead; 101 102 CallbackThread = CreateThread(NULL, 0, KmtUserCallbackThread, NULL, 0, NULL); 103 104 if (!DeviceIoControl(KmtestHandle, IOCTL_KMTEST_RUN_TEST, (PVOID)TestName, (DWORD)strlen(TestName), NULL, 0, &BytesRead, NULL)) 105 error(Error); 106 107 if (CallbackThread != NULL) 108 CloseHandle(CallbackThread); 109 110 return Error; 111 } 112 113 static WCHAR TestServiceName[MAX_PATH]; 114 static SC_HANDLE TestServiceHandle; 115 static HANDLE TestDeviceHandle; 116 117 /** 118 * @name KmtLoadDriver 119 * 120 * Load the specified special-purpose driver (create/start the service) 121 * 122 * @param ServiceName 123 * Name of the driver service (Kmtest- prefix will be added automatically) 124 * @param RestartIfRunning 125 * TRUE to stop and restart the service if it is already running 126 */ 127 VOID 128 KmtLoadDriver( 129 IN PCWSTR ServiceName, 130 IN BOOLEAN RestartIfRunning) 131 { 132 DWORD Error = ERROR_SUCCESS; 133 WCHAR ServicePath[MAX_PATH]; 134 135 StringCbCopyW(ServicePath, sizeof(ServicePath), ServiceName); 136 StringCbCatW(ServicePath, sizeof(ServicePath), L"_drv.sys"); 137 138 StringCbCopyW(TestServiceName, sizeof(TestServiceName), L"Kmtest-"); 139 StringCbCatW(TestServiceName, sizeof(TestServiceName), ServiceName); 140 141 Error = KmtCreateAndStartService(TestServiceName, ServicePath, NULL, &TestServiceHandle, RestartIfRunning); 142 143 if (Error) 144 { 145 // TODO 146 __debugbreak(); 147 } 148 } 149 150 /** 151 * @name KmtUnloadDriver 152 * 153 * Unload special-purpose driver (stop and delete the service) 154 */ 155 VOID 156 KmtUnloadDriver(VOID) 157 { 158 DWORD Error; 159 160 Error = KmtStopService(TestServiceName, &TestServiceHandle); 161 162 if (Error) 163 { 164 fprintf(stderr, "Failed to stop %ls service with error 0x%lx\n", TestServiceName, Error); 165 } 166 167 Error = KmtDeleteService(TestServiceName, &TestServiceHandle); 168 169 if (Error) 170 { 171 fprintf(stderr, "Failed to delete %ls service with error 0x%lx\n", TestServiceName, Error); 172 } 173 } 174 175 /** 176 * @name KmtOpenDriver 177 * 178 * Open special-purpose driver (acquire a device handle) 179 */ 180 VOID 181 KmtOpenDriver(VOID) 182 { 183 DWORD Error = ERROR_SUCCESS; 184 WCHAR DevicePath[MAX_PATH]; 185 186 StringCbCopyW(DevicePath, sizeof(DevicePath), L"\\\\.\\Global\\GLOBALROOT\\Device\\"); 187 StringCbCatW(DevicePath, sizeof(DevicePath), TestServiceName); 188 189 TestDeviceHandle = CreateFile(DevicePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); 190 if (TestDeviceHandle == INVALID_HANDLE_VALUE) 191 error(Error); 192 193 if (Error) 194 { 195 // TODO 196 __debugbreak(); 197 } 198 199 } 200 201 /** 202 * @name KmtCloseDriver 203 * 204 * Close special-purpose driver (close device handle) 205 */ 206 VOID 207 KmtCloseDriver(VOID) 208 { 209 DWORD Error = ERROR_SUCCESS; 210 211 if (TestDeviceHandle && !CloseHandle(TestDeviceHandle)) 212 error(Error); 213 214 if (Error) 215 { 216 // TODO 217 __debugbreak(); 218 } 219 } 220 221 /** 222 * @name KmtSendToDriver 223 * 224 * Send an I/O control message with no arguments to the driver opened with KmtOpenDriver 225 * 226 * @param ControlCode 227 * 228 * @return Win32 error code as returned by DeviceIoControl 229 */ 230 DWORD 231 KmtSendToDriver( 232 IN DWORD ControlCode) 233 { 234 DWORD BytesRead; 235 236 assert(ControlCode < 0x400); 237 238 if (!DeviceIoControl(TestDeviceHandle, KMT_MAKE_CODE(ControlCode), NULL, 0, NULL, 0, &BytesRead, NULL)) 239 return GetLastError(); 240 241 return ERROR_SUCCESS; 242 } 243 244 /** 245 * @name KmtSendStringToDriver 246 * 247 * Send an I/O control message with a string argument to the driver opened with KmtOpenDriver 248 * 249 * @param ControlCode 250 * @param String 251 * 252 * @return Win32 error code as returned by DeviceIoControl 253 */ 254 DWORD 255 KmtSendStringToDriver( 256 IN DWORD ControlCode, 257 IN PCSTR String) 258 { 259 DWORD BytesRead; 260 261 assert(ControlCode < 0x400); 262 263 if (!DeviceIoControl(TestDeviceHandle, KMT_MAKE_CODE(ControlCode), (PVOID)String, (DWORD)strlen(String), NULL, 0, &BytesRead, NULL)) 264 return GetLastError(); 265 266 return ERROR_SUCCESS; 267 } 268 269 /** 270 * @name KmtSendWStringToDriver 271 * 272 * Send an I/O control message with a wide string argument to the driver opened with KmtOpenDriver 273 * 274 * @param ControlCode 275 * @param String 276 * 277 * @return Win32 error code as returned by DeviceIoControl 278 */ 279 DWORD 280 KmtSendWStringToDriver( 281 IN DWORD ControlCode, 282 IN PCWSTR String) 283 { 284 DWORD BytesRead; 285 286 assert(ControlCode < 0x400); 287 288 if (!DeviceIoControl(TestDeviceHandle, KMT_MAKE_CODE(ControlCode), (PVOID)String, (DWORD)wcslen(String) * sizeof(WCHAR), NULL, 0, &BytesRead, NULL)) 289 return GetLastError(); 290 291 return ERROR_SUCCESS; 292 } 293 294 /** 295 * @name KmtSendUlongToDriver 296 * 297 * Send an I/O control message with an integer argument to the driver opened with KmtOpenDriver 298 * 299 * @param ControlCode 300 * @param Value 301 * 302 * @return Win32 error code as returned by DeviceIoControl 303 */ 304 DWORD 305 KmtSendUlongToDriver( 306 IN DWORD ControlCode, 307 IN DWORD Value) 308 { 309 DWORD BytesRead; 310 311 assert(ControlCode < 0x400); 312 313 if (!DeviceIoControl(TestDeviceHandle, KMT_MAKE_CODE(ControlCode), &Value, sizeof(Value), NULL, 0, &BytesRead, NULL)) 314 return GetLastError(); 315 316 return ERROR_SUCCESS; 317 } 318 319 /** 320 * @name KmtSendBufferToDriver 321 * 322 * Send an I/O control message with the specified arguments to the driver opened with KmtOpenDriver 323 * 324 * @param ControlCode 325 * @param Buffer 326 * @param InLength 327 * @param OutLength 328 * 329 * @return Win32 error code as returned by DeviceIoControl 330 */ 331 DWORD 332 KmtSendBufferToDriver( 333 IN DWORD ControlCode, 334 IN OUT PVOID Buffer OPTIONAL, 335 IN DWORD InLength, 336 IN OUT PDWORD OutLength) 337 { 338 assert(OutLength); 339 assert(Buffer || (!InLength && !*OutLength)); 340 assert(ControlCode < 0x400); 341 342 if (!DeviceIoControl(TestDeviceHandle, KMT_MAKE_CODE(ControlCode), Buffer, InLength, Buffer, *OutLength, OutLength, NULL)) 343 return GetLastError(); 344 345 return ERROR_SUCCESS; 346 } 347