git: 16f6ce3f826b - stable/14 - ptrace tests: Add a test using PROC_REAP_KILL to kill a traced debuggee

From: Mark Johnston <markj_at_FreeBSD.org>
Date: Mon, 15 Apr 2024 14:05:33 UTC
The branch stable/14 has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=16f6ce3f826b402390459ece55df719737695abb

commit 16f6ce3f826b402390459ece55df719737695abb
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2024-03-31 18:11:47 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2024-04-15 14:05:13 +0000

    ptrace tests: Add a test using PROC_REAP_KILL to kill a traced debuggee
    
    This exercises the bug fix in commit 9241ebc796c1
    ("thread_single(9): decline external requests for traced or debugger-stopped procs").
    
    Reviewed by:    kib
    MFC after:      2 weeks
    Differential Revision:  https://reviews.freebsd.org/D44564
    
    (cherry picked from commit 43b4da44118e4fe29e9d7456db4390c9cbb53636)
---
 tests/sys/kern/ptrace_test.c | 47 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/tests/sys/kern/ptrace_test.c b/tests/sys/kern/ptrace_test.c
index 5666215f9377..5152affa0e8b 100644
--- a/tests/sys/kern/ptrace_test.c
+++ b/tests/sys/kern/ptrace_test.c
@@ -4369,6 +4369,52 @@ ATF_TC_BODY(ptrace__PT_SC_REMOTE_getpid, tc)
 	ATF_REQUIRE(ptrace(PT_DETACH, fpid, (caddr_t)1, 0) != -1);
 }
 
+/*
+ * Ensure that procctl(PROC_REAP_KILL) won't block forever waiting for a target
+ * process that stopped to report its status to a debugger.
+ */
+ATF_TC_WITHOUT_HEAD(ptrace__reap_kill_stopped);
+ATF_TC_BODY(ptrace__reap_kill_stopped, tc)
+{
+	struct procctl_reaper_kill prk;
+	pid_t debuggee, wpid;
+	int error, status;
+
+	REQUIRE_EQ(procctl(P_PID, getpid(), PROC_REAP_ACQUIRE, NULL), 0);
+
+	debuggee = fork();
+	ATF_REQUIRE(debuggee >= 0);
+	if (debuggee == 0) {
+		trace_me();
+		for (;;)
+			sleep(10);
+		_exit(0);
+	}
+	wpid = waitpid(debuggee, &status, 0);
+	REQUIRE_EQ(wpid, debuggee);
+	ATF_REQUIRE(WIFSTOPPED(status));
+	REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
+
+	/* Resume the child and ask it to stop during syscall exits. */
+	ATF_REQUIRE(ptrace(PT_TO_SCX, debuggee, (caddr_t)1, 0) != -1);
+
+	/* Give the debuggee some time to go to sleep. */
+	usleep(100000);
+
+	/*
+	 * Kill the child process.  procctl() may attempt to stop the target
+	 * process to prevent it from adding new children to the reaper subtree,
+	 * and this should not conflict with the child stopping itself for the
+	 * debugger.
+	 */
+	memset(&prk, 0, sizeof(prk));
+	prk.rk_sig = SIGTERM;
+	error = procctl(P_PID, getpid(), PROC_REAP_KILL, &prk);
+	REQUIRE_EQ(error, 0);
+	REQUIRE_EQ(1, prk.rk_killed);
+	REQUIRE_EQ(-1, prk.rk_fpid);
+}
+
 ATF_TP_ADD_TCS(tp)
 {
 	ATF_TP_ADD_TC(tp, ptrace__parent_wait_after_trace_me);
@@ -4435,6 +4481,7 @@ ATF_TP_ADD_TCS(tp)
 	ATF_TP_ADD_TC(tp, ptrace__procdesc_wait_child);
 	ATF_TP_ADD_TC(tp, ptrace__procdesc_reparent_wait_child);
 	ATF_TP_ADD_TC(tp, ptrace__PT_SC_REMOTE_getpid);
+	ATF_TP_ADD_TC(tp, ptrace__reap_kill_stopped);
 
 	return (atf_no_error());
 }