Page MenuHomeFreeBSD

D58264.id183015.diff
No OneTemporary

D58264.id183015.diff

diff --git a/lib/libsys/pdfork.2 b/lib/libsys/pdfork.2
--- a/lib/libsys/pdfork.2
+++ b/lib/libsys/pdfork.2
@@ -103,6 +103,9 @@
flag, closing that descriptor kills the process.
.It Dv PD_CLOEXEC
Set close-on-exec on process descriptor.
+.It Dv PD_NOWAITPID
+The parent does not get the child status with
+.Xr waitpid 2 .
.El
.Pp
The
@@ -176,7 +179,7 @@
.Fa fd
process descriptor.
See the description of the
-.Xr wait6
+.Xr wait6 2
system call for the behavior specification.
.Pp
The
@@ -197,6 +200,52 @@
argument is reserved and must be zero.
Certain file descriptor types cannot be copied this way, namely
kqueues.
+.Sh INTERACTION OF PROCESS DESCRIPTORS AND Xr WAITPID 2
+.Pp
+The
+.Fn pdwait
+system call may be called on a process descriptor
+an unlimited number of times.
+In particular, it does not reap the target process,
+even if it has exited.
+Each time, it returns the same status.
+.Bl -dash
+.It
+If the process was forked with
+.Fn pdfork ,
+and the
+.Dv PD_NOWAITPID
+flag was specified, then the process is automatically reaped after the
+last process descriptor referencing that process is closed.
+No
+.Xr waitpid 2
+call
+.Pq or a call from the same family of the wait functions which operate on PIDs
+are needed to reap the zombie process.
+.It
+If the process was created by
+.Fn pdfork ,
+and the
+.Dv PD_NOWAITPID
+flag was not specified, then after exiting,
+the process will not be reaped until the parent or reaper has called
+.Xr waitpid 2
+and all process descriptors referencing the process are closed.
+.It
+If the process was created by the
+.Xr fork 2
+system call
+.Pq which does not allocate a process descriptor for the child ,
+and later the process was opened by
+.Fn pdopenpid ,
+then a
+.Xr waitpid 2
+call from the parent is needed to reap the exited child.
+.El
+.Pp
+In any case, the PID of the process is not reused until its zombie
+is reaped, and all its process descriptors are closed.
+.Sh INTERACTION OF PROCESS DESCRIPTORS WITH SOME SYSTEM CALLS
.Pp
The following system calls also have effects specific to process descriptors:
.Pp
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
@@ -683,8 +683,7 @@
* exit().
*/
signal_parent = 0;
- procdesc_exit(p);
- if (p->p_procdesc == NULL) {
+ if (p->p_procdesc == NULL || procdesc_exit(p)) {
/*
* Notify parent that we're gone. If parent has the
* PS_NOCLDWAIT flag set, or if the handler is set to SIG_IGN,
@@ -986,7 +985,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;
@@ -1010,6 +1010,13 @@
return;
}
+ p->p_zombieref &= ~zombieref;
+ if ((p->p_zombieref & PZOMBIEREF_REFMASK) != 0) {
+ sx_xunlock(&proctree_lock);
+ PROC_UNLOCK(p);
+ return;
+ }
+
PROC_LOCK(q);
sigqueue_take(p->p_ksi);
PROC_UNLOCK(q);
@@ -1192,9 +1199,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 & PZOMBIEREF_PARENT) != 0 ||
+ (p->p_pptr == td->td_proc && (p->p_flag & P_TRACED) != 0)) {
break;
}
@@ -1246,14 +1252,15 @@
return (0);
}
- if (p_canwait(td, p)) {
+ if (p_canwait(td, p) != 0 ||
+ ((options & WEXITED) == 0 && p->p_state == PRS_ZOMBIE) ||
+ (p->p_zombieref & PZOMBIEREF_PARENT) == 0) {
PROC_UNLOCK(p);
return (0);
}
-
- if ((options & WEXITED) == 0 && p->p_state == PRS_ZOMBIE) {
+ if (check_only) {
PROC_UNLOCK(p);
- return (0);
+ return (1);
}
/*
@@ -1279,8 +1286,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, PZOMBIEREF_PARENT);
return (-1);
}
return (1);
@@ -1481,18 +1488,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);
@@ -1523,7 +1518,6 @@
if (ret != 0) {
KASSERT(ret != -1, ("reaped an orphan (pid %d)",
(int)td->td_retval[0]));
- PROC_UNLOCK(p);
nfound++;
break;
}
@@ -1679,6 +1673,18 @@
child->p_pptr = parent;
if (set_oppid)
child->p_oppid = parent->p_pid;
+
+ /*
+ * When reparenting the child to the real parent which expects
+ * to be able to call waitpid(), or reaper, re-enable
+ * waitpid(2) for it, so that the zombie can be collected.
+ */
+ if ((child->p_flag & P_TRACED) == 0 &&
+ ((proc_realparent(child) == parent &&
+ (child->p_zombieref & PZOMBIEREF_NEEDPARENT) != 0)
+ || child->p_reaper == parent) &&
+ (child->p_zombieref & PZOMBIEREF_PARENT) == 0)
+ child->p_zombieref |= PZOMBIEREF_PARENT;
}
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,15 @@
P2_STKGAP_DISABLE | P2_STKGAP_DISABLE_EXEC | P2_NO_NEW_PRIVS |
P2_WXORX_DISABLE | P2_WXORX_ENABLE_EXEC | P2_LOGSIGEXIT_CTL |
P2_LOGSIGEXIT_ENABLE);
+ if ((fr->fr_flags & RFPROCDESC) != 0) {
+ p2->p_zombieref = PZOMBIEREF_PROCDESC;
+ if ((fr->fr_pd_flags & PD_NOWAITPID) == 0 &&
+ (fr->fr_flags & RFNOWAIT) == 0)
+ p2->p_zombieref |= (PZOMBIEREF_PARENT |
+ PZOMBIEREF_NEEDPARENT);
+ } else {
+ p2->p_zombieref = PZOMBIEREF_PARENT | PZOMBIEREF_NEEDPARENT;
+ }
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
@@ -278,7 +278,7 @@
* We use the proctree_lock to ensure that process exit either happens
* strictly before or strictly after a concurrent call to procdesc_close().
*/
-void
+bool
procdesc_exit(struct proc *p)
{
struct procdesc *pd;
@@ -289,7 +289,7 @@
pd = p->p_procdesc;
if (pd == NULL)
- return;
+ goto out;
PROCDESC_LOCK(pd);
KASSERT(pd->pd_fpcount > 0, ("%s: closed procdesc %p", __func__, pd));
@@ -304,6 +304,8 @@
/* Wakeup all waiters for this procdesc' process exit. */
wakeup(&p->p_procdesc);
+out:
+ return ((p->p_zombieref & PZOMBIEREF_PARENT) != 0);
}
void
@@ -418,15 +420,7 @@
} else {
PROC_LOCK(p);
AUDIT_ARG_PROCESS(p);
- if (p->p_state == PRS_ZOMBIE) {
- /*
- * If the process is already dead and just awaiting
- * reaping, do that now. This will release the
- * process's reference to the process descriptor when it
- * calls back into procdesc_reap().
- */
- proc_reap(curthread, p, NULL, 0);
- } else if (pd->pd_fpcount == 0) /* last procdesc */ {
+ if (pd->pd_fpcount == 0) /* last procdesc */ {
/*
* If the process is not yet dead, we need to kill it,
* but we can't wait around synchronously for it to go
@@ -438,9 +432,16 @@
p->p_procdesc = NULL;
pd->pd_pid = -1;
procdesc_free(pd);
-
- /* Failed finstall() should not cause reaping. */
- if ((fp->f_pdflags & F_PD_NOFINSTALL) == 0) {
+ if (p->p_state == PRS_ZOMBIE) {
+ proc_reap(curthread, p, NULL, 0,
+ PZOMBIEREF_PROCDESC);
+ goto out;
+ /*
+ * A reference for waitpid() or failed
+ * finstall() should not cause reaping.
+ */
+ } else if ((fp->f_pdflags & F_PD_NOFINSTALL) == 0 &&
+ (p->p_zombieref & PZOMBIEREF_PARENT) == 0) {
/*
* Next, reparent it to its reaper
* (usually init(8)) so that there's
@@ -461,7 +462,7 @@
procdesc_close_tail(fp, p);
}
}
-
+out:
/*
* Release the file descriptor's reference on the process descriptor.
*/
@@ -652,6 +653,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);
@@ -663,6 +665,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);
@@ -718,7 +722,7 @@
AUDIT_ARG_PID(args->pid);
AUDIT_ARG_FFLAGS(args->flags);
- if ((args->flags & ~(PD_ALLOWED_AT_FORK)) != 0)
+ if ((args->flags & ~(PD_ALLOWED_AT_OPENPID)) != 0)
return (EINVAL);
return (kern_pdopenpid(td, args->pid, args->flags));
}
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,14 @@
#define P_TREE_REAPER 0x00000004 /* Reaper of subtree */
#define P_TREE_GRPEXITED 0x00000008 /* exit1() done with job ctl */
+/*
+ * p_zombieref; protected by proctree_lock.
+ */
+#define PZOMBIEREF_PARENT 0x00000001 /* Ref for waitpid() */
+#define PZOMBIEREF_PROCDESC 0x00000002 /* Ref for pdwait() */
+#define PZOMBIEREF_NEEDPARENT 0x80000000 /* Had ref for waitpid() */
+#define PZOMBIEREF_REFMASK (PZOMBIEREF_PARENT | PZOMBIEREF_PROCDESC)
+
/*
* These were process status values (p_stat), now they are only used in
* legacy conversion code.
@@ -1205,7 +1214,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);
diff --git a/sys/sys/procdesc.h b/sys/sys/procdesc.h
--- a/sys/sys/procdesc.h
+++ b/sys/sys/procdesc.h
@@ -108,7 +108,7 @@
/*
* In-kernel interfaces to process descriptors.
*/
-void procdesc_exit(struct proc *);
+bool procdesc_exit(struct proc *);
void procdesc_fork(struct proc *p, pid_t child_pid);
void procdesc_jobstate(struct proc *p);
int kern_pdgetpid(struct thread *, int fd, const cap_rights_t *,
@@ -160,7 +160,9 @@
*/
#define PD_DAEMON 0x00000001 /* Don't exit when procdesc closes. */
#define PD_CLOEXEC 0x00000002 /* Close file descriptor on exec. */
+#define PD_NOWAITPID 0x00000004 /* Reap without waitpid(). */
-#define PD_ALLOWED_AT_FORK (PD_DAEMON | PD_CLOEXEC)
+#define PD_ALLOWED_AT_FORK (PD_DAEMON | PD_CLOEXEC | PD_NOWAITPID)
+#define PD_ALLOWED_AT_OPENPID (PD_DAEMON | PD_CLOEXEC)
#endif /* !_SYS_PROCDESC_H_ */

File Metadata

Mime Type
text/plain
Expires
Sat, Aug 1, 5:34 AM (8 h, 24 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
35810741
Default Alt Text
D58264.id183015.diff (11 KB)

Event Timeline