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
cfi_check.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 <stdio.h>
20 #include <stdlib.h>
21 #include <errno.h>
22 #include <string.h>
23 
24 #include <sys/user.h>
25 #include <sys/ptrace.h>
26 #include <inttypes.h>
27 
28 #include <signal.h>
29 
30 #include <argp.h>
31 
32 #include "log.h"
33 #include "dwdebug.h"
34 #include "target_api.h"
35 #include "target.h"
36 
37 #include "probe_api.h"
38 #include "probe.h"
39 #include "alist.h"
40 #include "list.h"
41 
42 #include "cfi.h"
43 
44 struct target *target = NULL;
45 struct target *otarget = NULL;
46 struct probe *cfi_probe = NULL;
47 
48 static int result_counter = 0;
49 
50 void cleanup_probes(void) {
51  if (target)
52  target_pause(target);
53  if (cfi_probe) {
54  probe_free(cfi_probe,1);
55  cfi_probe = NULL;
56  }
57 }
58 
59 void sigh_cleanup_probes(int signo,siginfo_t *siginfo,void *x) {
61 }
62 
63 result_t cfi_handler(struct probe *probe,tid_t tid,void *data,
64  struct probe *trigger,struct probe *base) {
65  struct cfi_data *cfi = (struct cfi_data *)probe_priv(probe);
66  struct cfi_thread_status *cts;
67  /* struct cfi_status *cs; */
68  char *buf;
69 
70  cts = (struct cfi_thread_status *)probe_summarize_tid(probe,tid);
71  /* cs = (struct cfi_status *)probe_summarize(probe); */
72 
73  if (cts->status.isviolation) {
74  buf = cfi_thread_backtrace(cfi,cts," | ");
75  fprintf(stdout,
76  "RESULT:: (i:%d) cfi (2) CFIViolation \"CFI violation!\""
77  " (badretaddr=0x%"PRIxADDR",oldretaddr=0x%"PRIxADDR","
78  " depth=%d,violations=%d,stack=%s) ::RESULT\n",
81  array_list_len(cts->shadow_stack),cts->status.violations,buf);
82  fflush(stdout);
83  free(buf);
84  }
85  /*
86  else {
87  fprintf(stdout,"RESULT:: (i:%d) rop (0) CFIClean \"CFI clean\""
88  " (retaddr=0x%"PRIxADDR",violations=%d,total=%d,"
89  "fpviolations=%d,jmpfpviolations=%d,jccfpviolations=%d,"
90  "isfpviolation=%d) ::RESULT\n",
91  ++result_counter,rop_status->current_ret_addr,
92  rop_status->violations,rop_status->total,
93  rop_status->fpviolations,rop_status->jmpfpviolations,
94  rop_status->jccfpviolations,rop_status->isfpviolation);
95  }
96 
97  fflush(stdout);
98  */
99  return 0;
100 }
101 
103  struct cfi_data *cfi = (struct cfi_data *)probe_priv(probe);
104  struct cfi_thread_status *cts;
105  char *buf;
106  GHashTableIter iter;
107  gpointer key;
108  int i;
109 
110  i = 0;
111  g_hash_table_iter_init(&iter,cfi->thread_status);
112  while (g_hash_table_iter_next(&iter,&key,(gpointer *)&cts)) {
113  if (cts->status.isviolation) {
114  buf = cfi_thread_backtrace(cfi,cts," | ");
115  fprintf(stdout,
116  "RESULT:: (f:%d) cfi (2) CFIViolation \"CFI violation!\""
117  " (tid=%d,badretaddr=0x%"PRIxADDR",oldretaddr=0x%"PRIxADDR","
118  " depth=%d,violations=%d,stack=%s) ::RESULT\n",
119  ++i,(int)(uintptr_t)key,
121  array_list_len(cts->shadow_stack),cts->status.violations,buf);
122  fflush(stdout);
123  free(buf);
124  }
125  else if (array_list_len(cts->shadow_stack)) {
126  buf = cfi_thread_backtrace(cfi,cts," | ");
127  fprintf(stdout,
128  "RESULT:: (f:%d) cfi (3) CFIStackRemainingViolation \"CFI violation -- inferred due to remaining shadow stack items!\""
129  " (tid=%d,depth=%d,violations=%d,stack=%s) ::RESULT\n",
130  ++i,(int)(uintptr_t)key,
131  array_list_len(cts->shadow_stack),cts->status.violations,buf);
132  fflush(stdout);
133  free(buf);
134  }
135  else {
136  fprintf(stdout,
137  "RESULT:: (f:%d) cfi (0) CFIClean \"CFI clean!\""
138  " (tid=%d,violations=%d) ::RESULT\n",
139  ++i,(int)(uintptr_t)key,cts->status.violations);
140  fflush(stdout);
141  }
142  }
143 }
144 
148  int argc;
149  char **argv;
152 };
153 
155 
156 struct argp_option cc_argp_opts[] = {
157  { "overlay",'V',"<name_or_id>:<spec_opts>",0,"Lookup name or id as an overlay target once the main target is instantiated, and try to open it. All spec_opts (normal target/dwdebug opts) then apply to the overlay target.",0 },
158  { "mode",'M',"dynamic|static",0,"Set the CFI mode (only dynamic now).",-3 },
159  { "no-autofollow",'N',NULL,0,
160  "Do not add functions to the CFI checked set.",-3 },
161  { "no-singlestep-unknown",'S',NULL,0,
162  "Don't singlestep unknown areas in the target.",-3 },
163  { "fix-stack",'f',NULL,0,
164  "Fix the stack before a RET that would violate CFI.",-3 },
165  { 0,0,0,0,0,0 },
166 };
167 
168 error_t cc_argp_parse_opt(int key,char *arg,struct argp_state *state) {
169  struct cc_argp_state *opts = \
170  (struct cc_argp_state *)target_argp_driver_state(state);
171  struct array_list *argv_list;
172  char *argptr;
173  char *nargptr;
174  char *vargptr;
175  int inesc;
176  int inquote;
177  int quotechar;
178 
179  switch (key) {
180  case ARGP_KEY_ARG:
181  return ARGP_ERR_UNKNOWN;
182  case ARGP_KEY_ARGS:
183  /* Eat all the remaining args. */
184  if (state->quoted > 0)
185  opts->argc = state->quoted - state->next;
186  else
187  opts->argc = state->argc - state->next;
188  if (opts->argc > 0) {
189  opts->argv = calloc(opts->argc,sizeof(char *));
190  memcpy(opts->argv,&state->argv[state->next],opts->argc*sizeof(char *));
191  state->next += opts->argc;
192  }
193  return 0;
194  case ARGP_KEY_INIT:
196  return 0;
197  case ARGP_KEY_END:
198  case ARGP_KEY_NO_ARGS:
199  case ARGP_KEY_SUCCESS:
200  return 0;
201  case ARGP_KEY_ERROR:
202  case ARGP_KEY_FINI:
203  return 0;
204  case 'V':
205  /*
206  * We need to split the <name_or_id>:<spec> part; then split
207  * <spec> into an argv. Simple rules: \ escapes the next char;
208  * space not in ' or " causes us to end the current argv[i] and
209  * start the next one.
210  */
211  argptr = index(arg,':');
212  if (!argptr) {
213  verror("bad overlay spec!\n");
214  return EINVAL;
215  }
216  argv_list = array_list_create(32);
217  array_list_append(argv_list,"dumptarget_overlay");
218 
219  opts->overlay_name_or_id = arg;
220  *argptr = '\0';
221  ++argptr;
222 
223  while (*argptr == ' ')
224  ++argptr;
225 
226  inesc = 0;
227  inquote = 0;
228  quotechar = 0;
229  nargptr = argptr;
230  vargptr = argptr;
231  while (*argptr != '\0') {
232  if (*argptr == '\\') {
233  if (inesc) {
234  inesc = 0;
235  *nargptr = '\\';
236  ++nargptr;
237  }
238  else {
239  /* Don't copy the escape char. */
240  inesc = 1;
241  ++argptr;
242  continue;
243  }
244  }
245  else if (inesc) {
246  inesc = 0;
247  /* Just copy it. */
248  *nargptr = *argptr;
249  ++nargptr;
250  }
251  else if (inquote && *argptr == quotechar) {
252  /* Ended the quoted sequence; don't copy quotes. */
253  inquote = 0;
254  quotechar = 0;
255  ++argptr;
256  continue;
257  }
258  else if (*argptr == '\'' || *argptr == '"') {
259  inquote = 1;
260  quotechar = *argptr;
261  ++argptr;
262  continue;
263  }
264  else if (!inquote && *argptr == ' ') {
265  *nargptr = *argptr = '\0';
266  if (vargptr) {
267  array_list_append(argv_list,vargptr);
268  //printf("vargptr (%p) = '%s'\n",vargptr,vargptr);
269  vargptr = NULL;
270  }
271  vargptr = NULL;
272  nargptr = ++argptr;
273  continue;
274  }
275  else {
276  if (!vargptr)
277  vargptr = nargptr;
278 
279  *nargptr = *argptr;
280  ++nargptr;
281  }
282 
283  /* Default increment. */
284  ++argptr;
285  }
286  if (vargptr) {
287  *nargptr = '\0';
288  array_list_append(argv_list,vargptr);
289  //printf("vargptr (%p) = '%s'\n",vargptr,vargptr);
290  }
291  array_list_append(argv_list,NULL);
292 
293  opts->overlay_spec = target_argp_driver_parse_one(NULL,NULL,
294  array_list_len(argv_list) - 1,
295  (char **)argv_list->list,
297  if (!opts->overlay_spec) {
298  verror("could not parse overlay spec!\n");
299  array_list_free(argv_list);
300  return EINVAL;
301  }
302 
303  array_list_free(argv_list);
304  break;
305 
306  default:
307  return ARGP_ERR_UNKNOWN;
308  }
309 
310  return 0;
311 }
312 
313 struct argp cc_argp = {
314  cc_argp_opts,cc_argp_parse_opt,NULL,NULL,NULL,NULL,NULL,
315 };
316 
317 int main(int argc,char **argv) {
318  target_status_t tstat;
319  struct target_spec *tspec;
320  char targetstr[128];
321  struct array_list *root_function_list;
322  struct array_list *root_addr_list;
323  int i;
324  struct bsymbol *function;
325  struct target *rtarget;
326  int oid;
327  tid_t otid;
328  char *tmp = NULL;
329  char *endptr = NULL;
330  ADDR addr;
331 
332  target_init();
333  atexit(target_fini);
334 
336 
337  memset(&opts,0,sizeof(opts));
339 
340  tspec = target_argp_driver_parse_one(&cc_argp,&opts,argc,argv,
342  | TARGET_TYPE_GDB,1);
343 
344  if (!tspec) {
345  verror("could not parse target arguments!\n");
346  exit(-1);
347  }
348 
349  rtarget = target = target_instantiate(tspec,NULL);
350  if (!target) {
351  verror("could not instantiate target!\n");
352  exit(-1);
353  }
354  target_snprintf(target,targetstr,sizeof(targetstr));
355 
356  if (target_open(target)) {
357  fprintf(stderr,"could not open %s!\n",targetstr);
358  exit(-4);
359  }
360 
361  /*
362  * Load an overlay target, if there is one.
363  */
365  errno = 0;
366  oid = (int)strtol(opts.overlay_name_or_id,&tmp,0);
367  if (errno || tmp == opts.overlay_name_or_id)
368  otid =
371  else
372  otid = target_lookup_overlay_thread_by_id(target,oid);
373  if (otid < 0) {
374  verror("could not find overlay thread '%s', exiting!\n",
376  cleanup_probes();
378  exit(-111);
379  }
380  otarget = target_instantiate_overlay(target,otid,opts.overlay_spec);
381  if (!otarget) {
382  verror("could not instantiate overlay target '%s'!\n",
384  cleanup_probes();
386  exit(-112);
387  }
388 
389  if (target_open(otarget)) {
390  fprintf(stderr,"could not open overlay target!\n");
391  cleanup_probes();
393  exit(-114);
394  }
395 
396  target_snprintf(target,targetstr,sizeof(targetstr));
397 
398  rtarget = otarget;
399  }
400 
401  if (opts.argc > 0) {
402  root_function_list = array_list_create(opts.argc);
403  root_addr_list = array_list_create(opts.argc);
404  for (i = 0; i < opts.argc; ++i) {
405  function = target_lookup_sym(rtarget,opts.argv[i],NULL,NULL,
407  if (!function) {
408  addr = (ADDR)strtoll(opts.argv[i],&endptr,16);
409  if (endptr == opts.argv[i]) {
410  fprintf(stderr,"Could not convert %s to address!\n",
411  opts.argv[i]);
412  cleanup_probes();
414  exit(-3);
415  }
416  /*
417  else
418  function = target_lookup_sym_addr(rtarget,addr);
419  */
420  }
421 
422  if (function)
423  array_list_append(root_function_list,function);
424  else
425  array_list_append(root_addr_list,(void *)(uintptr_t)addr);
426  }
427  }
428  else {
429  root_function_list = array_list_create(1);
430  root_addr_list = array_list_create(0);
431 
432  function = target_lookup_sym(rtarget,"main",NULL,NULL,
434  if (!function) {
435  vwarn("could not lookup symbol main; trying __libc_start_main!\n");
436  function = target_lookup_sym(rtarget,"__libc_start_main",
437  NULL,NULL,SYMBOL_TYPE_FLAG_NONE);
438  if (!function) {
439  verror("could not lookup symbol __libc_start_main;"
440  " aborting!\n");
441  cleanup_probes();
443  exit(-3);
444  }
445  else
446  array_list_append(root_function_list,function);
447  }
448  else
449  array_list_append(root_function_list,function);
450  }
451 
452  /* Install probes... */
453  cfi_probe = probe_cfi(rtarget,TID_GLOBAL,opts.mode,opts.flags,
454  root_function_list,root_addr_list,
455  cfi_handler,cfi_handler,NULL);
456  if (!cfi_probe) {
457  verror("could not instantiate the CFI meta-probe; aborting!\n");
458  cleanup_probes();
460  exit(-4);
461  }
462 
463  /*
464  * The target was paused after instantiation; we have to resume it
465  * now that we've registered probes.
466  */
467  target_resume(target);
468 
469  fprintf(stdout,"Starting CFI monitoring!\n");
470  fflush(stdout);
471 
472  while (1) {
473  tstat = target_monitor(target);
474  if (tstat == TSTATUS_PAUSED) {
475  fflush(stderr);
476  fflush(stdout);
477  vwarn("target %s interrupted at 0x%"PRIxREGVAL"; trying resume!\n",
478  targetstr,target_read_creg(target,TID_GLOBAL,CREG_IP));
479 
480  if (target_resume(target)) {
481  verror("could not resume target\n");
482  cleanup_probes();
484  exit(-16);
485  }
486  }
487  else if (tstat == TSTATUS_EXITING) {
488  fflush(stderr);
489  fflush(stdout);
490  if (cfi_probe) {
491  fprintf(stdout,"target %s exiting, printing final results...\n",
492  targetstr);
493 
495 
496  fprintf(stdout,"target %s exiting, removing probes safely...\n",
497  targetstr);
498 
499  probe_free(cfi_probe,1);
500  cfi_probe = NULL;
501  }
502 
503  if (target_resume(target)) {
504  verror("could not resume target!\n");
505  cleanup_probes();
507  exit(-16);
508  }
509  }
510  else if (tstat == TSTATUS_DONE) {
511  fflush(stderr);
512  fflush(stdout);
513  if (cfi_probe) {
514  fprintf(stdout,"target %s exited, printing final results...\n",
515  targetstr);
516 
518 
519  probe_free(cfi_probe,1);
520  cfi_probe = NULL;
521  }
522 
523  fprintf(stdout,"target %s exited, cleaning up.\n",targetstr);
524 
525  cleanup_probes();
527  goto out;
528  }
529  else {
530  fflush(stderr);
531  fflush(stdout);
532  if (cfi_probe) {
533  fprintf(stdout,
534  "target %s interrupted at 0x%"PRIxREGVAL
535  " -- bad status (%d), printing final results...\n",
536  targetstr,target_read_creg(target,TID_GLOBAL,CREG_IP),
537  tstat);
538 
540 
541  probe_free(cfi_probe,1);
542  cfi_probe = NULL;
543  }
544 
545  fprintf(stdout,
546  "target %s interrupted at 0x%"PRIxREGVAL
547  " -- bad status (%d), exiting\n",
548  targetstr,target_read_creg(target,TID_GLOBAL,CREG_IP),tstat);
549 
550  goto err;
551  }
552  }
553 
554  err:
555  fflush(stderr);
556  fflush(stdout);
557  cleanup_probes();
559 
560  out:
561  fflush(stderr);
562  fflush(stdout);
563  exit(0);
564 }
struct target * target_instantiate_overlay(struct target *target, tid_t tid, struct target_spec *spec)
Definition: target_api.c:757
tid_t target_lookup_overlay_thread_by_name(struct target *target, char *name)
Definition: target_api.c:713
struct probe * probe_cfi(struct target *target, tid_t tid, cfi_mode_t mode, cfi_flags_t flags, struct array_list *root_functions, struct array_list *root_addrs, probe_handler_t pre_handler, probe_handler_t post_handler, void *handler_data)
Definition: cfi_util.c:1118
int32_t tid_t
Definition: common.h:36
void * target_argp_driver_state(struct argp_state *state)
Definition: target.c:716
GHashTable * thread_status
Definition: cfi.h:184
target_status_t
Definition: target_api.h:197
tid_t target_lookup_overlay_thread_by_id(struct target *target, int id)
Definition: target_api.c:693
struct target_spec * tspec
Definition: dumptarget.c:113
static uint64_t unsigned int i
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
void target_init(void)
Definition: target.c:69
Definition: arch.h:74
int target_resume(struct target *target)
Definition: target_api.c:1012
struct cc_argp_state opts
Definition: cfi_check.c:154
cfi_mode_t mode
Definition: cfi_check.c:146
int target_pause(struct target *target)
Definition: target_api.c:1027
result_t cfi_handler(struct probe *probe, tid_t tid, void *data, struct probe *trigger, struct probe *base)
Definition: cfi_check.c:63
void cleanup_probes(void)
Definition: cfi_check.c:50
char * cfi_thread_backtrace(struct cfi_data *cfi, struct cfi_thread_status *cts, char *sep)
Definition: cfi_util.c:1056
char * overlay_name_or_id
Definition: cfi_check.c:150
struct argp_option cc_argp_opts[]
Definition: cfi_check.c:156
#define verror(format,...)
Definition: log.h:30
int target_install_default_sighandlers(void(*sighandler)(int signo, siginfo_t *siginfo, void *x))
Definition: target.c:240
void ** list
Definition: alist.h:34
ADDR oldretaddr
Definition: cfi.h:133
void target_fini(void)
Definition: target.c:91
#define vwarn(format,...)
Definition: log.h:33
struct array_list * shadow_stack
Definition: cfi.h:141
int target_snprintf(struct target *target, char *buf, int bufsiz)
Definition: target_api.c:829
void free(void *ptr)
Definition: debugserver.c:207
struct cfi_status status
Definition: cfi.h:143
tid_t tid
Definition: probe.h:344
char ** argv
Definition: cfi_check.c:149
void target_default_cleanup()
Definition: target.c:128
cfi_flags_t flags
Definition: cfi_check.c:147
int result_counter
Definition: spf.c:165
int probe_free(struct probe *probe, int force)
Definition: probe.c:777
void * probe_summarize_tid(struct probe *probe, tid_t tid)
Definition: probe.c:1793
void * probe_priv(struct probe *probe)
Definition: probe.c:1951
cfi_flags_t
Definition: cfi.h:78
Definition: probe.h:308
REGVAL target_read_creg(struct target *target, tid_t tid, common_reg_t reg)
Definition: target_api.c:1178
void * calloc(size_t nmemb, size_t size)
Definition: debugserver.c:200
struct argp cc_argp
Definition: cfi_check.c:313
result_t
Definition: common.h:25
void cfi_check_print_final_results(struct probe *probe)
Definition: cfi_check.c:102
cfi_mode_t
Definition: cfi.h:44
struct target_spec * overlay_spec
Definition: cfi_check.c:151
struct probe * cfi_probe
Definition: cfi_check.c:46
uint32_t ADDR
Definition: common.h:64
uint16_t violations
Definition: cfi.h:136
Definition: cfi.h:146
int target_open(struct target *target)
Definition: target_api.c:513
target_status_t target_monitor(struct target *target)
Definition: target_api.c:869
#define PRIxADDR
Definition: common.h:67
void sigh_cleanup_probes(int signo, siginfo_t *siginfo, void *x)
Definition: cfi_check.c:59
error_t cc_argp_parse_opt(int key, char *arg, struct argp_state *state)
Definition: cfi_check.c:168
struct target_spec * target_argp_driver_parse_one(struct argp *driver_parser, void *driver_state, int argc, char **argv, target_type_t target_types, int filter_quoted)
Definition: target.c:802
struct target * target_instantiate(struct target_spec *spec, struct evloop *evloop)
Definition: target_api.c:55
uint8_t isviolation
Definition: cfi.h:131
ADDR newretaddr
Definition: cfi.h:134
struct target * otarget
Definition: cfi_check.c:45
int main(int argc, char **argv)
Definition: cfi_check.c:317
#define TID_GLOBAL
Definition: target_api.h:145
void target_driver_argp_init_children(struct argp_state *state)
Definition: target.c:1057
#define PRIxREGVAL
Definition: common.h:72