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 DWORD 128 KmtLoadDriver( 129 IN PCWSTR ServiceName, 130 IN BOOLEAN RestartIfRunning) 131 { 132 WCHAR ServicePath[MAX_PATH]; 133 134 StringCbCopyW(ServicePath, sizeof(ServicePath), ServiceName); 135 StringCbCatW(ServicePath, sizeof(ServicePath), L"_drv.sys"); 136 137 StringCbCopyW(TestServiceName, sizeof(TestServiceName), L"Kmtest-"); 138 StringCbCatW(TestServiceName, sizeof(TestServiceName), ServiceName); 139 140 return KmtCreateAndStartService(TestServiceName, ServicePath, NULL, &TestServiceHandle, RestartIfRunning); 141 } 142 143 /** 144 * @name KmtUnloadDriverKeepService 145 * 146 * Unload special-purpose driver (stop the service only) 147 */ 148 VOID 149 KmtUnloadDriverKeepService(VOID) 150 { 151 DWORD Error; 152 153 Error = KmtStopService(TestServiceName, &TestServiceHandle); 154 155 if (Error) 156 { 157 fprintf(stderr, "Failed to stop %ls service with error 0x%lx\n", TestServiceName, Error); 158 } 159 } 160 161 /** 162 * @name KmtUnloadDriver 163 * 164 * Unload special-purpose driver (stop and delete the service) 165 */ 166 VOID 167 KmtUnloadDriver(VOID) 168 { 169 DWORD Error; 170 171 Error = KmtStopService(TestServiceName, &TestServiceHandle); 172 173 if (Error) 174 { 175 fprintf(stderr, "Failed to stop %ls service with error 0x%lx\n", TestServiceName, Error); 176 } 177 178 Error = KmtDeleteService(TestServiceName, &TestServiceHandle); 179 180 if (Error) 181 { 182 fprintf(stderr, "Failed to delete %ls service with error 0x%lx\n", TestServiceName, Error); 183 } 184 } 185 186 /** 187 * @name KmtOpenDriver 188 * 189 * Open special-purpose driver (acquire a device handle) 190 */ 191 DWORD 192 KmtOpenDriver(VOID) 193 { 194 DWORD Error = ERROR_SUCCESS; 195 WCHAR DevicePath[MAX_PATH]; 196 197 StringCbCopyW(DevicePath, sizeof(DevicePath), L"\\\\.\\Global\\GLOBALROOT\\Device\\"); 198 StringCbCatW(DevicePath, sizeof(DevicePath), TestServiceName); 199 200 TestDeviceHandle = CreateFile(DevicePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); 201 if (TestDeviceHandle == INVALID_HANDLE_VALUE) 202 error(Error); 203 204 return Error; 205 } 206 207 /** 208 * @name KmtOpenDriver 209 * 210 * Load and open special-purpose driver (acquire a device handle) 211 */ 212 DWORD 213 KmtLoadAndOpenDriver( 214 IN PCWSTR ServiceName, 215 IN BOOLEAN RestartIfRunning) 216 { 217 DWORD Error; 218 219 Error = KmtLoadDriver(ServiceName, RestartIfRunning); 220 if (Error) 221 return Error; 222 223 Error = KmtOpenDriver(); 224 if (Error) 225 return Error; 226 227 return ERROR_SUCCESS; 228 } 229 230 /** 231 * @name KmtCloseDriver 232 * 233 * Close special-purpose driver (close device handle) 234 */ 235 VOID 236 KmtCloseDriver(VOID) 237 { 238 DWORD Error = ERROR_SUCCESS; 239 240 if (TestDeviceHandle && !CloseHandle(TestDeviceHandle)) 241 error(Error); 242 243 if (Error) 244 { 245 DPRINT1("CloseHandle failed: 0x%lx\n", Error); 246 } 247 } 248 249 /** 250 * @name KmtSendToDriver 251 * 252 * Send an I/O control message with no arguments to the driver opened with KmtOpenDriver 253 * 254 * @param ControlCode 255 * 256 * @return Win32 error code as returned by DeviceIoControl 257 */ 258 DWORD 259 KmtSendToDriver( 260 IN DWORD ControlCode) 261 { 262 DWORD BytesRead; 263 264 assert(ControlCode < 0x400); 265 266 if (!DeviceIoControl(TestDeviceHandle, KMT_MAKE_CODE(ControlCode), NULL, 0, NULL, 0, &BytesRead, NULL)) 267 return GetLastError(); 268 269 return ERROR_SUCCESS; 270 } 271 272 /** 273 * @name KmtSendStringToDriver 274 * 275 * Send an I/O control message with a string argument to the driver opened with KmtOpenDriver 276 * 277 * @param ControlCode 278 * @param String 279 * 280 * @return Win32 error code as returned by DeviceIoControl 281 */ 282 DWORD 283 KmtSendStringToDriver( 284 IN DWORD ControlCode, 285 IN PCSTR String) 286 { 287 DWORD BytesRead; 288 289 assert(ControlCode < 0x400); 290 291 if (!DeviceIoControl(TestDeviceHandle, KMT_MAKE_CODE(ControlCode), (PVOID)String, (DWORD)strlen(String), NULL, 0, &BytesRead, NULL)) 292 return GetLastError(); 293 294 return ERROR_SUCCESS; 295 } 296 297 /** 298 * @name KmtSendWStringToDriver 299 * 300 * Send an I/O control message with a wide string argument to the driver opened with KmtOpenDriver 301 * 302 * @param ControlCode 303 * @param String 304 * 305 * @return Win32 error code as returned by DeviceIoControl 306 */ 307 DWORD 308 KmtSendWStringToDriver( 309 IN DWORD ControlCode, 310 IN PCWSTR String) 311 { 312 DWORD BytesRead; 313 314 assert(ControlCode < 0x400); 315 316 if (!DeviceIoControl(TestDeviceHandle, KMT_MAKE_CODE(ControlCode), (PVOID)String, (DWORD)wcslen(String) * sizeof(WCHAR), NULL, 0, &BytesRead, NULL)) 317 return GetLastError(); 318 319 return ERROR_SUCCESS; 320 } 321 322 /** 323 * @name KmtSendUlongToDriver 324 * 325 * Send an I/O control message with an integer argument to the driver opened with KmtOpenDriver 326 * 327 * @param ControlCode 328 * @param Value 329 * 330 * @return Win32 error code as returned by DeviceIoControl 331 */ 332 DWORD 333 KmtSendUlongToDriver( 334 IN DWORD ControlCode, 335 IN DWORD Value) 336 { 337 DWORD BytesRead; 338 339 assert(ControlCode < 0x400); 340 341 if (!DeviceIoControl(TestDeviceHandle, KMT_MAKE_CODE(ControlCode), &Value, sizeof(Value), NULL, 0, &BytesRead, NULL)) 342 return GetLastError(); 343 344 return ERROR_SUCCESS; 345 } 346 347 /** 348 * @name KmtSendBufferToDriver 349 * 350 * Send an I/O control message with the specified arguments to the driver opened with KmtOpenDriver 351 * 352 * @param ControlCode 353 * @param Buffer 354 * @param InLength 355 * @param OutLength 356 * 357 * @return Win32 error code as returned by DeviceIoControl 358 */ 359 DWORD 360 KmtSendBufferToDriver( 361 IN DWORD ControlCode, 362 IN OUT PVOID Buffer OPTIONAL, 363 IN DWORD InLength, 364 IN OUT PDWORD OutLength) 365 { 366 assert(OutLength); 367 assert(Buffer || (!InLength && !*OutLength)); 368 assert(ControlCode < 0x400); 369 370 if (!DeviceIoControl(TestDeviceHandle, KMT_MAKE_CODE(ControlCode), Buffer, InLength, Buffer, *OutLength, OutLength, NULL)) 371 return GetLastError(); 372 373 return ERROR_SUCCESS; 374 } 375