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