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
KmtUserCallbackThread(PVOID Parameter)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
KmtRunKernelTest(IN PCSTR TestName)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
KmtLoadDriver(IN PCWSTR ServiceName,IN BOOLEAN RestartIfRunning)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
KmtUnloadDriverKeepService(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
KmtUnloadDriver(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
KmtOpenDriver(VOID)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
KmtLoadAndOpenDriver(IN PCWSTR ServiceName,IN BOOLEAN RestartIfRunning)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
KmtCloseDriver(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
KmtSendToDriver(IN DWORD ControlCode)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
KmtSendStringToDriver(IN DWORD ControlCode,IN PCSTR String)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
KmtSendWStringToDriver(IN DWORD ControlCode,IN PCWSTR String)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
KmtSendUlongToDriver(IN DWORD ControlCode,IN DWORD Value)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
KmtSendBufferToDriver(IN DWORD ControlCode,IN OUT PVOID Buffer OPTIONAL,IN DWORD InLength,IN OUT PDWORD OutLength)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