queue.c
Go to the documentation of this file.
1 /*
2  * Bareflank Hypervisor
3  *
4  * Copyright (C) 2015 Assured Information Security, Inc.
5  * Author: Rian Quinn <quinnr@ainfosec.com>
6  * Author: Brendan Kerrigan <kerriganb@ainfosec.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 #include <debug.h>
24 #include <driver.h>
25 
26 /* -------------------------------------------------------------------------- */
27 /* Global */
28 /* -------------------------------------------------------------------------- */
29 
30 struct pmodule_t
31 {
32  char *data;
33  int64_t size;
34 };
35 
36 int64_t g_num_pmodules = 0;
37 struct pmodule_t pmodules[MAX_NUM_MODULES] = { 0 };
38 
39 uint64_t g_cpuid = 0;
40 uint64_t g_vcpuid = 0;
41 
42 /* -------------------------------------------------------------------------- */
43 /* IO Functions */
44 /* -------------------------------------------------------------------------- */
45 
46 static int64_t
47 ioctl_add_module(char *file, int64_t len)
48 {
49  char *buf;
50  int64_t ret;
51 
53  {
54  ALERT("IOCTL_ADD_MODULE: too many modules have been loaded\n");
55  return BF_IOCTL_FAILURE;
56  }
57 
58  buf = platform_alloc_rwe(len);
59  if (buf == NULL)
60  {
61  ALERT("IOCTL_ADD_MODULE: failed to allocate memory for the module\n");
62  return BF_IOCTL_FAILURE;
63  }
64 
65  platform_memset(buf, 0, len);
66  platform_memcpy(buf, file, len);
67 
68  ret = common_add_module(buf, len);
69  if (ret != BF_SUCCESS)
70  {
71  ALERT("IOCTL_ADD_MODULE: common_add_module failed: %p - %s\n",
72  (void *)ret, ec_to_str(ret));
73  goto failed;
74  }
75 
76  pmodules[g_num_pmodules].data = buf;
77  pmodules[g_num_pmodules].size = len;
78 
80 
81  DEBUG("IOCTL_ADD_MODULE: succeeded\n");
82  return BF_IOCTL_SUCCESS;
83 
84 failed:
85 
86  platform_free_rwe(buf, len);
87 
88  ALERT("IOCTL_ADD_MODULE: failed\n");
89  return BF_IOCTL_FAILURE;
90 }
91 
92 static int64_t
93 ioctl_unload_vmm(void)
94 {
95  int64_t i;
96  int64_t ret;
97  int64_t status = BF_IOCTL_SUCCESS;
98 
99  ret = common_unload_vmm();
100  if (ret != BF_SUCCESS)
101  {
102  ALERT("IOCTL_UNLOAD_VMM: common_unload_vmm failed: %p - %s\n",
103  (void *)ret, ec_to_str(ret));
104  status = BF_IOCTL_FAILURE;
105  }
106 
107  for (i = 0; i < g_num_pmodules; i++)
108  platform_free_rwe(pmodules[i].data, pmodules[i].size);
109 
110  g_num_pmodules = 0;
111  platform_memset(&pmodules, 0, sizeof(pmodules));
112 
113  if (status == BF_IOCTL_SUCCESS)
114  DEBUG("IOCTL_UNLOAD_VMM: succeeded\n");
115 
116  return status;
117 }
118 
119 static int64_t
120 ioctl_load_vmm(void)
121 {
122  int64_t ret;
123 
124  ret = common_load_vmm();
125  if (ret != BF_SUCCESS)
126  {
127  ALERT("IOCTL_LOAD_VMM: ioctl_load_vmm failed: %p - %s\n",
128  (void *)ret, ec_to_str(ret));
129  goto failure;
130  }
131 
132  DEBUG("IOCTL_LOAD_VMM: succeeded\n");
133  return BF_IOCTL_SUCCESS;
134 
135 failure:
136 
137  ioctl_unload_vmm();
138  return BF_IOCTL_FAILURE;
139 }
140 
141 static int64_t
142 ioctl_stop_vmm(void)
143 {
144  int64_t ret;
145  int64_t status = BF_IOCTL_SUCCESS;
146 
147  ret = common_stop_vmm();
148  if (ret != BF_SUCCESS)
149  {
150  ALERT("IOCTL_STOP_VMM: ioctl_stop_vmm failed: %p - %s\n",
151  (void *)ret, ec_to_str(ret));
152  status = BF_IOCTL_FAILURE;
153  }
154 
155  if (status == BF_IOCTL_SUCCESS)
156  DEBUG("IOCTL_STOP_VMM: succeeded\n");
157 
158  return status;
159 }
160 
161 static int64_t
162 ioctl_start_vmm(void)
163 {
164  int64_t ret;
165 
166  ret = common_start_vmm();
167  if (ret != BF_SUCCESS)
168  {
169  ALERT("IOCTL_START_VMM: ioctl_start_vmm failed: %p - %s\n",
170  (void *)ret, ec_to_str(ret));
171  goto failure;
172  }
173 
174  DEBUG("IOCTL_START_VMM: succeeded\n");
175  return BF_IOCTL_SUCCESS;
176 
177 failure:
178 
179  ioctl_stop_vmm();
180  return BF_IOCTL_FAILURE;
181 }
182 
183 static int64_t
184 ioctl_dump_vmm(struct debug_ring_resources_t *user_drr)
185 {
186  int64_t ret;
187  struct debug_ring_resources_t *drr = 0;
188 
189  ret = common_dump_vmm(&drr, g_vcpuid);
190  if (ret != BF_SUCCESS)
191  {
192  ALERT("IOCTL_DUMP_VMM: common_dump_vmm failed: %p - %s\n",
193  (void *)ret, ec_to_str(ret));
194  return BF_IOCTL_FAILURE;
195  }
196 
197  platform_memcpy(user_drr, drr, sizeof(struct debug_ring_resources_t));
198 
199  DEBUG("IOCTL_DUMP_VMM: succeeded\n");
200  return BF_IOCTL_SUCCESS;
201 }
202 
203 static int64_t
204 ioctl_vmm_status(int64_t *status)
205 {
206  int64_t vmm_status = common_vmm_status();
207 
208  if (status == 0)
209  {
210  ALERT("IOCTL_VMM_STATUS: common_vmm_status failed: NULL\n");
211  return BF_IOCTL_FAILURE;
212  }
213 
214  *status = vmm_status;
215 
216  DEBUG("IOCTL_VMM_STATUS: succeeded\n");
217  return BF_IOCTL_SUCCESS;
218 }
219 
220 static int64_t
221 ioctl_set_cpuid(uint64_t *cpuid)
222 {
223  if (cpuid == 0)
224  {
225  ALERT("IOCTL_SET_CPUID: failed with len == NULL\n");
226  return BF_IOCTL_FAILURE;
227  }
228 
229  g_cpuid = *cpuid;
230 
231  DEBUG("IOCTL_SET_CPUID: succeeded\n");
232  return BF_IOCTL_SUCCESS;
233 }
234 
235 static int64_t
236 ioctl_set_vcpuid(uint64_t *vcpuid)
237 {
238  if (vcpuid == 0)
239  {
240  ALERT("IOCTL_SET_VCPUID: failed with len == NULL\n");
241  return BF_IOCTL_FAILURE;
242  }
243 
244  g_vcpuid = *vcpuid;
245 
246  DEBUG("IOCTL_SET_VCPUID: succeeded\n");
247  return BF_IOCTL_SUCCESS;
248 }
249 
250 static int64_t
251 ioctl_vmcall(struct vmcall_registers_t *inregs, struct vmcall_registers_t *outregs)
252 {
253  int64_t ret;
254 
255  ret = common_vmcall(inregs, g_cpuid);
256  if (ret != 0)
257  {
258  ALERT("IOCTL_VMCALL: common_vmcall failed: %p - %s\n", \
259  (void *)ret, ec_to_str(ret));
260  return BF_IOCTL_FAILURE;
261  }
262 
263  RtlCopyMemory(outregs, inregs, sizeof(struct vmcall_registers_t));
264  return BF_IOCTL_SUCCESS;
265 }
266 
267 NTSTATUS
269  _In_ WDFDEVICE Device
270 )
271 {
272  WDFQUEUE queue;
273  NTSTATUS status;
274  WDF_IO_QUEUE_CONFIG queueConfig;
275 
276  WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(
277  &queueConfig,
278  WdfIoQueueDispatchParallel
279  );
280 
281  queueConfig.EvtIoStop = bareflankEvtIoStop;
282  queueConfig.EvtIoDeviceControl = bareflankEvtIoDeviceControl;
283 
284  status = WdfIoQueueCreate(Device, &queueConfig, WDF_NO_OBJECT_ATTRIBUTES, &queue);
285  if (!NT_SUCCESS(status))
286  return status;
287 
288  if (common_init() != BF_SUCCESS)
289  {
290  ALERT("common_init failed\n");
291  return STATUS_ACCESS_DENIED;
292  }
293 
294  DEBUG("bareflankQueueInitialize: success\n");
295  return STATUS_SUCCESS;
296 }
297 
298 VOID
300  _In_ WDFQUEUE Queue,
301  _In_ WDFREQUEST Request,
302  _In_ size_t OutputBufferLength,
303  _In_ size_t InputBufferLength,
304  _In_ ULONG IoControlCode
305 )
306 {
307  PVOID in = 0;
308  PVOID out = 0;
309  size_t in_size = 0;
310  size_t out_size = 0;
311 
312  int64_t ret = 0;
313  NTSTATUS status;
314 
315  UNREFERENCED_PARAMETER(Queue);
316 
317  if (InputBufferLength != 0)
318  {
319  status = WdfRequestRetrieveInputBuffer(Request, InputBufferLength, &in, &in_size);
320 
321  if (!NT_SUCCESS(status))
322  goto FAILURE;
323  }
324 
325  if (OutputBufferLength != 0)
326  {
327  status = WdfRequestRetrieveOutputBuffer(Request, OutputBufferLength, &out, &out_size);
328 
329  if (!NT_SUCCESS(status))
330  goto FAILURE;
331  }
332 
333  switch (IoControlCode)
334  {
335  case IOCTL_ADD_MODULE:
336  ret = ioctl_add_module((char *)in, (int64_t)in_size);
337  break;
338 
339  case IOCTL_LOAD_VMM:
340  ret = ioctl_load_vmm();
341  break;
342 
343  case IOCTL_UNLOAD_VMM:
344  ret = ioctl_unload_vmm();
345  break;
346 
347  case IOCTL_START_VMM:
348  ret = ioctl_start_vmm();
349  break;
350 
351  case IOCTL_STOP_VMM:
352  ret = ioctl_stop_vmm();
353  break;
354 
355  case IOCTL_DUMP_VMM:
356  ret = ioctl_dump_vmm((struct debug_ring_resources_t *)out);
357  break;
358 
359  case IOCTL_VMM_STATUS:
360  ret = ioctl_vmm_status((int64_t *)out);
361  break;
362 
363  case IOCTL_SET_CPUID:
364  ret = ioctl_set_cpuid((uint64_t *)in);
365  break;
366 
367  case IOCTL_SET_VCPUID:
368  ret = ioctl_set_vcpuid((uint64_t *)in);
369  break;
370 
371  case IOCTL_VMCALL:
372  ret = ioctl_vmcall((struct vmcall_registers_t *)in, (struct vmcall_registers_t *)out);
373  break;
374 
375  default:
376  goto FAILURE;
377  }
378 
379  if (OutputBufferLength != 0)
380  WdfRequestSetInformation(Request, out_size);
381 
382  if (ret != BF_IOCTL_SUCCESS)
383  goto FAILURE;
384 
385  WdfRequestComplete(Request, STATUS_SUCCESS);
386  return;
387 
388 FAILURE:
389 
390  WdfRequestComplete(Request, STATUS_ACCESS_DENIED);
391  return;
392 }
393 
394 VOID
396  _In_ WDFQUEUE Queue,
397  _In_ WDFREQUEST Request,
398  _In_ ULONG ActionFlags
399 )
400 {
401  UNREFERENCED_PARAMETER(Queue);
402  UNREFERENCED_PARAMETER(ActionFlags);
403 
404  WdfRequestComplete(Request, STATUS_SUCCESS);
405  return;
406 }
#define BF_SUCCESS
Definition: error_codes.h:105
int64_t common_add_module(const char *file, uint64_t fsize)
Definition: common.c:305
int64_t g_num_pmodules
Definition: queue.c:36
Definition: file.h:35
int64_t common_load_vmm(void)
Definition: common.c:357
void * platform_alloc_rwe(uint64_t len)
Definition: platform.c:62
int64_t unsigned long void * data
void platform_memcpy(void *dst, const void *src, uint64_t num)
Definition: platform.c:127
uint64_t g_vcpuid
Definition: queue.c:40
int64_t common_dump_vmm(struct debug_ring_resources_t **drr, uint64_t vcpuid)
Definition: common.c:592
VOID bareflankEvtIoDeviceControl(_In_ WDFQUEUE Queue, _In_ WDFREQUEST Request, _In_ size_t OutputBufferLength, _In_ size_t InputBufferLength, _In_ ULONG IoControlCode)
Definition: queue.c:299
Definition: vcpuid.h:29
void platform_free_rwe(void *addr, uint64_t len)
Definition: platform.c:95
void platform_memset(void *ptr, char value, uint64_t num)
Definition: platform.c:118
#define MAX_NUM_MODULES
Definition: constants.h:177
debug_ring_resources_t * drr
NTSTATUS bareflankQueueInitialize(_In_ WDFDEVICE Device)
Definition: queue.c:268
constexpr const auto size
#define ALERT(...)
Definition: debug.h:156
int64_t common_vmcall(struct vmcall_registers_t *regs, uint64_t cpuid)
Definition: common.c:610
#define BF_IOCTL_FAILURE
Definition: error_codes.h:122
int64_t common_stop_vmm(void)
Definition: common.c:543
#define BF_IOCTL_SUCCESS
Definition: error_codes.h:121
int64_t common_start_vmm(void)
Definition: common.c:490
int64_t common_init(void)
Definition: common.c:267
struct pmodule_t pmodules[MAX_NUM_MODULES]
Definition: queue.c:37
int64_t common_unload_vmm(void)
Definition: common.c:451
VOID bareflankEvtIoStop(_In_ WDFQUEUE Queue, _In_ WDFREQUEST Request, _In_ ULONG ActionFlags)
Definition: queue.c:395
#define DEBUG(...)
Definition: debug.h:155
int64_t common_vmm_status(void)
Definition: common.c:227
uint64_t g_cpuid
Definition: queue.c:39