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
nullpage_util.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 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 <stdio.h>
20 #include <errno.h>
21 #include <argp.h>
22 
23 #include "log.h"
24 #include "arch.h"
25 #include "arch_x86.h"
26 #include "arch_x86_64.h"
27 #include "probe_api.h"
28 #include "probe.h"
29 #include "target.h"
30 #include "target_api.h"
31 
32 #include "nullpage.h"
33 
37 error_t np_argp_parse_opt(int key,char *arg,struct argp_state *state);
38 
39 #define NP_ARGP_TTCTX 30000
40 #define NP_ARGP_TTDETAIL 30001
41 
42 struct argp_option np_argp_opts[] = {
43  { "np-mode",'N',"[mprotect[,mmap[,pgfault]]]",0,"Set the mode for the NULL page usage detector. mprotect is probably the cheapest option, because it is called less frequently than mmap, and must always be called to change protections for an mmap'd page (?). The pgfault style will be most expensive. To achieve certain, good coverage, choose all three!",0 },
44  { "ttctx",NP_ARGP_TTCTX,"none|self|hier|all (default self)",0,"Which threads to display when an event happens.",0 },
45  { "ttdetail",NP_ARGP_TTDETAIL,"-2|-1|0|1|2 (default 0)",0,"How much info to print for each thread that is printed.",0 },
46  { 0,0,0,0,0,0 },
47 };
48 struct argp np_argp = {
49  np_argp_opts,np_argp_parse_opt,NULL,NULL,NULL,NULL,NULL,
50 };
51 
52 error_t np_argp_parse_opt(int key,char *arg,struct argp_state *state) {
53  struct np_config *opts = \
54  (struct np_config *)target_argp_driver_state(state);
55  char *argptr;
56 
57  switch (key) {
58  case ARGP_KEY_ARG:
59  return ARGP_ERR_UNKNOWN;
60  case ARGP_KEY_ARGS:
61  return ARGP_ERR_UNKNOWN;
62  case ARGP_KEY_INIT:
64  return 0;
65  case ARGP_KEY_END:
66  case ARGP_KEY_NO_ARGS:
67  case ARGP_KEY_SUCCESS:
68  return 0;
69  case ARGP_KEY_ERROR:
70  case ARGP_KEY_FINI:
71  return 0;
72  case NP_ARGP_TTCTX:
73  if (strcmp(arg,"none") == 0)
74  opts->ttctx = 0;
75  else if (strcmp(arg,"self") == 0)
76  opts->ttctx = 1;
77  else if (strcmp(arg,"hier") == 0)
78  opts->ttctx = 2;
79  else if (strcmp(arg,"all") == 0)
80  opts->ttctx = 3;
81  else {
82  verror("invalid ttctx %s!\n",arg);
83  return EINVAL;
84  }
85  break;
86  case NP_ARGP_TTDETAIL:
87  opts->ttdetail = atoi(arg);
88  if (opts->ttdetail < -2 || opts->ttdetail > 2) {
89  verror("invalid ttdetail level %d!\n",opts->ttdetail);
90  return EINVAL;
91  }
92  break;
93  case 'N':
94  argptr = arg;
95  do {
96  if (strncmp("mmap",argptr,strlen("mmap")) == 0)
97  opts->do_mmap = 1;
98  else if (strncmp("mprotect",argptr,strlen("mprotect")) == 0)
99  opts->do_mprotect = 1;
100  else if (strncmp("pgfault",argptr,strlen("pgfault")) == 0)
101  opts->do_pgfault = 1;
102  else {
103  verror("bad nullpage flag spec!\n");
104  return EINVAL;
105  }
106  } while ((argptr = index(argptr,',')) != NULL && *++argptr != '\0');
107  break;
108  default:
109  return ARGP_ERR_UNKNOWN;
110  }
111 
112  return 0;
113 }
114 
118 const char *probe_gettype_np(struct probe *probe) {
119  return "nullpage";
120 }
121 
123  return probe->priv;
124 }
125 
126 int probe_fini_np(struct probe *probe) {
127  struct np_status *nps = (struct np_status *)probe->priv;
128 
129  if (nps->pgfault_probe) {
130  probe_free(nps->pgfault_probe,0);
131  nps->pgfault_probe = NULL;
132  }
133  if (nps->mprotect_probe) {
134  probe_free(nps->mprotect_probe,0);
135  nps->mprotect_probe = NULL;
136  }
137  if (nps->mmap_probe) {
138  probe_free(nps->mmap_probe,0);
139  nps->mmap_probe = NULL;
140  }
141 
142  free(nps->config);
143  free(nps);
144 
145  return 0;
146 }
147 
148 static struct probe_ops probe_ops_np = {
150  .summarize = probe_summarize_np,
151  .fini = probe_fini_np,
152 };
153 
158 #define NP_PROT_READ 0x1
159 #define NP_PROT_WRITE 0x2
160 #define NP_PROT_EXEC 0x4
161 
162 #define NP_MAP_FIXED 0x10
163 
164 result_t np_mmap_handler(struct probe *probe,tid_t tid,void *data,
165  struct probe *trigger,struct probe *base) {
166  struct np_status *nps = (struct np_status *)data;
167  struct target_location_ctxt *tlctxt;
168  ADDR addr = ADDRMAX;
169  unum_t flags = 0;
170  struct value *va,*vf;
171  int hit = 0;
172 
174  probe->bsymbol);
175 
176  va = target_load_symbol_member(probe->target,tlctxt,probe->bsymbol,"addr",
177  NULL,LOAD_FLAG_NONE);
178  if (!va) {
179  vwarn("could not load sys_mmap.addr!");
180  return 0;
181  }
182  vf = target_load_symbol_member(probe->target,tlctxt,probe->bsymbol,"flags",
183  NULL,LOAD_FLAG_NONE);
184  if (!vf) {
185  vwarn("could not load sys_mmap.vm_flags!");
186  value_free(va);
187  return 0;
188  }
189 
190  addr = v_addr(va);
191  flags = v_unum(vf);
192  if (addr == 0 && flags & NP_MAP_FIXED) {
193  vdebug(3,LA_USER,1,"NULLPAGE: tid %d tried to mmap at 0x0!\n",tid);
194  ++nps->mmap_violations;
195  ++nps->total_violations;
196  hit = 1;
197  }
198  else {
199  vdebug(5,LA_USER,1,"tid %d mmap(0x%"PRIxADDR",0x%"PRIxNUM")\n",
200  tid,addr,flags);
201  }
202 
203  value_free(va);
204  value_free(vf);
206 
207  if (hit)
208  return probe_do_sink_pre_handlers(probe,tid,data,trigger,base);
209  else
210  return 0;
211 }
212 
214  struct probe *trigger,struct probe *base) {
215  struct np_status *nps = (struct np_status *)data;
216  struct target_location_ctxt *tlctxt;
217  ADDR addr = ADDRMAX;
218  unum_t prot = 0;
219  struct value *va,*vp;
220  int hit = 0;
221 
223  probe->bsymbol);
224 
225  va = target_load_symbol_member(probe->target,tlctxt,probe->bsymbol,"start",
226  NULL,LOAD_FLAG_NONE);
227  if (!va) {
228  vwarn("could not load sys_mprotect.start!");
229  return 0;
230  }
231  vp = target_load_symbol_member(probe->target,tlctxt,probe->bsymbol,"prot",
232  NULL,LOAD_FLAG_NONE);
233  if (!vp) {
234  vwarn("could not load sys_mprotect.prot!");
235  value_free(va);
236  return 0;
237  }
238 
239  addr = v_addr(va);
240  prot = v_unum(vp);
241 
242  if (addr == 0 && prot & NP_PROT_EXEC) {
243  vdebug(3,LA_USER,1,"NULLPAGE: tid %d tried to mprotect(0x0,%d)!\n",
244  tid,(int)prot);
245  ++nps->mprotect_violations;
246  ++nps->total_violations;
247  hit = 1;
248  }
249  else {
250  vdebug(5,LA_USER,1,"tid %d mprotect(0x%"PRIxADDR",0x%x)\n",
251  tid,addr,(int)prot);
252  }
253 
254  value_free(va);
255  value_free(vp);
257 
258  if (hit)
259  return probe_do_sink_pre_handlers(probe,tid,data,trigger,base);
260  else
261  return 0;
262 }
263 
264 result_t np_pgfault_handler(struct probe *probe,tid_t tid,void *data,
265  struct probe *trigger,struct probe *base) {
266  struct np_status *nps = (struct np_status *)data;
267  struct target_location_ctxt *tlctxt;
268  ADDR addr = ADDRMAX;
269  unum_t error_code = 0;
270  struct value *vec;
271  int hit = 0;
272  struct target *target = probe->target;
273 
275  probe->bsymbol);
276 
277  vec = target_load_symbol_member(target,tlctxt,probe->bsymbol,
278  "error_code",NULL,LOAD_FLAG_NONE);
279  if (!vec) {
280  vwarn("could not load do_page_fault.error_code!");
281  return 0;
282  }
283  /*
284  va = target_load_symbol_member(target,tlctxt,probe->bsymbol,
285  "address",NULL,LOAD_FLAG_NONE);
286  if (!va) {
287  vwarn("could not load do_page_fault.address!");
288  value_free(vec);
289  return 0;
290  }
291  addr = v_addr(va);
292  */
293 
294  if (target->arch->type == ARCH_X86)
295  addr = target_read_reg(target,TID_GLOBAL,REG_X86_CR2);
296  else if (target->arch->type == ARCH_X86_64)
298  else {
299  verror("unsupported arch type %d!\n",target->arch->type);
300  return 0;
301  }
302 
303  error_code = v_unum(vec);
304 
305  /*
306  * Don't just look for instruction fetch faults; if the user tried
307  * first to read or write the page, that will be the fault, almost
308  * certainly.
309  */
310  if (addr == 0) {// && error_code & 0x10) {
311  vdebug(3,LA_USER,1,"NULLPAGE: tid %d tried to access(0x0) (0x%x!\n",
312  tid,(int)error_code);
313  ++nps->pgfault_violations;
314  ++nps->total_violations;
315  hit = 1;
316  }
317  else {
318  vdebug(5,LA_USER,1,"tid %d page_fault(0x%"PRIxADDR",0x%lx)\n",
319  tid,addr,(unsigned long)error_code);
320  }
321 
322  //value_free(va);
323  value_free(vec);
325 
326  if (hit)
327  return probe_do_sink_pre_handlers(probe,tid,data,trigger,base);
328  else
329  return 0;
330 }
331 
335 struct probe *probe_np(struct target *target,struct np_config *npc,
337  void *handler_data) {
338  struct np_status *nps;
339  struct bsymbol *bs = NULL;
340  char namebuf[64];
341  ADDR addr;
342 
343  snprintf(namebuf,64,"nullpage(target %d)",target->id);
344 
345  nps = (struct np_status *)calloc(1,sizeof(*nps));
346  nps->target = target;
347  nps->config = (struct np_config *)calloc(1,sizeof(*nps->config));
348  memcpy(nps->config,npc,sizeof(*nps->config));
349 
350  nps->np_probe =
351  probe_create(target,TID_GLOBAL,&probe_ops_np,namebuf,
352  pre_handler ? pre_handler : probe_do_sink_pre_handlers,
353  post_handler ? post_handler : probe_do_sink_post_handlers,
354  handler_data,0,1);
355  nps->np_probe->priv = nps;
356 
357  if (nps->config->do_mmap) {
358  bs = target_lookup_sym(target,"sys_mmap",NULL,NULL,
360  if (!bs)
361  goto errout;
362  nps->mmap_probe = probe_create(target,TID_GLOBAL,NULL,
363  bsymbol_get_name(bs),
364  np_mmap_handler,NULL,nps,0,1);
365  if (!probe_register_symbol(nps->mmap_probe,bs,PROBEPOINT_SW,0,0)) {
366  verror("could not register function entry/exit probe on %s;"
367  " aborting!\n",bsymbol_get_name(bs));
368  goto errout;
369  }
370  if (!probe_register_source(nps->np_probe,nps->mmap_probe)) {
371  verror("could not register nullpage meta probe %s atop probe %s!\n",
373  goto errout;
374  }
375  bsymbol_release(bs);
376  bs = NULL;
377  }
378 
379  if (nps->config->do_mprotect) {
380  bs = target_lookup_sym(target,"sys_mprotect",NULL,NULL,
382  if (!bs)
383  goto errout;
384  nps->mprotect_probe = probe_create(target,TID_GLOBAL,NULL,
385  bsymbol_get_name(bs),
386  np_mprotect_handler,NULL,nps,0,1);
388  verror("could not register function entry/exit probe on %s;"
389  " aborting!\n",bsymbol_get_name(bs));
390  goto errout;
391  }
393  verror("could not register nullpage meta probe %s atop probe %s!\n",
395  goto errout;
396  }
397  bsymbol_release(bs);
398  bs = NULL;
399  }
400 
401  if (nps->config->do_pgfault) {
402  bs = target_lookup_sym(target,"do_page_fault",NULL,NULL,
404  if (!bs)
405  goto errout;
406  nps->pgfault_probe = probe_create(target,TID_GLOBAL,NULL,
407  bsymbol_get_name(bs),
408  np_pgfault_handler,NULL,nps,0,1);
410  verror("could not register function entry/exit probe on %s;"
411  " aborting!\n",bsymbol_get_name(bs));
412  goto errout;
413  }
414  if (!probe_register_source(nps->np_probe,nps->pgfault_probe)) {
415  verror("could not register nullpage master probe %s atop probe %s!\n",
417  goto errout;
418  }
419  bsymbol_release(bs);
420  bs = NULL;
421  }
422 
423  return nps->np_probe;
424 
425  errout:
426  if (bs)
427  bsymbol_release(bs);
428  if (nps->np_probe) {
429  probe_free(nps->np_probe,1);
430  }
431  else {
432  if (nps->config)
433  free(nps->config);
434  if (nps)
435  free(nps);
436  }
437 
438  return NULL;
439 }
arch_type_t type
Definition: arch.h:117
result_t pre_handler(struct probe *probe, tid_t tid, void *data, struct probe *trigger, struct probe *base)
Definition: spf.c:903
#define NP_ARGP_TTDETAIL
Definition: nullpage_util.c:40
struct probe * mmap_probe
Definition: nullpage.h:45
int ttctx
Definition: nullpage.h:31
int32_t tid_t
Definition: common.h:36
void * target_argp_driver_state(struct argp_state *state)
Definition: target.c:716
struct argp_option np_argp_opts[]
Definition: nullpage_util.c:42
unsigned int pgfault_violations
Definition: nullpage.h:50
struct target * target
Definition: nullpage.h:38
struct probe * np_probe
Definition: nullpage.h:41
int ttdetail
Definition: nullpage.h:32
result_t np_mmap_handler(struct probe *probe, tid_t tid, void *data, struct probe *trigger, struct probe *base)
struct bsymbol * target_lookup_sym(struct target *target, const char *name, const char *delim, char *srcfile, symbol_type_flag_t ftype)
Definition: target.c:2199
result_t np_mprotect_handler(struct probe *probe, tid_t tid, void *data, struct probe *trigger, struct probe *base)
unsigned int do_mmap
Definition: nullpage.h:28
unsigned int do_pgfault
Definition: nullpage.h:28
struct target_location_ctxt * target_location_ctxt_create_from_bsymbol(struct target *target, tid_t tid, struct bsymbol *bsymbol)
Definition: target.c:5325
int probe_fini_np(struct probe *probe)
result_t probe_do_sink_post_handlers(struct probe *probe, tid_t tid, void *handler_data, struct probe *trigger, struct probe *base)
Definition: probe.c:109
char * bsymbol_get_name(struct bsymbol *bsymbol)
Definition: symbol.c:62
struct probe * pgfault_probe
Definition: nullpage.h:44
#define REG_X86_64_CR2
Definition: arch_x86_64.h:138
#define verror(format,...)
Definition: log.h:30
result_t probe_do_sink_pre_handlers(struct probe *probe, tid_t tid, void *handler_data, struct probe *trigger, struct probe *base)
Definition: probe.c:48
const char *(* gettype)(struct probe *probe)
Definition: probe_api.h:96
result_t(* probe_handler_t)(struct probe *probe, tid_t tid, void *handler_data, struct probe *trigger, struct probe *base)
Definition: probe_api.h:70
#define vwarn(format,...)
Definition: log.h:33
#define ADDRMAX
Definition: common.h:74
void free(void *ptr)
Definition: debugserver.c:207
REGVAL target_read_reg(struct target *target, tid_t tid, REG reg)
Definition: target_api.c:1132
struct probe * probe_np(struct target *target, struct np_config *npc, probe_handler_t pre_handler, probe_handler_t post_handler, void *handler_data)
#define NP_MAP_FIXED
struct probe * probe_register_source(struct probe *sink, struct probe *src)
Definition: probe.c:1593
REFCNT bsymbol_release(struct bsymbol *bsymbol)
Definition: symbol.c:90
unsigned int mmap_violations
Definition: nullpage.h:48
int probe_free(struct probe *probe, int force)
Definition: probe.c:777
struct dt_argp_state opts
Definition: dumptarget.c:111
#define PRIxNUM
Definition: common.h:91
error_t np_argp_parse_opt(int key, char *arg, struct argp_state *state)
Definition: nullpage_util.c:52
void value_free(struct value *value)
Definition: value.c:282
struct argp np_argp
Definition: nullpage_util.c:48
result_t np_pgfault_handler(struct probe *probe, tid_t tid, void *data, struct probe *trigger, struct probe *base)
Definition: probe.h:308
unsigned int mprotect_violations
Definition: nullpage.h:49
struct probe * probe_create(struct target *target, tid_t tid, struct probe_ops *pops, const char *name, probe_handler_t pre_handler, probe_handler_t post_handler, void *handler_data, int autofree, int tracked)
Definition: probe.c:729
struct np_config * config
Definition: nullpage.h:36
unsigned int do_mprotect
Definition: nullpage.h:28
#define vdebug(devel, areas, flags, format,...)
Definition: log.h:302
ADDR v_addr(struct value *v)
Definition: value.c:429
struct arch * arch
Definition: target_api.h:2603
#define REG_X86_CR2
Definition: arch_x86.h:101
void * calloc(size_t nmemb, size_t size)
Definition: debugserver.c:200
result_t post_handler(struct probe *probe, tid_t tid, void *data, struct probe *trigger, struct probe *base)
Definition: spf.c:908
result_t
Definition: common.h:25
Definition: arch.h:102
Definition: log.h:76
struct target * target
Definition: probe.h:342
uint32_t ADDR
Definition: common.h:64
struct probe * mprotect_probe
Definition: nullpage.h:46
unsigned int total_violations
Definition: nullpage.h:51
struct value * target_load_symbol_member(struct target *target, struct target_location_ctxt *tlctxt, struct bsymbol *bsymbol, const char *member, const char *delim, load_flags_t flags)
Definition: target.c:2920
void * probe_summarize_np(struct probe *probe)
#define PRIxADDR
Definition: common.h:67
void target_location_ctxt_free(struct target_location_ctxt *tlctxt)
Definition: target.c:5348
struct bsymbol * bsymbol
Definition: probe.h:389
#define NP_PROT_EXEC
int id
Definition: target_api.h:2514
const char * probe_gettype_np(struct probe *probe)
#define NP_ARGP_TTCTX
Definition: nullpage_util.c:39
uint64_t unum_t
Definition: common.h:88
char * probe_name(struct probe *probe)
Definition: probe.c:1935
void * priv
Definition: probe.h:318
struct probe * probe_register_symbol(struct probe *probe, struct bsymbol *bsymbol, probepoint_style_t style, probepoint_whence_t whence, probepoint_watchsize_t watchsize)
Definition: probe.c:1470
unum_t v_unum(struct value *v)
Definition: value.c:411
#define TID_GLOBAL
Definition: target_api.h:145
void target_driver_argp_init_children(struct argp_state *state)
Definition: target.c:1057
struct np_config npc