[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