NOMMU bogus syscall return values

Rich Felker dalias at libc.org
Mon Feb 29 20:56:54 UTC 2016


I've been trying to use strace on a NOMMU system (sh2) and have been
experiencing an issue where the return value (read from r0) and args
5/6 (r0,r1) are bogus, making the output much less useful than it
otherwise would be. The problem seems to be that the tracer is
desynced with the child's STOP parity and is confusing syscall
entry/exit, probably due to exec_or_die not stopping itself before
exec to sync with the parent. Even if not for the bug I'm
experiencing, this seems to be problematic in that early syscalls in
the child can be lost (I've actually hit that problem too).

The attached (very hackish at the moment) patch makes it work for me
by eliminating the need to define NOMMU_SYSTEM to 1 and using clone()
with CLONE_VM and a new stack for the child, instead of vfork. I see
some potential issues that need to be addressed before this could be
made into a proper solution, though:

1. I'm not sure if all NOMMU systems strace supports have clone. If
   so, I think vfork could be dropped completely and this used
   instead.

2. The feature checks which were bypassed on NOMMU, and which I
   hard-bypassed, could also be changed to use clone.

3. My approach is not directly applicable to daemonized tracer mode
   without some significant refactoring; either the entire remainder
   of init() and main() would need to be moved into a function that
   runs in the child, or longjmp back to the parent's call frame would
   need to be performed with some synchronization to make it safe.

An alternate approach would be to keep vfork but have strace self-exec
itself with a special argument to make it STOP itself then exec. For
what it's worth this could be significantly slower on NOMMU especially
if not using a binary format that's capable of sharing text.

Any thoughts on whether changes like this would be acceptable
upstream?

Rich
-------------- next part --------------
--- strace.c.orig	2016-02-29 03:53:49.113264699 +0000
+++ strace.c	2016-02-29 19:00:03.704101962 +0000
@@ -28,8 +28,10 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#define _GNU_SOURCE
 #include "defs.h"
 #include <stdarg.h>
+#include <sched.h>
 #include <sys/param.h>
 #include <fcntl.h>
 #include <sys/resource.h>
@@ -1155,6 +1157,14 @@ exec_or_die(void)
 	perror_msg_and_die("exec");
 }
 
+static char child_stack[16384];
+
+static int exec_or_die_wrapper(void *arg)
+{
+	exec_or_die();
+	return 0; /* unreachable */
+}
+
 static void
 startup_child(char **argv)
 {
@@ -1228,24 +1238,21 @@ startup_child(char **argv)
 	 * On NOMMU, can be safely freed only after execve in tracee.
 	 * It's hard to know when that happens, so we just leak it.
 	 */
-	params_for_tracee.pathname = NOMMU_SYSTEM ? strdup(pathname) : pathname;
+	//params_for_tracee.pathname = NOMMU_SYSTEM ? strdup(pathname) : pathname;
+	params_for_tracee.pathname = strdup(pathname);
 
 #if defined HAVE_PRCTL && defined PR_SET_PTRACER && defined PR_SET_PTRACER_ANY
 	if (daemonized_tracer)
 		prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY);
 #endif
 
-	pid = fork();
+	pid = daemonized_tracer ? fork() :
+		clone(exec_or_die_wrapper, child_stack + sizeof child_stack / 2,
+		CLONE_VM|SIGCHLD, 0);
 	if (pid < 0) {
 		perror_msg_and_die("fork");
 	}
-	if ((pid != 0 && daemonized_tracer)
-	 || (pid == 0 && !daemonized_tracer)
-	) {
-		/* We are to become the tracee. Two cases:
-		 * -D: we are parent
-		 * not -D: we are child
-		 */
+	if (pid && daemonized_tracer) {
 		exec_or_die();
 	}
 
@@ -1334,7 +1341,7 @@ test_ptrace_setoptions_followfork(void)
 					  PTRACE_O_TRACEVFORK;
 
 	/* Need fork for test. NOMMU has no forks */
-	if (NOMMU_SYSTEM)
+	if (1 || NOMMU_SYSTEM)
 		goto worked; /* be bold, and pretend that test succeeded */
 
 	pid = fork();
@@ -1454,7 +1461,7 @@ test_ptrace_setoptions_for_all(void)
 	int it_worked = 0;
 
 	/* Need fork for test. NOMMU has no forks */
-	if (NOMMU_SYSTEM)
+	if (1 || NOMMU_SYSTEM)
 		goto worked; /* be bold, and pretend that test succeeded */
 
 	pid = fork();
@@ -1540,7 +1547,7 @@ test_ptrace_seize(void)
 	int pid;
 
 	/* Need fork for test. NOMMU has no forks */
-	if (NOMMU_SYSTEM) {
+	if (1 || NOMMU_SYSTEM) {
 		post_attach_sigstop = 0; /* this sets use_seize to 1 */
 		return;
 	}


More information about the Strace-devel mailing list