Page MenuHomeFreeBSD

D58264.id182486.diff
No OneTemporary

D58264.id182486.diff

diff --git a/lib/libsys/pdfork.2 b/lib/libsys/pdfork.2
--- a/lib/libsys/pdfork.2
+++ b/lib/libsys/pdfork.2
@@ -176,9 +176,22 @@
.Fa fd
process descriptor.
See the description of the
-.Xr wait6
+.Xr wait6 2
system call for the behavior specification.
.Pp
+If the process was created by the
+.Xr fork 2
+system call
+.Pq which does not allocates a process descriptor for the child ,
+and later the process was opened by
+.Fn pdopenpid ,
+then the parent process can retrieve the process exit status with
+.Xr waitpid 2 ,
+and a call to
+.Fn pdwait
+is providing the status.
+To get rid of the zombie, both calls are needed.
+.Pp
The
.Fn pddupfd
function allows the caller to duplicate a file descriptor
diff --git a/lib/libsys/wait.2 b/lib/libsys/wait.2
--- a/lib/libsys/wait.2
+++ b/lib/libsys/wait.2
@@ -607,15 +607,6 @@
.Fa infop
must be checked against zero to determine if a process reported status.
.Pp
-The
-.Fn wait
-family of functions will only return a child process created with
-.Xr pdfork 2
-if the calling process is not in
-.Xr capsicum 4
-capability mode, and
-.Nm
-has been explicitly given the child's process ID.
.Sh ERRORS
The
.Fn wait
diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c
--- a/sys/kern/kern_exit.c
+++ b/sys/kern/kern_exit.c
@@ -124,6 +124,9 @@
}
parent = __containerof(p->p_orphan.le_prev, struct proc,
p_orphans.lh_first);
+ KASSERT(child->p_pptr != parent,
+ ("proc %d %p orphaned but parent %d %p is realparent",
+ child->p_pid, child, parent->p_pid, parent));
return (parent);
}
@@ -720,6 +723,21 @@
}
} else
PROC_LOCK(p->p_pptr);
+ if ((p->p_treeflag & P_TREE_ORPHANED) != 0) {
+ /*
+ * Process is orphaned. Add PZOMBIEREF_REALPARENT zombie
+ * reference if real parent created the process with
+ * fork() and not pdfork(). Also wake up the real
+ * parent, so it can collect the exit status and clear
+ * its zombie reference.
+ */
+ nq = proc_realparent(p);
+ if ((p->p_zombieref & PZOMBIEREF_PARENT) != 0) {
+ p->p_zombieref |= PZOMBIEREF_REALPARENT |
+ PZOMBIEREF_WREALPARENT;
+ }
+ wakeup(nq);
+ }
sx_xunlock(&proctree_lock);
if (signal_parent == 1) {
@@ -982,7 +1000,8 @@
* lock as part of its work.
*/
void
-proc_reap(struct thread *td, struct proc *p, int *status, int options)
+proc_reap(struct thread *td, struct proc *p, int *status, int options,
+ int zombieref)
{
struct proc *q, *t;
@@ -1006,6 +1025,13 @@
return;
}
+ p->p_zombieref &= ~zombieref;
+ if ((p->p_zombieref & PZOMBIEREF_STRONG) != 0) {
+ PROC_UNLOCK(p);
+ sx_xunlock(&proctree_lock);
+ return;
+ }
+
PROC_LOCK(q);
sigqueue_take(p->p_ksi);
PROC_UNLOCK(q);
@@ -1179,7 +1205,7 @@
static int
proc_to_reap(struct thread *td, struct proc *p, idtype_t idtype, id_t id,
int *status, int options, struct __wrusage *wrusage, siginfo_t *siginfo,
- bool check_only)
+ int zombieref)
{
sx_assert(&proctree_lock, SA_XLOCKED);
@@ -1187,9 +1213,8 @@
switch (idtype) {
case P_ALL:
- if (p->p_procdesc == NULL ||
- (p->p_pptr == td->td_proc &&
- (p->p_flag & P_TRACED) != 0)) {
+ if ((p->p_zombieref & zombieref) != 0 ||
+ (p->p_pptr == td->td_proc && (p->p_flag & P_TRACED) != 0)) {
break;
}
@@ -1241,12 +1266,9 @@
return (0);
}
- if (p_canwait(td, p)) {
- PROC_UNLOCK(p);
- return (0);
- }
-
- if ((options & WEXITED) == 0 && p->p_state == PRS_ZOMBIE) {
+ if (p_canwait(td, p) != 0 ||
+ ((options & WEXITED) == 0 && p->p_state == PRS_ZOMBIE) ||
+ (p->p_zombieref & zombieref) == 0) {
PROC_UNLOCK(p);
return (0);
}
@@ -1274,8 +1296,8 @@
*/
wait_fill_wrusage(p, wrusage);
- if (p->p_state == PRS_ZOMBIE && !check_only) {
- proc_reap(td, p, status, options);
+ if (p->p_state == PRS_ZOMBIE) {
+ proc_reap(td, p, status, options, zombieref);
return (-1);
}
return (1);
@@ -1468,7 +1490,7 @@
LIST_FOREACH(p, &q->p_children, p_sibling) {
pid = p->p_pid;
ret = proc_to_reap(td, p, idtype, id, status, options,
- wrusage, siginfo, false);
+ wrusage, siginfo, PZOMBIEREF_PARENT | PZOMBIEREF_WPARENT);
if (ret == 0)
continue;
else if (ret != 1) {
@@ -1476,18 +1498,6 @@
return (0);
}
- /*
- * When running in capsicum(4) mode, make wait(2) ignore
- * processes created with pdfork(2). This is because one can
- * disown them - by passing their process descriptor to another
- * process - which means it needs to be prevented from touching
- * them afterwards.
- */
- if (IN_CAPABILITY_MODE(td) && p->p_procdesc != NULL) {
- PROC_UNLOCK(p);
- continue;
- }
-
nfound++;
PROC_LOCK_ASSERT(p, MA_OWNED);
@@ -1514,13 +1524,13 @@
if (nfound == 0) {
LIST_FOREACH(p, &q->p_orphans, p_orphan) {
ret = proc_to_reap(td, p, idtype, id, NULL, options,
- NULL, NULL, true);
- if (ret != 0) {
- KASSERT(ret != -1, ("reaped an orphan (pid %d)",
- (int)td->td_retval[0]));
+ NULL, NULL, PZOMBIEREF_REALPARENT |
+ PZOMBIEREF_WREALPARENT);
+ if (ret == -1) {
PROC_UNLOCK(p);
- nfound++;
- break;
+ td->td_retval[0] = p->p_pid;
+ sx_xunlock(&proctree_lock);
+ return (0);
}
}
}
@@ -1583,7 +1593,8 @@
error = p_canwait(td, p);
if (error != 0)
break;
- if ((options & WEXITED) == 0 && p->p_state == PRS_ZOMBIE) {
+ if (((options & WEXITED) == 0 && p->p_state == PRS_ZOMBIE) ||
+ (p->p_zombieref & PZOMBIEREF_PROCDESC) == 0) {
error = ESRCH;
break;
}
@@ -1592,7 +1603,7 @@
wait_fill_wrusage(p, wrusage);
if (p->p_state == PRS_ZOMBIE) {
- proc_reap(td, p, status, options);
+ proc_reap(td, p, status, options, PZOMBIEREF_PROCDESC);
goto exit_unlocked;
}
@@ -1665,6 +1676,17 @@
child->p_pptr = parent;
if (set_oppid)
child->p_oppid = parent->p_pid;
+
+ /*
+ * When reparenting the child to the reaper, re-enable
+ * waitpid(2) for it, so that the zombie can be collected.
+ */
+ if ((child->p_flag & P_TRACED) == 0 && child->p_reaper == parent &&
+ (child->p_zombieref & PZOMBIEREF_PARENT) == 0) {
+ child->p_zombieref |= PZOMBIEREF_PARENT | PZOMBIEREF_WPARENT;
+ child->p_zombieref &= ~(PZOMBIEREF_REALPARENT |
+ PZOMBIEREF_WREALPARENT);
+ }
}
static void
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -547,6 +547,8 @@
P2_STKGAP_DISABLE | P2_STKGAP_DISABLE_EXEC | P2_NO_NEW_PRIVS |
P2_WXORX_DISABLE | P2_WXORX_ENABLE_EXEC | P2_LOGSIGEXIT_CTL |
P2_LOGSIGEXIT_ENABLE);
+ p2->p_zombieref = (fr->fr_flags & RFPROCDESC) != 0 ?
+ PZOMBIEREF_PROCDESC : (PZOMBIEREF_PARENT | PZOMBIEREF_WPARENT);
p2->p_swtick = ticks;
if (p1->p_flag & P_PROFIL)
startprofclock(p2);
diff --git a/sys/kern/sys_procdesc.c b/sys/kern/sys_procdesc.c
--- a/sys/kern/sys_procdesc.c
+++ b/sys/kern/sys_procdesc.c
@@ -307,6 +307,7 @@
PROCDESC_UNLOCK(pd);
pd->pd_proc = NULL;
p->p_procdesc = NULL;
+ p->p_zombieref &= ~PZOMBIEREF_PROCDESC;
procdesc_free(pd);
return (true);
}
@@ -316,7 +317,9 @@
/* Wakeup all waiters for this procdesc' process exit. */
wakeup(&p->p_procdesc);
- return (false);
+ return ((p->p_zombieref & (PZOMBIEREF_PARENT |
+ PZOMBIEREF_REALPARENT | PZOMBIEREF_WPARENT |
+ PZOMBIEREF_WREALPARENT)) != 0);
}
void
@@ -418,7 +421,7 @@
* process's reference to the process descriptor when it
* calls back into procdesc_reap().
*/
- proc_reap(curthread, p, NULL, 0);
+ proc_reap(curthread, p, NULL, 0, PZOMBIEREF_PROCDESC);
} else if (pd->pd_fpcount == 0) /* last procdesc */ {
/*
* If the process is not yet dead, we need to kill it,
@@ -429,11 +432,17 @@
*/
pd->pd_proc = NULL;
p->p_procdesc = NULL;
+ p->p_zombieref &= ~PZOMBIEREF_PROCDESC;
pd->pd_pid = -1;
procdesc_free(pd);
- /* Failed finstall() should not cause reaping. */
- if ((fp->f_pdflags & F_PD_NOFINSTALL) == 0) {
+ /*
+ * A reference for waitpid() or failed
+ * finstall() should not cause reaping.
+ */
+ if ((fp->f_pdflags & F_PD_NOFINSTALL) == 0 &&
+ (p->p_zombieref & (PZOMBIEREF_PARENT |
+ PZOMBIEREF_REALPARENT)) == 0) {
/*
* Next, reparent it to its reaper
* (usually init(8)) so that there's
@@ -642,6 +651,7 @@
}
pd = p->p_procdesc;
if (pd != NULL) {
+ MPASS((p->p_zombieref & PZOMBIEREF_PROCDESC) != 0);
refcount_acquire(&pd->pd_refcount);
PROCDESC_LOCK(pd);
MPASS(pd->pd_fpcount > 0);
@@ -653,6 +663,8 @@
pd->pd_proc = p;
pd->pd_pid = p->p_pid;
p->p_procdesc = pd;
+ MPASS((p->p_zombieref & PZOMBIEREF_PROCDESC) == 0);
+ p->p_zombieref |= PZOMBIEREF_PROCDESC;
}
procdesc_finit(pd, fp);
PROC_UNLOCK(p);
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -782,6 +782,7 @@
LIST_ENTRY(proc) p_jaillist; /* (d) Jail process linkage. */
u_int p_asig; /* (c) ASYNCEXIT pending signal. */
u_int p_tree_refcnt; /* (e) proctree refcount */
+ u_int p_zombieref; /* (e) References for reap. */
};
#define p_session p_pgrp->pg_session
@@ -911,6 +912,26 @@
#define P_TREE_REAPER 0x00000004 /* Reaper of subtree */
#define P_TREE_GRPEXITED 0x00000008 /* exit1() done with job ctl */
+/*
+ * p_zombieref; protected by proctree_lock.
+ *
+ * strong references: process is reaped when all of them go away:
+ */
+#define PZOMBIEREF_PARENT 0x00000001 /* Ref for waitpid() */
+#define PZOMBIEREF_PROCDESC 0x00000002 /* Ref for pdwait() */
+#define PZOMBIEREF_REALPARENT 0x00000004 /* Ref for waitpid() on
+ orphan */
+/*
+ * weak references: *wait*() is allowed, but a reference does not
+ * prevent reap:
+ */
+#define PZOMBIEREF_WPARENT 0x00010000 /* Weal ref for waitpid() */
+#define PZOMBIEREF_WREALPARENT 0x00020000 /* Weal ref for waitpid() on
+ orphan */
+
+#define PZOMBIEREF_STRONG \
+ (PZOMBIEREF_PARENT | PZOMBIEREF_PROCDESC | PZOMBIEREF_REALPARENT)
+
/*
* These were process status values (p_stat), now they are only used in
* legacy conversion code.
@@ -1205,7 +1226,8 @@
void proc_linkup0(struct proc *p, struct thread *td);
void proc_linkup(struct proc *p, struct thread *td);
struct proc *proc_realparent(struct proc *child);
-void proc_reap(struct thread *td, struct proc *p, int *status, int options);
+void proc_reap(struct thread *td, struct proc *p, int *status, int options,
+ int zombieref);
void proc_reparent(struct proc *child, struct proc *newparent, bool set_oppid);
void proc_set_p2_wexit(struct proc *p);
void proc_set_traced(struct proc *p, bool stop);

File Metadata

Mime Type
text/plain
Expires
Sat, Jul 25, 10:14 PM (16 h, 23 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
35502015
Default Alt Text
D58264.id182486.diff (10 KB)

Event Timeline