diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/kern/kern_exit.c | 92 | ||||
-rw-r--r-- | sys/kern/kern_fork.c | 6 | ||||
-rw-r--r-- | sys/kern/sys_process.c | 18 | ||||
-rw-r--r-- | sys/sys/proc.h | 15 | ||||
-rw-r--r-- | sys/sys/ptrace.h | 5 |
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 |