common.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 <common.h>
25 #include <platform.h>
26 
27 #include <entry.h>
28 #include <memory.h>
29 #include <constants.h>
30 #include <thread_context.h>
31 #include <driver_entry_interface.h>
32 
33 /* -------------------------------------------------------------------------- */
34 /* Global */
35 /* -------------------------------------------------------------------------- */
36 
38 
39 int64_t g_num_modules = 0;
41 
42 struct bfelf_loader_t g_loader;
43 
44 int64_t g_num_cpus_started = 0;
45 
46 void *g_tls = 0;
47 void *g_stack = 0;
48 
49 uint64_t g_tls_size = 0;
50 uint64_t g_stack_size = 0;
51 uint64_t g_stack_top = 0;
52 
53 /* -------------------------------------------------------------------------- */
54 /* Entry Points */
55 /* -------------------------------------------------------------------------- */
56 
58 
59 /* -------------------------------------------------------------------------- */
60 /* Helpers */
61 /* -------------------------------------------------------------------------- */
62 
63 struct module_t *
64 get_module(int64_t index)
65 {
66  if (index < 0 || index >= g_num_modules)
67  return 0;
68 
69  return &(g_modules[index]);
70 }
71 
72 uint64_t
73 symbol_length(const char *sym)
74 {
75  uint64_t len = 0;
76 
77  if (sym == 0)
78  return 0;
79 
80  while (sym[len] != '\0')
81  len++;
82 
83  return len;
84 }
85 
86 int64_t
87 resolve_symbol(const char *name, void **sym)
88 {
89  int64_t ret;
90 
91  if (name == 0 || sym == 0)
92  return BF_ERROR_INVALID_ARG;
93 
94  if (g_num_modules == 0)
96 
97  ret = bfelf_loader_resolve_symbol(&g_loader, name, sym);
98  if (ret != BFELF_SUCCESS)
99  {
100  ALERT("Failed to find: %s\n", name);
101  return ret;
102  }
103 
104  return BF_SUCCESS;
105 }
106 
107 int64_t
108 execute_symbol(const char *sym, uint64_t arg1, uint64_t arg2, uint64_t cpuid)
109 {
110  int64_t ret = 0;
111  void *entry_point = 0;
112  struct thread_context_t *tc = (struct thread_context_t *)(g_stack_top - sizeof(struct thread_context_t));
113 
114  if (sym == 0)
115  return BF_ERROR_INVALID_ARG;
116 
117  ret = resolve_symbol(sym, &entry_point);
118  if (ret != BF_SUCCESS)
119  return ret;
120 
121  tc->cpuid = cpuid;
122  tc->tlsptr = (uint64_t)g_tls + (THREAD_LOCAL_STORAGE_SIZE * cpuid);
123 
124  ret = execute_entry(g_stack_top - sizeof(struct thread_context_t) - 1, entry_point, arg1, arg2);
125  if (ret != ENTRY_SUCCESS)
126  {
127  ALERT("%s failed\n", sym);
128  return ret;
129  }
130 
131  return BF_SUCCESS;
132 }
133 
134 int64_t
136 {
137  int64_t ret = 0;
138  struct memory_descriptor md = {0, 0, 0};
139 
140  md.virt = virt;
141  md.phys = (uint64_t)platform_virt_to_phys((void *)md.virt);
142  md.type = type;
143 
144  ret = execute_symbol("add_md", (uint64_t)&md, 0, 0);
145  if (ret != MEMORY_MANAGER_SUCCESS)
146  return ret;
147 
148  return BF_SUCCESS;
149 }
150 
151 int64_t
153 {
154  int64_t ret = 0;
155  bfelf64_word s = 0;
156 
157  if (module == 0)
158  return BF_ERROR_INVALID_ARG;
159 
160  for (s = 0; s < bfelf_file_get_num_load_instrs(&module->file); s++)
161  {
162  uint64_t exec_s = 0;
163  uint64_t exec_e = 0;
164  struct bfelf_load_instr *instr = 0;
165 
166  ret = bfelf_file_get_load_instr(&module->file, s, &instr);
167  if (ret != BFELF_SUCCESS)
168  return ret;
169 
170  exec_s = (uint64_t)module->exec + instr->mem_offset;
171  exec_e = (uint64_t)module->exec + instr->mem_offset + instr->memsz;
172  exec_s &= ~(MAX_PAGE_SIZE - 1);
173  exec_e &= ~(MAX_PAGE_SIZE - 1);
174 
175  for (; exec_s <= exec_e; exec_s += MAX_PAGE_SIZE)
176  {
177  if ((instr->perm & bfpf_x) != 0)
179  else
181 
182  if (ret != MEMORY_MANAGER_SUCCESS)
183  return ret;
184  }
185  }
186 
187  return BF_SUCCESS;
188 }
189 
190 int64_t
191 load_elf_file(struct module_t *module)
192 {
193  bfelf64_word s = 0;
194 
195  if (module == 0)
196  return BF_ERROR_INVALID_ARG;
197 
198  platform_memset(module->exec, 0, module->size);
199 
200  for (s = 0; s < bfelf_file_get_num_load_instrs(&module->file); s++)
201  {
202  int64_t ret = 0;
203  struct bfelf_load_instr *instr = 0;
204 
205  const char *src = 0;
206  char *dst = 0;
207  uint64_t len = 0;
208 
209  ret = bfelf_file_get_load_instr(&module->file, s, &instr);
210  (void) ret;
211 
212  dst = module->exec + instr->mem_offset;
213  src = module->file.file + instr->file_offset;
214  len = instr->filesz;
215 
216  platform_memcpy(dst, src, len);
217  }
218 
219  return BF_SUCCESS;
220 }
221 
222 /* -------------------------------------------------------------------------- */
223 /* Implementation */
224 /* -------------------------------------------------------------------------- */
225 
226 int64_t
228 {
229  return g_vmm_status;
230 }
231 
232 int64_t
234 {
235  int64_t i;
236 
237  for (i = 0; i < g_num_modules; i++)
238  {
239  if (g_modules[i].exec != 0)
241  }
242 
243  platform_memset(&g_modules, 0, sizeof(g_modules));
244 
245  g_num_modules = 0;
247 
248  platform_memset(&g_loader, 0, sizeof(struct bfelf_loader_t));
249 
250  execute_entry = 0;
251  g_num_cpus_started = 0;
252 
253  if (g_tls != 0)
255 
256  if (g_stack != 0)
258 
259  g_tls = 0;
260  g_stack = 0;
261  g_stack_top = 0;
262 
263  return BF_SUCCESS;
264 }
265 
266 int64_t
268 {
269  return common_reset();
270 }
271 
272 int64_t
274 {
275  int64_t ret = 0;
276 
278  {
279  ret = common_stop_vmm();
280  if (ret != BF_SUCCESS)
281  ALERT("common_fini: failed to stop vmm\n");
282  }
283 
284  if (common_vmm_status() == VMM_LOADED)
285  {
286  ret = common_unload_vmm();
287  if (ret != BF_SUCCESS)
288  ALERT("common_fini: failed to unload vmm\n");
289  }
290 
292  return BF_ERROR_VMM_CORRUPTED;
293 
295  {
296  ret = common_reset();
297  if (ret != BF_SUCCESS)
298  ALERT("common_fini: failed to reset\n");
299  }
300 
301  return BF_SUCCESS;
302 }
303 
304 int64_t
305 common_add_module(const char *file, uint64_t fsize)
306 {
307  int64_t ret = 0;
308  struct module_t *module = 0;
309 
310  /*
311  * TODO: Might not be a bad idea to add the ability to detect when a
312  * module is alreayed added. Since we want the ability to have signed
313  * modules, we could combine the two and kill two birds with one stone.
314  */
315 
316  if (file == 0 || fsize == 0)
317  return BF_ERROR_INVALID_ARG;
318 
320  return BF_ERROR_VMM_CORRUPTED;
321 
324 
327 
328  module = &(g_modules[g_num_modules]);
329 
330  ret = bfelf_file_init(file, fsize, &module->file);
331  if (ret != BFELF_SUCCESS)
332  return ret;
333 
334  module->size = (uint64_t)bfelf_file_get_total_size(&module->file);
335  module->exec = platform_alloc_rwe(module->size);
336  if (module->exec == 0)
337  return BF_ERROR_OUT_OF_MEMORY;
338 
339  ret = load_elf_file(module);
340  if (ret != BF_SUCCESS)
341  goto failure;
342 
343  DEBUG("common_add_module [%d]:\n", (int)g_num_modules);
344  DEBUG(" addr = %p\n", (void *)module->exec);
345  DEBUG(" size = %p\n", (void *)module->size);
346 
347  g_num_modules++;
348  return BF_SUCCESS;
349 
350 failure:
351 
352  platform_free_rwe(module->exec, module->size);
353  return ret;
354 }
355 
356 int64_t
358 {
359  int64_t i = 0;
360  int64_t ret = 0;
361  int64_t ignore_ret = 0;
362  struct module_t *module = 0;
363 
365  return BF_ERROR_VMM_CORRUPTED;
366 
367  if (common_vmm_status() == VMM_LOADED)
368  return BF_SUCCESS;
369 
372 
373  if (g_num_modules == 0)
375 
377  g_stack_size = STACK_SIZE * 2;
378 
380  if (g_tls == 0)
381  return BF_ERROR_OUT_OF_MEMORY;
382 
384  if (g_stack == 0)
385  return BF_ERROR_OUT_OF_MEMORY;
386 
387  g_stack_top = (uint64_t)g_stack + g_stack_size;
388  g_stack_top = (g_stack_top & ~(STACK_SIZE - 1)) - 1;
389 
391  platform_memset(&g_loader, 0, sizeof(struct bfelf_loader_t));
392 
393  for (i = 0; (module = get_module(i)) != 0; i++)
394  {
395  ret = bfelf_loader_add(&g_loader, &module->file, module->exec, module->exec);
396  if (ret != BFELF_SUCCESS)
397  goto failure;
398  }
399 
400  ret = bfelf_loader_relocate(&g_loader);
401  if (ret != BFELF_SUCCESS)
402  goto failure;
403 
404  ret = resolve_symbol("execute_entry", (void **)&execute_entry);
405  if (ret != BF_SUCCESS)
406  goto failure;
407 
408  for (i = 0; (module = get_module(i)) != 0; i++)
409  {
410  struct section_info_t info = {0, 0, 0, 0, 0, 0, 0, 0};
411 
412  ret = bfelf_file_get_section_info(&module->file, &info);
413  (void) ret;
414 
415  ret = execute_symbol("local_init", (uint64_t)&info, 0, 0);
416  if (ret != BF_SUCCESS)
417  goto failure;
418  }
419 
420  for (i = 0; (module = get_module(i)) != 0; i++)
421  {
422  ret = add_md_to_memory_manager(module);
423  if (ret != BF_SUCCESS)
424  goto failure;
425  }
426 
427  {
428  uint64_t tlss = (uint64_t)g_tls;
429  uint64_t tlse = tlss + g_tls_size;
430 
431  for (; tlss <= tlse; tlss += MAX_PAGE_SIZE)
432  {
434  if (ret != BF_SUCCESS)
435  return ret;
436  }
437  }
438 
440  return BF_SUCCESS;
441 
442 failure:
443 
444  ignore_ret = common_unload_vmm();
445  (void) ignore_ret;
446 
447  return ret;
448 }
449 
450 int64_t
452 {
453  int64_t i = 0;
454  int64_t ret = 0;
455  struct module_t *module = 0;
456 
458  return BF_ERROR_VMM_CORRUPTED;
459 
462 
463  if (common_vmm_status() == VMM_LOADED)
464  {
465  for (i = g_num_modules - 1; (module = get_module(i)) != 0; i--)
466  {
467  struct section_info_t info = {0, 0, 0, 0, 0, 0, 0, 0};
468 
469  ret = bfelf_file_get_section_info(&module->file, &info);
470  (void) ret;
471 
472  ret = execute_symbol("local_fini", (uint64_t)&info, 0, 0);
473  if (ret != BF_SUCCESS)
474  goto corrupted;
475  }
476  }
477 
478  common_reset();
479 
481  return BF_SUCCESS;
482 
483 corrupted:
484 
486  return ret;
487 }
488 
489 int64_t
491 {
492  int64_t ret = 0;
493  int64_t cpuid = 0;
494  int64_t ignore_ret = 0;
495  int64_t caller_affinity = 0;
496  struct vmcall_registers_t regs;
497 
499  return BF_ERROR_VMM_CORRUPTED;
500 
502  return BF_SUCCESS;
503 
506 
507  for (cpuid = 0, g_num_cpus_started = 0; cpuid < platform_num_cpus(); cpuid++)
508  {
509  regs.r00 = VMCALL_START;
510  regs.r01 = VMCALL_MAGIC_NUMBER;
511 
512  ret = caller_affinity = platform_set_affinity(cpuid);
513  if (caller_affinity < 0)
514  goto failure;
515 
516  ret = execute_symbol("start_vmm", (uint64_t)cpuid, 0, (uint64_t)cpuid);
517  if (ret != BF_SUCCESS)
518  goto failure;
519 
521 
522  platform_vmcall(&regs);
523  if (regs.r01 != 0)
525 
526  platform_start();
527  platform_restore_affinity(caller_affinity);
528 
530  }
531 
532  return BF_SUCCESS;
533 
534 failure:
535 
536  ignore_ret = common_stop_vmm();
537  (void) ignore_ret;
538 
539  return ret;
540 }
541 
542 int64_t
544 {
545  int64_t ret = 0;
546  int64_t cpuid = 0;
547  int64_t caller_affinity = 0;
548  struct vmcall_registers_t regs;
549 
551  return BF_ERROR_VMM_CORRUPTED;
552 
553  if (common_vmm_status() == VMM_LOADED)
554  return BF_SUCCESS;
555 
558 
559  for (cpuid = g_num_cpus_started - 1; cpuid >= 0 ; cpuid--)
560  {
561  regs.r00 = VMCALL_STOP;
562  regs.r01 = VMCALL_MAGIC_NUMBER;
563 
564  ret = caller_affinity = platform_set_affinity(cpuid);
565  if (caller_affinity < 0)
566  goto corrupted;
567 
568  platform_vmcall(&regs);
569  if (regs.r01 != 0)
571 
572  ret = execute_symbol("stop_vmm", (uint64_t)cpuid, 0, (uint64_t)cpuid);
573  if (ret != BFELF_SUCCESS)
574  goto corrupted;
575 
577 
578  platform_stop();
579  platform_restore_affinity(caller_affinity);
580  }
581 
583  return BF_SUCCESS;
584 
585 corrupted:
586 
588  return ret;
589 }
590 
591 int64_t
593 {
594  int64_t ret = 0;
595 
596  if (drr == 0)
597  return BF_ERROR_INVALID_ARG;
598 
601 
602  ret = execute_symbol("get_drr", (uint64_t)vcpuid, (uint64_t)drr, 0);
603  if (ret != BFELF_SUCCESS)
604  return ret;
605 
606  return BF_SUCCESS;
607 }
608 
609 int64_t
610 common_vmcall(struct vmcall_registers_t *regs, uint64_t cpuid)
611 {
612  int64_t ret = 0;
613  int64_t caller_affinity = 0;
614  int64_t signed_cpuid = (int64_t)cpuid;
615 
617  return BF_ERROR_VMM_CORRUPTED;
618 
619  if (common_vmm_status() == VMM_LOADED)
621 
624 
625  if (regs == 0)
626  return BF_ERROR_INVALID_ARG;
627 
628  if (signed_cpuid >= g_num_cpus_started)
629  return BF_ERROR_INVALID_ARG;
630 
631  if (signed_cpuid >= 0)
632  {
633  ret = caller_affinity = platform_set_affinity((int64_t)cpuid);
634  if (caller_affinity < 0)
635  return ret;
636  }
637 
638  if (regs->r00 == VMCALL_EVENT)
639  platform_vmcall_event(regs);
640  else
641  platform_vmcall(regs);
642 
643  if (signed_cpuid >= 0)
644  platform_restore_affinity(caller_affinity);
645 
646  return BF_SUCCESS;
647 }
#define ENTRY_ERROR_VMM_START_FAILED
Definition: error_codes.h:51
#define BF_SUCCESS
Definition: error_codes.h:105
#define MEMORY_MANAGER_SUCCESS
Definition: error_codes.h:98
void platform_vmcall_event(struct vmcall_registers_t *regs)
Definition: platform.c:168
uint64_t type
Definition: memory.h:63
int64_t common_vmm_status(void)
Definition: common.c:227
int64_t load_elf_file(struct module_t *module)
Definition: common.c:191
#define VMM_LOADED
Definition: file.h:35
int64_t(* execute_entry_t)(uint64_t stack, void *func, uint64_t arg1, uint64_t arg2)
Definition: entry.h:55
char * exec
Definition: common.h:55
int64_t common_dump_vmm(struct debug_ring_resources_t **drr, uint64_t vcpuid)
Definition: common.c:592
int64_t platform_set_affinity(int64_t affinity)
Definition: platform.c:163
void * platform_alloc_rwe(uint64_t len)
Definition: platform.c:62
#define MEMORY_TYPE_E
Definition: memory.h:41
#define MEMORY_TYPE_W
Definition: memory.h:40
void * g_tls
Definition: common.c:46
execute_entry_t execute_entry
Definition: common.c:57
void platform_restore_affinity(int64_t affinity)
Definition: platform.c:182
int64_t common_reset(void)
Definition: common.c:233
int64_t common_fini(void)
Definition: common.c:273
void platform_start(void)
Definition: platform.c:136
bfelf64_off mem_offset
Definition: bfelf_loader.h:210
#define BF_ERROR_VMM_INVALID_STATE
Definition: error_codes.h:110
#define BF_ERROR_MAX_MODULES_REACHED
Definition: error_codes.h:109
void platform_memcpy(void *dst, const void *src, uint64_t num)
Definition: platform.c:127
void * platform_alloc_rw(uint64_t len)
Definition: platform.c:43
int64_t g_num_modules
Definition: common.c:39
int64_t execute_symbol(const char *sym, uint64_t arg1, uint64_t arg2, uint64_t cpuid)
Definition: common.c:108
#define MEMORY_TYPE_R
Definition: memory.h:39
Definition: vcpuid.h:29
void platform_free_rwe(void *addr, uint64_t len)
Definition: platform.c:95
uint64_t g_stack_size
Definition: common.c:50
void platform_vmcall(struct vmcall_registers_t *regs)
Definition: platform.c:162
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
bfelf64_off file_offset
Definition: bfelf_loader.h:211
void * platform_virt_to_phys(void *virt)
Definition: platform.c:109
constexpr const auto size
#define THREAD_LOCAL_STORAGE_SIZE
Definition: constants.h:241
#define MAX_PAGE_SIZE
Definition: constants.h:116
void platform_stop(void)
Definition: platform.c:144
auto index(const T virt, const F from)
int64_t common_vmcall(struct vmcall_registers_t *regs, uint64_t cpuid)
Definition: common.c:610
uint64_t g_stack_top
Definition: common.c:51
uint64_t symbol_length(const char *sym)
Definition: common.c:73
#define ALERT(...)
Definition: debug.h:156
int64_t common_stop_vmm(void)
Definition: common.c:543
int64_t common_start_vmm(void)
Definition: common.c:490
uint64_t size
Definition: common.h:56
struct module_t * get_module(int64_t index)
Definition: common.c:64
struct bfelf_loader_t g_loader
Definition: common.c:42
#define VMM_UNLOADED
int64_t g_vmm_status
Definition: common.c:37
constexpr page_table_x64::integer_pointer virt
int64_t common_add_module(const char *file, uint64_t fsize)
Definition: common.c:305
#define BFELF_SUCCESS
Definition: error_codes.h:80
void * g_stack
Definition: common.c:47
int64_t add_md_to_memory_manager(struct module_t *module)
Definition: common.c:152
uint64_t g_tls_size
Definition: common.c:49
int64_t common_load_vmm(void)
Definition: common.c:357
#define BF_ERROR_OUT_OF_MEMORY
Definition: error_codes.h:113
void platform_free_rw(void *addr, uint64_t len)
Definition: platform.c:81
#define BF_ERROR_NO_MODULES_ADDED
Definition: error_codes.h:108
constexpr const auto name
Definition: cpuid_x64.h:81
#define ENTRY_SUCCESS
Definition: error_codes.h:48
#define STACK_SIZE
Definition: constants.h:225
bfelf64_xword filesz
Definition: bfelf_loader.h:213
#define ENTRY_ERROR_VMM_STOP_FAILED
Definition: error_codes.h:52
struct module_t g_modules[MAX_NUM_MODULES]
Definition: common.c:40
int64_t add_raw_md_to_memory_manager(uint64_t virt, uint64_t type)
Definition: common.c:135
#define VMM_RUNNING
int64_t platform_num_cpus(void)
Definition: platform.c:152
#define VMM_CORRUPT
uint64_t phys
Definition: memory.h:61
int64_t common_init(void)
Definition: common.c:267
bfelf64_word perm
Definition: bfelf_loader.h:209
#define BF_ERROR_INVALID_ARG
Definition: error_codes.h:106
#define DEBUG(...)
Definition: debug.h:155
uint64_t virt
Definition: memory.h:62
struct bfelf_file_t file
Definition: common.h:57
int64_t common_unload_vmm(void)
Definition: common.c:451
bfelf64_xword memsz
Definition: bfelf_loader.h:212
int64_t resolve_symbol(const char *name, void **sym)
Definition: common.c:87
#define BF_ERROR_VMM_CORRUPTED
Definition: error_codes.h:114
int64_t g_num_cpus_started
Definition: common.c:44
#define VMCALL_MAGIC_NUMBER