44 if (addr == 0 && symbol == NULL) {
77 if (oldretaddr == 0 && symbol == NULL) {
84 oldretaddr = (
ADDR)(uintptr_t) \
90 "popping retaddr = 0x%"PRIxADDR" (%d) (0x%s);"
91 " replacing with NULL (also skipped a NULL)\n",
101 return __cfit_stack_makenull(cfit);
110 "popping retaddr = 0x%"PRIxADDR" (%d) (0x%s);"
111 " replacing with NULL\n",
121 return __cfit_stack_makenull(cfit);
126 return __cfit_stack_makenull(cfit);
131 struct probe *trigger,
struct probe *base) {
140 "skipping cfi probe in tid %d that is not our tid (%d)\n",
146 g_hash_table_lookup(cfi->
thread_status,(gpointer)(uintptr_t)tid);
148 cfit =
calloc(1,
sizeof(*cfit));
151 g_hash_table_insert(cfi->
thread_status,(gpointer)(uintptr_t)tid,cfit);
157 verror(
"could not read SP!\n");
164 (
unsigned char *)&retaddr)) {
165 verror(
"could not read top of stack!\n");
172 verror(
"could not read IP!\n");
178 if (cfi_instrument_func(cfi,bsymbol,0)) {
180 " 0x%"PRIxADDR" (%s) probe(%s) (trying code block)!\n",
192 " 0x%"PRIxADDR" (%s) probe(%s) (tracking)\n",
201 array_list_append(cfit->
shadow_stack,(
void *)(uintptr_t)retaddr);
209 " 0x%"PRIxADDR" probe(%s) (trying code block)\n",
213 if (cfi_instrument_block(cfi,ip,0)) {
214 vwarn(
"tid %d could not instrument code block for ip 0x%"PRIxADDR
";"
215 " not tracking!\n",tid,ip);
217 __cfit_stack_makenull(cfit);
226 array_list_append(cfit->
shadow_stack,(
void *)(uintptr_t)retaddr);
240 struct probe *trigger,
struct probe *base) {
248 "skipping cfi probe in tid %d that is not our tid (%d)\n",
254 g_hash_table_lookup(cfi->
thread_status,(gpointer)(uintptr_t)tid);
256 cfit =
calloc(1,
sizeof(*cfit));
259 g_hash_table_insert(cfi->
thread_status,(gpointer)(uintptr_t)tid,cfit);
265 verror(
"could not read IP!\n");
272 if (cfi_instrument_func(cfi,bsymbol,0)) {
274 " (%s); not tracking (removing last call)!\n",
296 if (cfi_instrument_block(cfi,ip,0)) {
297 vwarn(
"tid %d could not instrument code block for branch target"
299 " not tracking (removing last call)!\n",
302 __cfit_stack_makelastnull(cfit);
313 struct probe *trigger,
struct probe *base) {
325 "skipping cfi probe in tid %d that is not our tid (%d)\n",
331 g_hash_table_lookup(cfi->
thread_status,(gpointer)(uintptr_t)tid);
333 cfit =
calloc(1,
sizeof(*cfit));
336 g_hash_table_insert(cfi->
thread_status,(gpointer)(uintptr_t)tid,cfit);
351 verror(
"could not read SP!\n");
355 oldretaddr = (
ADDR)(uintptr_t) \
358 symbol = (
struct bsymbol *) \
363 (
unsigned char *)&newretaddr)) {
364 verror(
"tid %d could not read retaddr from top of stack!\n",tid);
370 if (oldretaddr == 0 && symbol == NULL) {
376 oldretaddr2 = (
ADDR)(uintptr_t) \
386 if (oldretaddr2 == newretaddr) {
390 oldretaddr = (
ADDR)(uintptr_t) \
393 symbol = (
struct bsymbol *) \
398 "tid %d leaving untracked sequence; newretaddr = 0x%"PRIxADDR";"
399 " oldretaddr = 0x%"PRIxADDR" (probe %s)!\n",
406 "tid %d not leaving untracked sequence; newretaddr = 0x%"PRIxADDR";"
407 " oldretaddr = 0x%"PRIxADDR" (probe %s)!\n",
412 else if (newretaddr != oldretaddr) {
426 "tid %d retaddr = 0x%"PRIxADDR" (%d) (ret-immediate; oldretaddr ="
428 tid,newretaddr,array_list_len(cfit->
shadow_stack),oldretaddr,
432 if (cfi_instrument_func(cfi,bsymbol,0)) {
433 vwarn(
"tid %d could not instrument function %s (0x%"PRIxADDR
");"
434 " trying code block!\n",
442 if (cfi_instrument_block(cfi,newretaddr,0)) {
443 vwarn(
"tid %d could not instrument code block for RETI"
444 " newretaddr 0x%"PRIxADDR
"; not tracking!\n",
479 "tid %d retaddr = 0x%"PRIxADDR" (%d) (violation! oldretaddr ="
481 tid,newretaddr,array_list_len(cfit->
shadow_stack),oldretaddr,
489 (
unsigned char *)&oldretaddr)) {
490 verror(
"could not fixup top of stack in retaddr_check!\n");
542 struct probe **probe_alt) {
574 (gpointer)(uintptr_t)iaddr,(gpointer)1);
587 struct probe *cprobe = NULL;
588 struct probe *rprobe = NULL;
589 struct probe *jprobe = NULL;
592 struct bsymbol *absolute_branch_symbol;
593 ADDR absolute_branch_addr;
601 verror(
"could not resolve base addr for function %s!\n",
612 if (!g_hash_table_lookup(cfi->
disfuncs,(gpointer)funcstart)) {
619 bufsiz =
sizeof(
"call_in_") + strlen(name) + 1;
621 snprintf(buf,bufsiz,
"call_in_%s",name);
624 bufsiz =
sizeof(
"call_in_") +
sizeof(
ADDR) * 2 + 1;
626 snprintf(buf,bufsiz,
"call_in_%"PRIxADDR,funcstart);
635 bufsiz =
sizeof(
"ret_in_") + strlen(name) + 1;
637 snprintf(buf,bufsiz,
"ret_in_%s",name);
640 bufsiz =
sizeof(
"ret_in_") +
sizeof(
ADDR) * 2 + 1;
642 snprintf(buf,bufsiz,
"ret_in_%"PRIxADDR,funcstart);
651 bufsiz =
sizeof(
"jmp_in_") + strlen(name) + 1;
653 snprintf(buf,bufsiz,
"jmp_in_%s",name);
656 bufsiz =
sizeof(
"jmp_in_") +
sizeof(
ADDR) * 2 + 1;
658 snprintf(buf,bufsiz,
"jmp_in_%"PRIxADDR,funcstart);
665 pds.absolute_branch_targets = array_list_create(0);
679 cfi_probe_disasm_handler,&pds,
689 cfi_probe_disasm_handler,&pds,
702 "no call sites in %s; removing\n",
probe_name(cprobe));
707 g_hash_table_insert(cfi->
probes,(gpointer)cprobe,(gpointer)cprobe);
709 "registered %d call probes on %s\n",
720 "no return sites in %s; removing\n",
probe_name(rprobe));
725 g_hash_table_insert(cfi->
probes,(gpointer)rprobe,(gpointer)rprobe);
727 "registered %d return probes on %s\n",
734 "no indirect jmp sites in %s; removing\n",
probe_name(jprobe));
739 g_hash_table_insert(cfi->
probes,(gpointer)jprobe,(gpointer)jprobe);
741 "registered %d jmp probes on %s\n",
749 if (!cprobe && !rprobe && !jprobe) {
750 array_list_free(pds.absolute_branch_targets);
753 (gpointer)funcstart,(gpointer)1);
758 g_hash_table_insert(cfi->
disfuncs,(gpointer)funcstart,(gpointer)1);
768 if (array_list_len(pds.absolute_branch_targets) > 0) {
770 absolute_branch_addr = (
ADDR)item;
771 absolute_branch_symbol =
774 if (absolute_branch_symbol) {
775 if (cfi_instrument_func(cfi,absolute_branch_symbol,0)) {
777 "could not find symbol for ip 0x%"PRIxADDR" (%s);"
778 " trying code block!\n",
779 absolute_branch_addr,
782 absolute_branch_symbol = NULL;
786 if (!absolute_branch_symbol) {
787 if (cfi_instrument_block(cfi,absolute_branch_addr,0)) {
789 " CFI might be BUGGY!\n",
790 absolute_branch_addr);
794 if (absolute_branch_symbol)
798 array_list_free(pds.absolute_branch_targets);
804 static int cfi_instrument_block(
struct cfi_data *cfi,
ADDR ip,
int isroot) {
805 ADDR start = 0,end = 0;
808 struct probe *cprobe = NULL;
809 struct probe *rprobe = NULL;
810 struct probe *jprobe = NULL;
812 struct bsymbol *absolute_branch_symbol;
813 ADDR absolute_branch_addr;
818 verror(
"no safe disasm range contains target ip 0x%"PRIxADDR"!\n",ip);
826 if (!g_hash_table_lookup(cfi->
disfuncs,(gpointer)start)) {
827 bufsiz =
sizeof(
"call_in_") +
sizeof(
ADDR) * 2 + 1;
829 snprintf(buf,bufsiz,
"call_in_%"PRIxADDR,start);
836 bufsiz =
sizeof(
"ret_in_") +
sizeof(
ADDR) * 2 + 1;
838 snprintf(buf,bufsiz,
"ret_in_%"PRIxADDR,start);
845 bufsiz =
sizeof(
"jmp_in_") +
sizeof(
ADDR) * 2 + 1;
847 snprintf(buf,bufsiz,
"jmp_in_%"PRIxADDR,start);
853 pds.absolute_branch_targets = array_list_create(0);
866 if (!probe_register_block_instrs(cfi->
target,start,end,
868 cfi_probe_disasm_handler,&pds,
877 if (!probe_register_block_instrs(cfi->
target,start,end,
879 cfi_probe_disasm_handler,&pds,
892 "no call sites in %s; removing\n",
probe_name(cprobe));
897 g_hash_table_insert(cfi->
probes,(gpointer)cprobe,(gpointer)cprobe);
899 "registered %d call probes on %s\n",
910 "no return sites in %s; removing\n",
probe_name(rprobe));
915 g_hash_table_insert(cfi->
probes,(gpointer)rprobe,(gpointer)rprobe);
917 "registered %d return probes on %s\n",
924 "no indirect jmp sites in %s; removing\n",
probe_name(jprobe));
929 g_hash_table_insert(cfi->
probes,(gpointer)jprobe,(gpointer)jprobe);
931 "registered %d jmp probes on %s\n",
939 if (!cprobe && !rprobe && !jprobe) {
940 array_list_free(pds.absolute_branch_targets);
943 (gpointer)start,(gpointer)1);
948 g_hash_table_insert(cfi->
disfuncs,(gpointer)start,(gpointer)1);
958 if (array_list_len(pds.absolute_branch_targets) > 0) {
960 absolute_branch_addr = (
ADDR)item;
961 absolute_branch_symbol =
964 if (absolute_branch_symbol) {
965 if (cfi_instrument_func(cfi,absolute_branch_symbol,0)) {
967 "could not find symbol for ip 0x%"PRIxADDR" (%s);"
968 " trying code block!\n",
969 absolute_branch_addr,
972 absolute_branch_symbol = NULL;
976 if (!absolute_branch_symbol) {
977 if (cfi_instrument_block(cfi,absolute_branch_addr,0)) {
979 " CFI might be BUGGY!\n",
980 absolute_branch_addr);
984 if (absolute_branch_symbol)
988 array_list_free(pds.absolute_branch_targets);
1010 g_hash_table_lookup(cfi->
thread_status,(gpointer)(uintptr_t)tid);
1017 GHashTableIter iter;
1018 struct probe *tprobe;
1020 struct bsymbol *symbol;
1023 g_hash_table_destroy(cfi->
disfuncs);
1026 g_hash_table_iter_init(&iter,cfi->
probes);
1027 while (g_hash_table_iter_next(&iter,NULL,(gpointer *)&tprobe)) {
1030 g_hash_table_destroy(cfi->
probes);
1033 while (g_hash_table_iter_next(&iter,NULL,(gpointer *)&tdata)) {
1034 array_list_free(tdata->shadow_stack);
1039 array_list_free(tdata->shadow_stack_symbols);
1049 static struct probe_ops probe_ops_cfi = {
1062 struct bsymbol *
function;
1101 rcr = snprintf(buf + rc,buflen - rc,
1103 (
ADDR)(uintptr_t)retaddr,name,base);
1105 if ((i + 1) < alen) {
1106 rcr = snprintf(buf + rc,buflen - rc,
"%s",sep);
1111 buf[buflen - 1] =
'\0';
1123 void *handler_data) {
1128 struct bsymbol *
function;
1135 verror(
"unsupported CFI mode %d!\n",mode);
1140 vwarn(
"unsupported SINGLESTEP_UNKNOWN option!\n");
1144 vwarn(
"CFI with specific thread %d might be buggy!\n",tid);
1148 snprintf(namebuf,64,
"cfi(target %d tid %d)",target->
id,tid);
1155 cfi_probe->
priv = cfi;
1162 cfi->
disfuncs = g_hash_table_new(g_direct_hash,g_direct_equal);
1163 cfi->
disfuncs_noflow = g_hash_table_new(g_direct_hash,g_direct_equal);
1164 cfi->
probes = g_hash_table_new(g_direct_hash,g_direct_equal);
1165 cfi->
thread_status = g_hash_table_new(g_direct_hash,g_direct_equal);
1172 if (root_functions) {
1174 if (cfi_instrument_func(cfi,
function,1)) {
1182 if (cfi_instrument_block(cfi,addr,1)) {
result_t pre_handler(struct probe *probe, tid_t tid, void *data, struct probe *trigger, struct probe *base)
struct array_list * shadow_stack_symbols
probe_handler_t pre_handler
GHashTable * thread_status
void * probe_summarize_cfi(struct probe *probe)
result_t cfi_dynamic_jmp_target_instr(struct probe *probe, tid_t tid, void *data, struct probe *trigger, struct probe *base)
static uint64_t unsigned int i
int target_bsymbol_resolve_base(struct target *target, struct target_location_ctxt *tlctxt, struct bsymbol *bsymbol, ADDR *o_addr, struct memrange **o_range)
struct target_location_ctxt * target_location_ctxt_create_from_bsymbol(struct target *target, tid_t tid, struct bsymbol *bsymbol)
result_t probe_do_sink_post_handlers(struct probe *probe, tid_t tid, void *handler_data, struct probe *trigger, struct probe *base)
char * bsymbol_get_name(struct bsymbol *bsymbol)
int probe_fini_cfi(struct probe *probe)
#define verror(format,...)
result_t probe_do_sink_pre_handlers(struct probe *probe, tid_t tid, void *handler_data, struct probe *trigger, struct probe *base)
unsigned char * target_read_addr(struct target *target, ADDR addr, unsigned long length, unsigned char *buf)
const char *(* gettype)(struct probe *probe)
result_t(* probe_handler_t)(struct probe *probe, tid_t tid, void *handler_data, struct probe *trigger, struct probe *base)
#define vwarn(format,...)
struct array_list * shadow_stack
struct array_list * absolute_branch_targets
ADDR probe_addr(struct probe *probe)
result_t cfi_dynamic_retaddr_check(struct probe *probe, tid_t tid, void *data, struct probe *trigger, struct probe *base)
#define array_list_foreach(alist, lpc, placeholder)
REFCNT bsymbol_release(struct bsymbol *bsymbol)
int probe_free(struct probe *probe, int force)
struct bsymbol * target_lookup_sym_addr(struct target *target, ADDR addr)
int probe_num_sources(struct probe *probe)
char * cfi_thread_backtrace(struct cfi_data *cfi, struct cfi_thread_status *cts, char *sep)
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)
REGVAL target_read_creg(struct target *target, tid_t tid, common_reg_t reg)
#define vdebug(devel, areas, flags, format,...)
struct cf_inst_data::@12 cf
GHashTable * ret_immediate_addrs
void * calloc(size_t nmemb, size_t size)
result_t post_handler(struct probe *probe, tid_t tid, void *data, struct probe *trigger, struct probe *base)
void * probe_summarize_tid_cfi(struct probe *probe, tid_t tid)
result_t cfi_dynamic_retaddr_save(struct probe *probe, tid_t tid, void *data, struct probe *trigger, struct probe *base)
void target_location_ctxt_free(struct target_location_ctxt *tlctxt)
void * malloc(size_t size)
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)
unsigned long target_write_addr(struct target *target, ADDR addr, unsigned long length, unsigned char *buf)
int target_lookup_safe_disasm_range(struct target *target, ADDR addr, ADDR *start, ADDR *end, void **data)
#define array_list_foreach_fakeptr_t(alist, lpc, placeholder, intertype)
char * probe_name(struct probe *probe)
const char * probe_gettype_cfi(struct probe *probe)
probe_handler_t post_handler
GHashTable * disfuncs_noflow