Skip to contentSkip to conversation

syscalls/ptrace07: handle potential SIGSEGV on older kernels

PATCH New Jan Stancek 3 participants 4 messages Dec 21, 2018 – Jan 3, 2019

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 syscalls/ptrace07: handle potential SIGSEGV on older kernels

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.

---
 testcases/kernel/syscalls/ptrace/ptrace07.c | 26 +++++++++++++++++++++++---
 1 file changed, 23 insertions(+), 3 deletions(-)
testcases/kernel/syscalls/ptrace/ptrace07.c +23 -3
index 46ae59a105cf..9cbaefc3fbda 100644
@@ -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);
 	}
Signature · 1 line
1.8.3.1
#1 lore raw

PATCH 1/1 syscalls/ptrace07: handle potential SIGSEGV on older kernels

Quoted 28 lines · Jan Stancek
testcases/kernel/syscalls/ptrace/ptrace07.c +18 -2
@@ -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));
+	}

testcases/kernel/syscalls/ptrace/ptrace07.c static void do_test(void) · line 183

Quoted 10 lines
testcases/kernel/syscalls/ptrace/ptrace07.c +5 -1
+	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);

Thanks Jan!

I think this change is correct.

Oleg.

#2 lore raw

PATCH 1/1 syscalls/ptrace07: handle potential SIGSEGV on older kernels

In reply to Jan Stancek
Quoted 17 lines · Jan Stancek

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().

Quoted 3 lines

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.

ptrace07(with this patch applied) passed with kernel 3.10 and 4.18 multi arches test.

Quoted 3 lines
Signature · 2 lines
Regards,
Li Wang
#3 lore raw

PATCH 1/1 syscalls/ptrace07: handle potential SIGSEGV on older kernels

----- Original Message -----

Quoted 22 lines · Jan Stancek
Quoted 17 lines

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().

Quoted 3 lines

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.

Quoted 8 lines

ptrace07(with this patch applied) passed with kernel 3.10 and 4.18 multi arches test.

Quoted 3 lines

Pushed.

Regards,
Jan