Set the p_oppid field of orphans when exiting.

Such processes will be reparented to the reaper when the current
parent is done with them (i.e., ptrace detached), so p_oppid must be
updated accordingly.

Add a regression test to exercise this code path.  Previously it
would not be possible to reap an orphan with a stale oppid.

Reviewed by:	kib, mjg
Tested by:	pho
MFC after:	2 weeks
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D19825
This commit is contained in:
Mark Johnston 2019-04-07 14:26:14 +00:00
parent 0dc2db13ec
commit 128c9bc05b
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=346009
2 changed files with 67 additions and 0 deletions

View File

@ -543,6 +543,11 @@ exit1(struct thread *td, int rval, int signo)
*/
while ((q = LIST_FIRST(&p->p_orphans)) != NULL) {
PROC_LOCK(q);
KASSERT(q->p_oppid == p->p_pid,
("orphan %p of %p has unexpected oppid %d", q, p,
q->p_oppid));
q->p_oppid = q->p_reaper->p_pid;
/*
* If we are the real parent of this process
* but it has been reparented to a debugger, then

View File

@ -451,6 +451,67 @@ ATF_TC_BODY(ptrace__parent_sees_exit_after_unrelated_debugger, tc)
ATF_REQUIRE(WEXITSTATUS(status) == 1);
}
/*
* Make sure that we can collect the exit status of an orphaned process.
*/
ATF_TC_WITHOUT_HEAD(ptrace__parent_exits_before_child);
ATF_TC_BODY(ptrace__parent_exits_before_child, tc)
{
ssize_t n;
int cpipe1[2], cpipe2[2], gcpipe[2], status;
pid_t child, gchild;
ATF_REQUIRE(pipe(cpipe1) == 0);
ATF_REQUIRE(pipe(cpipe2) == 0);
ATF_REQUIRE(pipe(gcpipe) == 0);
ATF_REQUIRE(procctl(P_PID, getpid(), PROC_REAP_ACQUIRE, NULL) == 0);
ATF_REQUIRE((child = fork()) != -1);
if (child == 0) {
CHILD_REQUIRE((gchild = fork()) != -1);
if (gchild == 0) {
status = 1;
do {
n = read(gcpipe[0], &status, sizeof(status));
} while (n == -1 && errno == EINTR);
_exit(status);
}
CHILD_REQUIRE(write(cpipe1[1], &gchild, sizeof(gchild)) ==
sizeof(gchild));
CHILD_REQUIRE(read(cpipe2[0], &status, sizeof(status)) ==
sizeof(status));
_exit(status);
}
ATF_REQUIRE(read(cpipe1[0], &gchild, sizeof(gchild)) == sizeof(gchild));
ATF_REQUIRE(ptrace(PT_ATTACH, gchild, NULL, 0) == 0);
status = 0;
ATF_REQUIRE(write(cpipe2[1], &status, sizeof(status)) ==
sizeof(status));
ATF_REQUIRE(waitpid(child, &status, 0) == child);
ATF_REQUIRE(WIFEXITED(status) && WEXITSTATUS(status) == 0);
status = 0;
ATF_REQUIRE(write(gcpipe[1], &status, sizeof(status)) ==
sizeof(status));
ATF_REQUIRE(waitpid(gchild, &status, 0) == gchild);
ATF_REQUIRE(WIFSTOPPED(status));
ATF_REQUIRE(ptrace(PT_DETACH, gchild, (caddr_t)1, 0) == 0);
ATF_REQUIRE(waitpid(gchild, &status, 0) == gchild);
ATF_REQUIRE(WIFEXITED(status) && WEXITSTATUS(status) == 0);
ATF_REQUIRE(close(cpipe1[0]) == 0);
ATF_REQUIRE(close(cpipe1[1]) == 0);
ATF_REQUIRE(close(cpipe2[0]) == 0);
ATF_REQUIRE(close(cpipe2[1]) == 0);
ATF_REQUIRE(close(gcpipe[0]) == 0);
ATF_REQUIRE(close(gcpipe[1]) == 0);
}
/*
* The parent process should always act the same regardless of how the
* debugger is attached to it.
@ -3850,6 +3911,7 @@ ATF_TP_ADD_TCS(tp)
ATF_TP_ADD_TC(tp, ptrace__parent_wait_after_attach);
ATF_TP_ADD_TC(tp, ptrace__parent_sees_exit_after_child_debugger);
ATF_TP_ADD_TC(tp, ptrace__parent_sees_exit_after_unrelated_debugger);
ATF_TP_ADD_TC(tp, ptrace__parent_exits_before_child);
ATF_TP_ADD_TC(tp, ptrace__follow_fork_both_attached);
ATF_TP_ADD_TC(tp, ptrace__follow_fork_child_detached);
ATF_TP_ADD_TC(tp, ptrace__follow_fork_parent_detached);