diff options
author | jake <jake@FreeBSD.org> | 2000-12-23 19:43:10 +0000 |
---|---|---|
committer | jake <jake@FreeBSD.org> | 2000-12-23 19:43:10 +0000 |
commit | fa7a58ab48542df270919dc02881d5c4a2d4f344 (patch) | |
tree | 51c7f08e6064351afd60db7b45fcd14756284805 /sys/kern | |
parent | 974f411f61d6549db784519d520f6a33719e3f6c (diff) | |
download | FreeBSD-src-fa7a58ab48542df270919dc02881d5c4a2d4f344.zip FreeBSD-src-fa7a58ab48542df270919dc02881d5c4a2d4f344.tar.gz |
Protect proc.p_pptr and proc.p_children/p_sibling with the
proctree_lock.
linprocfs not locked pending response from informal maintainer.
Reviewed by: jhb, -smp@
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/kern_exec.c | 2 | ||||
-rw-r--r-- | sys/kern/kern_exit.c | 40 | ||||
-rw-r--r-- | sys/kern/kern_fork.c | 2 | ||||
-rw-r--r-- | sys/kern/kern_kthread.c | 4 | ||||
-rw-r--r-- | sys/kern/kern_ktrace.c | 6 | ||||
-rw-r--r-- | sys/kern/kern_proc.c | 17 | ||||
-rw-r--r-- | sys/kern/kern_prot.c | 12 | ||||
-rw-r--r-- | sys/kern/kern_sig.c | 11 | ||||
-rw-r--r-- | sys/kern/sys_process.c | 12 |
9 files changed, 82 insertions, 24 deletions
diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index 6c0ef15..ec1a497 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -267,10 +267,12 @@ interpret: * it that it now has its own resources back */ p->p_flag |= P_EXEC; + PROCTREE_LOCK(PT_SHARED); if (p->p_pptr && (p->p_flag & P_PPWAIT)) { p->p_flag &= ~P_PPWAIT; wakeup((caddr_t)p->p_pptr); } + PROCTREE_LOCK(PT_RELEASE); /* * Implement image setuid/setgid. diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index 816d062..e6a640b 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -267,17 +267,10 @@ exit1(p, rv) ALLPROC_LOCK(AP_EXCLUSIVE); LIST_REMOVE(p, p_list); LIST_INSERT_HEAD(&zombproc, p, p_list); - LIST_REMOVE(p, p_hash); ALLPROC_LOCK(AP_RELEASE); - /* - * We have to wait until after releasing this lock before - * changing p_stat. If we block on a mutex while waiting to - * release the allproc_lock, then we will be back at SRUN when - * we resume here and our parent will never harvest us. - */ - p->p_stat = SZOMB; + PROCTREE_LOCK(PT_EXCLUSIVE); q = LIST_FIRST(&p->p_children); if (q) /* only need this if any child is S_ZOMB */ wakeup((caddr_t) initproc); @@ -343,7 +336,7 @@ exit1(p, rv) psignal(p->p_pptr, SIGCHLD); } - wakeup((caddr_t)p->p_pptr); + PROCTREE_LOCK(PT_RELEASE); /* * Clear curproc after we've done all operations * that could block, and before tearing down the rest @@ -419,6 +412,7 @@ wait1(q, uap, compat) return (EINVAL); loop: nfound = 0; + PROCTREE_LOCK(PT_SHARED); LIST_FOREACH(p, &q->p_children, p_sibling) { if (uap->pid != WAIT_ANY && p->p_pid != uap->pid && p->p_pgid != -uap->pid) @@ -440,6 +434,7 @@ loop: mtx_enter(&sched_lock, MTX_SPIN); if (p->p_stat == SZOMB) { mtx_exit(&sched_lock, MTX_SPIN); + PROCTREE_LOCK(PT_RELEASE); /* charge childs scheduling cpu usage to parent */ if (curproc->p_pid != 1) { @@ -466,12 +461,17 @@ loop: * If we got the child via a ptrace 'attach', * we need to give it back to the old parent. */ - if (p->p_oppid && (t = pfind(p->p_oppid))) { - p->p_oppid = 0; - proc_reparent(p, t); - psignal(t, SIGCHLD); - wakeup((caddr_t)t); - return (0); + if (p->p_oppid) { + PROCTREE_LOCK(PT_EXCLUSIVE); + if ((t = pfind(p->p_oppid)) != NULL) { + p->p_oppid = 0; + proc_reparent(p, t); + psignal(t, SIGCHLD); + wakeup((caddr_t)t); + PROCTREE_LOCK(PT_RELEASE); + return (0); + } + PROCTREE_LOCK(PT_RELEASE); } p->p_xstat = 0; ruadd(&q->p_stats->p_cru, p->p_ru); @@ -519,10 +519,14 @@ loop: * Unlink it from its process group and free it. */ leavepgrp(p); + ALLPROC_LOCK(AP_EXCLUSIVE); LIST_REMOVE(p, p_list); /* off zombproc */ ALLPROC_LOCK(AP_RELEASE); + + PROCTREE_LOCK(PT_EXCLUSIVE); LIST_REMOVE(p, p_sibling); + PROCTREE_LOCK(PT_RELEASE); if (--p->p_procsig->ps_refcnt == 0) { if (p->p_sigacts != &p->p_addr->u_sigacts) @@ -545,6 +549,7 @@ loop: if (p->p_stat == SSTOP && (p->p_flag & P_WAITED) == 0 && (p->p_flag & P_TRACED || uap->options & WUNTRACED)) { mtx_exit(&sched_lock, MTX_SPIN); + PROCTREE_LOCK(PT_RELEASE); p->p_flag |= P_WAITED; q->p_retval[0] = p->p_pid; #ifdef COMPAT_43 @@ -563,6 +568,7 @@ loop: } mtx_exit(&sched_lock, MTX_SPIN); } + PROCTREE_LOCK(PT_RELEASE); if (nfound == 0) return (ECHILD); if (uap->options & WNOHANG) { @@ -575,7 +581,8 @@ loop: } /* - * make process 'parent' the new parent of process 'child'. + * Make process 'parent' the new parent of process 'child'. + * Must be called with an exclusive hold of proctree lock. */ void proc_reparent(child, parent) @@ -583,6 +590,7 @@ proc_reparent(child, parent) register struct proc *parent; { + PROCTREE_ASSERT(PT_EXCLUSIVE); if (child->p_pptr == parent) return; diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index 60171a5..1c8cb38 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -476,8 +476,10 @@ again: pptr = initproc; else pptr = p1; + PROCTREE_LOCK(PT_EXCLUSIVE); p2->p_pptr = pptr; LIST_INSERT_HEAD(&pptr->p_children, p2, p_sibling); + PROCTREE_LOCK(PT_RELEASE); LIST_INIT(&p2->p_children); LIST_INIT(&p2->p_heldmtx); LIST_INIT(&p2->p_contested); diff --git a/sys/kern/kern_kthread.c b/sys/kern/kern_kthread.c index 6d0146a..8292a8d 100644 --- a/sys/kern/kern_kthread.c +++ b/sys/kern/kern_kthread.c @@ -30,6 +30,7 @@ #include <sys/systm.h> #include <sys/proc.h> #include <sys/kthread.h> +#include <sys/lock.h> #include <sys/resourcevar.h> #include <sys/signalvar.h> #include <sys/unistd.h> @@ -113,7 +114,10 @@ kthread_create(void (*func)(void *), void *arg, void kthread_exit(int ecode) { + + PROCTREE_LOCK(PT_EXCLUSIVE); proc_reparent(curproc, initproc); + PROCTREE_LOCK(PT_RELEASE); exit1(curproc, W_EXITCODE(ecode, 0)); } diff --git a/sys/kern/kern_ktrace.c b/sys/kern/kern_ktrace.c index 59321fe..f0f187f 100644 --- a/sys/kern/kern_ktrace.c +++ b/sys/kern/kern_ktrace.c @@ -317,7 +317,6 @@ ktrace(curp, uap) ret |= ktrsetchildren(curp, p, ops, facs, vp); else ret |= ktrops(curp, p, ops, facs, vp); - } else { /* * by pid @@ -426,6 +425,7 @@ ktrsetchildren(curp, top, ops, facs, vp) register int ret = 0; p = top; + PROCTREE_LOCK(PT_SHARED); for (;;) { ret |= ktrops(curp, p, ops, facs, vp); /* @@ -436,8 +436,10 @@ ktrsetchildren(curp, top, ops, facs, vp) if (!LIST_EMPTY(&p->p_children)) p = LIST_FIRST(&p->p_children); else for (;;) { - if (p == top) + if (p == top) { + PROCTREE_LOCK(PT_RELEASE); return (ret); + } if (LIST_NEXT(p, p_sibling)) { p = LIST_NEXT(p, p_sibling); break; diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c index 814a29e..83ba993 100644 --- a/sys/kern/kern_proc.c +++ b/sys/kern/kern_proc.c @@ -73,6 +73,7 @@ u_long pgrphash; struct proclist allproc; struct proclist zombproc; struct lock allproc_lock; +struct lock proctree_lock; vm_zone_t proc_zone; vm_zone_t ithread_zone; @@ -84,6 +85,7 @@ procinit() { lockinit(&allproc_lock, PZERO, "allproc", 0, 0); + lockinit(&proctree_lock, PZERO, "proctree", 0, 0); LIST_INIT(&allproc); LIST_INIT(&zombproc); pidhashtbl = hashinit(maxproc / 4, M_PROC, &pidhash); @@ -106,11 +108,16 @@ int inferior(p) register struct proc *p; { + int rval = 1; + PROCTREE_LOCK(PT_SHARED); for (; p != curproc; p = p->p_pptr) - if (p->p_pid == 0) - return (0); - return (1); + if (p->p_pid == 0) { + rval = 0; + break; + } + PROCTREE_LOCK(PT_RELEASE); + return (rval); } /* @@ -281,6 +288,7 @@ fixjobc(p, pgrp, entering) * Check p's parent to see whether p qualifies its own process * group; if so, adjust count for p's process group. */ + PROCTREE_LOCK(PT_SHARED); if ((hispgrp = p->p_pptr->p_pgrp) != pgrp && hispgrp->pg_session == mysession) { if (entering) @@ -303,6 +311,7 @@ fixjobc(p, pgrp, entering) else if (--hispgrp->pg_jobc == 0) orphanpg(hispgrp); } + PROCTREE_LOCK(PT_RELEASE); } /* @@ -414,8 +423,10 @@ fill_kinfo_proc(p, kp) kp->ki_rtprio = p->p_rtprio; kp->ki_runtime = p->p_runtime; kp->ki_pid = p->p_pid; + PROCTREE_LOCK(PT_SHARED); if (p->p_pptr) kp->ki_ppid = p->p_pptr->p_pid; + PROCTREE_LOCK(PT_RELEASE); sp = NULL; if (p->p_pgrp) { kp->ki_pgid = p->p_pgrp->pg_id; diff --git a/sys/kern/kern_prot.c b/sys/kern/kern_prot.c index 5e11a3f..51ca919 100644 --- a/sys/kern/kern_prot.c +++ b/sys/kern/kern_prot.c @@ -50,6 +50,7 @@ #include <sys/systm.h> #include <sys/sysproto.h> #include <sys/kernel.h> +#include <sys/lock.h> #include <sys/proc.h> #include <sys/malloc.h> #include <sys/pioctl.h> @@ -65,8 +66,9 @@ struct getpid_args { #endif /* - * NOT MP SAFE due to p_pptr access + * getpid - MP SAFE */ + /* ARGSUSED */ int getpid(p, uap) @@ -76,11 +78,17 @@ getpid(p, uap) p->p_retval[0] = p->p_pid; #if defined(COMPAT_43) || defined(COMPAT_SUNOS) + PROCTREE_LOCK(PT_SHARED); p->p_retval[1] = p->p_pptr->p_pid; + PROCTREE_LOCK(PT_RELEASE); #endif return (0); } +/* + * getppid - MP SAFE + */ + #ifndef _SYS_SYSPROTO_H_ struct getppid_args { int dummy; @@ -93,7 +101,9 @@ getppid(p, uap) struct getppid_args *uap; { + PROCTREE_LOCK(PT_SHARED); p->p_retval[0] = p->p_pptr->p_pid; + PROCTREE_LOCK(PT_RELEASE); return (0); } diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index c6daeed..d52b1fc 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -1158,9 +1158,11 @@ psignal(p, sig) goto out; SIGDELSET(p->p_siglist, sig); p->p_xstat = sig; + PROCTREE_LOCK(PT_SHARED); if ((p->p_pptr->p_procsig->ps_flag & PS_NOCLDSTOP) == 0) psignal(p->p_pptr, SIGCHLD); stop(p); + PROCTREE_LOCK(PT_RELEASE); goto out; } else goto runfast; @@ -1296,14 +1298,17 @@ issignal(p) * stopped until released by the parent. */ p->p_xstat = sig; + PROCTREE_LOCK(PT_SHARED); psignal(p->p_pptr, SIGCHLD); do { stop(p); + PROCTREE_LOCK(PT_RELEASE); mtx_enter(&sched_lock, MTX_SPIN); DROP_GIANT_NOSWITCH(); mi_switch(); mtx_exit(&sched_lock, MTX_SPIN); PICKUP_GIANT(); + PROCTREE_LOCK(PT_SHARED); } while (!trace_req(p) && p->p_flag & P_TRACED); @@ -1369,9 +1374,11 @@ issignal(p) prop & SA_TTYSTOP)) break; /* == ignore */ p->p_xstat = sig; + PROCTREE_LOCK(PT_SHARED); stop(p); if ((p->p_pptr->p_procsig->ps_flag & PS_NOCLDSTOP) == 0) psignal(p->p_pptr, SIGCHLD); + PROCTREE_LOCK(PT_RELEASE); mtx_enter(&sched_lock, MTX_SPIN); DROP_GIANT_NOSWITCH(); mi_switch(); @@ -1414,13 +1421,15 @@ issignal(p) /* * Put the argument process into the stopped state and notify the parent * via wakeup. Signals are handled elsewhere. The process must not be - * on the run queue. + * on the run queue. Must be called with at least a shared hold of the + * proctree lock. */ void stop(p) register struct proc *p; { + PROCTREE_ASSERT(PT_SHARED); mtx_enter(&sched_lock, MTX_SPIN); p->p_stat = SSTOP; p->p_flag &= ~P_WAITED; diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c index 5bdeb78..f6622b3 100644 --- a/sys/kern/sys_process.c +++ b/sys/kern/sys_process.c @@ -276,8 +276,12 @@ ptrace(curp, uap) return EPERM; /* not being traced by YOU */ - if (p->p_pptr != curp) + PROCTREE_LOCK(PT_SHARED); + if (p->p_pptr != curp) { + PROCTREE_LOCK(PT_RELEASE); return EBUSY; + } + PROCTREE_LOCK(PT_RELEASE); /* not currently stopped */ mtx_enter(&sched_lock, MTX_SPIN); @@ -311,15 +315,19 @@ ptrace(curp, uap) case PT_TRACE_ME: /* set my trace flag and "owner" so it can read/write me */ p->p_flag |= P_TRACED; + PROCTREE_LOCK(PT_SHARED); p->p_oppid = p->p_pptr->p_pid; + PROCTREE_LOCK(PT_RELEASE); return 0; case PT_ATTACH: /* security check done above */ p->p_flag |= P_TRACED; + PROCTREE_LOCK(PT_EXCLUSIVE); p->p_oppid = p->p_pptr->p_pid; if (p->p_pptr != curp) proc_reparent(p, curp); + PROCTREE_LOCK(PT_RELEASE); uap->data = SIGSTOP; goto sendsig; /* in PT_CONTINUE below */ @@ -350,12 +358,14 @@ ptrace(curp, uap) if (uap->req == PT_DETACH) { /* reset process parent */ + PROCTREE_LOCK(PT_EXCLUSIVE); if (p->p_oppid != p->p_pptr->p_pid) { struct proc *pp; pp = pfind(p->p_oppid); proc_reparent(p, pp ? pp : initproc); } + PROCTREE_LOCK(PT_RELEASE); p->p_flag &= ~(P_TRACED | P_WAITED); p->p_oppid = 0; |