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
rop_checkret.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 "rop.h"
43 
44 struct target *target = NULL;
45 struct target *otarget = NULL;
46 
47 static int result_counter = 0;
48 static int final_result_counter = 0;
49 
50 static int oldformat = 0;
51 
52 GHashTable *probes = NULL;
54 
56  GHashTableIter iter;
57  gpointer key;
58  struct probe *probe;
59 
60  if (probes) {
61  if (target)
62  target_pause(target);
63 
64  g_hash_table_iter_init(&iter,probes);
65  while (g_hash_table_iter_next(&iter,
66  (gpointer)&key,
67  (gpointer)&probe)) {
68  probe_unregister(probe,1);
69  probe_free(probe,1);
70  }
71 
72  g_hash_table_destroy(probes);
73  probes = NULL;
74  }
75 }
76 
77 void sigh_cleanup_probes(int signo,siginfo_t *siginfo,void *x) {
79 }
80 
81 result_t rop_handler(struct probe *probe,tid_t tid,void *data,
82  struct probe *trigger,struct probe *base) {
83  char *buf;
84  int buflen;
85  struct rop_checkret_status *rop_status = \
86  (struct rop_checkret_status *)probe_summarize(probe);
87  struct rop_checkret_data *rop_data = \
88  (struct rop_checkret_data *)probe_priv(probe);
89 
90  fflush(stderr);
91 
92  if (rop_status->isviolation) {
93  if (!oldformat) {
94  fprintf(stdout,
95  "RESULT:: (i:%d) rop (2) CFIViolation \"CFI violation!\""
96  " (retaddr=0x%"PRIxADDR",violations=%d,total=%d,"
97  "fpviolations=%d,jmpfpviolations=%d,jccfpviolations=%d,"
98  "isfpviolation=%d,gadgetstart=0x%"PRIxADDR","
99  "gadgetend=0x%"PRIxADDR",gadgetcontinstr=0x%"PRIxADDR
100  ") ::RESULT\n",
101  ++result_counter,rop_status->current_ret_addr,
102  rop_status->violations,rop_status->total,
103  rop_status->fpviolations,rop_status->jmpfpviolations,
104  rop_status->jccfpviolations,rop_status->isfpviolation,
105  rop_data->gadget->start,rop_data->gadget->end,
106  rop_data->cont_instr_start);
107  }
108  else
109  fprintf(stdout,"%s: CFI violation %s",probe_name(probe),
110  rop_status->isfpviolation ? "(false pos?)" : "");
111 
112  buflen = 64 + strlen(rop_data->gadget->meta);
113  buf = malloc(buflen);
114  snprintf(buf,buflen,"gadget 0x%"PRIxADDR", retaddr 0x%"PRIxADDR
115  " %s\n",
116  probe_addr(rop_data->entry_probe),rop_status->current_ret_addr,
117  rop_data->gadget->meta);
118  array_list_append(rop_violation_list,buf);
119  }
120  else {
121  if (!oldformat) {
122  fprintf(stdout,"RESULT:: (i:%d) rop (0) CFIClean \"CFI clean\""
123  " (retaddr=0x%"PRIxADDR",violations=%d,total=%d,"
124  "fpviolations=%d,jmpfpviolations=%d,jccfpviolations=%d,"
125  "isfpviolation=%d,gadgetstart=0x%"PRIxADDR","
126  "gadgetend=0x%"PRIxADDR",gadgetcontinstr=0x%"PRIxADDR
127  ") ::RESULT\n",
128  ++result_counter,rop_status->current_ret_addr,
129  rop_status->violations,rop_status->total,
130  rop_status->fpviolations,rop_status->jmpfpviolations,
131  rop_status->jccfpviolations,rop_status->isfpviolation,
132  rop_data->gadget->start,rop_data->gadget->end,
133  rop_data->cont_instr_start);
134  }
135  else {
136  fprintf(stdout,"%s: CFI clean",probe_name(probe));
137  fprintf(stdout," (retaddr=0x%"PRIxADDR",violations=%d,total=%d,fpviolations=%d,jmpfpviolations=%d,jccfpviolations=%d)\n",
138  rop_status->current_ret_addr,rop_status->violations,
139  rop_status->total,rop_status->fpviolations,
140  rop_status->jmpfpviolations,rop_status->jccfpviolations);
141  }
142  }
143 
144  fflush(stdout);
145 
146  return 0;
147 }
148 
150  int argc;
151  char **argv;
154 };
155 
157 
158 struct argp_option rc_argp_opts[] = {
159  { "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 },
160  { 0,0,0,0,0,0 },
161 };
162 
163 error_t rc_argp_parse_opt(int key,char *arg,struct argp_state *state) {
164  struct rc_argp_state *opts = \
165  (struct rc_argp_state *)target_argp_driver_state(state);
166  struct array_list *argv_list;
167  char *argptr;
168  char *nargptr;
169  char *vargptr;
170  int inesc;
171  int inquote;
172  int quotechar;
173 
174  switch (key) {
175  case ARGP_KEY_ARG:
176  return ARGP_ERR_UNKNOWN;
177  case ARGP_KEY_ARGS:
178  /* Eat all the remaining args. */
179  if (state->quoted > 0)
180  opts->argc = state->quoted - state->next;
181  else
182  opts->argc = state->argc - state->next;
183  if (opts->argc > 0) {
184  opts->argv = calloc(opts->argc,sizeof(char *));
185  memcpy(opts->argv,&state->argv[state->next],opts->argc*sizeof(char *));
186  state->next += opts->argc;
187  }
188  return 0;
189  case ARGP_KEY_INIT:
191  return 0;
192  case ARGP_KEY_END:
193  case ARGP_KEY_NO_ARGS:
194  case ARGP_KEY_SUCCESS:
195  return 0;
196  case ARGP_KEY_ERROR:
197  case ARGP_KEY_FINI:
198  return 0;
199  case 'V':
200  /*
201  * We need to split the <name_or_id>:<spec> part; then split
202  * <spec> into an argv. Simple rules: \ escapes the next char;
203  * space not in ' or " causes us to end the current argv[i] and
204  * start the next one.
205  */
206  argptr = index(arg,':');
207  if (!argptr) {
208  verror("bad overlay spec!\n");
209  return EINVAL;
210  }
211  argv_list = array_list_create(32);
212  array_list_append(argv_list,"dumptarget_overlay");
213 
214  opts->overlay_name_or_id = arg;
215  *argptr = '\0';
216  ++argptr;
217 
218  while (*argptr == ' ')
219  ++argptr;
220 
221  inesc = 0;
222  inquote = 0;
223  quotechar = 0;
224  nargptr = argptr;
225  vargptr = argptr;
226  while (*argptr != '\0') {
227  if (*argptr == '\\') {
228  if (inesc) {
229  inesc = 0;
230  *nargptr = '\\';
231  ++nargptr;
232  }
233  else {
234  /* Don't copy the escape char. */
235  inesc = 1;
236  ++argptr;
237  continue;
238  }
239  }
240  else if (inesc) {
241  inesc = 0;
242  /* Just copy it. */
243  *nargptr = *argptr;
244  ++nargptr;
245  }
246  else if (inquote && *argptr == quotechar) {
247  /* Ended the quoted sequence; don't copy quotes. */
248  inquote = 0;
249  quotechar = 0;
250  ++argptr;
251  continue;
252  }
253  else if (*argptr == '\'' || *argptr == '"') {
254  inquote = 1;
255  quotechar = *argptr;
256  ++argptr;
257  continue;
258  }
259  else if (!inquote && *argptr == ' ') {
260  *nargptr = *argptr = '\0';
261  if (vargptr) {
262  array_list_append(argv_list,vargptr);
263  //printf("vargptr (%p) = '%s'\n",vargptr,vargptr);
264  vargptr = NULL;
265  }
266  vargptr = NULL;
267  nargptr = ++argptr;
268  continue;
269  }
270  else {
271  if (!vargptr)
272  vargptr = nargptr;
273 
274  *nargptr = *argptr;
275  ++nargptr;
276  }
277 
278  /* Default increment. */
279  ++argptr;
280  }
281  if (vargptr) {
282  *nargptr = '\0';
283  array_list_append(argv_list,vargptr);
284  //printf("vargptr (%p) = '%s'\n",vargptr,vargptr);
285  }
286  array_list_append(argv_list,NULL);
287 
288  opts->overlay_spec = target_argp_driver_parse_one(NULL,NULL,
289  array_list_len(argv_list) - 1,
290  (char **)argv_list->list,
292  if (!opts->overlay_spec) {
293  verror("could not parse overlay spec!\n");
294  array_list_free(argv_list);
295  return EINVAL;
296  }
297 
298  array_list_free(argv_list);
299  break;
300 
301  default:
302  return ARGP_ERR_UNKNOWN;
303  }
304 
305  return 0;
306 }
307 
308 struct argp rc_argp = {
309  rc_argp_opts,rc_argp_parse_opt,NULL,NULL,NULL,NULL,NULL,
310 };
311 
312 int main(int argc,char **argv) {
313  target_status_t tstat;
314  GHashTableIter iter;
315  gpointer key;
316  struct rop_gadget *gadget;
317  struct probe *probe;
318  int i;
319  GHashTable *gadgets;
320  struct target_spec *tspec;
321  char targetstr[128];
322  struct target *rtarget;
323  int oid;
324  tid_t otid;
325  char *tmp = NULL;
326 
327  target_init();
328  atexit(target_fini);
329 
331 
332  memset(&opts,0,sizeof(opts));
333 
334  tspec = target_argp_driver_parse_one(&rc_argp,&opts,argc,argv,
336  | TARGET_TYPE_GDB,1);
337 
338  if (!tspec) {
339  verror("could not parse target arguments!\n");
340  exit(-1);
341  }
342 
343  if (opts.argc > 0)
344  gadgets = rop_load_gadget_file(opts.argv[0]);
345  else
346  gadgets = rop_load_gadget_stream(stdin);
347 
348  if (!gadgets || g_hash_table_size(gadgets) == 0) {
349  verror("No gadgets in file!\n");
350  return -2;
351  }
352 
353  rtarget = target = target_instantiate(tspec,NULL);
354  if (!target) {
355  verror("could not instantiate target!\n");
356  exit(-1);
357  }
358  target_snprintf(target,targetstr,sizeof(targetstr));
359 
360  if (target_open(target)) {
361  fprintf(stderr,"could not open %s!\n",targetstr);
362  exit(-4);
363  }
364 
365  /*
366  * Load an overlay target, if there is one.
367  */
369  errno = 0;
370  oid = (int)strtol(opts.overlay_name_or_id,&tmp,0);
371  if (errno || tmp == opts.overlay_name_or_id)
372  otid =
375  else
376  otid = target_lookup_overlay_thread_by_id(target,oid);
377  if (otid < 0) {
378  verror("could not find overlay thread '%s', exiting!\n",
380  cleanup_probes();
382  exit(-111);
383  }
384  otarget = target_instantiate_overlay(target,otid,opts.overlay_spec);
385  if (!otarget) {
386  verror("could not instantiate overlay target '%s'!\n",
388  cleanup_probes();
390  exit(-112);
391  }
392 
393  if (target_open(otarget)) {
394  fprintf(stderr,"could not open overlay target!\n");
395  cleanup_probes();
397  exit(-114);
398  }
399 
400  target_snprintf(target,targetstr,sizeof(targetstr));
401 
402  rtarget = otarget;
403  }
404 
405  /* Install probes... */
406  rop_violation_list = array_list_create(128);
407  probes = g_hash_table_new(g_direct_hash,g_direct_equal);
408  g_hash_table_iter_init(&iter,gadgets);
409  while (g_hash_table_iter_next(&iter,(gpointer)&key,(gpointer)&gadget)) {
410  probe = probe_rop_checkret(rtarget,TID_GLOBAL,gadget,NULL,rop_handler,NULL);
411  if (!probe) {
412  fprintf(stderr,"could not install probe on gadget at 0x%"PRIxADDR"\n",
413  gadget->start);
414  tstat = TSTATUS_ERROR;
415  goto err;
416  }
417  g_hash_table_insert(probes,(gpointer)probe,(gpointer)probe);
418  }
419 
420  /* The target is paused after the attach; we have to resume it now
421  * that we've registered probes.
422  */
423  target_resume(target);
424 
425  fprintf(stdout,"Starting watch loop!\n");
426  fflush(stdout);
427 
428  while (1) {
429  tstat = target_monitor(target);
430  if (tstat == TSTATUS_PAUSED || tstat == TSTATUS_INTERRUPTED) {
431  fflush(stderr);
432  fflush(stdout);
433  printf("target interrupted at 0x%"PRIxREGVAL"; trying to resume!\n",
434  target_read_reg(target,TID_GLOBAL,target->ipregno));
435 
436  if (target_resume(target)) {
437  fprintf(stderr,"could not resume target\n");
438  cleanup_probes();
440  exit(-16);
441  }
442  }
443  else if (tstat == TSTATUS_EXITING) {
444  fflush(stderr);
445  fflush(stdout);
446  fprintf(stdout,"target %s exiting, removing probes safely...\n",
447  targetstr);
448 
449  cleanup_probes();
450 
451  if (target_resume(target)) {
452  verror("could not resume target!\n");
454  exit(-16);
455  }
456  }
457  else if (tstat == TSTATUS_DONE) {
458  fflush(stderr);
459  fflush(stdout);
460  printf("target exited, cleaning up.\n");
461  cleanup_probes();
463 
464  goto out;
465  }
466  else {
467  fflush(stderr);
468  fflush(stdout);
469  printf("target interrupted at 0x%"PRIxREGVAL" -- bad status (%d)\n",
470  target_read_reg(target,TID_GLOBAL,target->ipregno),tstat);
471  goto err;
472  }
473  }
474 
475  err:
476  fflush(stderr);
477  fflush(stdout);
478  cleanup_probes();
480 
481  out:
482  if (array_list_len(rop_violation_list)) {
483  if (!oldformat)
484  fprintf(stdout,"RESULT:: (f:%d) rop (1) Violations \"ROP violations detected.\" ::RESULT\n",
485  ++final_result_counter);
486  else {
487  fprintf(stdout,"ROP violations detected!\n");
488 
489  fprintf(stdout,"Gadgets used:\n");
490 
491  for (i = 0; i < array_list_len(rop_violation_list); ++i) {
492  char *rv = (char *)array_list_item(rop_violation_list,i);
493  fprintf(stdout,"%s",rv);
494  free(rv);
495  }
496  }
497  }
498  else {
499  if (!oldformat)
500  fprintf(stdout,"RESULT:: (f:%d) rop (0) NoViolations \"No ROP violations detected.\" ::RESULT\n",
501  ++final_result_counter);
502  else
503  fprintf(stdout,"No ROP violations detected!\n");
504  }
505 
506  if (tstat == TSTATUS_DONE) {
507  printf("%s finished.\n",targetstr);
508  exit(0);
509  }
510  else if (tstat == TSTATUS_ERROR) {
511  printf("%s monitoring failed!\n",targetstr);
512  exit(-9);
513  }
514  else {
515  printf("%s monitoring failed with %d!\n",targetstr,tstat);
516  exit(-10);
517  }
518 }
struct target * target_instantiate_overlay(struct target *target, tid_t tid, struct target_spec *spec)
Definition: target_api.c:757
GHashTable * rop_load_gadget_stream(FILE *stream)
Definition: rop_util.c:36
struct rc_argp_state opts
Definition: rop_checkret.c:156
tid_t target_lookup_overlay_thread_by_name(struct target *target, char *name)
Definition: target_api.c:713
ADDR current_ret_addr
Definition: rop.h:44
struct argp_option rc_argp_opts[]
Definition: rop_checkret.c:158
int probe_unregister(struct probe *probe, int force)
Definition: probe.c:1137
void cleanup_probes()
Definition: rop_checkret.c:55
struct target * otarget
Definition: rop_checkret.c:45
int32_t tid_t
Definition: common.h:36
void * target_argp_driver_state(struct argp_state *state)
Definition: target.c:716
struct target_spec * overlay_spec
Definition: rop_checkret.c:153
target_status_t
Definition: target_api.h:197
Definition: rop.h:27
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
uint16_t fpviolations
Definition: rop.h:40
static uint64_t unsigned int i
void target_init(void)
Definition: target.c:69
void sigh_cleanup_probes(int signo, siginfo_t *siginfo, void *x)
Definition: rop_checkret.c:77
int target_resume(struct target *target)
Definition: target_api.c:1012
uint8_t isviolation
Definition: rop.h:34
int target_pause(struct target *target)
Definition: target_api.c:1027
GHashTable * probes
Definition: rop_checkret.c:52
struct probe * entry_probe
Definition: rop.h:92
struct list_head probe
Definition: probe.h:379
#define verror(format,...)
Definition: log.h:30
char * meta
Definition: rop.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
void target_fini(void)
Definition: target.c:91
char * overlay_name_or_id
Definition: rop_checkret.c:152
int target_snprintf(struct target *target, char *buf, int bufsiz)
Definition: target_api.c:829
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
ADDR probe_addr(struct probe *probe)
Definition: probe.c:1959
struct array_list * rop_violation_list
Definition: rop_checkret.c:53
result_t rop_handler(struct probe *probe, tid_t tid, void *data, struct probe *trigger, struct probe *base)
Definition: rop_checkret.c:81
tid_t tid
Definition: probe.h:344
uint16_t total
Definition: rop.h:43
void target_default_cleanup()
Definition: target.c:128
uint16_t jmpfpviolations
Definition: rop.h:41
int main(int argc, char **argv)
Definition: rop_checkret.c:312
int result_counter
Definition: spf.c:165
int probe_free(struct probe *probe, int force)
Definition: probe.c:777
ADDR start
Definition: rop.h:28
error_t rc_argp_parse_opt(int key, char *arg, struct argp_state *state)
Definition: rop_checkret.c:163
void * probe_priv(struct probe *probe)
Definition: probe.c:1951
void * probe_summarize(struct probe *probe)
Definition: probe.c:1786
Definition: probe.h:308
uint8_t isfpviolation
Definition: rop.h:34
ADDR end
Definition: rop.h:29
GHashTable * rop_load_gadget_file(char *filename)
Definition: rop_util.c:89
void * calloc(size_t nmemb, size_t size)
Definition: debugserver.c:200
result_t
Definition: common.h:25
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
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
struct probe * probe_rop_checkret(struct target *target, tid_t tid, struct rop_gadget *rg, probe_handler_t pre_handler, probe_handler_t post_handler, void *handler_data)
Definition: rop_util.c:492
void * malloc(size_t size)
Definition: debugserver.c:214
uint16_t violations
Definition: rop.h:39
ADDR cont_instr_start
Definition: rop.h:90
char * probe_name(struct probe *probe)
Definition: probe.c:1935
uint16_t jccfpviolations
Definition: rop.h:42
struct argp rc_argp
Definition: rop_checkret.c:308
REG ipregno
Definition: target_api.h:2508
#define TID_GLOBAL
Definition: target_api.h:145
void target_driver_argp_init_children(struct argp_state *state)
Definition: target.c:1057
struct rop_gadget * gadget
Definition: rop.h:82
#define PRIxREGVAL
Definition: common.h:72