[LTP] [PATCH] syscalls/ptrace07: handle potential SIGSEGV on older kernels

Jan Stancek jstancek@redhat.com
Fri Dec 21 14:51:43 CET 2018


If a ptraced test process hits SIGSEGV, the entire testcase hangs.

Older kernels such as RHEL7 (3.10.0), check the error code returned
by restore_fpu_checking() and do drop_init_fpu() if it fails.
So the FPU state of the prev task can't leak.

But in the more likely case a task with xcomp_bv != 0 will be killed
by SIGSEGV; either from do_device_not_available() or from
sys_rt_sigreturn()->__restore_xstate_sig().

And this is why the test case hangs; it wrongly assumes that the
traced child can only exit and report nothing else. But since it
receives SIGSEGV it reports this signal to the main process and
sleeps in ptrace_stop(), it does not exit and thus the test-case
hangs in tst_reap_children() after return from do_test().

Replace PTRACE_CONT with PTRACE_DETACH, so we don't need to
handle subsequent stops. And treat exit code from test process
as info-only.

Debugged-by: Oleg Nesterov <onestero@redhat.com>
Signed-off-by: Jan Stancek <jstancek@redhat.com>
---
 testcases/kernel/syscalls/ptrace/ptrace07.c | 26 +++++++++++++++++++++++---
 1 file changed, 23 insertions(+), 3 deletions(-)

diff --git a/testcases/kernel/syscalls/ptrace/ptrace07.c b/testcases/kernel/syscalls/ptrace/ptrace07.c
index 46ae59a105cf..9cbaefc3fbda 100644
--- a/testcases/kernel/syscalls/ptrace/ptrace07.c
+++ b/testcases/kernel/syscalls/ptrace/ptrace07.c
@@ -153,12 +153,32 @@ static void do_test(void)
 			"PTRACE_SETREGSET failed with unexpected error");
 	}
 
-	TEST(ptrace(PTRACE_CONT, pid, 0, 0));
+	/*
+	 * It is possible for test child 'pid' to crash on AMD
+	 * systems (e.g. AMD Opteron(TM) Processor 6234) with
+	 * older kernels. This causes tracee to stop and sleep
+	 * in ptrace_stop(). Without resuming the tracee, the
+	 * test hangs at do_test()->tst_reap_children() called
+	 * by the library. Use detach here, so we don't need to
+	 * worry about potential stops after this point.
+	 */
+	TEST(ptrace(PTRACE_DETACH, pid, 0, 0));
 	if (TST_RET != 0)
-		tst_brk(TBROK | TTERRNO, "PTRACE_CONT failed");
+		tst_brk(TBROK | TTERRNO, "PTRACE_DETACH failed");
+
+	/* If child 'pid' crashes, only report it as info. */
+	SAFE_WAITPID(pid, &status, 0);
+	if (WIFEXITED(status)) {
+		tst_res(TINFO, "test child %d exited, retcode: %d",
+			pid, WEXITSTATUS(status));
+	}
+	if (WIFSIGNALED(status)) {
+		tst_res(TINFO, "test child %d exited, termsig: %d",
+			pid, WTERMSIG(status));
+	}
 
 	okay = true;
-	for (i = 0; i < num_cpus + 1; i++) {
+	for (i = 0; i < num_cpus; i++) {
 		SAFE_WAIT(&status);
 		okay &= (WIFEXITED(status) && WEXITSTATUS(status) == 0);
 	}
-- 
1.8.3.1



More information about the ltp mailing list