Implement inject and fault actions
* 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.
This commit is contained in:
parent
4c2d68c14b
commit
ae02a6cbb8
@ -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].data.flags)
|
||||
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->data.flags)
|
||||
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");
|
||||
}
|
||||
|
1
defs.h
1
defs.h
@ -648,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 *);
|
||||
|
||||
|
8
filter.h
8
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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
125
filter_qualify.c
125
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)
|
||||
{
|
||||
@ -150,30 +148,39 @@ 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;
|
||||
const char *delim = qualify_mode ? ":" : ";";
|
||||
|
||||
*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;
|
||||
*opts = (struct inject_opts) {
|
||||
.first = 1,
|
||||
.step = 1
|
||||
};
|
||||
|
||||
for (token = strtok_r(str, delim, &saveptr); token;
|
||||
token = strtok_r(NULL, delim, &saveptr)) {
|
||||
if (!parse_inject_token(token, opts, fault_tokens_only)) {
|
||||
/* return an error by resetting inject flags */
|
||||
opts->data.flags = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (name)
|
||||
return name;
|
||||
|
||||
parse_error:
|
||||
free(*buf);
|
||||
return *buf = NULL;
|
||||
/* If neither of retval, error, or signal is specified, then ... */
|
||||
if (!opts->data.flags) {
|
||||
if (fault_tokens_only) {
|
||||
/* in fault= syntax the default error code is ENOSYS. */
|
||||
opts->data.rval = -ENOSYS;
|
||||
opts->data.flags |= INJECT_F_RETVAL;
|
||||
} else {
|
||||
/* in inject= syntax this is not allowed. */
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@ -245,74 +252,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
|
||||
};
|
||||
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);
|
||||
}
|
||||
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 neither of retval, error, or signal is specified, then ... */
|
||||
if (!opts.data.flags) {
|
||||
if (fault_tokens_only) {
|
||||
/* in fault= syntax the default error code is ENOSYS. */
|
||||
opts.data.rval = -ENOSYS;
|
||||
opts.data.flags |= INJECT_F_RETVAL;
|
||||
} else {
|
||||
/* in inject= syntax this is not allowed. */
|
||||
error_msg_and_die("invalid %s '%s'", description, str);
|
||||
}
|
||||
}
|
||||
if (args)
|
||||
*(args++) = '\0';
|
||||
|
||||
struct number_set *tmp_set =
|
||||
alloc_number_set_array(SUPPORTED_PERSONALITIES);
|
||||
qualify_syscall_tokens(name, tmp_set, description);
|
||||
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->data.flags)
|
||||
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 {
|
||||
@ -360,10 +332,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;
|
||||
}
|
||||
|
3
strace.c
3
strace.c
@ -2411,7 +2411,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);
|
||||
|
16
syscall.c
16
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));
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user