Bitdefender Hypervisor Memory Introspection
handlers.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020 Bitdefender
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 #include "handlers.h"
6 #include "defs.h"
7 #include "common.h"
8 
9 #include "hvmi.h"
10 
12  unsigned long r15;
13  unsigned long r14;
14  unsigned long r13;
15  unsigned long r12;
16  unsigned long bx;
17 
18  unsigned long bp;
19  unsigned long ret_addr;
20 };
21 
22 
32 def_detour_vars(compat_arch_ptrace);
37 def_detour_vars(__vma_adjust);
39 def_detour_vars(__vma_rb_erase);
43 def_detour_vars(__text_poke);
46 def_detour_vars(crash_kexec);
48 def_detour_hijack_vars(mprotect_fixup, vma_wants_writenotify);
49 def_detour_hijack_vars(do_munmap, rb_erase);
51 
52 
54  .DetoursCount = det_max_id,
55  .Detours = {
65  init_detour_field(compat_arch_ptrace),
70  init_detour_field(__vma_adjust),
72  init_detour_field(__vma_rb_erase),
76  init_detour_field(__text_poke),
79  init_detour_field(crash_kexec),
81  init_detour_hijack_field(mprotect_fixup, vma_wants_writenotify),
82  init_detour_hijack_field(do_munmap, rb_erase),
84  },
85 };
86 
87 //
88 // Helper functions
89 //
90 
91 
92 #define current_task \
93 ({ \
94  void *ret; \
95  asm volatile("mov %[ret], gs:[%[value]]" \
96  : [ret] "=r" (ret) \
97  : [value] "rm" ((unsigned long long)hypercall_info.OsSpecificFields.CurrentTaskOffset) : ); \
98  (void *)ret; \
99 })
100 
101 
102 #define current_cpu \
103 ({ \
104  uint32_t ret; \
105  asm volatile("mov %[ret], gs:[%[value]]" \
106  : [ret] "=r" (ret) \
107  : [value] "rm" ((unsigned long long)hypercall_info.OsSpecificFields.CurrentCpuOffset) : ); \
108  ret; \
109 })
110 
111 
114 {
115  return (hypercall_info.Detours[id].EnableOptions == -1ULL)
117 }
118 
119 
121 static size_t vmcall(DETOUR_ID id)
122 {
123  if (!is_detour_enabled(id)) {
124  return 0;
125  }
126 
127  size_t _out_value = 34, _out_param = 0;
128 
129  asm volatile("vmcall" : "+S" (_out_param), "+a"(_out_value) : "D"(24), "b"(id): );
130 
131  // Used to clean the stack of the interrupted task
132  volatile struct inactive_task_frame _reserved = { 0 };
133  (void)(_reserved);
134 
135  return _out_param;
136 }
137 
138 
140 char *d_path(void *path_struct)
141 {
142  void *path = (void *)((unsigned long)hypercall_info.OsSpecificFields.PercpuMemPtr + (current_cpu * PAGE_SIZE));
143 
144  return hypercall_info.OsSpecificFields.DPathFnPtr(path_struct, path, PAGE_SIZE);
145 }
146 
147 
149 void *_memcpy (void *dest, const void *src, size_t len)
150 {
151  char *d = dest;
152  const char *s = src;
153 
154  while (len--)
155  {
156  *d++ = *s++;
157  }
158 
159  return dest;
160 }
161 
162 
164 void store_regs(void)
165 {
166  IG_ARCH_REGS regs;
167 
168  regs.Rax = __read_reg("rax");
169  regs.Rcx = __read_reg("rcx");
170  regs.Rdx = __read_reg("rdx");
171  regs.Rbx = __read_reg("rbx");
172  regs.Rsp = __read_reg("rsp");
173  regs.Rbp = __read_reg("rbp");
174  regs.Rsi = __read_reg("rsi");
175  regs.Rdi = __read_reg("rdi");
176  regs.R8 = __read_reg("r8");
177  regs.R9 = __read_reg("r9");
178  regs.R10 = __read_reg("r10");
179  regs.R11 = __read_reg("r11");
180  regs.R12 = __read_reg("r12");
181  regs.R13 = __read_reg("r13");
182  regs.R14 = __read_reg("r14");
183  regs.R15 = __read_reg("r15");
184 
185  void *dst = (void *)((unsigned long)hypercall_info.OsSpecificFields.PercpuMemPtr + (current_cpu * PAGE_SIZE));
186  _memcpy(dst, &regs, sizeof(regs));
187 }
188 
189 
192 void commit_creds (long *creds)
193 {
194  void *current = current_task;
195 
197  uint32_t *in_execve = (uint32_t *)((unsigned long)(current) + hypercall_info.OsSpecificFields.Task.InExecve);
198 
199  if ((*in_execve & BIT(hypercall_info.OsSpecificFields.Task.InExecveBit))) {
200  return;
201  }
202  }
203 
204  vmcall_2(det_commit_creds, current, creds);
205 }
206 
207 
210 void module_param_sysfs_setup(void *module)
211 {
213 }
214 
215 
218 void module_param_sysfs_remove(void *module)
219 {
221 }
222 
223 
226 void wake_up_new_task(long task)
227 {
229 }
230 
231 
234 int flush_old_exec(long binprm)
235 {
236  unsigned long file = *(unsigned long *)(binprm + hypercall_info.OsSpecificFields.Binprm.FileOffset);
237  unsigned long path_struct = 0;
238 
239  if (!file) {
240  goto _vmcall;
241  }
242 
243  path_struct = file + hypercall_info.OsSpecificFields.File.PathOffset;
244 
245 _vmcall:
246  return vmcall_3(det_flush_old_exec, current_task, binprm, d_path((void *)path_struct));
247 }
248 
249 
252 int begin_new_exec(long binprm)
253 {
254  unsigned long file = *(unsigned long *)(binprm + hypercall_info.OsSpecificFields.Binprm.FileOffset);
255  unsigned long path_struct = 0;
256 
257  if (!file) {
258  goto _vmcall;
259  }
260 
261  path_struct = file + hypercall_info.OsSpecificFields.File.PathOffset;
262 
263 _vmcall:
264  return vmcall_3(det_begin_new_exec, current_task, binprm, d_path((void *)path_struct));
265 }
266 
267 
270 void do_exit(long code)
271 {
273 }
274 
275 
278 long arch_ptrace(long child, long request)
279 {
280  if (request == PTRACE_POKEDATA
281  || request == PTRACE_POKETEXT
282  || request == PTRACE_SETFPREGS
283  || request == PTRACE_SETFPXREGS
284  || request == PTRACE_SETREGS)
285  {
286  return vmcall_2(det_arch_ptrace, child, request);
287  }
288 
289  return 0;
290 }
291 
292 
295 size_t process_vm_rw_core(int pid, void *iter, void *rvec, unsigned long riovcnt,
296  unsigned long flags, int vm_write)
297 {
298  if (!vm_write) {
299  return 0;
300  }
301 
303 }
304 
305 
308 void __vma_link_rb(void *mm, void *vma, void **rb_link, void *rb_parent)
309 {
310  long mm_flags = *(long *)((long)(mm) + hypercall_info.OsSpecificFields.Mm.FlagsOffset);
311 
312  if (!(mm_flags & BIT(hypercall_info.OsSpecificFields.Mm.ProtectionBit))) {
313  return;
314  }
315 
316  long file = *(long *)((long)(vma) + hypercall_info.OsSpecificFields.Vma.FileOffset);
317  if (file) {
318  return;
319  }
320 
321  long vm_flags = *(long *)((long)(vma) + hypercall_info.OsSpecificFields.Vma.FlagsOffset);
322  if (!(vm_flags & VM_EXEC)) {
323  return;
324  }
325 
326  vmcall_2(det___vma_link_rb, vma, mm);
327 }
328 
329 
332 void change_protection(long vma, unsigned long start, unsigned long end,
333  unsigned long newprot, int dirty_accountable, int prot_numa)
334 {
335  long file = *(long *)(vma + hypercall_info.OsSpecificFields.Vma.FileOffset);
336  if (file) {
337  return;
338  }
339 
340  long mm = *(long *)(vma + hypercall_info.OsSpecificFields.Vma.MmOffset);
341  long mm_flags = *(long *)(mm + hypercall_info.OsSpecificFields.Mm.FlagsOffset);
342 
343  if (!(mm_flags & BIT(hypercall_info.OsSpecificFields.Mm.ProtectionBit))) {
344  return;
345  }
346 
347  long vm_flags = *(long *)(vma + hypercall_info.OsSpecificFields.Vma.FlagsOffset);
348 
349  if (((vm_flags & BIT(hypercall_info.OsSpecificFields.Vma.ProtectionBit)) && !(vm_flags & VM_EXEC))
350  || (!(vm_flags & BIT(hypercall_info.OsSpecificFields.Vma.ProtectionBit)) && (vm_flags & VM_EXEC))) {
351 
352  // Either we protected it and now the X bit will be removed, or we didn't and now the X bit will be set
354  }
355 }
356 
357 
360 void pre_vma_adjust(long vma, unsigned long start, unsigned long end,
361  unsigned long pgoff, void *insert, void *expand,
362  long *skip_call, long *saved_vma, long *next, long *prev)
363 {
364  *skip_call = 1;
365 
366  long vm_flags = *(long *)(vma + hypercall_info.OsSpecificFields.Vma.FlagsOffset);
367  if (!(vm_flags & BIT(hypercall_info.OsSpecificFields.Vma.ProtectionBit))) {
368  return;
369  }
370 
371  *saved_vma = vma;
372  *next = *(long *)(vma + hypercall_info.OsSpecificFields.Vma.VmNextOffset);
373  *prev = *(long *)(vma + hypercall_info.OsSpecificFields.Vma.VmPrevOffset);
374  *skip_call = 0;
375 
376  return;
377 }
378 
379 
381 void vma_adjust(long _vma, unsigned long _start, unsigned long _end,
382  unsigned long _pgoff, void *_insert, void *_expand,
383  long *_skip_call, long saved_vma, long next, long prev)
384 {
385  long svma = saved_vma;
386  long mm = *(long *)(saved_vma + hypercall_info.OsSpecificFields.Vma.MmOffset);
387 
388  vmcall_4(det_vma_adjust, svma, mm, next, prev);
389  vmcall_4(det___vma_adjust, svma, mm, next, prev);
390 }
391 
392 
395 void vma_rb_erase(long vma, void *root)
396 {
397  long vm_flags = *(long *)(vma + hypercall_info.OsSpecificFields.Vma.FlagsOffset);
398  if (!(vm_flags & BIT(hypercall_info.OsSpecificFields.Vma.ProtectionBit))) {
399  return;
400  }
401 
404 }
405 
406 
409 void expand_downwards(long vma, unsigned long address)
410 {
411  long vm_flags = *(long *)(vma + hypercall_info.OsSpecificFields.Vma.FlagsOffset);
412  if (!(vm_flags & BIT(hypercall_info.OsSpecificFields.Vma.ProtectionBit))) {
413  return;
414  }
415 
416  vmcall_3(det_expand_downwards, vma, *(long *)(vma + hypercall_info.OsSpecificFields.Vma.MmOffset), address);
417 }
418 
419 
422 int complete_signal(int sig, void *task, enum pid_type type)
423 {
424  if (sig != SIGQUIT
425  && sig != SIGILL
426  && sig != SIGIOT
427  && sig != SIGBUS
428  && sig != SIGFPE
429  && sig != SIGSEGV) {
430 
431  return sig;
432  }
433 
434  int new_sig = vmcall_3(det_complete_signal, task, sig, type);
435  return new_sig ? new_sig : sig;
436 }
437 
438 
441 void text_poke(void *addr, const void *opcode, size_t len)
442 {
443  vmcall_3(det_text_poke, addr, opcode, len);
444  vmcall_3(det___text_poke, addr, opcode, len);
445 }
446 
447 
450 void ftrace_write(unsigned long ip, const char *val, int size)
451 {
452  vmcall_3(det_ftrace_write, ip, val, size);
453 }
454 
455 
458 void panic(const char *fmt)
459 {
460  vmcall(det_panic);
461 }
462 
463 
466 void arch_jump_label_transform(void *entry, enum jump_label_type type)
467 {
469 }
470 
471 
474 void __access_remote_vm(void *task, void *mm, unsigned long addr,
475  void *buf, int len, unsigned int gup_flags)
476 {
477  if ((gup_flags & 1) == 0) {
478  return;
479  }
480 
481  vmcall_5(det___access_remote_vm, mm, addr, buf, len, gup_flags);
482 }
483 
484 
487 void do_munmap_rb_erase(unsigned long vma_vm_rb, unsigned long mm_mm_rb)
488 {
489  unsigned long vma = vma_vm_rb - hypercall_info.OsSpecificFields.Vma.Rb;
490  unsigned long mm = mm_mm_rb - hypercall_info.OsSpecificFields.Mm.Rb;
491  long vm_flags = *(long *)(vma + hypercall_info.OsSpecificFields.Vma.FlagsOffset);
492 
493  if (!(vm_flags & BIT(hypercall_info.OsSpecificFields.Vma.ProtectionBit))) {
494  return;
495  }
496 
498 }
499 
500 
503 void vma_adjust_rb_erase(unsigned long vma_vm_rb, unsigned long mm_mm_rb)
504 {
505  unsigned long vma = vma_vm_rb - hypercall_info.OsSpecificFields.Vma.Rb;
506  unsigned long mm = mm_mm_rb - hypercall_info.OsSpecificFields.Mm.Rb;
507  long vm_flags = *(long *)(vma + hypercall_info.OsSpecificFields.Vma.FlagsOffset);
508 
509  if (!(vm_flags & BIT(hypercall_info.OsSpecificFields.Vma.ProtectionBit))) {
510  return;
511  }
512 
514 }
515 
516 
520 {
521  long file = *(long *)(vma + hypercall_info.OsSpecificFields.Vma.FileOffset);
522  if (file) {
523  return;
524  }
525 
526  long mm = *(long *)(vma + hypercall_info.OsSpecificFields.Vma.MmOffset);
527  long mm_flags = *(long *)(mm + hypercall_info.OsSpecificFields.Mm.FlagsOffset);
528 
529  if (!(mm_flags & BIT(hypercall_info.OsSpecificFields.Mm.ProtectionBit))) {
530  return;
531  }
532 
533  long vm_flags = *(long *)(vma + hypercall_info.OsSpecificFields.Vma.FlagsOffset);
534 
535  if (((vm_flags & BIT(hypercall_info.OsSpecificFields.Vma.ProtectionBit)) && !(vm_flags & VM_EXEC))
536  || (!(vm_flags & BIT(hypercall_info.OsSpecificFields.Vma.ProtectionBit)) && (vm_flags & VM_EXEC))) {
537 
538  // Either we protected it and now the X bit will be removed, or we didn't and now the X bit will be set
540  }
541 }
542 
543 
544 // Will be droped by the compiler, but will generate usefull #defines for asm
545 void __asm_defines(void)
546 {
556  def_detour_asm_vars(compat_arch_ptrace);
561  def_detour_asm_vars(__vma_adjust);
563  def_detour_asm_vars(__vma_rb_erase);
567  def_detour_asm_vars(__text_poke);
570  def_detour_asm_vars(crash_kexec);
572 
573  def_detour_hijack_asm_vars(mprotect_fixup, vma_wants_writenotify);
574  def_detour_hijack_asm_vars(do_munmap, rb_erase);
576 }
577 
578 
struct _LIX_GUEST_OS_SPECIFIC::@265 File
#define PTRACE_SETREGS
Definition: lixddefs.h:106
struct _LIX_GUEST_OS_SPECIFIC::@263 Task
struct _LIX_GUEST_OS_SPECIFIC::@262 Mm
#define SIGQUIT
Definition: lixddefs.h:197
#define PTRACE_POKETEXT
Definition: lixddefs.h:98
#define def_detour_hijack_asm_vars(fn_name, hijack_fn_name)
Definition: common.h:48
unsigned long r12
Definition: handlers.c:15
#define BIT(x)
Definition: common.h:68
__default_fn_attr void module_param_sysfs_setup(void *module)
Definition: handlers.c:210
#define SIGIOT
Definition: lixddefs.h:201
__default_fn_attr void * _memcpy(void *dest, const void *src, size_t len)
Definition: handlers.c:149
#define SIGFPE
Definition: lixddefs.h:203
#define SIGBUS
Definition: lixddefs.h:202
void __asm_defines(void)
Definition: handlers.c:545
#define def_detour_asm_vars(fn_name)
Definition: common.h:45
LIX_HYPERCALL_PAGE hypercall_info
Definition: handlers.c:53
__default_fn_attr void text_poke(void *addr, const void *opcode, size_t len)
Definition: handlers.c:441
__default_fn_attr void change_protection(long vma, unsigned long start, unsigned long end, unsigned long newprot, int dirty_accountable, int prot_numa)
Definition: handlers.c:332
unsigned int VmPrevOffset
Definition: handlers.h:55
__default_fn_attr long arch_ptrace(long child, long request)
Definition: handlers.c:278
struct _LIX_GUEST_OS_SPECIFIC::@260 Info
__default_fn_attr char * d_path(void *path_struct)
Definition: handlers.c:140
__default_fn_attr void vma_adjust(long _vma, unsigned long _start, unsigned long _end, unsigned long _pgoff, void *_insert, void *_expand, long *_skip_call, long saved_vma, long next, long prev)
Definition: handlers.c:381
LIX_GUEST_OS_SPECIFIC OsSpecificFields
Definition: handlers.h:117
unsigned long long EnableOptions
Definition: handlers.h:106
pid_type
Definition: defs.h:8
__default_fn_attr int complete_signal(int sig, void *task, enum pid_type type)
Definition: handlers.c:422
unsigned int FileOffset
Definition: handlers.h:53
unsigned long r15
Definition: handlers.c:12
__default_fn_attr void module_param_sysfs_remove(void *module)
Definition: handlers.c:218
__default_fn_attr void wake_up_new_task(long task)
Definition: handlers.c:226
static __default_fn_attr size_t vmcall(DETOUR_ID id)
Definition: handlers.c:121
unsigned long r13
Definition: handlers.c:14
unsigned int Rb
Definition: handlers.h:56
def_detour_vars(commit_creds)
#define vmcall_1(id, p1)
Definition: common.h:97
unsigned long ret_addr
Definition: handlers.c:19
def_detour_hijack_vars(mprotect_fixup, vma_wants_writenotify)
jump_label_type
Definition: defs.h:17
__default_fn_attr void expand_downwards(long vma, unsigned long address)
Definition: handlers.c:409
__default_fn_attr size_t process_vm_rw_core(int pid, void *iter, void *rvec, unsigned long riovcnt, unsigned long flags, int vm_write)
Definition: handlers.c:295
__default_fn_attr void store_regs(void)
Definition: handlers.c:164
d_path_fn * DPathFnPtr
Definition: handlers.h:96
unsigned int InExecveBit
Definition: handlers.h:70
__default_fn_attr void __access_remote_vm(void *task, void *mm, unsigned long addr, void *buf, int len, unsigned int gup_flags)
Definition: handlers.c:474
#define __section(S)
Definition: common.h:76
#define vmcall_5(id, p1, p2, p3, p4, p5)
Definition: common.h:131
__default_fn_attr void do_munmap_rb_erase(unsigned long vma_vm_rb, unsigned long mm_mm_rb)
Definition: handlers.c:487
__default_fn_attr void panic(const char *fmt)
Definition: handlers.c:458
__default_fn_attr void do_exit(long code)
Definition: handlers.c:270
#define VM_EXEC
Definition: lixddefs.h:43
#define __default_fn_attr
Definition: common.h:78
#define current_task
Definition: handlers.c:92
#define init_detour_field(fn_name)
Definition: common.h:56
unsigned int InExecve
Definition: handlers.h:69
__default_fn_attr void ftrace_write(unsigned long ip, const char *val, int size)
Definition: handlers.c:450
#define vmcall_4(id, p1, p2, p3, p4)
Definition: common.h:121
LIX_GUEST_DETOUR Detours[det_max_id]
Definition: handlers.h:115
struct _LIX_GUEST_OS_SPECIFIC::@264 Binprm
#define PAGE_SIZE
Definition: common.h:70
unsigned int ProtectionBit
Definition: handlers.h:58
#define vmcall_3(id, p1, p2, p3)
Definition: common.h:112
#define __read_reg(reg)
Definition: common.h:153
__default_fn_attr void arch_jump_label_transform(void *entry, enum jump_label_type type)
Definition: handlers.c:466
unsigned int MmOffset
Definition: handlers.h:51
__default_fn_attr int begin_new_exec(long binprm)
Definition: handlers.c:252
unsigned long bp
Definition: handlers.c:18
unsigned int PathOffset
Definition: handlers.h:79
#define vmcall_2(id, p1, p2)
Definition: common.h:104
#define PTRACE_POKEDATA
Definition: lixddefs.h:99
unsigned int VmNextOffset
Definition: handlers.h:54
__default_fn_attr void pre_vma_adjust(long vma, unsigned long start, unsigned long end, unsigned long pgoff, void *insert, void *expand, long *skip_call, long *saved_vma, long *next, long *prev)
Definition: handlers.c:360
__default_fn_attr void commit_creds(long *creds)
Definition: handlers.c:192
__default_fn_attr void mprotect_fixup_vma_wants_writenotify(unsigned long vma)
Definition: handlers.c:519
static __default_fn_attr bool is_detour_enabled(DETOUR_ID id)
Definition: handlers.c:113
#define SIGSEGV
Definition: lixddefs.h:206
unsigned long r14
Definition: handlers.c:13
unsigned int FlagsOffset
Definition: handlers.h:52
__default_fn_attr void vma_adjust_rb_erase(unsigned long vma_vm_rb, unsigned long mm_mm_rb)
Definition: handlers.c:503
__default_fn_attr void vma_rb_erase(long vma, void *root)
Definition: handlers.c:395
#define PTRACE_SETFPXREGS
Definition: lixddefs.h:110
Holds register state.
Definition: glueiface.h:30
unsigned long long ProtectionOptions
Definition: handlers.h:112
__default_fn_attr void __vma_link_rb(void *mm, void *vma, void **rb_link, void *rb_parent)
Definition: handlers.c:308
#define SIGILL
Definition: lixddefs.h:198
__default_fn_attr int flush_old_exec(long binprm)
Definition: handlers.c:234
#define current_cpu
Definition: handlers.c:102
unsigned long bx
Definition: handlers.c:16
#define init_detour_hijack_field(fn_name, hijack_fn_name)
Definition: common.h:64
unsigned int CredAltered
Definition: handlers.h:47
#define PTRACE_SETFPREGS
Definition: lixddefs.h:108
struct _LIX_GUEST_OS_SPECIFIC::@261 Vma
DETOUR_ID
Definition: handlers.h:10