[PATCH v13 1/4] Prepare for adding support for Lua scripting
Victor Krapivensky
krapivenskiy.va at phystech.edu
Fri Sep 15 13:10:05 UTC 2017
* Makefile.am (strace_SOURCES): Add defs_shared.h and ffi.h.
* basic_filters.c (syscall_classes): make global and terminate by a
null entry.
(lookup_class): use global null entry-terminated variable.
* defs.h (TCB_AD_HOC_INJECT, TCB_HOOK): New TCB flags.
(QUAL_HOOK_ENTRY, QUAL_HOOK_EXIT): New qualifier flags.
(RVAL_HOOKED): New return value flag.
(struct ioctlent, struct tcb): move to...
* defs_shared.h: ...new file.
* ffi.h: New file.
* filter_qualify.c (qual_flags): Introduce QUALBIT macro and use it.
* number_set.c (number_unsetbit, remove_number_from_set,
extend_set_with_number, make_number_set_universal,
extend_set_array_with_number, make_number_set_array_universal): New
functions.
* strace.c (enum trace_event): Introduce new TE_SYSCALL_STOP_HOOK_EXIT
trace event.
(enum hook_state): New enumeration.
(trace_syscall): Add a hook state argument.
(dispatch_event): Add a "hooked" argument, support invoking with
TE_SYSCALL_STOP_HOOK_EXIT event.
* syscall.c: (errnoent_vec, nerrnoent_vec, signalent_vec,
nsignalent_vec, ioctlent_vec, nioctlent_vec, personality_wordsize,
personality_klongsize): New global variables.
(personality_names): New global variable (if SUPPORTED_PERSONALITIES >
1).
(update_personality): Use personality_names for reporting personality
name.
(tcb_inject_opts): Introduce step argument, change return type to struct
inject_data, rename to tcb_inject_data.
(tamper_with_syscall_entering): Don't copy inject_vec here and do
counter decrement logic here; pass true as a second argument to
tcb_inject_data.
(tamper_with_syscall_exiting): Pass false as a second argument to
tcb_inject_data.
(syscall_ad_hoc_inject): New function.
(syscall_entering_trace): Perform ad hoc injection even if the syscall
is not traced.
(syscall_exiting_decode): Don't return 0 ("bail out") if exiting hook is
set up for this syscall, or if an ad hoc injection was performed.
Call tamper_with_syscall_exiting on success.
(syscall_exiting_trace): Don't call tamper_with_syscall_exiting, check
if the syscall is not traced again.
(syscall_exiting_finish): Clear TCB_AD_HOC_INJECT bit.
* sysent.h: Modify to support inclusing with FFI_CDEF defined.
---
Makefile.am | 2 +
basic_filters.c | 60 ++++++++-------
defs.h | 59 ++++++---------
defs_shared.h | 63 ++++++++++++++++
ffi.h | 19 +++++
filter_qualify.c | 20 ++---
number_set.c | 47 ++++++++++++
number_set.h | 16 ++++
strace.c | 63 ++++++++++++----
syscall.c | 220 +++++++++++++++++++++++++++++++++++++++----------------
sysent.h | 24 +++++-
11 files changed, 436 insertions(+), 157 deletions(-)
create mode 100644 defs_shared.h
create mode 100644 ffi.h
diff --git a/Makefile.am b/Makefile.am
index 4aa9846c..0ab788b8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -107,6 +107,7 @@ strace_SOURCES = \
copy_file_range.c \
count.c \
defs.h \
+ defs_shared.h \
desc.c \
dirent.c \
dirent64.c \
@@ -132,6 +133,7 @@ strace_SOURCES = \
fetch_struct_stat.c \
fetch_struct_stat64.c \
fetch_struct_statfs.c \
+ ffi.h \
file_handle.c \
file_ioctl.c \
filter_qualify.c \
diff --git a/basic_filters.c b/basic_filters.c
index 7b7f0a54..0f31fd32 100644
--- a/basic_filters.c
+++ b/basic_filters.c
@@ -94,40 +94,38 @@ qualify_syscall_regex(const char *s, struct number_set *set)
return found;
}
+const struct syscall_class syscall_classes[] = {
+ { "desc", TRACE_DESC },
+ { "file", TRACE_FILE },
+ { "memory", TRACE_MEMORY },
+ { "process", TRACE_PROCESS },
+ { "signal", TRACE_SIGNAL },
+ { "ipc", TRACE_IPC },
+ { "network", TRACE_NETWORK },
+ { "%desc", TRACE_DESC },
+ { "%file", TRACE_FILE },
+ { "%memory", TRACE_MEMORY },
+ { "%process", TRACE_PROCESS },
+ { "%signal", TRACE_SIGNAL },
+ { "%ipc", TRACE_IPC },
+ { "%network", TRACE_NETWORK },
+ { "%stat", TRACE_STAT },
+ { "%lstat", TRACE_LSTAT },
+ { "%fstat", TRACE_FSTAT },
+ { "%%stat", TRACE_STAT_LIKE },
+ { "%statfs", TRACE_STATFS },
+ { "%fstatfs", TRACE_FSTATFS },
+ { "%%statfs", TRACE_STATFS_LIKE },
+ {}
+};
+
static unsigned int
lookup_class(const char *s)
{
- static const struct {
- const char *name;
- unsigned int value;
- } syscall_class[] = {
- { "desc", TRACE_DESC },
- { "file", TRACE_FILE },
- { "memory", TRACE_MEMORY },
- { "process", TRACE_PROCESS },
- { "signal", TRACE_SIGNAL },
- { "ipc", TRACE_IPC },
- { "network", TRACE_NETWORK },
- { "%desc", TRACE_DESC },
- { "%file", TRACE_FILE },
- { "%memory", TRACE_MEMORY },
- { "%process", TRACE_PROCESS },
- { "%signal", TRACE_SIGNAL },
- { "%ipc", TRACE_IPC },
- { "%network", TRACE_NETWORK },
- { "%stat", TRACE_STAT },
- { "%lstat", TRACE_LSTAT },
- { "%fstat", TRACE_FSTAT },
- { "%%stat", TRACE_STAT_LIKE },
- { "%statfs", TRACE_STATFS },
- { "%fstatfs", TRACE_FSTATFS },
- { "%%statfs", TRACE_STATFS_LIKE },
- };
-
- unsigned int i;
- for (i = 0; i < ARRAY_SIZE(syscall_class); ++i) {
- if (strcmp(s, syscall_class[i].name) == 0) {
- return syscall_class[i].value;
+ const struct syscall_class *c;
+ for (c = syscall_classes; c->name; ++c) {
+ if (strcmp(s, c->name) == 0) {
+ return c->value;
}
}
diff --git a/defs.h b/defs.h
index 34261f2e..f4252fa5 100644
--- a/defs.h
+++ b/defs.h
@@ -175,11 +175,6 @@ extern char *stpcpy(char *dst, const char *src);
# define PERSONALITY2_INCLUDE_FUNCS "empty.h"
#endif
-typedef struct ioctlent {
- const char *symbol;
- unsigned int code;
-} struct_ioctlent;
-
#define INJECT_F_SIGNAL 1
#define INJECT_F_RETVAL 2
@@ -197,39 +192,7 @@ struct inject_opts {
#define MAX_ERRNO_VALUE 4095
-/* Trace Control Block */
-struct tcb {
- int flags; /* See below for TCB_ values */
- int pid; /* If 0, this tcb is free */
- int qual_flg; /* qual_flags[scno] or DEFAULT_QUAL_FLAGS + RAW */
- unsigned long u_error; /* Error code */
- kernel_ulong_t scno; /* System call number */
- kernel_ulong_t u_arg[MAX_ARGS]; /* System call arguments */
- kernel_long_t u_rval; /* Return value */
-#if SUPPORTED_PERSONALITIES > 1
- unsigned int currpers; /* Personality at the time of scno update */
-#endif
- int sys_func_rval; /* Syscall entry parser's return value */
- int curcol; /* Output column for this process */
- FILE *outf; /* Output file for this process */
- const char *auxstr; /* Auxiliary info from syscall (see RVAL_STR) */
- void *_priv_data; /* Private data for syscall decoding functions */
- void (*_free_priv_data)(void *); /* Callback for freeing priv_data */
- const struct_sysent *s_ent; /* sysent[scno] or dummy struct for bad scno */
- const struct_sysent *s_prev_ent; /* for "resuming interrupted SYSCALL" msg */
- struct inject_opts *inject_vec[SUPPORTED_PERSONALITIES];
- struct timeval stime; /* System time usage as of last process wait */
- struct timeval dtime; /* Delta for system time usage */
- struct timeval etime; /* Syscall entry time */
-
-#ifdef USE_LIBUNWIND
- struct UPT_info *libunwind_ui;
- struct mmap_cache_t *mmap_cache;
- unsigned int mmap_cache_size;
- unsigned int mmap_cache_generation;
- struct queue_t *queue;
-#endif
-};
+#include "defs_shared.h"
/* TCB flags */
/* We have attached to this process, but did not see it stopping yet */
@@ -253,6 +216,8 @@ struct tcb {
#define TCB_TAMPERED 0x40 /* A syscall has been tampered with */
#define TCB_HIDE_LOG 0x80 /* We should hide everything (until execve) */
#define TCB_SKIP_DETACH_ON_FIRST_EXEC 0x100 /* -b execve should skip detach on first execve */
+#define TCB_AD_HOC_INJECT 0x200 /* an ad hoc injection was performed by Lua script */
+#define TCB_HOOK 0x400 /* there is Lua hook for this syscall entry or exit */
/* qualifier flags */
#define QUAL_TRACE 0x001 /* this system call should be traced */
@@ -260,6 +225,8 @@ struct tcb {
#define QUAL_VERBOSE 0x004 /* decode the structures of this syscall */
#define QUAL_RAW 0x008 /* print all args in hex for this syscall */
#define QUAL_INJECT 0x010 /* tamper with this system call on purpose */
+#define QUAL_HOOK_ENTRY 0x800 /* return this syscall on entry from next_sc() */
+#define QUAL_HOOK_EXIT 0x1000 /* return this syscall on exit from next_sc() */
#define DEFAULT_QUAL_FLAGS (QUAL_TRACE | QUAL_ABBREV | QUAL_VERBOSE)
@@ -318,6 +285,8 @@ extern const struct xlat whence_codes[];
#define RVAL_IOCTL_DECODED 0200 /* ioctl sub-parser successfully decoded
the argument */
+#define RVAL_HOOKED 0400 /* there is Lua hook for this syscall entry or exit */
+
#define IOCTL_NUMBER_UNKNOWN 0
#define IOCTL_NUMBER_HANDLED 1
#define IOCTL_NUMBER_STOP_LOOKUP 010
@@ -362,6 +331,7 @@ typedef enum {
CFLAG_ONLY_STATS,
CFLAG_BOTH
} cflag_t;
+extern const struct syscall_class syscall_classes[];
extern cflag_t cflag;
extern bool debug_flag;
extern bool Tflag;
@@ -950,6 +920,19 @@ extern const char *const errnoent0[];
extern const char *const signalent0[];
extern const struct_ioctlent ioctlent0[];
+extern const char *const *errnoent_vec[SUPPORTED_PERSONALITIES];
+extern const char *const *signalent_vec[SUPPORTED_PERSONALITIES];
+extern const struct_ioctlent *const ioctlent_vec[SUPPORTED_PERSONALITIES];
+extern const unsigned int nerrnoent_vec[SUPPORTED_PERSONALITIES];
+extern const unsigned int nsignalent_vec[SUPPORTED_PERSONALITIES];
+extern const unsigned int nioctlent_vec[SUPPORTED_PERSONALITIES];
+
+extern const int personality_wordsize[SUPPORTED_PERSONALITIES];
+extern const int personality_klongsize[SUPPORTED_PERSONALITIES];
+#if SUPPORTED_PERSONALITIES > 1
+extern const char *const personality_names[];
+#endif
+
#if SUPPORTED_PERSONALITIES > 1
extern const struct_sysent *sysent;
extern const char *const *errnoent;
diff --git a/defs_shared.h b/defs_shared.h
new file mode 100644
index 00000000..1113fc0c
--- /dev/null
+++ b/defs_shared.h
@@ -0,0 +1,63 @@
+/*
+ * Should only be included without FFI_CDEF from defs.h, so no include guards.
+ */
+
+#include "ffi.h"
+
+FFI_CONTENT(
+struct syscall_class {
+ const char *name;
+ unsigned int value;
+};
+)
+
+FFI_CONTENT(
+typedef struct ioctlent {
+ const char *symbol;
+ unsigned int code;
+} struct_ioctlent;
+)
+
+/* Trace Control Block */
+FFI_CONTENT(
+struct tcb {
+ int flags; /* See below for TCB_ values */
+ int pid; /* If 0, this tcb is free */
+ int qual_flg; /* qual_flags[scno] or DEFAULT_QUAL_FLAGS + RAW */
+ unsigned long u_error; /* Error code */
+ kernel_ulong_t scno; /* System call number */
+ kernel_ulong_t u_arg[MAX_ARGS]; /* System call arguments */
+ kernel_long_t u_rval; /* Return value */
+)
+
+#if SUPPORTED_PERSONALITIES > 1
+FFI_CONTENT(
+ unsigned int currpers; /* Personality at the time of scno update */
+)
+#endif
+
+#ifndef FFI_CDEF
+ int sys_func_rval; /* Syscall entry parser's return value */
+ int curcol; /* Output column for this process */
+ FILE *outf; /* Output file for this process */
+ const char *auxstr; /* Auxiliary info from syscall (see RVAL_STR) */
+ void *_priv_data; /* Private data for syscall decoding functions */
+ void (*_free_priv_data)(void *); /* Callback for freeing priv_data */
+ const struct_sysent *s_ent; /* sysent[scno] or dummy struct for bad scno */
+ const struct_sysent *s_prev_ent; /* for "resuming interrupted SYSCALL" msg */
+ struct inject_opts *inject_vec[SUPPORTED_PERSONALITIES];
+ struct timeval stime; /* System time usage as of last process wait */
+ struct timeval dtime; /* Delta for system time usage */
+ struct timeval etime; /* Syscall entry time */
+# ifdef USE_LIBUNWIND
+ struct UPT_info *libunwind_ui;
+ struct mmap_cache_t *mmap_cache;
+ unsigned int mmap_cache_size;
+ unsigned int mmap_cache_generation;
+ struct queue_t *queue;
+# endif
+#endif /* !FFI_CDEF */
+
+FFI_CONTENT(
+};
+)
diff --git a/ffi.h b/ffi.h
new file mode 100644
index 00000000..7b89e7a4
--- /dev/null
+++ b/ffi.h
@@ -0,0 +1,19 @@
+#ifndef STRACE_FFI_H
+#define STRACE_FFI_H
+
+#include "macros.h"
+
+#define FFI_CONCAT(a, b) a ## b
+#define FFI_CONCAT2(a, b) FFI_CONCAT(a, b)
+
+/*
+ * FFI_CONTENT expands to FFI_CONTENT_ (which strigifies its arguments) when
+ * FFI_CDEF is defined, and to FFI_CONTENT_FFI_CDEF (which simply expands to its
+ * arguments) when it is not.
+ */
+#define FFI_CONTENT FFI_CONCAT2(FFI_CONTENT_, FFI_CDEF)
+
+#define FFI_CONTENT_(...) STRINGIFY(__VA_ARGS__)
+#define FFI_CONTENT_FFI_CDEF(...) __VA_ARGS__
+
+#endif /* !STRACE_FFI_H */
diff --git a/filter_qualify.c b/filter_qualify.c
index 5b0ef28c..71766fd1 100644
--- a/filter_qualify.c
+++ b/filter_qualify.c
@@ -360,14 +360,14 @@ qualify(const char *str)
unsigned int
qual_flags(const unsigned int scno)
{
- return (is_number_in_set_array(scno, trace_set, current_personality)
- ? QUAL_TRACE : 0)
- | (is_number_in_set_array(scno, abbrev_set, current_personality)
- ? QUAL_ABBREV : 0)
- | (is_number_in_set_array(scno, verbose_set, current_personality)
- ? QUAL_VERBOSE : 0)
- | (is_number_in_set_array(scno, raw_set, current_personality)
- ? QUAL_RAW : 0)
- | (is_number_in_set_array(scno, inject_set, current_personality)
- ? QUAL_INJECT : 0);
+#define QUALBIT(set, qualbit) \
+ (is_number_in_set_array(scno, set, current_personality) ? qualbit : 0)
+
+ return QUALBIT(trace_set, QUAL_TRACE)
+ | QUALBIT(abbrev_set, QUAL_ABBREV)
+ | QUALBIT(verbose_set, QUAL_VERBOSE)
+ | QUALBIT(raw_set, QUAL_RAW)
+ | QUALBIT(inject_set, QUAL_INJECT)
+ ;
+#undef QUALBIT
}
diff --git a/number_set.c b/number_set.c
index b8aa28c7..a2e049a1 100644
--- a/number_set.c
+++ b/number_set.c
@@ -50,6 +50,12 @@ number_setbit(const unsigned int i, number_slot_t *const vec)
vec[i / BITS_PER_SLOT] |= (number_slot_t) 1 << (i % BITS_PER_SLOT);
}
+static void
+number_unsetbit(const unsigned int i, number_slot_t *const vec)
+{
+ vec[i / BITS_PER_SLOT] &= ~((number_slot_t) 1 << (i % BITS_PER_SLOT));
+}
+
static bool
number_isset(const unsigned int i, const number_slot_t *const vec)
{
@@ -97,6 +103,29 @@ add_number_to_set(const unsigned int number, struct number_set *const set)
}
void
+remove_number_from_set(const unsigned int number, struct number_set *const set)
+{
+ if (number / BITS_PER_SLOT < set->nslots)
+ number_unsetbit(number, set->vec);
+}
+
+void
+extend_set_with_number(const unsigned int number, struct number_set *const set)
+{
+ if (set->not)
+ remove_number_from_set(number, set);
+ else
+ add_number_to_set(number, set);
+}
+
+void
+make_number_set_universal(struct number_set *const set)
+{
+ free(set->vec);
+ *set = (struct number_set) { .not = true };
+}
+
+void
add_number_to_set_array(const unsigned int number, struct number_set *const set,
const unsigned int idx)
{
@@ -104,6 +133,14 @@ add_number_to_set_array(const unsigned int number, struct number_set *const set,
}
void
+extend_set_array_with_number(const unsigned int number,
+ struct number_set *const set,
+ const unsigned int idx)
+{
+ extend_set_with_number(number, &set[idx]);
+}
+
+void
clear_number_set_array(struct number_set *const set, const unsigned int nmemb)
{
unsigned int i;
@@ -125,6 +162,16 @@ invert_number_set_array(struct number_set *const set, const unsigned int nmemb)
set[i].not = !set[i].not;
}
+void
+make_number_set_array_universal(struct number_set *set,
+ const unsigned int nmemb)
+{
+ unsigned int i;
+
+ for (i = 0; i < nmemb; ++i)
+ make_number_set_universal(&set[i]);
+}
+
struct number_set *
alloc_number_set_array(const unsigned int nmemb)
{
diff --git a/number_set.h b/number_set.h
index ec53bc1b..953b1545 100644
--- a/number_set.h
+++ b/number_set.h
@@ -45,6 +45,22 @@ extern void
add_number_to_set(unsigned int number, struct number_set *);
extern void
+remove_number_from_set(unsigned int number, struct number_set *);
+
+extern void
+extend_set_with_number(unsigned int number, struct number_set *);
+
+extern void
+make_number_set_universal(struct number_set *);
+
+extern void
+make_number_set_array_universal(struct number_set *, unsigned int nmemb);
+
+extern void
+extend_set_array_with_number(const unsigned int number,
+ struct number_set *const set, const unsigned int idx);
+
+extern void
add_number_to_set_array(unsigned int number, struct number_set *, unsigned int idx);
extern void
diff --git a/strace.c b/strace.c
index 6ed86a6f..7b8a0e24 100644
--- a/strace.c
+++ b/strace.c
@@ -2216,6 +2216,9 @@ enum trace_event {
*/
TE_SYSCALL_STOP,
+ /* Syscall entry or exit, after hook. */
+ TE_SYSCALL_STOP_HOOK_EXIT,
+
/*
* Tracee received signal with number WSTOPSIG(*pstatus); signal info
* is written to *si. Restart the tracee (with that signal number
@@ -2406,24 +2409,47 @@ next_event(int *pstatus, siginfo_t *si)
}
}
+enum hook_state {
+ HOOK_ENTER,
+ HOOK_EXIT,
+ HOOK_IGNORE,
+};
+
static int
-trace_syscall(struct tcb *tcp, unsigned int *sig)
+trace_syscall(struct tcb *tcp, unsigned int *sig, enum hook_state state)
{
if (entering(tcp)) {
- int res = syscall_entering_decode(tcp);
- switch (res) {
- case 0:
- return 0;
- case 1:
+ int res;
+ switch (state) {
+ case HOOK_ENTER:
+ case HOOK_IGNORE:
+ res = syscall_entering_decode(tcp);
+ if (res == 0)
+ return 0;
+ if (res == 1)
+ if (state == HOOK_ENTER &&
+ (tcp->qual_flg & QUAL_HOOK_ENTRY))
+ return RVAL_HOOKED;
+ /* Fall through */
+ case HOOK_EXIT:
res = syscall_entering_trace(tcp, sig);
}
syscall_entering_finish(tcp, res);
return res;
} else {
- struct timeval tv = {};
- int res = syscall_exiting_decode(tcp, &tv);
- if (res != 0) {
- res = syscall_exiting_trace(tcp, tv, res);
+ static struct timeval tv;
+ int res = 1;
+ switch (state) {
+ case HOOK_ENTER:
+ case HOOK_IGNORE:
+ res = syscall_exiting_decode(tcp, &tv);
+ if (res == 1 && state == HOOK_ENTER &&
+ (tcp->qual_flg & QUAL_HOOK_EXIT))
+ return RVAL_HOOKED;
+ /* Fall through */
+ case HOOK_EXIT:
+ if (res != 0)
+ res = syscall_exiting_trace(tcp, tv, res);
}
syscall_exiting_finish(tcp);
return res;
@@ -2432,10 +2458,11 @@ trace_syscall(struct tcb *tcp, unsigned int *sig)
/* Returns true iff the main trace loop has to continue. */
static bool
-dispatch_event(enum trace_event ret, int *pstatus, siginfo_t *si)
+dispatch_event(enum trace_event ret, int *pstatus, siginfo_t *si, bool hooked)
{
unsigned int restart_op = PTRACE_SYSCALL;
unsigned int restart_sig = 0;
+ int res;
switch (ret) {
case TE_BREAK:
@@ -2448,7 +2475,17 @@ dispatch_event(enum trace_event ret, int *pstatus, siginfo_t *si)
break;
case TE_SYSCALL_STOP:
- if (trace_syscall(current_tcp, &restart_sig) < 0) {
+ case TE_SYSCALL_STOP_HOOK_EXIT:
+ res = trace_syscall(current_tcp, &restart_sig,
+ hooked ? (ret == TE_SYSCALL_STOP ? HOOK_ENTER : HOOK_EXIT) :
+ HOOK_IGNORE);
+
+ if (res == RVAL_HOOKED) {
+ current_tcp->flags |= TCB_HOOK;
+ return true;
+ }
+
+ if (res < 0) {
/*
* ptrace() failed in trace_syscall().
* Likely a result of process disappearing mid-flight.
@@ -2593,7 +2630,7 @@ main(int argc, char *argv[])
int status;
siginfo_t si;
- while (dispatch_event(next_event(&status, &si), &status, &si))
+ while (dispatch_event(next_event(&status, &si), &status, &si, false))
;
terminate();
}
diff --git a/syscall.c b/syscall.c
index b1047feb..abc3f80c 100644
--- a/syscall.c
+++ b/syscall.c
@@ -160,6 +160,16 @@ enum {
#endif
};
+const char *const *errnoent_vec[SUPPORTED_PERSONALITIES] = {
+ errnoent0,
+#if SUPPORTED_PERSONALITIES > 1
+ errnoent1,
+# if SUPPORTED_PERSONALITIES > 2
+ errnoent2,
+# endif
+#endif
+};
+
enum {
nerrnos0 = ARRAY_SIZE(errnoent0)
#if SUPPORTED_PERSONALITIES > 1
@@ -170,6 +180,16 @@ enum {
#endif
};
+const unsigned int nerrnoent_vec[] = {
+ nerrnos0,
+#if SUPPORTED_PERSONALITIES > 1
+ nerrnos1,
+# if SUPPORTED_PERSONALITIES > 2
+ nerrnos2,
+# endif
+#endif
+};
+
enum {
nsignals0 = ARRAY_SIZE(signalent0)
#if SUPPORTED_PERSONALITIES > 1
@@ -180,6 +200,26 @@ enum {
#endif
};
+const char *const *signalent_vec[SUPPORTED_PERSONALITIES] = {
+ signalent0,
+#if SUPPORTED_PERSONALITIES > 1
+ signalent1,
+# if SUPPORTED_PERSONALITIES > 2
+ signalent2,
+# endif
+#endif
+};
+
+const unsigned int nsignalent_vec[] = {
+ nsignals0,
+#if SUPPORTED_PERSONALITIES > 1
+ nsignals1,
+# if SUPPORTED_PERSONALITIES > 2
+ nsignals2,
+# endif
+#endif
+};
+
enum {
nioctlents0 = ARRAY_SIZE(ioctlent0)
#if SUPPORTED_PERSONALITIES > 1
@@ -190,6 +230,26 @@ enum {
#endif
};
+const unsigned int nioctlent_vec[] = {
+ nioctlents0,
+#if SUPPORTED_PERSONALITIES > 1
+ nioctlents1,
+# if SUPPORTED_PERSONALITIES > 2
+ nioctlents2,
+# endif
+#endif
+};
+
+const struct_ioctlent *const ioctlent_vec[SUPPORTED_PERSONALITIES] = {
+ ioctlent0,
+#if SUPPORTED_PERSONALITIES > 1
+ ioctlent1,
+# if SUPPORTED_PERSONALITIES > 2
+ ioctlent2,
+# endif
+#endif
+};
+
#if SUPPORTED_PERSONALITIES > 1
const struct_sysent *sysent = sysent0;
const char *const *errnoent = errnoent0;
@@ -222,29 +282,55 @@ const struct_sysent *const sysent_vec[SUPPORTED_PERSONALITIES] = {
#endif
};
+const int personality_wordsize[SUPPORTED_PERSONALITIES] = {
+ PERSONALITY0_WORDSIZE,
#if SUPPORTED_PERSONALITIES > 1
+ PERSONALITY1_WORDSIZE,
+#endif
+#if SUPPORTED_PERSONALITIES > 2
+ PERSONALITY2_WORDSIZE,
+#endif
+};
+
+const int personality_klongsize[SUPPORTED_PERSONALITIES] = {
+ PERSONALITY0_KLONGSIZE,
+#if SUPPORTED_PERSONALITIES > 1
+ PERSONALITY1_KLONGSIZE,
+#endif
+#if SUPPORTED_PERSONALITIES > 2
+ PERSONALITY2_KLONGSIZE,
+#endif
+};
+
+#if SUPPORTED_PERSONALITIES > 1
+
+const char *const personality_names[] =
+# if defined POWERPC64
+ {"64 bit", "32 bit"}
+# elif defined X86_64
+ {"64 bit", "32 bit", "x32"}
+# elif defined X32
+ {"x32", "32 bit"}
+# elif defined AARCH64
+ {"64 bit", "32 bit"}
+# elif defined TILE
+ {"64-bit", "32-bit"}
+# else
+# error Add personality names for your achitecture.
+# endif
+ ;
+
unsigned current_personality;
# ifndef current_wordsize
unsigned current_wordsize;
-static const int personality_wordsize[SUPPORTED_PERSONALITIES] = {
- PERSONALITY0_WORDSIZE,
- PERSONALITY1_WORDSIZE,
-# if SUPPORTED_PERSONALITIES > 2
- PERSONALITY2_WORDSIZE,
# endif
-};
+# ifndef current_klongsize
+unsigned current_klongsize;
# endif
# ifndef current_klongsize
unsigned current_klongsize;
-static const int personality_klongsize[SUPPORTED_PERSONALITIES] = {
- PERSONALITY0_KLONGSIZE,
- PERSONALITY1_KLONGSIZE,
-# if SUPPORTED_PERSONALITIES > 2
- PERSONALITY2_KLONGSIZE,
-# endif
-};
# endif
void
@@ -307,21 +393,10 @@ update_personality(struct tcb *tcp, unsigned int personality)
return;
tcp->currpers = personality;
-# undef PERSONALITY_NAMES
-# if defined X86_64
-# define PERSONALITY_NAMES {"64 bit", "32 bit", "x32"}
-# elif defined X32
-# define PERSONALITY_NAMES {"x32", "32 bit"}
-# elif SUPPORTED_PERSONALITIES == 2
-# define PERSONALITY_NAMES {"64 bit", "32 bit"}
-# endif
-# ifdef PERSONALITY_NAMES
if (!qflag) {
- static const char *const names[] = PERSONALITY_NAMES;
error_msg("[ Process PID=%d runs in %s mode. ]",
- tcp->pid, names[personality]);
+ tcp->pid, personality_names[personality]);
}
-# endif
}
#endif
@@ -539,18 +614,11 @@ static int arch_set_success(struct tcb *);
struct inject_opts *inject_vec[SUPPORTED_PERSONALITIES];
-static struct inject_opts *
-tcb_inject_opts(struct tcb *tcp)
-{
- return (scno_in_range(tcp->scno) && tcp->inject_vec[current_personality])
- ? &tcp->inject_vec[current_personality][tcp->scno] : NULL;
-}
-
-
-static long
-tamper_with_syscall_entering(struct tcb *tcp, unsigned int *signo)
+static struct inject_data
+tcb_inject_data(struct tcb *tcp, bool step)
{
- if (!tcp->inject_vec[current_personality]) {
+ if (step && !tcp->inject_vec[current_personality] &&
+ inject_vec[current_personality]) {
tcp->inject_vec[current_personality] =
xcalloc(nsyscalls, sizeof(**inject_vec));
memcpy(tcp->inject_vec[current_personality],
@@ -558,21 +626,31 @@ tamper_with_syscall_entering(struct tcb *tcp, unsigned int *signo)
nsyscalls * sizeof(**inject_vec));
}
- struct inject_opts *opts = tcb_inject_opts(tcp);
-
- if (!opts || opts->first == 0)
- return 0;
-
- --opts->first;
-
- if (opts->first != 0)
- return 0;
+ struct inject_opts *opts =
+ scno_in_range(tcp->scno) && tcp->inject_vec[current_personality]
+ ? &tcp->inject_vec[current_personality][tcp->scno] : NULL;
+ struct inject_data res = {};
+ if (opts) {
+ if (step) {
+ if (opts->first != 0 && --opts->first == 0) {
+ res = opts->data;
+ opts->first = opts->step;
+ }
+ } else {
+ res = opts->data;
+ }
+ }
+ return res;
+}
- opts->first = opts->step;
+static long
+tamper_with_syscall_entering(struct tcb *tcp, unsigned int *signo)
+{
+ struct inject_data data = tcb_inject_data(tcp, true);
- if (opts->data.flags & INJECT_F_SIGNAL)
- *signo = opts->data.signo;
- if (opts->data.flags & INJECT_F_RETVAL && !arch_set_scno(tcp, -1))
+ if (data.flags & INJECT_F_SIGNAL)
+ *signo = data.signo;
+ if ((data.flags & INJECT_F_RETVAL) && !arch_set_scno(tcp, -1))
tcp->flags |= TCB_TAMPERED;
return 0;
@@ -581,22 +659,22 @@ tamper_with_syscall_entering(struct tcb *tcp, unsigned int *signo)
static long
tamper_with_syscall_exiting(struct tcb *tcp)
{
- struct inject_opts *opts = tcb_inject_opts(tcp);
+ struct inject_data data = tcb_inject_data(tcp, false);
- if (!opts)
+ if (!(data.flags & INJECT_F_RETVAL))
return 0;
- if (opts->data.rval >= 0) {
+ if (data.rval >= 0) {
kernel_long_t u_rval = tcp->u_rval;
- tcp->u_rval = opts->data.rval;
+ tcp->u_rval = data.rval;
if (arch_set_success(tcp)) {
tcp->u_rval = u_rval;
} else {
tcp->u_error = 0;
}
} else {
- unsigned long new_error = -opts->data.rval;
+ unsigned long new_error = -data.rval;
if (new_error != tcp->u_error && new_error <= MAX_ERRNO_VALUE) {
unsigned long u_error = tcp->u_error;
@@ -659,6 +737,12 @@ syscall_entering_decode(struct tcb *tcp)
return 1;
}
+static bool
+syscall_ad_hoc_injected(struct tcb *tcp)
+{
+ return (tcp->qual_flg & QUAL_INJECT) && (tcp->flags & TCB_AD_HOC_INJECT);
+}
+
int
syscall_entering_trace(struct tcb *tcp, unsigned int *sig)
{
@@ -679,20 +763,20 @@ syscall_entering_trace(struct tcb *tcp, unsigned int *sig)
if (!traced(tcp) || (tracing_paths && !pathtrace_match(tcp))) {
tcp->flags |= TCB_FILTERED;
- return 0;
+ goto maybe_ad_hoc_tamper;
}
tcp->flags &= ~TCB_FILTERED;
if (hide_log(tcp)) {
- return 0;
+ goto maybe_ad_hoc_tamper;
}
if (inject(tcp))
tamper_with_syscall_entering(tcp, sig);
if (cflag == CFLAG_ONLY_STATS) {
- return 0;
+ goto maybe_ad_hoc_tamper;
}
#ifdef USE_LIBUNWIND
@@ -707,6 +791,11 @@ syscall_entering_trace(struct tcb *tcp, unsigned int *sig)
int res = raw(tcp) ? printargs(tcp) : tcp->s_ent->sys_func(tcp);
fflush(tcp->outf);
return res;
+
+maybe_ad_hoc_tamper:
+ if (syscall_ad_hoc_injected(tcp))
+ tamper_with_syscall_entering(tcp, sig);
+ return 0;
}
void
@@ -747,21 +836,28 @@ syscall_exiting_decode(struct tcb *tcp, struct timeval *ptv)
}
#endif
- if (filtered(tcp) || hide_log(tcp))
+ if ((filtered(tcp) || hide_log(tcp))
+ && !(tcp->qual_flg & QUAL_HOOK_EXIT) && !syscall_ad_hoc_injected(tcp))
return 0;
get_regs(tcp->pid);
#if SUPPORTED_PERSONALITIES > 1
update_personality(tcp, tcp->currpers);
#endif
- return get_regs_error ? -1 : get_syscall_result(tcp);
+ if (get_regs_error || get_syscall_result(tcp) == -1)
+ return -1;
+
+ if (syserror(tcp) && syscall_tampered(tcp))
+ tamper_with_syscall_exiting(tcp);
+
+ return 1;
}
int
syscall_exiting_trace(struct tcb *tcp, struct timeval tv, int res)
{
- if (syserror(tcp) && syscall_tampered(tcp))
- tamper_with_syscall_exiting(tcp);
+ if (filtered(tcp) || hide_log(tcp))
+ return 0;
if (cflag) {
count_syscall(tcp, &tv);
@@ -970,7 +1066,7 @@ syscall_exiting_trace(struct tcb *tcp, struct timeval tv, int res)
void
syscall_exiting_finish(struct tcb *tcp)
{
- tcp->flags &= ~(TCB_INSYSCALL | TCB_TAMPERED);
+ tcp->flags &= ~(TCB_INSYSCALL | TCB_TAMPERED | TCB_AD_HOC_INJECT);
tcp->sys_func_rval = 0;
free_tcb_priv_data(tcp);
}
diff --git a/sysent.h b/sysent.h
index 92de7468..15b83693 100644
--- a/sysent.h
+++ b/sysent.h
@@ -1,13 +1,31 @@
-#ifndef STRACE_SYSENT_H
-#define STRACE_SYSENT_H
+#if !defined(STRACE_SYSENT_H) || defined(FFI_CDEF)
+#ifndef FFI_CDEF
+# define STRACE_SYSENT_H
+#endif
+#include "ffi.h"
+
+FFI_CONTENT(
typedef struct sysent {
unsigned nargs;
int sys_flags;
+)
+/* We don't want to expose sen and sys_func to LuaJIT */
+#ifdef FFI_CDEF
+FFI_CONTENT(
+ int priv1;
+ void *priv2;
+)
+#else
+FFI_CONTENT(
int sen;
int (*sys_func)();
+)
+#endif
+FFI_CONTENT(
const char *sys_name;
} struct_sysent;
+)
#define TRACE_FILE 00000001 /* Trace file-related syscalls. */
#define TRACE_IPC 00000002 /* Trace IPC-related syscalls. */
@@ -29,4 +47,4 @@ typedef struct sysent {
#define TRACE_FSTAT 00400000 /* Trace *fstat{,at}{,64} syscalls. */
#define TRACE_STAT_LIKE 01000000 /* Trace *{,l,f}stat{,x,at}{,64} syscalls. */
-#endif /* !STRACE_SYSENT_H */
+#endif /* !defined(STRACE_SYSENT_H) || defined(FFI_CDEF) */
--
2.11.0
More information about the Strace-devel
mailing list