summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/kern/kern_exit.c92
-rw-r--r--sys/kern/kern_fork.c6
-rw-r--r--sys/kern/sys_process.c18
-rw-r--r--sys/sys/proc.h15
-rw-r--r--sys/sys/ptrace.h5
5 files changed, 107 insertions, 29 deletions
diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c
index 73b90e24cff..1ed8f8f3474 100644
--- a/sys/kern/kern_exit.c
+++ b/sys/kern/kern_exit.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_exit.c,v 1.186 2020/03/13 09:25:21 mpi Exp $ */
+/* $OpenBSD: kern_exit.c,v 1.187 2020/03/16 11:58:46 mpi Exp $ */
/* $NetBSD: kern_exit.c,v 1.39 1996/04/22 01:38:25 christos Exp $ */
/*
@@ -76,6 +76,7 @@
#endif
void proc_finish_wait(struct proc *, struct proc *);
+void process_clear_orphan(struct process *);
void process_zap(struct process *);
void proc_free(struct proc *);
void unveil_destroy(struct process *ps);
@@ -253,21 +254,22 @@ exit1(struct proc *p, int xexit, int xsig, int flags)
}
/*
- * Give orphaned children to init(8).
+ * Reparent children to their original parent, in case
+ * they were being traced, or to init(8).
*/
qr = LIST_FIRST(&pr->ps_children);
if (qr) /* only need this if any child is S_ZOMB */
wakeup(initprocess);
for (; qr != 0; qr = nqr) {
nqr = LIST_NEXT(qr, ps_sibling);
- proc_reparent(qr, initprocess);
/*
* Traced processes are killed since their
* existence means someone is screwing up.
*/
if (qr->ps_flags & PS_TRACED &&
!(qr->ps_flags & PS_EXITING)) {
- atomic_clearbits_int(&qr->ps_flags, PS_TRACED);
+ process_untrace(qr);
+
/*
* If single threading is active,
* direct the signal to the active
@@ -278,8 +280,19 @@ exit1(struct proc *p, int xexit, int xsig, int flags)
STHREAD);
else
prsignal(qr, SIGKILL);
+ } else {
+ process_reparent(qr, initprocess);
}
}
+
+ /*
+ * Make sure orphans won't remember the exiting process.
+ */
+ while ((qr = LIST_FIRST(&pr->ps_orphans)) != NULL) {
+ KASSERT(qr->ps_oppid == pr->ps_pid);
+ qr->ps_oppid = 0;
+ process_clear_orphan(qr);
+ }
}
/* add thread's accumulated rusage into the process's total */
@@ -310,7 +323,7 @@ exit1(struct proc *p, int xexit, int xsig, int flags)
*/
if (pr->ps_flags & PS_NOZOMBIE) {
struct process *ppr = pr->ps_pptr;
- proc_reparent(pr, initprocess);
+ process_reparent(pr, initprocess);
wakeup(ppr);
}
@@ -562,6 +575,29 @@ loop:
return (0);
}
}
+ /*
+ * Look in the orphans list too, to allow the parent to
+ * collect it's child exit status even if child is being
+ * debugged.
+ *
+ * Debugger detaches from the parent upon successful
+ * switch-over from parent to child. At this point due to
+ * re-parenting the parent loses the child to debugger and a
+ * wait4(2) call would report that it has no children to wait
+ * for. By maintaining a list of orphans we allow the parent
+ * to successfully wait until the child becomes a zombie.
+ */
+ if (nfound == 0) {
+ LIST_FOREACH(pr, &q->p_p->ps_orphans, ps_orphan) {
+ if ((pr->ps_flags & PS_NOZOMBIE) ||
+ (pid != WAIT_ANY &&
+ pr->ps_pid != pid &&
+ pr->ps_pgid != -pid))
+ continue;
+ nfound++;
+ break;
+ }
+ }
if (nfound == 0)
return (ECHILD);
if (options & WNOHANG) {
@@ -586,9 +622,9 @@ proc_finish_wait(struct proc *waiter, struct proc *p)
pr = p->p_p;
if (pr->ps_oppid != 0 && (pr->ps_oppid != pr->ps_pptr->ps_pid) &&
(tr = prfind(pr->ps_oppid))) {
- atomic_clearbits_int(&pr->ps_flags, PS_TRACED);
pr->ps_oppid = 0;
- proc_reparent(pr, tr);
+ atomic_clearbits_int(&pr->ps_flags, PS_TRACED);
+ process_reparent(pr, tr);
prsignal(tr, SIGCHLD);
wakeup(tr);
} else {
@@ -602,17 +638,56 @@ proc_finish_wait(struct proc *waiter, struct proc *p)
}
/*
+ * give process back to original parent or init(8)
+ */
+void
+process_untrace(struct process *pr)
+{
+ struct process *ppr = NULL;
+
+ KASSERT(pr->ps_flags & PS_TRACED);
+
+ if (pr->ps_oppid != 0 &&
+ (pr->ps_oppid != pr->ps_pptr->ps_pid))
+ ppr = prfind(pr->ps_oppid);
+
+ /* not being traced any more */
+ pr->ps_oppid = 0;
+ atomic_clearbits_int(&pr->ps_flags, PS_TRACED);
+ process_reparent(pr, ppr ? ppr : initprocess);
+}
+
+void
+process_clear_orphan(struct process *pr)
+{
+ if (pr->ps_flags & PS_ORPHAN) {
+ LIST_REMOVE(pr, ps_orphan);
+ atomic_clearbits_int(&pr->ps_flags, PS_ORPHAN);
+ }
+}
+
+/*
* make process 'parent' the new parent of process 'child'.
*/
void
-proc_reparent(struct process *child, struct process *parent)
+process_reparent(struct process *child, struct process *parent)
{
if (child->ps_pptr == parent)
return;
+ KASSERT(child->ps_oppid == 0 ||
+ child->ps_oppid == child->ps_pptr->ps_pid);
+
LIST_REMOVE(child, ps_sibling);
LIST_INSERT_HEAD(&parent->ps_children, child, ps_sibling);
+
+ process_clear_orphan(child);
+ if (child->ps_flags & PS_TRACED) {
+ atomic_setbits_int(&child->ps_flags, PS_ORPHAN);
+ LIST_INSERT_HEAD(&child->ps_pptr->ps_orphans, child, ps_orphan);
+ }
+
child->ps_pptr = parent;
}
@@ -628,6 +703,7 @@ process_zap(struct process *pr)
*/
leavepgrp(pr);
LIST_REMOVE(pr, ps_sibling);
+ process_clear_orphan(pr);
/*
* Decrement the count of procs running with this uid.
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
index 613ec3c8d8f..71129dd4079 100644
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_fork.c,v 1.223 2020/02/21 11:10:23 claudio Exp $ */
+/* $OpenBSD: kern_fork.c,v 1.224 2020/03/16 11:58:46 mpi Exp $ */
/* $NetBSD: kern_fork.c,v 1.29 1996/02/09 18:59:34 christos Exp $ */
/*
@@ -190,6 +190,7 @@ process_initialize(struct process *pr, struct proc *p)
KASSERT(p->p_ucred->cr_ref >= 2); /* new thread and new process */
LIST_INIT(&pr->ps_children);
+ LIST_INIT(&pr->ps_orphans);
LIST_INIT(&pr->ps_ftlist);
LIST_INIT(&pr->ps_sigiolst);
TAILQ_INIT(&pr->ps_tslpqueue);
@@ -430,8 +431,7 @@ fork1(struct proc *curp, int flags, void (*func)(void *), void *arg,
if (pr->ps_flags & PS_TRACED) {
pr->ps_oppid = curpr->ps_pid;
- if (pr->ps_pptr != curpr->ps_pptr)
- proc_reparent(pr, curpr->ps_pptr);
+ process_reparent(pr, curpr->ps_pptr);
/*
* Set ptrace status.
diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c
index 513ccd24d28..9481d6a7424 100644
--- a/sys/kern/sys_process.c
+++ b/sys/kern/sys_process.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sys_process.c,v 1.82 2019/12/11 07:30:09 guenther Exp $ */
+/* $OpenBSD: sys_process.c,v 1.83 2020/03/16 11:58:46 mpi Exp $ */
/* $NetBSD: sys_process.c,v 1.55 1996/05/15 06:17:47 tls Exp $ */
/*-
@@ -476,17 +476,8 @@ ptrace_ctrl(struct proc *p, int req, pid_t pid, caddr_t addr, int data)
goto fail;
#endif
- /* give process back to original parent or init */
- if (tr->ps_oppid != tr->ps_pptr->ps_pid) {
- struct process *ppr;
-
- ppr = prfind(tr->ps_oppid);
- proc_reparent(tr, ppr ? ppr : initprocess);
- }
-
- /* not being traced any more */
- tr->ps_oppid = 0;
- atomic_clearbits_int(&tr->ps_flags, PS_TRACED|PS_WAITED);
+ process_untrace(tr);
+ atomic_clearbits_int(&tr->ps_flags, PS_WAITED);
sendsig:
memset(tr->ps_ptstat, 0, sizeof(*tr->ps_ptstat));
@@ -523,8 +514,7 @@ ptrace_ctrl(struct proc *p, int req, pid_t pid, caddr_t addr, int data)
*/
atomic_setbits_int(&tr->ps_flags, PS_TRACED);
tr->ps_oppid = tr->ps_pptr->ps_pid;
- if (tr->ps_pptr != p->p_p)
- proc_reparent(tr, p->p_p);
+ process_reparent(tr, p->p_p);
if (tr->ps_ptstat == NULL)
tr->ps_ptstat = malloc(sizeof(*tr->ps_ptstat),
M_SUBPROC, M_WAITOK);
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index 3de46326551..d685dd71365 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: proc.h,v 1.289 2020/02/21 11:10:23 claudio Exp $ */
+/* $OpenBSD: proc.h,v 1.290 2020/03/16 11:58:46 mpi Exp $ */
/* $NetBSD: proc.h,v 1.44 1996/04/22 01:23:21 christos Exp $ */
/*-
@@ -182,6 +182,15 @@ struct process {
LIST_HEAD(, process) ps_children;/* Pointer to list of children. */
LIST_ENTRY(process) ps_hash; /* Hash chain. */
+ /*
+ * An orphan is the child that has been re-parented to the
+ * debugger as a result of attaching to it. Need to keep
+ * track of them for parent to be able to collect the exit
+ * status of what used to be children.
+ */
+ LIST_ENTRY(process) ps_orphan; /* List of orphan processes. */
+ LIST_HEAD(, process) ps_orphans;/* Pointer to list of orphans. */
+
struct sigiolst ps_sigiolst; /* List of sigio structures. */
struct sigacts *ps_sigacts; /* Signal actions, state */
struct vnode *ps_textvp; /* Vnode of executable. */
@@ -303,13 +312,15 @@ struct process {
#define PS_PLEDGE 0x00100000 /* Has called pledge(2) */
#define PS_WXNEEDED 0x00200000 /* Process may violate W^X */
#define PS_EXECPLEDGE 0x00400000 /* Has exec pledges */
+#define PS_ORPHAN 0x00800000 /* Process is on an orphan list */
#define PS_BITS \
("\20" "\01CONTROLT" "\02EXEC" "\03INEXEC" "\04EXITING" "\05SUGID" \
"\06SUGIDEXEC" "\07PPWAIT" "\010ISPWAIT" "\011PROFIL" "\012TRACED" \
"\013WAITED" "\014COREDUMP" "\015SINGLEEXIT" "\016SINGLEUNWIND" \
"\017NOZOMBIE" "\020STOPPED" "\021SYSTEM" "\022EMBRYO" "\023ZOMBIE" \
- "\024NOBROADCASTKILL" "\025PLEDGE" "\026WXNEEDED" "\027EXECPLEDGE" )
+ "\024NOBROADCASTKILL" "\025PLEDGE" "\026WXNEEDED" "\027EXECPLEDGE" \
+ "\028ORPHAN")
struct kcov_dev;
diff --git a/sys/sys/ptrace.h b/sys/sys/ptrace.h
index 7133d13fe23..8e127c51390 100644
--- a/sys/sys/ptrace.h
+++ b/sys/sys/ptrace.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ptrace.h,v 1.15 2016/10/19 08:31:33 guenther Exp $ */
+/* $OpenBSD: ptrace.h,v 1.16 2020/03/16 11:58:46 mpi Exp $ */
/* $NetBSD: ptrace.h,v 1.21 1996/02/09 18:25:26 christos Exp $ */
/*-
@@ -104,7 +104,8 @@ struct reg;
struct fpreg;
#endif
-void proc_reparent(struct process *_child, struct process *_newparent);
+void process_reparent(struct process *_child, struct process *_newparent);
+void process_untrace(struct process *_tr);
#ifdef PT_GETFPREGS
int process_read_fpregs(struct proc *_t, struct fpreg *);
#endif