summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authorjake <jake@FreeBSD.org>2000-12-23 19:43:10 +0000
committerjake <jake@FreeBSD.org>2000-12-23 19:43:10 +0000
commitfa7a58ab48542df270919dc02881d5c4a2d4f344 (patch)
tree51c7f08e6064351afd60db7b45fcd14756284805 /sys/kern
parent974f411f61d6549db784519d520f6a33719e3f6c (diff)
downloadFreeBSD-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.c2
-rw-r--r--sys/kern/kern_exit.c40
-rw-r--r--sys/kern/kern_fork.c2
-rw-r--r--sys/kern/kern_kthread.c4
-rw-r--r--sys/kern/kern_ktrace.c6
-rw-r--r--sys/kern/kern_proc.c17
-rw-r--r--sys/kern/kern_prot.c12
-rw-r--r--sys/kern/kern_sig.c11
-rw-r--r--sys/kern/sys_process.c12
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;
OpenPOWER on IntegriCloud