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:
parent
0dc2db13ec
commit
128c9bc05b
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=346009
@ -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
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user