Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 5 Aug 2019 20:15:46 +0000 (UTC)
From:      Mariusz Zaborski <oshogbo@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r350612 - in head: sys/kern tests/sys/kern
Message-ID:  <201908052015.x75KFk2R088667@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: oshogbo
Date: Mon Aug  5 20:15:46 2019
New Revision: 350612
URL: https://svnweb.freebsd.org/changeset/base/350612

Log:
  procdesc: fix reparenting when the debugger is attached
  
  The process is reparented to the debugger while it is attached.
    B          B
   /   ---->   |
  A          A D
  
  Every time when the process is reparented, it is added to the orphan list
  of the previous parent:
  
  A->orphan = B
  D->orphan = NULL
  
  When the A process will close the process descriptor to the B process,
  the B process will be reparented to the init process.
    B            B - init
    |   ---->
  A D          A   D
  
  A->orphan = B
  D->orphan = B
  
  In this scenario, the B process is in the orphan list of A and D.
  
  When the last process descriptor is closed instead of reparenting
  it to the reaper let it stay with the debugger process and set
  our previews parent to the reaper.
  
  Add test case for this situation.
  Notice that without this patch the kernel will crash with this test case:
  panic: orphan 0xfffff8000e990530 of 0xfffff8000e990000 has unexpected oppid 1
  
  Reviewed by:	markj, kib
  MFC after:	1 month
  Differential Revision:	https://reviews.freebsd.org/D20361

Modified:
  head/sys/kern/sys_procdesc.c
  head/tests/sys/kern/ptrace_test.c

Modified: head/sys/kern/sys_procdesc.c
==============================================================================
--- head/sys/kern/sys_procdesc.c	Mon Aug  5 20:11:57 2019	(r350611)
+++ head/sys/kern/sys_procdesc.c	Mon Aug  5 20:15:46 2019	(r350612)
@@ -416,7 +416,13 @@ procdesc_close(struct file *fp, struct thread *td)
 			 * terminate with prejudice.
 			 */
 			p->p_sigparent = SIGCHLD;
-			proc_reparent(p, p->p_reaper, true);
+			if ((p->p_flag & P_TRACED) == 0) {
+				proc_reparent(p, p->p_reaper, true);
+			} else {
+				clear_orphan(p);
+				p->p_oppid = p->p_reaper->p_pid;
+				proc_add_orphan(p, p->p_reaper);
+			}
 			if ((pd->pd_flags & PDF_DAEMON) == 0)
 				kern_psignal(p, SIGKILL);
 			PROC_UNLOCK(p);

Modified: head/tests/sys/kern/ptrace_test.c
==============================================================================
--- head/tests/sys/kern/ptrace_test.c	Mon Aug  5 20:11:57 2019	(r350611)
+++ head/tests/sys/kern/ptrace_test.c	Mon Aug  5 20:15:46 2019	(r350612)
@@ -32,6 +32,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/file.h>
 #include <sys/time.h>
 #include <sys/procctl.h>
+#include <sys/procdesc.h>
 #include <sys/ptrace.h>
 #include <sys/queue.h>
 #include <sys/runq.h>
@@ -4075,6 +4076,60 @@ ATF_TC_BODY(ptrace__syscall_args, tc)
 	ATF_REQUIRE(errno == ECHILD);
 }
 
+/*
+ * Verify that when the process is traced that it isn't reparent
+ * to the init process when we close all process descriptors.
+ */
+ATF_TC(ptrace__proc_reparent);
+ATF_TC_HEAD(ptrace__proc_reparent, tc)
+{
+
+	atf_tc_set_md_var(tc, "timeout", "2");
+}
+ATF_TC_BODY(ptrace__proc_reparent, tc)
+{
+	pid_t traced, debuger, wpid;
+	int pd, status;
+
+	traced = pdfork(&pd, 0);
+	ATF_REQUIRE(traced >= 0);
+	if (traced == 0) {
+		raise(SIGSTOP);
+		exit(0);
+	}
+	ATF_REQUIRE(pd >= 0);
+
+	debuger = fork();
+	ATF_REQUIRE(debuger >= 0);
+	if (debuger == 0) {
+		/* The traced process is reparented to debuger. */
+		ATF_REQUIRE(ptrace(PT_ATTACH, traced, 0, 0) == 0);
+		wpid = waitpid(traced, &status, 0);
+		ATF_REQUIRE(wpid == traced);
+		ATF_REQUIRE(WIFSTOPPED(status));
+		ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
+		ATF_REQUIRE(close(pd) == 0);
+		ATF_REQUIRE(ptrace(PT_DETACH, traced, (caddr_t)1, 0) == 0);
+
+		/* We closed pd so we should not have any child. */
+		wpid = wait(&status);
+		ATF_REQUIRE(wpid == -1);
+		ATF_REQUIRE(errno == ECHILD);
+
+		exit(0);
+	}
+
+	ATF_REQUIRE(close(pd) == 0);
+	wpid = waitpid(debuger, &status, 0);
+	ATF_REQUIRE(wpid == debuger);
+	ATF_REQUIRE(WEXITSTATUS(status) == 0);
+
+	/* Check if we still have any child. */
+	wpid = wait(&status);
+	ATF_REQUIRE(wpid == -1);
+	ATF_REQUIRE(errno == ECHILD);
+}
+
 ATF_TP_ADD_TCS(tp)
 {
 
@@ -4137,6 +4192,7 @@ ATF_TP_ADD_TCS(tp)
 #endif
 	ATF_TP_ADD_TC(tp, ptrace__PT_LWPINFO_stale_siginfo);
 	ATF_TP_ADD_TC(tp, ptrace__syscall_args);
+	ATF_TP_ADD_TC(tp, ptrace__proc_reparent);
 
 	return (atf_no_error());
 }



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201908052015.x75KFk2R088667>