Stackdb
Stackdb is a stackable, multi-target and -level source debugger and memory forensics library.
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
target_xen_vm_mem_libvmi.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2012, 2013, 2014 The University of Utah
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of
7  * the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18 
19 #include "config.h"
20 
21 #include <errno.h>
22 #include <assert.h>
23 #include <ctype.h>
24 #include <unistd.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28 #include <sys/mman.h>
29 
30 #include "common.h"
31 #include "arch.h"
32 #include "arch_x86.h"
33 #include "arch_x86_64.h"
34 #include "target_api.h"
35 #include "target.h"
36 #include "target_arch_x86.h"
37 #include "target_os.h"
38 
39 #include <xenctrl.h>
40 #include <xs.h>
41 #include "libvmi.h"
42 #include "target_xen_vm.h"
43 
44 
46  /* VMI instance used to read/write domain's memory */
47  vmi_instance_t vmi_instance;
49 };
50 
51 /*
52  * Prototypes.
53  */
54 
56  struct xen_vm_state *xstate;
58 
59  xstate = (struct xen_vm_state *)target->state;
60 
61  mstate = (struct xen_vm_mem_libvmi_state *)calloc(1,sizeof(*mstate));
62 
63  if (vmi_init(&mstate->vmi_instance,
64  VMI_XEN|VMI_INIT_PARTIAL, xstate->name) == VMI_FAILURE) {
65  verror("failed to init vmi instance for dom %d\n", xstate->id);
66  free(mstate);
67  return -1;
68  }
69 
70  xstate->memops_priv = mstate;
71 
72  return 0;
73 }
74 
76  struct xen_vm_state *xstate;
78  unsigned int size;
79  char *tmp;
80  char *val;
81  char *symbol_file;
82  OFFSET tasks_offset,pid_offset,mm_offset,pgd_offset;
83 
84  xstate = (struct xen_vm_state *)target->state;
85  mstate = (struct xen_vm_mem_libvmi_state *)xstate->memops_priv;
86 
87  /*
88  * Make sure xenaccess/libvmi is setup to read from userspace
89  * memory.
90  *
91  * This is hacky, but we do it by reading properties that the
92  * personality has (hopefully) set.
93  */
94  val = (char *)g_hash_table_lookup(target->config,"OS_KERNEL_TASKS_OFFSET");
95  if (val)
96  tasks_offset = (ADDR)strtol(val,NULL,0);
97  val = (char *)g_hash_table_lookup(target->config,"OS_KERNEL_PID_OFFSET");
98  if (val)
99  pid_offset = (ADDR)strtol(val,NULL,0);
100  val = (char *)g_hash_table_lookup(target->config,"OS_KERNEL_MM_OFFSET");
101  if (val)
102  mm_offset = (ADDR)strtol(val,NULL,0);
103  val = (char *)g_hash_table_lookup(target->config,"OS_KERNEL_MM_PGD_OFFSET");
104  if (val)
105  pgd_offset = (ADDR)strtol(val,NULL,0);
106 
107  symbol_file = (char *)g_hash_table_lookup(target->config,
108  "OS_KERNEL_SYSMAP_FILE");
109  if (!symbol_file)
110  symbol_file = "";
111 
112  /*
113  * Offsets are:
114  * linux_tasks: offset of "tasks" in task_struct
115  * linux_mm: offset of "mm" in task_struct
116  * linux_pid: offset of "pid" in task_struct
117  * linux_pgd: offset of "pgd" in mm_struct
118  */
119 #define LIBVMI_CONFIG_TEMPLATE "{ostype=\"Linux\";" \
120  " sysmap=\"%s\"; linux_tasks=0x%"PRIxOFFSET"; linux_mm=0x%"PRIxOFFSET";" \
121  " linux_pid=0x%"PRIxOFFSET"; linux_pgd=0x%"PRIxOFFSET";" \
122  " }"
123 #define LIBVMI_CONFIG_TEMPLATE_HVM "{ ostype=\"Linux\"; sysmap=\"%s\"; }"
124 
125  if (0 && xstate->hvm) {
126  size = strlen(LIBVMI_CONFIG_TEMPLATE_HVM) + strlen(symbol_file) + 1;
127  tmp = malloc(size);
128  snprintf(tmp,size,LIBVMI_CONFIG_TEMPLATE_HVM,symbol_file);
129  }
130  else {
131  size = strlen(LIBVMI_CONFIG_TEMPLATE) + strlen(symbol_file) + 4 * 16 + 1;
132  tmp = malloc(size);
133  snprintf(tmp,size,LIBVMI_CONFIG_TEMPLATE,
134  symbol_file,tasks_offset,mm_offset,pid_offset,pgd_offset);
135  }
136 
137  if (vmi_init_complete(&mstate->vmi_instance, tmp) == VMI_FAILURE) {
138  verror("failed to complete init of vmi instance for dom %d (config was '%s')\n",
139  xstate->id,tmp);
140  vmi_destroy(mstate->vmi_instance);
141  free(tmp);
142  tmp = NULL;
143  return -1;
144  }
145 
146  /* XXX this is in the vmi_instance, but they don't expose it! */
147  mstate->vmi_page_size = XC_PAGE_SIZE;
148 
149  return 0;
150 }
151 
153  return 0;
154 }
155 
157  struct xen_vm_state *xstate;
159  struct xen_vm_spec *xspec;
160 
161  xstate = (struct xen_vm_state *)target->state;
162  xspec = (struct xen_vm_spec *)target->spec->backend_spec;
163  mstate = (struct xen_vm_mem_libvmi_state *)xstate->memops_priv;
164 
165  /* XXX is this right? */
166  if (xspec->clear_mem_caches_each_exception) {
167  vmi_v2pcache_flush(mstate->vmi_instance);
168  vmi_symcache_flush(mstate->vmi_instance);
169  vmi_pidcache_flush(mstate->vmi_instance);
170  }
171 
172  return 0;
173 }
174 
176  struct xen_vm_state *xstate;
178  struct xen_vm_spec *xspec;
179 
180  xstate = (struct xen_vm_state *)target->state;
181  xspec = (struct xen_vm_spec *)target->spec->backend_spec;
182  mstate = (struct xen_vm_mem_libvmi_state *)xstate->memops_priv;
183 
184  /* XXX is this right? */
185  if (xspec->clear_mem_caches_each_exception) {
186  vmi_v2pcache_flush(mstate->vmi_instance);
187  vmi_symcache_flush(mstate->vmi_instance);
188  vmi_pidcache_flush(mstate->vmi_instance);
189  }
190 
191  return 0;
192 }
193 
195  ADDR vaddr,ADDR *paddr) {
196  struct xen_vm_state *xstate;
198  uint64_t tvaddr = 0;
199  uint64_t tpaddr = 0;
200  uint64_t opaddr = 0;
201 
202  xstate = (struct xen_vm_state *)target->state;
203  mstate = (struct xen_vm_mem_libvmi_state *)xstate->memops_priv;
204 
205  /*
206  * Strip the offset bits to improve libvmi cache perf.
207  */
208  tvaddr = vaddr & ~(__PAGE_SIZE - 1);
209 
210  tpaddr = vmi_pagetable_lookup(mstate->vmi_instance,pgd,tvaddr);
211  if (tpaddr == 0) {
212  verror("could not lookup vaddr 0x%"PRIxADDR" in tid %"PRIiTID
213  " pgd 0x%"PRIxADDR"!\n",
214  vaddr,tid,pgd);
215  return -1;
216  }
217 
218  *paddr = tpaddr | (vaddr & (__PAGE_SIZE - 1));
219  target_arch_x86_v2p(target,pgd,vaddr,ARCH_X86_V2P_LMA,&opaddr);
220 
222  "tid %"PRIiTID" vaddr 0x%"PRIxADDR" -> paddr 0x%"PRIxADDR" (paddr 0x%"PRIxADDR")\n",
223  tid,vaddr,*paddr,opaddr);
224 
225  return 0;
226 }
227 
228 unsigned char *xen_vm_mem_libvmi_read_phys(struct target *target,ADDR paddr,
229  unsigned long length,
230  unsigned char *buf) {
231  struct xen_vm_state *xstate;
233  unsigned char *retval = NULL;
234 
235  xstate = (struct xen_vm_state *)target->state;
236  mstate = (struct xen_vm_mem_libvmi_state *)xstate->memops_priv;
237 
238  if (!buf)
239  retval = (unsigned char *)malloc(length+1);
240  else
241  retval = buf;
242 
243  if (vmi_read_pa(mstate->vmi_instance,paddr,retval,length) != length) {
244  verror("could not read %lu bytes at paddr 0x%"PRIxADDR": %s!\n",
245  length,paddr,strerror(errno));
246  goto errout;
247  }
248 
249  return retval;
250 
251  errout:
252  if (!buf && retval)
253  free(retval);
254  if (!errno)
255  errno = EFAULT;
256  return NULL;
257 }
258 
259 unsigned long xen_vm_mem_libvmi_write_phys(struct target *target,ADDR paddr,
260  unsigned long length,
261  unsigned char *buf) {
262  struct xen_vm_state *xstate;
264 
265  xstate = (struct xen_vm_state *)target->state;
266  mstate = (struct xen_vm_mem_libvmi_state *)xstate->memops_priv;
267 
268  if (vmi_write_pa(mstate->vmi_instance,paddr,buf,length) != length) {
269  verror("could not write %lu bytes at paddr 0x%"PRIxADDR": %s!\n",
270  length,paddr,strerror(errno));
271  goto errout;
272  }
273 
274  return length;
275 
276  errout:
277  if (!errno)
278  errno = EFAULT;
279  return 0;
280 }
281 
282 /*
283  * Reads a block of memory from the target. If @buf is non-NULL, we
284  * assume it is at least @length bytes long; the result is placed into
285  * @buf and @buf is returned. If @buf is NULL, we allocate a buffer
286  * large enough to hold the result (@length if @length >0; if @length is
287  * 0 we attempt to read a string at that address; we stop when we hit a
288  * NULL byte).
289  *
290  * On error, returns NULL, and sets errno.
291  */
292 unsigned char *xen_vm_mem_libvmi_read_tid(struct target *target,
293  tid_t tid,ADDR pgd,ADDR addr,
294  unsigned long target_length,
295  unsigned char *buf)
296 {
297  struct xen_vm_state *xstate;
299  vmi_instance_t vmi;
300  int alloced = 0;
301  size_t cc;
302  ADDR paddr;
303 
304  xstate = (struct xen_vm_state *)target->state;
305  mstate = (struct xen_vm_mem_libvmi_state *)xstate->memops_priv;
306  vmi = mstate->vmi_instance;
307 
308  fflush(stderr);
309  fflush(stdout);
310 
311  /*
312  * Change the TID to 0 if TID was global. The Xen backend always
313  * defaults non-tid-specific reads/writes to the kernel, via
314  * TID_GLOBAL.
315  */
316  if (tid == TID_GLOBAL)
317  tid = 0;
318 
319  xen_vm_mem_libvmi_addr_v2p(target,tid,pgd,addr,&paddr);
320 
322  "read dom %d: addr=0x%"PRIxADDR" len=%d tid=%d\n",
323  xstate->id,addr,target_length,tid);
324 
325  /* if length == 0, we are copying in a string. */
326  if (target_length == 0)
327  return (unsigned char *)vmi_read_str_va(vmi, (addr_t)addr, tid);
328 
329  /* allocate buffer if necessary */
330  if (!buf) {
331  buf = malloc(target_length + 1);
332  alloced = 1;
333  }
334 
335  /* read the data */
336  if (buf) {
337  cc = vmi_read_va(vmi, (addr_t)addr, tid, buf, target_length);
338 
339  /* there is no provision for a partial read, assume an error */
340  if ((unsigned long)cc != target_length) {
341  if (cc)
342  verror("vmi_read_va returns partial data (%lu of %lu)\n",
343  (unsigned long)cc, target_length);
344  else
345  verror("vmi_read_va returns no data (%lu of %lu)\n",
346  (unsigned long)cc, target_length);
347  if (alloced)
348  free(buf);
349  return NULL;
350  }
351  else {
353  "read dom %d: addr=0x%"PRIxADDR" len=%d tid=%d SUCCESS\n",
354  xstate->id,addr,target_length,tid);
355  }
356  }
357  else
358  verror("could not malloc buf\n");
359 
360  return buf;
361 }
362 
363 /*
364  * Writes @length bytes from @buf to @addr. Returns the number of bytes
365  * written (and sets errno nonzero if there is an error). Successful if
366  * @return == @length.
367  */
369  tid_t tid,ADDR pgd,ADDR addr,
370  unsigned long length,
371  unsigned char *buf) {
372  struct xen_vm_state *xstate;
374 
375  xstate = (struct xen_vm_state *)target->state;
376  mstate = (struct xen_vm_mem_libvmi_state *)xstate->memops_priv;
377 
378  /*
379  * Change the TID to 0 if TID was global. The Xen backend always
380  * defaults non-tid-specific reads/writes to the kernel, via
381  * TID_GLOBAL.
382  */
383  if (tid == TID_GLOBAL)
384  tid = 0;
385 
387  "write dom %d: addr=0x%"PRIxADDR" len=%d tid=%d\n",
388  xstate->id,addr,length,tid);
389 
390  return (unsigned long)vmi_write_va(mstate->vmi_instance, (addr_t)addr,
391  tid, buf, (size_t)length);
392 }
393 
395  struct xen_vm_state *xstate;
396 
397  xstate = (struct xen_vm_state *)target->state;
398 
399  if (xstate->memops_priv) {
400  free(xstate->memops_priv);
401  xstate->memops_priv = NULL;
402  }
403 
404  return 0;
405 }
406 
409  .attach = xen_vm_mem_libvmi_attach,
410  .handle_exception_any = xen_vm_mem_libvmi_handle_exception_any,
411  .handle_exception_ours = xen_vm_mem_libvmi_handle_exception_ours,
412  .handle_pause = xen_vm_mem_libvmi_handle_pause,
413  .addr_v2p = xen_vm_mem_libvmi_addr_v2p,
414  .read_phys = xen_vm_mem_libvmi_read_phys,
415  .write_phys = xen_vm_mem_libvmi_write_phys,
416  .read_tid = xen_vm_mem_libvmi_read_tid,
417  .write_tid = xen_vm_mem_libvmi_write_tid,
418  .fini = xen_vm_mem_libvmi_fini,
419 };
int target_arch_x86_v2p(struct target *target, ADDR pgd, ADDR virt, arch_x86_v2p_flags_t flags, ADDR *phys)
int xen_vm_mem_libvmi_addr_v2p(struct target *target, tid_t tid, ADDR pgd, ADDR vaddr, ADDR *paddr)
GHashTable * config
Definition: target_api.h:2622
void * state
Definition: target_api.h:2526
void * backend_spec
Definition: target_api.h:2290
#define LIBVMI_CONFIG_TEMPLATE_HVM
int32_t tid_t
Definition: common.h:36
unsigned char * xen_vm_mem_libvmi_read_phys(struct target *target, ADDR paddr, unsigned long length, unsigned char *buf)
unsigned char * xen_vm_mem_libvmi_read_tid(struct target *target, tid_t tid, ADDR pgd, ADDR addr, unsigned long target_length, unsigned char *buf)
int(* init)(struct target *target)
#define LIBVMI_CONFIG_TEMPLATE
struct malloc_state * mstate
Definition: dlmalloc.c:2609
int xen_vm_mem_libvmi_attach(struct target *target)
int32_t OFFSET
Definition: common.h:65
#define verror(format,...)
Definition: log.h:30
unsigned int hvm
unsigned int clear_mem_caches_each_exception
Definition: target_xen_vm.h:77
void free(void *ptr)
Definition: debugserver.c:207
void * memops_priv
int xen_vm_mem_libvmi_handle_exception_any(struct target *target)
#define __PAGE_SIZE
int xen_vm_mem_libvmi_init(struct target *target)
struct xen_vm_mem_ops xen_vm_mem_ops_libvmi
#define vdebug(devel, areas, flags, format,...)
Definition: log.h:302
Definition: log.h:172
void * calloc(size_t nmemb, size_t size)
Definition: debugserver.c:200
unsigned long xen_vm_mem_libvmi_write_tid(struct target *target, tid_t tid, ADDR pgd, ADDR addr, unsigned long length, unsigned char *buf)
Definition: log.h:70
#define PRIiTID
Definition: common.h:37
uint32_t ADDR
Definition: common.h:64
#define PRIxADDR
Definition: common.h:67
int xen_vm_mem_libvmi_fini(struct target *target)
struct target_spec * spec
Definition: target_api.h:2605
void * malloc(size_t size)
Definition: debugserver.c:214
int xen_vm_mem_libvmi_handle_exception_ours(struct target *target)
int xen_vm_mem_libvmi_handle_pause(struct target *target)
#define TID_GLOBAL
Definition: target_api.h:145
unsigned long xen_vm_mem_libvmi_write_phys(struct target *target, ADDR paddr, unsigned long length, unsigned char *buf)