entry.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 <linux/fs.h>
24 #include <linux/module.h>
25 #include <linux/uaccess.h>
26 #include <linux/miscdevice.h>
27 #include <linux/vmalloc.h>
28 #include <linux/kallsyms.h>
29 #include <linux/notifier.h>
30 #include <linux/reboot.h>
31 
32 #include <debug.h>
33 #include <types.h>
34 #include <common.h>
35 #include <constants.h>
36 #include <driver_entry_interface.h>
37 
38 /* -------------------------------------------------------------------------- */
39 /* Global */
40 /* -------------------------------------------------------------------------- */
41 
42 uint64_t g_module_length = 0;
43 
44 int64_t g_num_files = 0;
45 char *files[MAX_NUM_MODULES] = {0};
46 uint64_t files_size[MAX_NUM_MODULES] = { 0 };
47 
48 uint64_t g_cpuid = 0;
49 uint64_t g_vcpuid = 0;
50 
51 /* -------------------------------------------------------------------------- */
52 /* Misc Device */
53 /* -------------------------------------------------------------------------- */
54 
55 static int
56 dev_open(struct inode *inode, struct file *file)
57 {
58  (void) inode;
59  (void) file;
60 
61  DEBUG("dev_open succeeded\n");
62  return 0;
63 }
64 
65 static int
66 dev_release(struct inode *inode, struct file *file)
67 {
68  (void) inode;
69  (void) file;
70 
71  DEBUG("dev_release succeeded\n");
72  return 0;
73 }
74 
75 static long
76 ioctl_add_module(char *file)
77 {
78  char *buf;
79  int64_t ret;
80 
82  {
83  ALERT("IOCTL_ADD_MODULE: too many modules have been loaded\n");
84  return BF_IOCTL_FAILURE;
85  }
86 
87  /*
88  * On Linux, we are not given a size for the IOCTL. Appearently
89  * it is common practice to seperate this information into two
90  * different IOCTLs, which is what we do here. This however means
91  * that we have to store state, so userspace has to be careful
92  * to send these IOCTLs in the correct order.
93  *
94  * Linux also does not copy userspace memory for us, so we need
95  * to do this ourselves. As a result, we alloc memory for the
96  * buffer that userspace is providing us so that we can copy this
97  * memory from userspace as needed.
98  */
99 
100  buf = vmalloc(g_module_length);
101  if (buf == NULL)
102  {
103  ALERT("IOCTL_ADD_MODULE: failed to allocate memory for the module\n");
104  return BF_IOCTL_FAILURE;
105  }
106 
107  ret = copy_from_user(buf, file, g_module_length);
108  if (ret != 0)
109  {
110  ALERT("IOCTL_ADD_MODULE: failed to copy memory from userspace\n");
111  goto failed;
112  }
113 
115  if (ret != BF_SUCCESS)
116  {
117  ALERT("IOCTL_ADD_MODULE: common_add_module failed: %p - %s\n", \
118  (void *)ret, ec_to_str(ret));
119  goto failed;
120  }
121 
122  files[g_num_files] = buf;
124 
125  g_num_files++;
126 
127  DEBUG("IOCTL_ADD_MODULE: succeeded\n");
128  return BF_IOCTL_SUCCESS;
129 
130 failed:
131 
132  vfree(buf);
133 
134  ALERT("IOCTL_ADD_MODULE: failed\n");
135  return BF_IOCTL_FAILURE;
136 }
137 
138 static long
139 ioctl_add_module_length(uint64_t *len)
140 {
141  int64_t ret;
142 
143  if (len == 0)
144  {
145  ALERT("IOCTL_ADD_MODULE_LENGTH: failed with len == NULL\n");
146  return BF_IOCTL_FAILURE;
147  }
148 
149  ret = copy_from_user(&g_module_length, len, sizeof(uint64_t));
150  if (ret != 0)
151  {
152  ALERT("IOCTL_ADD_MODULE_LENGTH: failed to copy memory from userspace\n");
153  return BF_IOCTL_FAILURE;
154  }
155 
156  DEBUG("IOCTL_ADD_MODULE_LENGTH: succeeded\n");
157  return BF_IOCTL_SUCCESS;
158 }
159 
160 static long
161 ioctl_unload_vmm(void)
162 {
163  int i;
164  int64_t ret;
165  long status = BF_IOCTL_SUCCESS;
166 
167  ret = common_unload_vmm();
168  if (ret != BF_SUCCESS)
169  {
170  ALERT("IOCTL_UNLOAD_VMM: common_unload_vmm failed: %p - %s\n", \
171  (void *)ret, ec_to_str(ret));
172  status = BF_IOCTL_FAILURE;
173  }
174 
175  for (i = 0; i < g_num_files; i++)
176  {
177  vfree(files[i]);
178 
179  files[i] = 0;
180  files_size[i] = 0;
181  }
182 
183  g_num_files = 0;
184 
185  if (status == BF_IOCTL_SUCCESS)
186  DEBUG("IOCTL_UNLOAD_VMM: succeeded\n");
187 
188  return status;
189 }
190 
191 static long
192 ioctl_load_vmm(void)
193 {
194  int64_t ret;
195 
196  ret = common_load_vmm();
197  if (ret != BF_SUCCESS)
198  {
199  ALERT("IOCTL_LOAD_VMM: common_load_vmm failed: %p - %s\n", \
200  (void *)ret, ec_to_str(ret));
201  goto failure;
202  }
203 
204  DEBUG("IOCTL_LOAD_VMM: succeeded\n");
205  return BF_IOCTL_SUCCESS;
206 
207 failure:
208 
209  ioctl_unload_vmm();
210  return BF_IOCTL_FAILURE;
211 }
212 
213 static long
214 ioctl_stop_vmm(void)
215 {
216  int64_t ret;
217  long status = BF_IOCTL_SUCCESS;
218 
219  ret = common_stop_vmm();
220 
221  if (ret != BF_SUCCESS)
222  {
223  ALERT("IOCTL_STOP_VMM: common_stop_vmm failed: %p - %s\n", \
224  (void *)ret, ec_to_str(ret));
225  status = BF_IOCTL_FAILURE;
226  }
227 
228  if (status == BF_IOCTL_SUCCESS)
229  DEBUG("IOCTL_STOP_VMM: succeeded\n");
230 
231  return status;
232 }
233 
234 static long
235 ioctl_start_vmm(void)
236 {
237  int64_t ret;
238 
239  ret = common_start_vmm();
240  if (ret != BF_SUCCESS)
241  {
242  ALERT("IOCTL_START_VMM: common_start_vmm failed: %p - %s\n", \
243  (void *)ret, ec_to_str(ret));
244  goto failure;
245  }
246 
247  DEBUG("IOCTL_START_VMM: succeeded\n");
248  return BF_IOCTL_SUCCESS;
249 
250 failure:
251 
252  ioctl_stop_vmm();
253  return BF_IOCTL_FAILURE;
254 }
255 
256 static long
257 ioctl_dump_vmm(struct debug_ring_resources_t *user_drr)
258 {
259  int64_t ret;
260  struct debug_ring_resources_t *drr = 0;
261 
262  ret = common_dump_vmm(&drr, g_vcpuid);
263  if (ret != BF_SUCCESS)
264  {
265  ALERT("IOCTL_DUMP_VMM: common_dump_vmm failed: %p - %s\n", \
266  (void *)ret, ec_to_str(ret));
267  return BF_IOCTL_FAILURE;
268  }
269 
270  ret = copy_to_user(user_drr, drr, sizeof(struct debug_ring_resources_t));
271  if (ret != 0)
272  {
273  ALERT("IOCTL_DUMP_VMM: failed to copy memory from userspace\n");
274  return BF_IOCTL_FAILURE;
275  }
276 
277  DEBUG("IOCTL_DUMP_VMM: succeeded\n");
278  return BF_IOCTL_SUCCESS;
279 }
280 
281 static long
282 ioctl_vmm_status(int64_t *status)
283 {
284  int64_t ret;
285  int64_t vmm_status = common_vmm_status();
286 
287  if (status == 0)
288  {
289  ALERT("IOCTL_VMM_STATUS: common_vmm_status failed: NULL\n");
290  return BF_IOCTL_FAILURE;
291  }
292 
293  ret = copy_to_user(status, &vmm_status, sizeof(int64_t));
294  if (ret != 0)
295  {
296  ALERT("IOCTL_VMM_STATUS: failed to copy memory from userspace\n");
297  return BF_IOCTL_FAILURE;
298  }
299 
300  return BF_IOCTL_SUCCESS;
301 }
302 
303 static long
304 ioctl_set_cpuid(uint64_t *cpuid)
305 {
306  int64_t ret;
307 
308  if (cpuid == 0)
309  {
310  ALERT("IOCTL_SET_CPUID: failed with cpuid == NULL\n");
311  return BF_IOCTL_FAILURE;
312  }
313 
314  ret = copy_from_user(&g_cpuid, cpuid, sizeof(uint64_t));
315  if (ret != 0)
316  {
317  ALERT("IOCTL_SET_CPUID: failed to copy memory from userspace\n");
318  return BF_IOCTL_FAILURE;
319  }
320 
321  return BF_IOCTL_SUCCESS;
322 }
323 
324 static long
325 ioctl_set_vcpuid(uint64_t *vcpuid)
326 {
327  int64_t ret;
328 
329  if (vcpuid == 0)
330  {
331  ALERT("IOCTL_SET_VCPUID: failed with vcpuid == NULL\n");
332  return BF_IOCTL_FAILURE;
333  }
334 
335  ret = copy_from_user(&g_vcpuid, vcpuid, sizeof(uint64_t));
336  if (ret != 0)
337  {
338  ALERT("IOCTL_SET_VCPUID: failed to copy memory from userspace\n");
339  return BF_IOCTL_FAILURE;
340  }
341 
342  return BF_IOCTL_SUCCESS;
343 }
344 
345 static long
346 ioctl_vmcall(struct vmcall_registers_t *regs)
347 {
348  int64_t ret;
349  struct vmcall_registers_t r;
350 
351  if (regs == 0)
352  {
353  ALERT("IOCTL_VMCALL: regs == NULL\n");
354  return BF_IOCTL_FAILURE;
355  }
356 
357  ret = copy_from_user(&r, regs, sizeof(struct vmcall_registers_t));
358  if (ret != 0)
359  {
360  ALERT("IOCTL_VMCALL: failed to copy memory from userspace\n");
361  return BF_IOCTL_FAILURE;
362  }
363 
364  ret = common_vmcall(&r, g_cpuid);
365  if (ret != 0)
366  {
367  ALERT("IOCTL_VMCALL: common_vmcall failed: %p - %s\n", \
368  (void *)ret, ec_to_str(ret));
369  return BF_IOCTL_FAILURE;
370  }
371 
372  ret = copy_to_user(regs, &r, sizeof(struct vmcall_registers_t));
373  if (ret != 0)
374  {
375  ALERT("IOCTL_VMCALL: failed to copy memory to userspace\n");
376  return BF_IOCTL_FAILURE;
377  }
378 
379  return BF_IOCTL_SUCCESS;
380 }
381 
382 static long
383 dev_unlocked_ioctl(struct file *file,
384  unsigned int cmd,
385  unsigned long arg)
386 {
387  (void) file;
388 
389  switch (cmd)
390  {
391  case IOCTL_ADD_MODULE:
392  return ioctl_add_module((char *)arg);
393 
394  case IOCTL_ADD_MODULE_LENGTH:
395  return ioctl_add_module_length((uint64_t *)arg);
396 
397  case IOCTL_LOAD_VMM:
398  return ioctl_load_vmm();
399 
400  case IOCTL_UNLOAD_VMM:
401  return ioctl_unload_vmm();
402 
403  case IOCTL_START_VMM:
404  return ioctl_start_vmm();
405 
406  case IOCTL_STOP_VMM:
407  return ioctl_stop_vmm();
408 
409  case IOCTL_DUMP_VMM:
410  return ioctl_dump_vmm((struct debug_ring_resources_t *)arg);
411 
412  case IOCTL_VMM_STATUS:
413  return ioctl_vmm_status((int64_t *)arg);
414 
415  case IOCTL_SET_CPUID:
416  return ioctl_set_cpuid((uint64_t *)arg);
417 
418  case IOCTL_SET_VCPUID:
419  return ioctl_set_vcpuid((uint64_t *)arg);
420 
421  case IOCTL_VMCALL:
422  return ioctl_vmcall((struct vmcall_registers_t *)arg);
423 
424  default:
425  return -EINVAL;
426  }
427 }
428 
429 static struct file_operations fops =
430 {
431  .open = dev_open,
432  .release = dev_release,
433  .unlocked_ioctl = dev_unlocked_ioctl,
434 };
435 
436 static struct miscdevice bareflank_dev =
437 {
438  MISC_DYNAMIC_MINOR,
440  &fops
441 };
442 
443 /* -------------------------------------------------------------------------- */
444 /* Entry / Exit */
445 /* -------------------------------------------------------------------------- */
446 
447 int
448 dev_reboot(struct notifier_block *nb,
449  unsigned long code, void *unused)
450 {
451  (void) nb;
452  (void) code;
453  (void) unused;
454 
455  common_fini();
456 
457  return NOTIFY_DONE;
458 }
459 
460 static struct notifier_block bareflank_notifier_block =
461 {
462  .notifier_call = dev_reboot
463 };
464 
465 int
466 dev_init(void)
467 {
468  register_reboot_notifier(&bareflank_notifier_block);
469 
470  if (misc_register(&bareflank_dev) != 0)
471  {
472  ALERT("misc_register failed\n");
473  return -EPERM;
474  }
475 
476  if (common_init() != 0)
477  {
478  ALERT("common_init failed\n");
479  return -EPERM;
480  }
481 
482  DEBUG("dev_init succeeded\n");
483  return 0;
484 }
485 
486 void
487 dev_exit(void)
488 {
489  common_fini();
490 
491  misc_deregister(&bareflank_dev);
492  unregister_reboot_notifier(&bareflank_notifier_block);
493 
494  DEBUG("dev_exit succeeded\n");
495  return;
496 }
497 
500 
501 MODULE_LICENSE("GPL");
#define BF_SUCCESS
Definition: error_codes.h:105
int64_t common_add_module(const char *file, uint64_t fsize)
Definition: common.c:305
Definition: file.h:35
module_init(dev_init)
int64_t common_load_vmm(void)
Definition: common.c:357
int64_t common_fini(void)
Definition: common.c:273
uint64_t g_cpuid
Definition: entry.c:48
uint64_t g_vcpuid
Definition: entry.c:49
int64_t common_dump_vmm(struct debug_ring_resources_t **drr, uint64_t vcpuid)
Definition: common.c:592
Definition: vcpuid.h:29
#define MAX_NUM_MODULES
Definition: constants.h:177
debug_ring_resources_t * drr
uint64_t files_size[MAX_NUM_MODULES]
Definition: entry.c:46
#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
uint64_t g_module_length
Definition: entry.c:42
int64_t common_start_vmm(void)
Definition: common.c:490
void dev_exit(void)
Definition: entry.c:487
int64_t common_init(void)
Definition: common.c:267
int dev_init(void)
Definition: entry.c:466
int64_t common_unload_vmm(void)
Definition: common.c:451
module_exit(dev_exit)
#define DEBUG(...)
Definition: debug.h:155
int64_t g_num_files
Definition: entry.c:44
MODULE_LICENSE("GPL")
int64_t common_vmm_status(void)
Definition: common.c:227
int dev_reboot(struct notifier_block *nb, unsigned long code, void *unused)
Definition: entry.c:448
#define BAREFLANK_NAME
char * files[MAX_NUM_MODULES]
Definition: entry.c:45