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 
10  unsigned long r15;
11  unsigned long r14;
12  unsigned long r13;
13  unsigned long r12;
14  unsigned long bx;
15 
16  unsigned long bp;
17  unsigned long ret_addr;
18 };
19 
20 
29 def_detour_vars(compat_arch_ptrace);
34 def_detour_vars(__vma_adjust);
36 def_detour_vars(__vma_rb_erase);
40 def_detour_vars(__text_poke);
43 def_detour_vars(crash_kexec);
45 def_detour_hijack_vars(mprotect_fixup, vma_wants_writenotify);
46 def_detour_hijack_vars(do_munmap, rb_erase);
48 
49 
51  .DetoursCount = det_max_id,
52  .Detours = {
61  init_detour_field(compat_arch_ptrace),
66  init_detour_field(__vma_adjust),
68  init_detour_field(__vma_rb_erase),
72  init_detour_field(__text_poke),
75  init_detour_field(crash_kexec),
77  init_detour_hijack_field(mprotect_fixup, vma_wants_writenotify),
78  init_detour_hijack_field(do_munmap, rb_erase),
80  },
81 };
82 
83 //
84 // Helper functions
85 //
86 
87 
88 #define current_task \
89 ({ \
90  void *ret; \
91  asm volatile("mov %[ret], gs:[%[value]]" \
92  : [ret] "=r" (ret) \
93  : [value] "rm" ((unsigned long long)hypercall_info.OsSpecificFields.CurrentTaskOffset) : ); \
94  (void *)ret; \
95 })
96 
97 
98 #define current_cpu \
99 ({ \
100  uint32_t ret; \
101  asm volatile("mov %[ret], gs:[%[value]]" \
102  : [ret] "=r" (ret) \
103  : [value] "rm" ((unsigned long long)hypercall_info.OsSpecificFields.CurrentCpuOffset) : ); \
104  ret; \
105 })
106 
107 
110 {
111  return (hypercall_info.Detours[id].EnableOptions == -1ULL)
113 }
114 
115 
117 static size_t vmcall(DETOUR_ID id)
118 {
119  if (!is_detour_enabled(id)) {
120  return 0;
121  }
122 
123  size_t _out_value = 34, _out_param = 0;
124 
125  asm volatile("vmcall" : "+S" (_out_param), "+a"(_out_value) : "D"(24), "b"(id): );
126 
127  // Used to clean the stack of the interrupted task
128  volatile struct inactive_task_frame _reserved = { 0 };
129  (void)(_reserved);
130 
131  return _out_param;
132 }
133 
134 
136 char *d_path(void *path_struct)
137 {
138  void *path = (void *)((unsigned long)hypercall_info.OsSpecificFields.PercpuMemPtr + (current_cpu * PAGE_SIZE));
139 
140  return hypercall_info.OsSpecificFields.DPathFnPtr(path_struct, path, PAGE_SIZE);
141 }
142 
143 
146 void commit_creds (long *creds)
147 {
148  void *current = current_task;
149  uint32_t *in_execve = (uint32_t *)((unsigned long)(current) + hypercall_info.OsSpecificFields.Task.InExecve);
150 
151  if ((*in_execve & BIT(hypercall_info.OsSpecificFields.Task.InExecveBit))) {
152  return;
153  }
154 
155  vmcall_2(det_commit_creds, current, creds);
156 }
157 
158 
161 void module_param_sysfs_setup(void *module)
162 {
164 }
165 
166 
169 void module_param_sysfs_remove(void *module)
170 {
172 }
173 
174 
177 void wake_up_new_task(long task)
178 {
180 }
181 
182 
185 int flush_old_exec(long binprm)
186 {
187  unsigned long file = *(unsigned long *)(binprm + hypercall_info.OsSpecificFields.Binprm.FileOffset);
188  unsigned long path_struct = 0;
189 
190  if (!file) {
191  goto _vmcall;
192  }
193 
194  path_struct = file + hypercall_info.OsSpecificFields.File.PathOffset;
195 
196 _vmcall:
197  return vmcall_3(det_flush_old_exec, current_task, binprm, d_path((void *)path_struct));
198 }
199 
200 
203 void do_exit(long code)
204 {
206 }
207 
208 
211 long arch_ptrace(long child, long request)
212 {
213  if (request == PTRACE_POKEDATA
214  || request == PTRACE_POKETEXT
215  || request == PTRACE_SETFPREGS
216  || request == PTRACE_SETFPXREGS
217  || request == PTRACE_SETREGS)
218  {
219  return vmcall_2(det_arch_ptrace, child, request);
220  }
221 
222  return 0;
223 }
224 
225 
228 size_t process_vm_rw_core(int pid, void *iter, void *rvec, unsigned long riovcnt,
229  unsigned long flags, int vm_write)
230 {
231  if (!vm_write) {
232  return 0;
233  }
234 
236 }
237 
238 
241 void __vma_link_rb(void *mm, void *vma, void **rb_link, void *rb_parent)
242 {
243  long mm_flags = *(long *)((long)(mm) + hypercall_info.OsSpecificFields.Mm.FlagsOffset);
244 
245  if (!(mm_flags & BIT(hypercall_info.OsSpecificFields.Mm.ProtectionBit))) {
246  return;
247  }
248 
249  long file = *(long *)((long)(vma) + hypercall_info.OsSpecificFields.Vma.FileOffset);
250  if (file) {
251  return;
252  }
253 
254  long vm_flags = *(long *)((long)(vma) + hypercall_info.OsSpecificFields.Vma.FlagsOffset);
255  if (!(vm_flags & VM_EXEC)) {
256  return;
257  }
258 
259  vmcall_2(det___vma_link_rb, vma, mm);
260 }
261 
262 
265 void change_protection(long vma, unsigned long start, unsigned long end,
266  unsigned long newprot, int dirty_accountable, int prot_numa)
267 {
268  long file = *(long *)(vma + hypercall_info.OsSpecificFields.Vma.FileOffset);
269  if (file) {
270  return;
271  }
272 
273  long mm = *(long *)(vma + hypercall_info.OsSpecificFields.Vma.MmOffset);
274  long mm_flags = *(long *)(mm + hypercall_info.OsSpecificFields.Mm.FlagsOffset);
275 
276  if (!(mm_flags & BIT(hypercall_info.OsSpecificFields.Mm.ProtectionBit))) {
277  return;
278  }
279 
280  long vm_flags = *(long *)(vma + hypercall_info.OsSpecificFields.Vma.FlagsOffset);
281 
282  if (((vm_flags & BIT(hypercall_info.OsSpecificFields.Vma.ProtectionBit)) && !(vm_flags & VM_EXEC))
283  || (!(vm_flags & BIT(hypercall_info.OsSpecificFields.Vma.ProtectionBit)) && (vm_flags & VM_EXEC))) {
284 
285  // Either we protected it and now the X bit will be removed, or we didn't and now the X bit will be set
287  }
288 }
289 
290 
293 void pre_vma_adjust(long vma, unsigned long start, unsigned long end,
294  unsigned long pgoff, void *insert, void *expand,
295  long *skip_call, long *saved_vma, long *next, long *prev)
296 {
297  *skip_call = 1;
298 
299  long vm_flags = *(long *)(vma + hypercall_info.OsSpecificFields.Vma.FlagsOffset);
300  if (!(vm_flags & BIT(hypercall_info.OsSpecificFields.Vma.ProtectionBit))) {
301  return;
302  }
303 
304  *saved_vma = vma;
305  *next = *(long *)(vma + hypercall_info.OsSpecificFields.Vma.VmNextOffset);
306  *prev = *(long *)(vma + hypercall_info.OsSpecificFields.Vma.VmPrevOffset);
307  *skip_call = 0;
308 
309  return;
310 }
311 
312 
314 void vma_adjust(long _vma, unsigned long _start, unsigned long _end,
315  unsigned long _pgoff, void *_insert, void *_expand,
316  long *_skip_call, long saved_vma, long next, long prev)
317 {
318  long svma = saved_vma;
319  long mm = *(long *)(saved_vma + hypercall_info.OsSpecificFields.Vma.MmOffset);
320 
321  vmcall_4(det_vma_adjust, svma, mm, next, prev);
322  vmcall_4(det___vma_adjust, svma, mm, next, prev);
323 }
324 
325 
328 void vma_rb_erase(long vma, void *root)
329 {
330  long vm_flags = *(long *)(vma + hypercall_info.OsSpecificFields.Vma.FlagsOffset);
331  if (!(vm_flags & BIT(hypercall_info.OsSpecificFields.Vma.ProtectionBit))) {
332  return;
333  }
334 
337 }
338 
339 
342 void expand_downwards(long vma, unsigned long address)
343 {
344  long vm_flags = *(long *)(vma + hypercall_info.OsSpecificFields.Vma.FlagsOffset);
345  if (!(vm_flags & BIT(hypercall_info.OsSpecificFields.Vma.ProtectionBit))) {
346  return;
347  }
348 
349  vmcall_3(det_expand_downwards, vma, *(long *)(vma + hypercall_info.OsSpecificFields.Vma.MmOffset), address);
350 }
351 
352 
355 int complete_signal(int sig, void *task, enum pid_type type)
356 {
357  if (sig != SIGQUIT
358  && sig != SIGILL
359  && sig != SIGIOT
360  && sig != SIGBUS
361  && sig != SIGFPE
362  && sig != SIGSEGV) {
363 
364  return sig;
365  }
366 
367  int new_sig = vmcall_3(det_complete_signal, task, sig, type);
368  return new_sig ? new_sig : sig;
369 }
370 
371 
374 void text_poke(void *addr, const void *opcode, size_t len)
375 {
376  vmcall_3(det_text_poke, addr, opcode, len);
377  vmcall_3(det___text_poke, addr, opcode, len);
378 }
379 
380 
383 void ftrace_write(unsigned long ip, const char *val, int size)
384 {
385  vmcall_3(det_ftrace_write, ip, val, size);
386 }
387 
388 
391 void panic(const char *fmt)
392 {
393  vmcall(det_panic);
394 }
395 
396 
399 void arch_jump_label_transform(void *entry, enum jump_label_type type)
400 {
402 }
403 
404 
407 void __access_remote_vm(void *task, void *mm, unsigned long addr,
408  void *buf, int len, unsigned int gup_flags)
409 {
410  if ((gup_flags & 1) == 0) {
411  return;
412  }
413 
414  vmcall_5(det___access_remote_vm, mm, addr, buf, len, gup_flags);
415 }
416 
417 
420 void do_munmap_rb_erase(unsigned long vma_vm_rb, unsigned long mm_mm_rb)
421 {
422  unsigned long vma = vma_vm_rb - hypercall_info.OsSpecificFields.Vma.Rb;
423  unsigned long mm = mm_mm_rb - hypercall_info.OsSpecificFields.Mm.Rb;
424  long vm_flags = *(long *)(vma + hypercall_info.OsSpecificFields.Vma.FlagsOffset);
425 
426  if (!(vm_flags & BIT(hypercall_info.OsSpecificFields.Vma.ProtectionBit))) {
427  return;
428  }
429 
431 }
432 
433 
436 void vma_adjust_rb_erase(unsigned long vma_vm_rb, unsigned long mm_mm_rb)
437 {
438  unsigned long vma = vma_vm_rb - hypercall_info.OsSpecificFields.Vma.Rb;
439  unsigned long mm = mm_mm_rb - hypercall_info.OsSpecificFields.Mm.Rb;
440  long vm_flags = *(long *)(vma + hypercall_info.OsSpecificFields.Vma.FlagsOffset);
441 
442  if (!(vm_flags & BIT(hypercall_info.OsSpecificFields.Vma.ProtectionBit))) {
443  return;
444  }
445 
447 }
448 
449 
453 {
454  long file = *(long *)(vma + hypercall_info.OsSpecificFields.Vma.FileOffset);
455  if (file) {
456  return;
457  }
458 
459  long mm = *(long *)(vma + hypercall_info.OsSpecificFields.Vma.MmOffset);
460  long mm_flags = *(long *)(mm + hypercall_info.OsSpecificFields.Mm.FlagsOffset);
461 
462  if (!(mm_flags & BIT(hypercall_info.OsSpecificFields.Mm.ProtectionBit))) {
463  return;
464  }
465 
466  long vm_flags = *(long *)(vma + hypercall_info.OsSpecificFields.Vma.FlagsOffset);
467 
468  if (((vm_flags & BIT(hypercall_info.OsSpecificFields.Vma.ProtectionBit)) && !(vm_flags & VM_EXEC))
469  || (!(vm_flags & BIT(hypercall_info.OsSpecificFields.Vma.ProtectionBit)) && (vm_flags & VM_EXEC))) {
470 
471  // Either we protected it and now the X bit will be removed, or we didn't and now the X bit will be set
473  }
474 }
475 
476 
477 // Will be droped by the compiler, but will generate usefull #defines for asm
478 void __asm_defines(void)
479 {
488  def_detour_asm_vars(compat_arch_ptrace);
493  def_detour_asm_vars(__vma_adjust);
495  def_detour_asm_vars(__vma_rb_erase);
499  def_detour_asm_vars(__text_poke);
502  def_detour_asm_vars(crash_kexec);
504 
505  def_detour_hijack_asm_vars(mprotect_fixup, vma_wants_writenotify);
506  def_detour_hijack_asm_vars(do_munmap, rb_erase);
508 }
509 
510 
#define PTRACE_SETREGS
Definition: lixddefs.h:106
#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:13
#define BIT(x)
Definition: common.h:51
__default_fn_attr void module_param_sysfs_setup(void *module)
Definition: handlers.c:161
#define SIGIOT
Definition: lixddefs.h:201
#define SIGFPE
Definition: lixddefs.h:203
#define SIGBUS
Definition: lixddefs.h:202
void __asm_defines(void)
Definition: handlers.c:478
#define def_detour_asm_vars(fn_name)
Definition: common.h:45
LIX_HYPERCALL_PAGE hypercall_info
Definition: handlers.c:50
__default_fn_attr void text_poke(void *addr, const void *opcode, size_t len)
Definition: handlers.c:374
__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:265
unsigned int VmPrevOffset
Definition: handlers.h:50
__default_fn_attr long arch_ptrace(long child, long request)
Definition: handlers.c:211
struct _LIX_GUEST_OS_SPECIFIC::@254 Vma
__default_fn_attr char * d_path(void *path_struct)
Definition: handlers.c:136
__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:314
LIX_GUEST_OS_SPECIFIC OsSpecificFields
Definition: handlers.h:112
unsigned long long EnableOptions
Definition: handlers.h:101
pid_type
Definition: defs.h:8
__default_fn_attr int complete_signal(int sig, void *task, enum pid_type type)
Definition: handlers.c:355
unsigned int FileOffset
Definition: handlers.h:48
unsigned long r15
Definition: handlers.c:10
__default_fn_attr void module_param_sysfs_remove(void *module)
Definition: handlers.c:169
__default_fn_attr void wake_up_new_task(long task)
Definition: handlers.c:177
static __default_fn_attr size_t vmcall(DETOUR_ID id)
Definition: handlers.c:117
unsigned long r13
Definition: handlers.c:12
unsigned int Rb
Definition: handlers.h:51
def_detour_vars(commit_creds)
#define vmcall_1(id, p1)
Definition: common.h:97
unsigned long ret_addr
Definition: handlers.c:17
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:342
__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:228
d_path_fn * DPathFnPtr
Definition: handlers.h:91
unsigned int InExecveBit
Definition: handlers.h:65
struct _LIX_GUEST_OS_SPECIFIC::@256 Task
__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:407
#define __section(S)
Definition: common.h:59
#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:420
__default_fn_attr void panic(const char *fmt)
Definition: handlers.c:391
__default_fn_attr void do_exit(long code)
Definition: handlers.c:203
#define VM_EXEC
Definition: lixddefs.h:43
#define __default_fn_attr
Definition: common.h:61
#define current_task
Definition: handlers.c:88
#define init_detour_field(fn_name)
Definition: common.h:56
unsigned int InExecve
Definition: handlers.h:64
__default_fn_attr void ftrace_write(unsigned long ip, const char *val, int size)
Definition: handlers.c:383
#define vmcall_4(id, p1, p2, p3, p4)
Definition: common.h:121
LIX_GUEST_DETOUR Detours[det_max_id]
Definition: handlers.h:110
#define PAGE_SIZE
Definition: common.h:53
struct _LIX_GUEST_OS_SPECIFIC::@257 Binprm
unsigned int ProtectionBit
Definition: handlers.h:53
#define vmcall_3(id, p1, p2, p3)
Definition: common.h:112
__default_fn_attr void arch_jump_label_transform(void *entry, enum jump_label_type type)
Definition: handlers.c:399
unsigned int MmOffset
Definition: handlers.h:46
unsigned long bp
Definition: handlers.c:16
unsigned int PathOffset
Definition: handlers.h:74
struct _LIX_GUEST_OS_SPECIFIC::@255 Mm
#define vmcall_2(id, p1, p2)
Definition: common.h:104
#define PTRACE_POKEDATA
Definition: lixddefs.h:99
unsigned int VmNextOffset
Definition: handlers.h:49
__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:293
__default_fn_attr void commit_creds(long *creds)
Definition: handlers.c:146
__default_fn_attr void mprotect_fixup_vma_wants_writenotify(unsigned long vma)
Definition: handlers.c:452
static __default_fn_attr bool is_detour_enabled(DETOUR_ID id)
Definition: handlers.c:109
#define SIGSEGV
Definition: lixddefs.h:206
unsigned long r14
Definition: handlers.c:11
unsigned int FlagsOffset
Definition: handlers.h:47
__default_fn_attr void vma_adjust_rb_erase(unsigned long vma_vm_rb, unsigned long mm_mm_rb)
Definition: handlers.c:436
__default_fn_attr void vma_rb_erase(long vma, void *root)
Definition: handlers.c:328
#define PTRACE_SETFPXREGS
Definition: lixddefs.h:110
unsigned long long ProtectionOptions
Definition: handlers.h:107
__default_fn_attr void __vma_link_rb(void *mm, void *vma, void **rb_link, void *rb_parent)
Definition: handlers.c:241
#define SIGILL
Definition: lixddefs.h:198
__default_fn_attr int flush_old_exec(long binprm)
Definition: handlers.c:185
#define current_cpu
Definition: handlers.c:98
unsigned long bx
Definition: handlers.c:14
struct _LIX_GUEST_OS_SPECIFIC::@258 File
#define init_detour_hijack_field(fn_name, hijack_fn_name)
Definition: common.h:64
#define PTRACE_SETFPREGS
Definition: lixddefs.h:108
DETOUR_ID
Definition: handlers.h:10