[PATCHv3 1/2] strace: implement signal injection

Seraphime Kirkovski kirkseraph at gmail.com
Wed Dec 28 16:22:36 UTC 2016


This extends the fault injection capability with :signal=SIG option
which injects a signal on entering each syscall from the specified set.

:signal and :error options are complementary, if they are both specified
the syscall will be fault injected as usual and the specified signal
will be delivered to the tracee.

Signed-off-by: Seraphime Kirkovski <kirkseraph at gmail.com>
---

This
  * changes the commit message as requested.
  * uses nsig.h rather than <signal.h>
  * tidies up checks
  * fixes some whitespace issues

 defs.h    |  5 +++--
 qualify.c | 15 ++++++++++++++-
 strace.c  |  4 +++-
 syscall.c | 16 +++++++++-------
 4 files changed, 29 insertions(+), 11 deletions(-)

diff --git a/defs.h b/defs.h
index 81d26d5..9591e17 100644
--- a/defs.h
+++ b/defs.h
@@ -217,7 +217,8 @@ typedef struct ioctlent {
 struct fault_opts {
 	uint16_t first;
 	uint16_t step;
-	uint16_t err;
+	int16_t err;
+	uint16_t signo;
 };
 
 /* Trace Control Block */
@@ -439,7 +440,7 @@ extern int read_int_from_file(const char *, int *);
 extern void set_sortby(const char *);
 extern void set_overhead(int);
 extern void print_pc(struct tcb *);
-extern int trace_syscall(struct tcb *);
+extern int trace_syscall(struct tcb *, unsigned int *);
 extern void count_syscall(struct tcb *, const struct timeval *);
 extern void call_summary(FILE *);
 
diff --git a/qualify.c b/qualify.c
index a7d276c..e052d39 100644
--- a/qualify.c
+++ b/qualify.c
@@ -26,6 +26,7 @@
  */
 
 #include "defs.h"
+#include "nsig.h"
 
 typedef unsigned int number_slot_t;
 #define BITS_PER_SLOT (sizeof(number_slot_t) * 8)
@@ -414,6 +415,11 @@ parse_fault_token(const char *const token, struct fault_opts *const fopts)
 		if (intval < 1)
 			return false;
 		fopts->err = intval;
+	} else if ((val = strip_prefix("signal=", token))) {
+		intval = sigstr_to_uint(val);
+		if (intval < 1 || intval > NSIG_BYTES * 8)
+			return false;
+		fopts->signo = intval;
 	} else {
 		return false;
 	}
@@ -494,13 +500,20 @@ qualify_fault(const char *const str)
 	struct fault_opts opts = {
 		.first = 1,
 		.step = 1,
-		.err = 0
+		.err = -1,
+		.signo = 0
 	};
 	char *buf = NULL;
 	char *name = parse_fault_expression(str, &buf, &opts);
 	if (!name) {
 		error_msg_and_die("invalid %s '%s'", "fault argument", str);
 	}
+	/*
+	 * If no error, nor signal is specified,
+	 * fallback to the default platform error
+	 */
+	if (opts.signo == 0 && opts.err == -1)
+		opts.err = 0;
 
 
 	struct number_set tmp_set[SUPPORTED_PERSONALITIES];
diff --git a/strace.c b/strace.c
index 4659ddb..23ca108 100644
--- a/strace.c
+++ b/strace.c
@@ -2447,7 +2447,8 @@ show_stopsig:
 	 * This should be syscall entry or exit.
 	 * Handle it.
 	 */
-	if (trace_syscall(tcp) < 0) {
+	sig = 0;
+	if (trace_syscall(tcp, &sig) < 0) {
 		/*
 		 * ptrace() failed in trace_syscall().
 		 * Likely a result of process disappearing mid-flight.
@@ -2461,6 +2462,7 @@ show_stopsig:
 		 */
 		return true;
 	}
+	goto restart_tracee;
 
 restart_tracee_with_sig_0:
 	sig = 0;
diff --git a/syscall.c b/syscall.c
index 6613a1e..c821d7e 100644
--- a/syscall.c
+++ b/syscall.c
@@ -568,7 +568,7 @@ tcb_fault_opts(struct tcb *tcp)
 
 
 static long
-inject_syscall_fault_entering(struct tcb *tcp)
+inject_syscall_fault_entering(struct tcb *tcp, unsigned int *signo)
 {
 	if (!tcp->fault_vec[current_personality]) {
 		tcp->fault_vec[current_personality] =
@@ -590,7 +590,9 @@ inject_syscall_fault_entering(struct tcb *tcp)
 
 	opts->first = opts->step;
 
-	if (!arch_set_scno(tcp, -1))
+	if (opts->signo > 0)
+		*signo = opts->signo;
+	if (opts->err != -1 && !arch_set_scno(tcp, -1))
 		tcp->flags |= TCB_FAULT_INJ;
 
 	return 0;
@@ -601,7 +603,7 @@ update_syscall_fault_exiting(struct tcb *tcp)
 {
 	struct fault_opts *opts = tcb_fault_opts(tcp);
 
-	if (opts && opts->err && tcp->u_error != opts->err) {
+	if (opts && opts->err > 0 && tcp->u_error != (uint16_t) opts->err) {
 		unsigned long u_error = tcp->u_error;
 		tcp->u_error = opts->err;
 		if (arch_set_error(tcp))
@@ -612,7 +614,7 @@ update_syscall_fault_exiting(struct tcb *tcp)
 }
 
 static int
-trace_syscall_entering(struct tcb *tcp)
+trace_syscall_entering(struct tcb *tcp, unsigned int *sig)
 {
 	int res, scno_good;
 
@@ -683,7 +685,7 @@ trace_syscall_entering(struct tcb *tcp)
 	}
 
 	if (tcp->qual_flg & QUAL_FAULT)
-		inject_syscall_fault_entering(tcp);
+		inject_syscall_fault_entering(tcp, sig);
 
 	if (cflag == CFLAG_ONLY_STATS) {
 		res = 0;
@@ -962,10 +964,10 @@ trace_syscall_exiting(struct tcb *tcp)
 }
 
 int
-trace_syscall(struct tcb *tcp)
+trace_syscall(struct tcb *tcp, unsigned int *signo)
 {
 	return exiting(tcp) ?
-		trace_syscall_exiting(tcp) : trace_syscall_entering(tcp);
+		trace_syscall_exiting(tcp) : trace_syscall_entering(tcp, signo);
 }
 
 bool
-- 
2.10.2





More information about the Strace-devel mailing list