Bitdefender Hypervisor Memory Introspection
exec.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020 Bitdefender
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 #include "../common.h"
6 
7 typedef void * (filp_open_fn)(const char *filename, int flags, unsigned short mode);
8 typedef int (filp_close_fn)(void *filp, void *id);
9 typedef void (flush_delayed_fput_fn)(void);
10 typedef void * (vmalloc_fn)(unsigned long size);
11 typedef unsigned int (__kernel_write_fn)(void *file, const void *buf, unsigned int count, long long *pos);
12 typedef int (kernel_write_fn)(void *file, const char *buf, size_t count, unsigned long pos);
13 typedef void (vfree_fn)(void *ptr);
14 typedef char ** (argv_split_fn)(unsigned int gfp, const char *str, int *argcp);
15 typedef void (argv_free_fn)(char **argv);
16 typedef void *(call_usermodehelper_setup_fn)(const char *path, char **argv, char **envp, unsigned long gfp_mask,
17  int (*init)(void *info, void *new), void (*cleanup)(void *info), void *data);
18 typedef int (call_usermodehelper_exec_fn)(void *sub_info, int wait);
19 typedef void (do_exit_fn)(long code);
20 typedef int (printk_fn)(const char *fmt, ...);
21 typedef int (chmod_common_fn)(void *path, unsigned short mode);
22 
23 #pragma pack(push, 1)
24 struct data {
26  struct {
27  unsigned long hypercall;
28  unsigned long completion;
29  unsigned long error;
30  } token;
31 
33  struct {
40  vfree_fn *vfree;
48  } func;
49 
51  struct {
52  unsigned long kernel_version;
53  unsigned long file_path_offset;
54 
55  unsigned long vmalloc_size;
56  char root[1];
57  char name[128];
58  char arg[1024];
59 
60  struct {
61  unsigned long wait_proc;
62  unsigned long wait_exec;
63  } umh;
64  } args;
65 };
66 
67 #pragma pack(pop)
68 
70 struct data _data __section(".adata") __aligned(1) = { 0 };
71 
72 extern void *__address;
73 
75 int call_usermodehelper(const char *path, char **argv, char **envp, unsigned int wait)
76 {
77  unsigned long gfp_mask = GFP_KERNEL;
78  void *info = _data.func.call_usermodehelper_setup(path, argv, envp, gfp_mask, NULL, NULL, NULL);
79  if (!info)
80  {
82  return -1;
83  }
84 
85  return _data.func.call_usermodehelper_exec(info, wait);
86 }
87 
89 void exec(void)
95 {
96  int ret = 0;
97  char **argv = NULL;
98 
99  char *envp[4];
100 
101  envp[0] = "HOME=/";
102  envp[1] = "TERM=linux";
103  envp[2] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
104  envp[3] = NULL;
105 
106  void *file = _data.func.filp_open(_data.args.root, O_CREAT | O_RDWR | O_TRUNC, 0500);
107  if (IS_ERR_VALUE(file))
108  {
109  breakpoint_1(_data.token.error, _data.func.filp_open);
110  return;
111  }
112 
113  void *ptr = _data.func.vmalloc(_data.args.vmalloc_size);
114  if (!ptr)
115  {
116  breakpoint_1(_data.token.error, _data.func.vmalloc);
117  goto _exit;
118  }
119 
120  unsigned int count = 0;
121  long long pos = 0;
122  do
123  {
124  count = breakpoint_1(_data.token.hypercall, ptr);
125  if (count == 0)
126  {
127  break;
128  }
129 
130  if (_data.args.kernel_version <= KERNEL_VERSION(2, 6, 72))
131  {
132  ret = _data.func.kernel_write(file, ptr, count, pos);
133  if (ret < 0)
134  {
136  goto _exit;
137  }
138 
139  pos += ret;
140  }
141  else
142  {
143  ret = _data.func.__kernel_write(file, ptr, count, &pos);
144  if (ret < 0)
145  {
147  goto _exit;
148  }
149  }
150 
151  } while (count);
152 
153  if (_data.func.chmod_common)
154  {
155  // This is a workaround for kernel version 4.4 because 'filp_open' doesn't set the execute attr for deployed file.
156  ret = _data.func.chmod_common(((void *)((unsigned long)(file) + _data.args.file_path_offset)), 0500);
157  if (ret < 0)
158  {
159  breakpoint_2(_data.token.error, _data.func.chmod_common, ret);
160  goto _exit;
161  }
162  }
163 
164  _data.func.filp_close(file, NULL);
165  file = NULL;
166 
167  if (_data.args.kernel_version > KERNEL_VERSION(2, 6, 72))
168  {
169  _data.func.flush_delayed_fput();
170  }
171 
172  argv = _data.func.argv_split(GFP_KERNEL, _data.args.arg, NULL);
173  if (!argv)
174  {
175  breakpoint_2(_data.token.error, _data.func.argv_split, argv);
176  goto _exit;
177  }
178 
179  ret = call_usermodehelper(argv[0], argv, envp, _data.args.umh.wait_exec);
180  if (ret)
181  {
183  goto _exit;
184  }
185 
186  char *argv_remove[4];
187  argv_remove[0] = "/bin/rm";
188  argv_remove[1] = "-f";
189  argv_remove[2] = _data.args.root;
190  argv_remove[3] = NULL;
191 
192  call_usermodehelper(argv_remove[0], argv_remove, envp, _data.args.umh.wait_exec);
193 
194  breakpoint(_data.token.completion);
195 
196 _exit:
197  if (file)
198  {
199  _data.func.filp_close(file, 0);
200  }
201 
202  if (argv)
203  {
204  _data.func.argv_free(argv);
205  }
206 
207  if (ptr)
208  {
209  _data.func.vfree(ptr);
210  }
211 
212  if (ret < 0)
213  {
214  call_usermodehelper(argv_remove[0], argv_remove, envp, _data.args.umh.wait_exec);
215  }
216 }
217 
218 
219 __fn_naked __section(".start")
220 void trampoline(void)
228 {
229  exec();
230 
231  __exit;
232  __do_exit(__address, _data.func.do_exit, _data.func.vfree);
233 }
#define O_CREAT
Definition: common.h:20
struct data::@2 args
The arguments of the agent.
unsigned long kernel_version
The version of the kernel.
Definition: deploy.c:48
__fn_naked void trampoline(void)
The trampoline of the agent.
Definition: exec.c:220
#define KERNEL_VERSION(K, Patch, Sublevel)
Definition: common.h:60
struct data::@0 token
The tokens used to communicate with Intocore.
void() vfree_fn(void *ptr)
Definition: exec.c:13
void *() vmalloc_fn(unsigned long size)
Definition: exec.c:10
call_usermodehelper_exec_fn * call_usermodehelper_exec
Definition: deploy.c:41
unsigned long hypercall
Definition: kthread.c:17
kernel_write_fn * kernel_write
Definition: deploy.c:34
char root[1]
The root path; allways &#39;/&#39;.
Definition: deploy.c:51
static __default_fn_attr unsigned long breakpoint(unsigned long token)
Generate INT3 instruction for hypercall.
Definition: common.h:167
flush_delayed_fput_fn * flush_delayed_fput
Definition: exec.c:36
#define GFP_KERNEL
Definition: common.h:15
#define IS_ERR_VALUE(x)
Definition: common.h:66
unsigned long file_path_offset
Used to store the current position in the file.
Definition: exec.c:53
int() call_usermodehelper_exec_fn(void *sub_info, int wait)
Definition: exec.c:18
int() kernel_write_fn(void *file, const char *buf, size_t count, unsigned long pos)
Definition: exec.c:12
#define O_RDWR
Definition: common.h:19
__default_fn_attr void init(void)
Allocates memory for detours and agents.
Definition: init.c:15
chmod_common_fn * chmod_common
Definition: exec.c:46
call_usermodehelper_setup_fn * call_usermodehelper_setup
Definition: deploy.c:40
void *() filp_open_fn(const char *filename, int flags, unsigned short mode)
Definition: exec.c:7
#define __fn_naked
Definition: common.h:79
#define __exit
Generates the exit asm-code for agents.
Definition: common.h:120
#define __section(S)
Definition: common.h:76
int() printk_fn(const char *fmt,...)
Definition: exec.c:20
void *() call_usermodehelper_setup_fn(const char *path, char **argv, char **envp, unsigned long gfp_mask, int(*init)(void *info, void *new), void(*cleanup)(void *info), void *data)
Definition: exec.c:16
void() do_exit_fn(long code)
Definition: exec.c:19
#define breakpoint_1(token, p1)
Hypercall using 1 argument.
Definition: common.h:177
unsigned long wait_proc
The value of UMH_WAIT_PROC.
Definition: deploy.c:55
filp_close_fn * filp_close
Definition: deploy.c:33
#define __default_fn_attr
Definition: common.h:78
#define breakpoint_2(token, p1, p2)
Hypercall using 2 argument.
Definition: common.h:185
char name[128]
The name of the deployed file.
Definition: deploy.c:52
__default_fn_attr int call_usermodehelper(const char *path, char **argv, char **envp, unsigned int wait)
Definition: exec.c:75
#define O_TRUNC
Definition: common.h:22
filp_open_fn * filp_open
Definition: deploy.c:32
unsigned long wait_exec
The value of UMH_WAIT_EXEC.
Definition: deploy.c:56
struct data::@5::@6 umh
__kernel_write_fn * __kernel_write
Definition: deploy.c:35
struct data::@1 func
The functions used by this agent.
unsigned long vmalloc_size
The size of allocation.
Definition: kthread.c:32
int() chmod_common_fn(void *path, unsigned short mode)
Definition: exec.c:21
argv_split_fn * argv_split
Definition: deploy.c:38
__default_fn_attr void exec(void)
Deploys the provided content on the disk and creates a new process of that content.
Definition: exec.c:89
unsigned long completion
Definition: kthread.c:18
void() flush_delayed_fput_fn(void)
Definition: exec.c:9
vfree_fn * vfree
Definition: deploy.c:37
void * __address
#define __do_exit(address, do_exit_fn, vfree_fn)
Pushes the exit address on the stack and jumps to the &#39;do_exit&#39; function in order to terminate the th...
Definition: common.h:126
do_exit_fn * do_exit
Definition: deploy.c:42
unsigned long error
Definition: kthread.c:19
vmalloc_fn * vmalloc
Definition: deploy.c:36
argv_free_fn * argv_free
Definition: deploy.c:39
char **() argv_split_fn(unsigned int gfp, const char *str, int *argcp)
Definition: exec.c:14
void() argv_free_fn(char **argv)
Definition: exec.c:15
int() filp_close_fn(void *filp, void *id)
Definition: exec.c:8
Definition: kthread.c:14
unsigned int() __kernel_write_fn(void *file, const void *buf, unsigned int count, long long *pos)
Definition: exec.c:11
char arg[1024]
The arguments of the process.
Definition: exec.c:58
printk_fn * printk
Definition: deploy.c:43