From 667b7a7c09f6fe86c9e72515afcc654cf3366c38 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 7 Sep 2010 22:38:03 +0200 Subject: adding stack limits dynamic check --- ChangeLog | 5 +++ TODO | 1 + doc/latrace.txt | 3 ++ src/Makefile | 3 +- src/audit.c | 3 +- src/audit.h | 3 ++ src/config.c | 21 +++++++---- src/config.h | 4 ++ src/stack.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 148 insertions(+), 9 deletions(-) create mode 100644 src/stack.c diff --git a/ChangeLog b/ChangeLog index 9a7a4dd..e8a6c12 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2010-09-07 Jiri Olsa + * adding stack limits dynamic check + - based on proposal from Akos Pasztory + - enabled by default, disable by new '-Y' option + 2010-08-05 Jiri Olsa * changed config file magic defines * separate arguments display code, so it could be diff --git a/TODO b/TODO index 47d02ac..0aef70a 100644 --- a/TODO +++ b/TODO @@ -6,6 +6,7 @@ olsajiri@gmail.com for 0.5.10 - testing/fixing bugs + - make automated tests for 0.6 - config - arrays in structures diff --git a/doc/latrace.txt b/doc/latrace.txt index 492561b..20be159 100644 --- a/doc/latrace.txt +++ b/doc/latrace.txt @@ -78,6 +78,9 @@ OPTIONS *-y, --framesize number*:: framesize for storing the stack before pltexit (default 100) +*-Y, --not-framesize-check*:: + disable framesize check + *-I, --no-indent-sym*:: do no indent symbols based on the their stack depth diff --git a/src/Makefile b/src/Makefile index cada828..796028a 100644 --- a/src/Makefile +++ b/src/Makefile @@ -27,7 +27,8 @@ AUDIT_OBJS=\ src/audit-init.o \ src/fifo.o \ src/output.o \ - src/objsearch.o + src/objsearch.o \ + src/stack.o ifeq ($(CONFIG_ARCH_HAVE_ARGS),y) AUDIT_OBJS+=\ diff --git a/src/audit.c b/src/audit.c index bba7e9f..2a97b75 100644 --- a/src/audit.c +++ b/src/audit.c @@ -294,7 +294,8 @@ pltenter(ElfW(Sym) *sym, unsigned int ndx, uintptr_t *refcook, } while(0); - *framesizep = lt_sh(&cfg, framesize); + *framesizep = lt_stack_framesize(&cfg, regs); + return sym->st_value; } diff --git a/src/audit.h b/src/audit.h index 1b7d20f..2633944 100644 --- a/src/audit.h +++ b/src/audit.h @@ -29,18 +29,21 @@ # define pltenter la_i86_gnu_pltenter # define pltexit la_i86_gnu_pltexit # define La_regs La_i86_regs +# define sp_reg lr_esp # define La_retval La_i86_retval # define int_retval lrv_eax #elif defined __x86_64__ # define pltenter la_x86_64_gnu_pltenter # define pltexit la_x86_64_gnu_pltexit # define La_regs La_x86_64_regs +# define sp_reg lr_rsp # define La_retval La_x86_64_retval # define int_retval lrv_rax #elif defined __arm__ # define pltenter la_arm_gnu_pltenter # define pltexit la_arm_gnu_pltexit # define La_regs La_arm_regs +# define sp_reg lr_sp # define La_retval La_arm_retval # define int_retval lrv_reg[0] #elif defined __powerpc__ && __WORDSIZE == 32 diff --git a/src/config.c b/src/config.c index 4b92b5b..18c07ba 100644 --- a/src/config.c +++ b/src/config.c @@ -51,6 +51,7 @@ static void usage() #endif printf("\n"); printf(" -y, --framesize number framesize for storing the stack before pltexit (default 1000)\n"); + printf(" -Y, --not-framesize-check disable framesize check\n"); printf(" -F, --not-follow-fork dont follow fork calls - childs\n"); printf(" -E, --not-follow-exec dont follow exec calls\n"); printf("\n"); @@ -111,12 +112,13 @@ int lt_config(struct lt_config_app *cfg, int argc, char **argv) cfg->sh = &cfg->sh_storage; /* default values settings */ - lt_sh(cfg, magic) = LT_CONFIG_MAGIC; - lt_sh(cfg, framesize) = 1000; - lt_sh(cfg, fout) = stdout; - lt_sh(cfg, indent_sym) = 1; - lt_sh(cfg, indent_size) = 2; - lt_sh(cfg, args_maxlen) = LR_ARGS_MAXLEN; + lt_sh(cfg, magic) = LT_CONFIG_MAGIC; + lt_sh(cfg, framesize) = 1000; + lt_sh(cfg, framesize_check) = 1; + lt_sh(cfg, fout) = stdout; + lt_sh(cfg, indent_sym) = 1; + lt_sh(cfg, indent_size) = 2; + lt_sh(cfg, args_maxlen) = LR_ARGS_MAXLEN; lt_sh(cfg, args_detail_maxlen) = LR_ARGS_DETAIL_MAXLEN; cfg->csort = LT_CSORT_CALL; @@ -142,6 +144,7 @@ int lt_config(struct lt_config_app *cfg, int argc, char **argv) {"enable-args", required_argument, 0, 'A'}, {"detail-args", required_argument, 0, 'D'}, {"framesize", required_argument, 0, 'y'}, + {"not-framesize-check ", no_argument, 0, 'Y'}, {"lib-subst", required_argument, 0, 'L'}, {"verbose", no_argument, 0, 'v'}, {"hide-tid", no_argument, 0, 'T'}, @@ -154,7 +157,7 @@ int lt_config(struct lt_config_app *cfg, int argc, char **argv) {0, 0, 0, 0} }; - c = getopt_long(argc, argv, "+s:l:t:f:vhi:BdISb:cC:y:L:po:a:ADVTFERq", + c = getopt_long(argc, argv, "+s:l:t:f:vhi:BdISb:cC:y:YL:po:a:ADVTFERq", long_options, &option_index); if (c == -1) @@ -242,6 +245,10 @@ int lt_config(struct lt_config_app *cfg, int argc, char **argv) lt_sh(cfg, framesize) = atoi(optarg); break; + case 'Y': + lt_sh(cfg, framesize_check) = 0; + break; + case 'L': if (strlen(optarg) > LT_SYMBOLS_MAXSIZE) return -1; diff --git a/src/config.h b/src/config.h index 6213292..2a36c58 100644 --- a/src/config.h +++ b/src/config.h @@ -115,6 +115,7 @@ struct lt_config_shared { int hide_tid; int not_follow_exec; int not_follow_fork; + int framesize_check; unsigned int framesize; /* for 'not_follow_fork' */ @@ -299,6 +300,9 @@ int lt_objsearch_init(struct lt_config_audit *cfg, char **ptr, int cnt); char* lt_objsearch(struct lt_config_audit *cfg, const char *name, uintptr_t *cookie, unsigned int flag); +/* stack */ +int lt_stack_framesize(struct lt_config_audit *cfg, La_regs *regs); + #define PRINT(fmt, args...) \ do { \ char lpbuf[1024]; \ diff --git a/src/stack.c b/src/stack.c new file mode 100644 index 0000000..ade5ef9 --- /dev/null +++ b/src/stack.c @@ -0,0 +1,114 @@ + +#include +#include +#include +#include + +#include "config.h" + +static __thread void *stack_start = NULL; +static __thread void *stack_end = NULL; + +static unsigned long get_stack_size(struct lt_config_audit *cfg) +{ + static unsigned long stack_size = 0; + static struct rlimit rlim; + + if (stack_size) + return stack_size; + + if (getrlimit(RLIMIT_STACK, &rlim)) + return 0; + + PRINT_VERBOSE(cfg, 1, "stack size: %lx\n", rlim.rlim_cur); + + return stack_size = rlim.rlim_cur; +} + +/* find and update current stack boundaries */ +static int load_stack(struct lt_config_audit *cfg, void *sp) +{ + FILE *maps; + char line[128]; + int found = 0; + void *start, *end; + + maps = fopen("/proc/self/maps", "r"); + if (!maps) { + PRINT_VERBOSE(cfg, 1, "failed to open maps: %s\n", + strerror(errno)); + return -1; + } + + + while (!found && fgets(line, sizeof(line), maps)) { + + if (1 != sscanf(line, "%*p-%p", &end)) + continue; + + /* FIXME + * what if the new stack is not GROWSDOWN? + * let's get the limit via RLIMIT_STACK, + * which should be ok for most cases now.. + * + * it does not feel safe/complete, but probably better + * than nothing + */ + start = end - get_stack_size(cfg); + + found = ((start < sp) && (sp < end)); + + PRINT_VERBOSE(cfg, 1, "start %p, end %p, sp %p, in %d\n", + start, end, sp, found); + } + + fclose(maps); + + if (found) { + stack_start = start; + stack_end = end; + } + + return found ? 0 : -1; +} + +/* check the current stack pointer and check its boundaries */ +int lt_stack_framesize(struct lt_config_audit *cfg, La_regs *regs) +{ + void *sp_top, *sp_bottom; + void *sp = (void*) regs->sp_reg; + unsigned int framesize = lt_sh(cfg, framesize); + + if (!lt_sh(cfg, framesize_check)) + return framesize; + + /* got here first time, or we are out of bounds */ + if (!stack_start || + (sp < stack_start || sp > stack_end)) { + + /* we are screeeeeewed */ + if (load_stack(cfg, sp)) + return framesize; + } + + /* FIXME what about stacks growing up.. arm might */ + sp_top = sp + framesize; + + if (sp_top > stack_end) { + framesize = stack_end - sp - 1; + PRINT_VERBOSE(cfg, 1, + "top reached, framesize changed to %lu\n", + framesize); + } + + sp_bottom = sp - framesize; + + if (sp_bottom < stack_start) { + framesize = sp - stack_start; + PRINT_VERBOSE(cfg, 1, + "bottom reached, framesize changed to %lu\n", + framesize); + } + + return framesize; +} -- cgit