* basic_actions.c (not_injected, apply_inject, parse_inject_common, parse_inject, apply_fault, parse_fault): New functions. * defs.h (struct inject_opts): Add init flag. (qual_flags): Remove declaration. * filter_action.c (action_types): Add inject and fault action types. (set_filter_action_priv_data): New function. * filter_qualify.c (inject_set): Remove variable. (parse_inject_expression): Remove function. (parse_inject_common_args): Add function for inject/fault arguments parsing. (qualify_inject_common): Use parse_inject_common_args instead of parse_inject_expression, use new filtering API. (qualify_fault, qualify_inject): Remove "argument" from description argument of qualify_inject_common. (qual_flags): Remove function. * filter.h (parse_inject_common_args, not_injected, set_filter_action_priv_data): New declarations. (DECL_FILTER_ACTION): Declare inject and fault actions. (DECL_FILTER_ACTION_PARSER): Declare inject and fault action parsers. * strace.c (trace_syscall): Call filter_syscall only when tcp->qual_flg is empty. * syscall.c (decode_socket_subcall): Remove qual_flags from decoder. (decode_ipc_subcall): Likewise. (decode_mips_subcall): Likewise. (get_scno): Likewise. (inject_vec, tamper_with_syscall_entering): Remove inject_vec support code. --- basic_actions.c | 53 +++++++++++++++++++++++ defs.h | 2 +- filter.h | 8 ++++ filter_action.c | 9 ++++ filter_qualify.c | 130 ++++++++++++++++++++----------------------------------- strace.c | 3 +- syscall.c | 16 +------ 7 files changed, 121 insertions(+), 100 deletions(-)
diff --git a/basic_actions.c b/basic_actions.c index a9b10ffa..42394494 100644 --- a/basic_actions.c +++ b/basic_actions.c @@ -34,6 +34,12 @@ is_traced(struct tcb *tcp) return traced(tcp); } +bool +not_injected(struct tcb *tcp) +{ + return !inject(tcp); +} + void * parse_null(const char *str) { @@ -63,3 +69,50 @@ apply_verbose(struct tcb *tcp, void *priv_data) { tcp->qual_flg |= QUAL_VERBOSE; } + +void +apply_inject(struct tcb *tcp, void *priv_data) +{ + struct inject_opts *opts = priv_data; + + tcp->qual_flg |= QUAL_INJECT; + if (!tcp->inject_vec[current_personality]) + tcp->inject_vec[current_personality] = + xcalloc(nsyscalls, sizeof(struct inject_opts)); + if (scno_in_range(tcp->scno) + && !tcp->inject_vec[current_personality][tcp->scno].init) + tcp->inject_vec[current_personality][tcp->scno] = *opts; +} + +static void * +parse_inject_common(const char *str, bool fault_tokens_only, + const char *description) +{ + struct inject_opts *opts = xmalloc(sizeof(struct inject_opts)); + char *buf = xstrdup(str); + + parse_inject_common_args(buf, opts, fault_tokens_only, false); + if (!opts->init) + error_msg_and_die("invalid %s argument '%s'", + description, str ? str : ""); + free(buf); + return opts; +} + +void * +parse_inject(const char *str) +{ + return parse_inject_common(str, false, "inject"); +} + +void +apply_fault(struct tcb *tcp, void *priv_data) +{ + apply_inject(tcp, priv_data); +} + +void * +parse_fault(const char *str) +{ + return parse_inject_common(str, true, "fault"); +} diff --git a/defs.h b/defs.h index 6b143a5a..6354d90f 100644 --- a/defs.h +++ b/defs.h @@ -185,6 +185,7 @@ struct inject_opts { uint16_t step; uint16_t signo; int rval; + bool init; }; #define MAX_ERRNO_VALUE 4095 @@ -647,7 +648,6 @@ print_struct_statfs64(struct tcb *, kernel_ulong_t addr, kernel_ulong_t size); extern void print_ifindex(unsigned int); extern void qualify(const char *); -extern unsigned int qual_flags(const unsigned int); extern void filtering_parsing_finish(void); extern void filter_syscall(struct tcb *); diff --git a/filter.h b/filter.h index aa945ceb..c66bf443 100644 --- a/filter.h +++ b/filter.h @@ -43,7 +43,10 @@ void qualify_tokens(const char *str, struct number_set *set, string_to_uint_func func, const char *name); void qualify_syscall_tokens(const char *str, struct number_set *set, const char *name); +void parse_inject_common_args(char *, struct inject_opts *, + const bool fault_tokens_only, bool qualify_mode); bool is_traced(struct tcb *); +bool not_injected(struct tcb *); /* filter api */ struct filter* add_filter_to_array(struct filter **, unsigned int *nfilters, @@ -58,6 +61,7 @@ void set_filters_qualify_mode(struct filter **, unsigned int *nfilters, struct filter *create_filter(struct filter_action *, const char *name); struct filter_action *find_or_add_action(const char *); void set_qualify_mode(struct filter_action *, unsigned int); +void set_filter_action_priv_data(struct filter_action *, void *); /* filter expression api */ struct bool_expression *create_expression(); @@ -85,6 +89,8 @@ DECL_FILTER_ACTION(trace); DECL_FILTER_ACTION(raw); DECL_FILTER_ACTION(abbrev); DECL_FILTER_ACTION(verbose); +DECL_FILTER_ACTION(inject); +DECL_FILTER_ACTION(fault); #undef DECL_FILTER_ACTION #define DECL_FILTER_ACTION_PARSER(name) \ @@ -93,6 +99,8 @@ parse_ ## name(const char *); \ /* End of DECL_FILTER_ACTION_PARSER definition. */ DECL_FILTER_ACTION_PARSER(null); +DECL_FILTER_ACTION_PARSER(inject); +DECL_FILTER_ACTION_PARSER(fault); #undef DECL_FILTER_ACTION_PARSER #endif /* !STRACE_FILTER_H */ diff --git a/filter_action.c b/filter_action.c index 8092cdec..da329380 100644 --- a/filter_action.c +++ b/filter_action.c @@ -42,6 +42,8 @@ static const struct filter_action_type { void (*apply)(struct tcb *, void *); } action_types[] = { FILTER_ACTION_TYPE(trace, 0, QUAL_TRACE, null, NULL), + FILTER_ACTION_TYPE(inject, 1, QUAL_INJECT, inject, not_injected), + FILTER_ACTION_TYPE(fault, 1, QUAL_INJECT, fault, not_injected), FILTER_ACTION_TYPE(raw, 2, QUAL_RAW, null, is_traced), FILTER_ACTION_TYPE(abbrev, 2, QUAL_ABBREV, null, is_traced), FILTER_ACTION_TYPE(verbose, 2, QUAL_VERBOSE, null, is_traced), @@ -181,3 +183,10 @@ filter_syscall(struct tcb *tcp) for (i = 0; i < nfilter_actions; ++i) run_filter_action(tcp, &filter_actions[i]); } + +void +set_filter_action_priv_data(struct filter_action *action, void *priv_data) +{ + if (action) + action->priv_data = priv_data; +} diff --git a/filter_qualify.c b/filter_qualify.c index abcb2b46..ffeeb498 100644 --- a/filter_qualify.c +++ b/filter_qualify.c @@ -35,8 +35,6 @@ struct number_set *read_set; struct number_set *write_set; struct number_set *signal_set; -static struct number_set *inject_set; - static int sigstr_to_uint(const char *s) { @@ -145,30 +143,37 @@ parse_inject_token(const char *const token, struct inject_opts *const fopts, return true; } -static char * -parse_inject_expression(const char *const s, char **buf, - struct inject_opts *const fopts, - const bool fault_tokens_only) +void +parse_inject_common_args(char *str, struct inject_opts *const opts, + const bool fault_tokens_only, bool qualify_mode) { char *saveptr = NULL; - char *name = NULL; char *token; - - *buf = xstrdup(s); - for (token = strtok_r(*buf, ":", &saveptr); token; - token = strtok_r(NULL, ":", &saveptr)) { - if (!name) - name = token; - else if (!parse_inject_token(token, fopts, fault_tokens_only)) - goto parse_error; + const char *delim = qualify_mode ? ":" : ";"; + + opts->first = 1; + opts->step = 1; + opts->rval = INJECT_OPTS_RVAL_DEFAULT; + opts->signo = 0; + opts->init = false; + + for (token = strtok_r(str, delim, &saveptr); token; + token = strtok_r(NULL, delim, &saveptr)) { + if (!parse_inject_token(token, opts, fault_tokens_only)) + return; } - if (name) - return name; - -parse_error: - free(*buf); - return *buf = NULL; + /* If neither of retval, error, or signal is specified, then ... */ + if (opts->rval == INJECT_OPTS_RVAL_DEFAULT && !opts->signo) { + if (fault_tokens_only) { + /* in fault syntax the default error code is ENOSYS. */ + opts->rval = -ENOSYS; + } else { + /* in inject syntax this is not allowed. */ + return; + } + } + opts->init = true; } static void @@ -240,75 +245,39 @@ qualify_inject_common(const char *const str, const bool fault_tokens_only, const char *const description) { - struct inject_opts opts = { - .first = 1, - .step = 1, - .rval = INJECT_OPTS_RVAL_DEFAULT, - .signo = 0 - }; - char *buf = NULL; - char *name = parse_inject_expression(str, &buf, &opts, fault_tokens_only); - if (!name) { - error_msg_and_die("invalid %s '%s'", description, str); - } - - /* If neither of retval, error, or signal is specified, then ... */ - if (opts.rval == INJECT_OPTS_RVAL_DEFAULT && !opts.signo) { - if (fault_tokens_only) { - /* in fault= syntax the default error code is ENOSYS. */ - opts.rval = -ENOSYS; - } else { - /* in inject= syntax this is not allowed. */ - error_msg_and_die("invalid %s '%s'", description, str); - } - } - - struct number_set *tmp_set = - alloc_number_set_array(SUPPORTED_PERSONALITIES); - qualify_syscall_tokens(name, tmp_set, description); + struct inject_opts *opts = xmalloc(sizeof(struct inject_opts)); + char *buf = xstrdup(str); + char *args = strchr(buf, ':'); + struct filter_action *action; + struct filter *filter; + + if (args) + *(args++) = '\0'; + + action = find_or_add_action(fault_tokens_only ? "fault" : "inject"); + filter = create_filter(action, "syscall"); + parse_filter(filter, buf); + set_qualify_mode(action, 1); + parse_inject_common_args(args, opts, fault_tokens_only, true); + if (!opts->init) + error_msg_and_die("invalid %s argument '%s'", description, + args ? args : ""); free(buf); - /* - * Initialize inject_vec accourding to tmp_set. - * Merge tmp_set into inject_set. - */ - unsigned int p; - for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) { - if (number_set_array_is_empty(tmp_set, p)) - continue; - - if (!inject_set) { - inject_set = - alloc_number_set_array(SUPPORTED_PERSONALITIES); - } - if (!inject_vec[p]) { - inject_vec[p] = xcalloc(nsyscall_vec[p], - sizeof(*inject_vec[p])); - } - - unsigned int i; - for (i = 0; i < nsyscall_vec[p]; ++i) { - if (is_number_in_set_array(i, tmp_set, p)) { - add_number_to_set_array(i, inject_set, p); - inject_vec[p][i] = opts; - } - } - } - - free_number_set_array(tmp_set, SUPPORTED_PERSONALITIES); + set_filter_action_priv_data(action, opts); } static void qualify_fault(const char *const str) { - qualify_inject_common(str, true, "fault argument"); + qualify_inject_common(str, true, "fault"); } static void qualify_inject(const char *const str) { - qualify_inject_common(str, false, "inject argument"); + qualify_inject_common(str, false, "inject"); } static const struct qual_options { @@ -356,10 +325,3 @@ qualify(const char *str) opt->qualify(str); } - -unsigned int -qual_flags(const unsigned int scno) -{ - return is_number_in_set_array(scno, inject_set, current_personality) - ? QUAL_INJECT : 0; -} diff --git a/strace.c b/strace.c index bd6d687a..1c2c47da 100644 --- a/strace.c +++ b/strace.c @@ -2416,7 +2416,8 @@ trace_syscall(struct tcb *tcp, unsigned int *sig) case 0: return 0; case 1: - filter_syscall(tcp); + if (!tcp->qual_flg) + filter_syscall(tcp); res = syscall_entering_trace(tcp, sig); } syscall_entering_finish(tcp, res); diff --git a/syscall.c b/syscall.c index 1d3b1232..b3893d00 100644 --- a/syscall.c +++ b/syscall.c @@ -342,7 +342,6 @@ decode_socket_subcall(struct tcb *tcp) return; tcp->scno = scno; - tcp->qual_flg = qual_flags(scno); tcp->s_ent = &sysent[scno]; unsigned int i; @@ -382,7 +381,6 @@ decode_ipc_subcall(struct tcb *tcp) } tcp->scno = SYS_ipc_subcall + call; - tcp->qual_flg = qual_flags(tcp->scno); tcp->s_ent = &sysent[tcp->scno]; const unsigned int n = tcp->s_ent->nargs; @@ -399,7 +397,6 @@ decode_mips_subcall(struct tcb *tcp) if (!scno_is_valid(tcp->u_arg[0])) return; tcp->scno = tcp->u_arg[0]; - tcp->qual_flg = qual_flags(tcp->scno); tcp->s_ent = &sysent[tcp->scno]; memmove(&tcp->u_arg[0], &tcp->u_arg[1], sizeof(tcp->u_arg) - sizeof(tcp->u_arg[0])); @@ -537,8 +534,6 @@ static void get_error(struct tcb *, const bool); static int arch_set_error(struct tcb *); static int arch_set_success(struct tcb *); -struct inject_opts *inject_vec[SUPPORTED_PERSONALITIES]; - static struct inject_opts * tcb_inject_opts(struct tcb *tcp) { @@ -550,14 +545,6 @@ tcb_inject_opts(struct tcb *tcp) static long tamper_with_syscall_entering(struct tcb *tcp, unsigned int *signo) { - if (!tcp->inject_vec[current_personality]) { - tcp->inject_vec[current_personality] = - xcalloc(nsyscalls, sizeof(**inject_vec)); - memcpy(tcp->inject_vec[current_personality], - inject_vec[current_personality], - nsyscalls * sizeof(**inject_vec)); - } - struct inject_opts *opts = tcb_inject_opts(tcp); if (!opts || opts->first == 0) @@ -1195,7 +1182,8 @@ get_scno(struct tcb *tcp) if (scno_is_valid(tcp->scno)) { tcp->s_ent = &sysent[tcp->scno]; - tcp->qual_flg = qual_flags(tcp->scno); + /* Clear qual_flg to distinguish valid syscall from printargs */ + tcp->qual_flg = 0; } else { struct sysent_buf *s = xcalloc(1, sizeof(*s)); -- 2.11.0 ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot _______________________________________________ Strace-devel mailing list Strace-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/strace-devel