From: Matthew Dillon Date: Mon, 14 Feb 2011 04:57:32 +0000 (-0800) Subject: kernel - Make numerous proc accesses use p->p_token instead of proc_token. X-Git-Tag: v2.11.0~267^2~79 X-Git-Url: https://gitweb.dragonflybsd.org/~tuxillo/dragonfly.git/commitdiff_plain/58c2553a79a1ecfcbfd3ab0cb8e383052af37406 kernel - Make numerous proc accesses use p->p_token instead of proc_token. * pfind() zpfind() now returns a referenced proc structure, callers must release the proc with PRELE(). Callers no longer need to hold proc_token for stable access. * Enhance pgrp, adding pgrp->pg_token and pgrp->pg_refs in addition to pgrp->pg_lock. The lock is used to interlock races between fork() and signals while the token and refs are used to control access. * Add pfindn(), a version of pfind() which does not ref the returned proc. Some code still uses it (linux emulation) ---> needs work. * Add pgref() and pgrel() to mess with the pgrp's pg_refs. pgrel() automatically destroys the pgrp when the last reference goes away. * Most process group operations now use the per-process token instead of proc_token, though pgfind() still needs it temporarily. * pgfind() now returns a referenced pgrp or NULL. * Interlock signal handling with p->p_token instead of proc_token. * Adjust most nice/priority functions to use the per-process token. * Add protective PHOLD()s in various places in the signal code, the ptrace code, and procfs. * Change funsetown() to take the address of the sigio pointer to match fsetown(), add sanity assertions. * pgrp's in tty sessions are now ref-counted. --- diff --git a/sys/dev/drm/drm_drv.c b/sys/dev/drm/drm_drv.c index 8ddd75356d..50de37beb9 100644 --- a/sys/dev/drm/drm_drv.c +++ b/sys/dev/drm/drm_drv.c @@ -672,7 +672,7 @@ int drm_close(struct dev_close_args *ap) !dev->driver->reclaim_buffers_locked) drm_reclaim_buffers(dev, file_priv); - funsetown(dev->buf_sigio); + funsetown(&dev->buf_sigio); if (dev->driver->postclose != NULL) dev->driver->postclose(dev, file_priv); diff --git a/sys/dev/misc/syscons/scmouse.c b/sys/dev/misc/syscons/scmouse.c index 6f23c8c5c0..b78b7b242e 100644 --- a/sys/dev/misc/syscons/scmouse.c +++ b/sys/dev/misc/syscons/scmouse.c @@ -573,6 +573,7 @@ sc_mouse_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag) mouse_info_t *mouse; scr_stat *cur_scp; scr_stat *scp; + struct proc *oproc; int f; scp = SC_STAT(tp->t_dev); @@ -586,15 +587,21 @@ sc_mouse_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag) switch (mouse->operation) { case MOUSE_MODE: if (ISSIGVALID(mouse->u.mode.signal)) { + oproc = scp->mouse_proc; scp->mouse_signal = mouse->u.mode.signal; scp->mouse_proc = curproc; scp->mouse_pid = curproc->p_pid; - } - else { + PHOLD(curproc); + } else { + oproc = scp->mouse_proc; scp->mouse_signal = 0; scp->mouse_proc = NULL; scp->mouse_pid = 0; } + if (oproc) { + PRELE(oproc); + oproc = NULL; + } return 0; case MOUSE_SHOW: @@ -688,10 +695,13 @@ sc_mouse_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag) if (cur_scp->mouse_signal) { /* has controlling process died? */ if (cur_scp->mouse_proc && - (cur_scp->mouse_proc != pfind(cur_scp->mouse_pid))){ + (cur_scp->mouse_proc != pfindn(cur_scp->mouse_pid))){ + oproc = cur_scp->mouse_proc; cur_scp->mouse_signal = 0; cur_scp->mouse_proc = NULL; cur_scp->mouse_pid = 0; + if (oproc) + PRELE(oproc); } else { ksignal(cur_scp->mouse_proc, cur_scp->mouse_signal); break; @@ -741,10 +751,13 @@ sc_mouse_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag) if (cur_scp->mouse_signal) { if (cur_scp->mouse_proc && - (cur_scp->mouse_proc != pfind(cur_scp->mouse_pid))){ + (cur_scp->mouse_proc != pfindn(cur_scp->mouse_pid))){ + oproc = cur_scp->mouse_proc; cur_scp->mouse_signal = 0; cur_scp->mouse_proc = NULL; cur_scp->mouse_pid = 0; + if (oproc) + PRELE(oproc); } else { ksignal(cur_scp->mouse_proc, cur_scp->mouse_signal); break; diff --git a/sys/dev/misc/syscons/syscons.c b/sys/dev/misc/syscons/syscons.c index 90b558c64c..869571630b 100644 --- a/sys/dev/misc/syscons/syscons.c +++ b/sys/dev/misc/syscons/syscons.c @@ -963,7 +963,7 @@ scioctl(struct dev_ioctl_args *ap) DPRINTF(5, ("sc%d: VT_SETMODE ", sc->unit)); if (scp->smode.mode == VT_PROCESS) { lwkt_gettoken(&proc_token); - if (scp->proc == pfind(scp->pid) && scp->proc != curproc) { + if (scp->proc == pfindn(scp->pid) && scp->proc != curproc) { DPRINTF(5, ("error EPERM\n")); lwkt_reltoken(&proc_token); lwkt_reltoken(&tty_token); @@ -2353,7 +2353,7 @@ sc_switch_scr(sc_softc_t *sc, u_int next_scr) cur_scp->proc && lwkt_trytoken(&proc_token)) { - if (cur_scp->proc != pfind(cur_scp->pid)) { + if (cur_scp->proc != pfindn(cur_scp->pid)) { /* * The controlling process has died!!. Do some clean up. * NOTE:`cur_scp->proc' and `cur_scp->smode.mode' @@ -2556,7 +2556,7 @@ vt_proc_alive(scr_stat *scp) lwkt_gettoken(&tty_token); lwkt_gettoken(&proc_token); if (scp->proc) { - if (scp->proc == pfind(scp->pid)) { + if (scp->proc == pfindn(scp->pid)) { lwkt_reltoken(&proc_token); lwkt_reltoken(&tty_token); return TRUE; diff --git a/sys/emulation/linux/i386/linprocfs/linprocfs.h b/sys/emulation/linux/i386/linprocfs/linprocfs.h index 96512299f0..488c5c2f04 100644 --- a/sys/emulation/linux/i386/linprocfs/linprocfs.h +++ b/sys/emulation/linux/i386/linprocfs/linprocfs.h @@ -128,7 +128,7 @@ struct reg; struct fpreg; struct dbreg; -#define PFIND(pid) ((pid) ? pfind(pid) : &proc0) +#define PFIND(pid) ((pid) ? pfindn(pid) : &proc0) /* pfindn() not MPSAFE XXX */ void linprocfs_init (void); void linprocfs_exit (struct thread *); diff --git a/sys/emulation/linux/i386/linprocfs/linprocfs_vnops.c b/sys/emulation/linux/i386/linprocfs/linprocfs_vnops.c index 4097a0fbc7..e385198929 100644 --- a/sys/emulation/linux/i386/linprocfs/linprocfs_vnops.c +++ b/sys/emulation/linux/i386/linprocfs/linprocfs_vnops.c @@ -228,6 +228,7 @@ linprocfs_close(struct vop_close_args *ap) * told to stop on an event, but then the requesting process * has gone away or forgotten about it. */ + p = NULL; if ((ap->a_vp->v_opencount < 2) && (p = pfind(pfs->pfs_pid)) && !(p->p_pfsflags & PF_LINGER)) { @@ -235,6 +236,8 @@ linprocfs_close(struct vop_close_args *ap) p->p_step = 0; wakeup(&p->p_step); } + if (p) + PRELE(p); break; default: break; @@ -261,8 +264,10 @@ linprocfs_ioctl(struct vop_ioctl_args *ap) return ENOTTY; } - if (p_trespass(ap->a_cred, procp->p_ucred)) - return EPERM; + if (p_trespass(ap->a_cred, procp->p_ucred)) { + error = EPERM; + goto done; + } switch (ap->a_command) { case PIOCBIS: @@ -279,7 +284,7 @@ linprocfs_ioctl(struct vop_ioctl_args *ap) #define NFLAGS (PF_ISUGID) flags = (unsigned char)*(unsigned int*)ap->a_data; if (flags & NFLAGS && (error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0))) - return error; + goto done; procp->p_pfsflags = flags; break; case PIOCGFL: @@ -301,7 +306,7 @@ linprocfs_ioctl(struct vop_ioctl_args *ap) if (procp->p_step == 0) { error = tsleep(&procp->p_stype, PCATCH, "piocwait", 0); if (error) - return error; + goto done; } psp->state = 1; /* It stopped */ psp->flags = procp->p_pfsflags; @@ -310,20 +315,29 @@ linprocfs_ioctl(struct vop_ioctl_args *ap) psp->val = procp->p_xstat; /* any extra info */ break; case PIOCCONT: /* Restart a proc */ - if (procp->p_step == 0) - return EINVAL; /* Can only start a stopped process */ + if (procp->p_step == 0) { + error = EINVAL; /* Can only start a stopped process */ + goto done; + } if ((signo = *(int*)ap->a_data) != 0) { - if (signo >= NSIG || signo <= 0) - return EINVAL; + if (signo >= NSIG || signo <= 0) { + error = EINVAL; + goto done; + } ksignal(procp, signo); } procp->p_step = 0; wakeup(&procp->p_step); break; default: - return (ENOTTY); + error = ENOTTY; + goto done; } - return 0; + error = 0; +done: + if (procp) + PRELE(procp); + return error; } /* @@ -428,7 +442,7 @@ linprocfs_getattr(struct vop_getattr_args *ap) switch (pfs->pfs_type) { case Proot: case Pself: - procp = 0; + procp = NULL; break; default: diff --git a/sys/emulation/linux/i386/linux_machdep.c b/sys/emulation/linux/i386/linux_machdep.c index 12295701e0..0c30fb5138 100644 --- a/sys/emulation/linux/i386/linux_machdep.c +++ b/sys/emulation/linux/i386/linux_machdep.c @@ -421,10 +421,10 @@ sys_linux_exit_group(struct linux_exit_group_args *args) LIST_INSERT_AFTER(e, em, threads); if ((e->flags & EMUL_DIDKILL) == 0) { e->flags |= EMUL_DIDKILL; - KKASSERT(pfind(e->proc->p_pid) == e->proc); - get_mplock(); + lwkt_gettoken(&proc_token); + KKASSERT(pfindn(e->proc->p_pid) == e->proc); ksignal(e->proc, SIGKILL); - rel_mplock(); + lwkt_reltoken(&proc_token); } } diff --git a/sys/emulation/linux/i386/linux_ptrace.c b/sys/emulation/linux/i386/linux_ptrace.c index daf28ff159..21622f70b4 100644 --- a/sys/emulation/linux/i386/linux_ptrace.c +++ b/sys/emulation/linux/i386/linux_ptrace.c @@ -266,6 +266,7 @@ sys_linux_ptrace(struct linux_ptrace_args *uap) void *addr; pid_t pid; int error, req; + struct proc *p = NULL; /* held process */ error = 0; @@ -498,5 +499,10 @@ sys_linux_ptrace(struct linux_ptrace_args *uap) break; } + /* + * Release held proces (if any) before returning. + */ + if (p) + PRELE(p); return (error); } diff --git a/sys/emulation/linux/linux_futex.c b/sys/emulation/linux/linux_futex.c index 08d2ae29e6..f67c451200 100644 --- a/sys/emulation/linux/linux_futex.c +++ b/sys/emulation/linux/linux_futex.c @@ -719,10 +719,10 @@ sys_linux_get_robust_list(struct linux_get_robust_list_args *args) if (priv_check(curthread, PRIV_CRED_SETUID) || priv_check(curthread, PRIV_CRED_SETEUID)/* || p_candebug(curproc, p) */) { + PRELE(p); return (EPERM); } - - + PRELE(p); } error = copyout(&len, args->len, sizeof(l_size_t)); diff --git a/sys/emulation/linux/linux_misc.c b/sys/emulation/linux/linux_misc.c index 40948298b6..336fb7dfe9 100644 --- a/sys/emulation/linux/linux_misc.c +++ b/sys/emulation/linux/linux_misc.c @@ -1705,6 +1705,7 @@ sys_linux_getppid(struct linux_getppid_args *args) } else { args->sysmsg_result = parent->p_pid; } + PRELE(p); out: return (0); @@ -1840,6 +1841,7 @@ sys_linux_sched_getaffinity(struct linux_sched_getaffinity_args *args) get_mplock(); if (args->pid == 0) { p = curproc; + PHOLD(p); } else { p = pfind(args->pid); if (p == NULL) { @@ -1862,6 +1864,8 @@ done: if (error == 0) args->sysmsg_iresult = sizeof(cpumask_t); #endif + if (p) + PRELE(p); return (error); } diff --git a/sys/emulation/linux/linux_signal.c b/sys/emulation/linux/linux_signal.c index 1b4ddc26b6..2f97b33eea 100644 --- a/sys/emulation/linux/linux_signal.c +++ b/sys/emulation/linux/linux_signal.c @@ -415,7 +415,6 @@ linux_do_tkill(l_int tgid, l_int pid, l_int sig) goto done2; } } - PHOLD(p); EMUL_LOCK(); em = emuldata_get(p); diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index 90b398cf76..77600751e5 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -64,6 +64,7 @@ #include #include +#include #include #include #include @@ -370,15 +371,20 @@ proc0_init(void *dummy __unused) * Create process 0 (the swapper). */ LIST_INSERT_HEAD(&allproc, p, p_list); - p->p_pgrp = &pgrp0; LIST_INSERT_HEAD(PGRPHASH(0), &pgrp0, pg_hash); LIST_INIT(&pgrp0.pg_members); + lwkt_token_init(&pgrp0.pg_token, "pgrp0"); + refcount_init(&pgrp0.pg_refs, 1); + lockinit(&pgrp0.pg_lock, "pgwt0", 0, 0); LIST_INSERT_HEAD(&pgrp0.pg_members, p, p_pglist); pgrp0.pg_session = &session0; session0.s_count = 1; session0.s_leader = p; + pgref(&pgrp0); + p->p_pgrp = &pgrp0; + p->p_sysent = &aout_sysvec; p->p_flag = P_SYSTEM; diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index 9c469a3778..f38aeaf532 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -645,26 +645,46 @@ retry: * MPSAFE */ void -funsetown(struct sigio *sigio) +funsetown(struct sigio **sigiop) { + struct pgrp *pgrp; + struct proc *p; + struct sigio *sigio; + + if ((sigio = *sigiop) != NULL) { + lwkt_gettoken(&proc_token); /* protect sigio */ + KKASSERT(sigiop == sigio->sio_myref); + sigio = *sigiop; + *sigiop = NULL; + lwkt_reltoken(&proc_token); + } if (sigio == NULL) return; - lwkt_gettoken(&proc_token); - *(sigio->sio_myref) = NULL; + if (sigio->sio_pgid < 0) { - SLIST_REMOVE(&sigio->sio_pgrp->pg_sigiolst, sigio, - sigio, sio_pgsigio); + pgrp = sigio->sio_pgrp; + sigio->sio_pgrp = NULL; + lwkt_gettoken(&pgrp->pg_token); + SLIST_REMOVE(&pgrp->pg_sigiolst, sigio, sigio, sio_pgsigio); + lwkt_reltoken(&pgrp->pg_token); + pgrel(pgrp); } else /* if ((*sigiop)->sio_pgid > 0) */ { - SLIST_REMOVE(&sigio->sio_proc->p_sigiolst, sigio, - sigio, sio_pgsigio); + p = sigio->sio_proc; + sigio->sio_proc = NULL; + PHOLD(p); + lwkt_gettoken(&p->p_token); + SLIST_REMOVE(&p->p_sigiolst, sigio, sigio, sio_pgsigio); + lwkt_reltoken(&p->p_token); + PRELE(p); } - lwkt_reltoken(&proc_token); crfree(sigio->sio_ucred); + sigio->sio_ucred = NULL; kfree(sigio, M_SIGIO); } /* - * Free a list of sigio structures. + * Free a list of sigio structures. Caller is responsible for ensuring + * that the list is MPSAFE. * * MPSAFE */ @@ -673,10 +693,8 @@ funsetownlst(struct sigiolst *sigiolst) { struct sigio *sigio; - lwkt_gettoken(&proc_token); while ((sigio = SLIST_FIRST(sigiolst)) != NULL) - funsetown(sigio); - lwkt_reltoken(&proc_token); + funsetown(sigio->sio_myref); } /* @@ -690,17 +708,16 @@ funsetownlst(struct sigiolst *sigiolst) int fsetown(pid_t pgid, struct sigio **sigiop) { - struct proc *proc; - struct pgrp *pgrp; + struct proc *proc = NULL; + struct pgrp *pgrp = NULL; struct sigio *sigio; int error; if (pgid == 0) { - funsetown(*sigiop); + funsetown(sigiop); return (0); } - lwkt_gettoken(&proc_token); if (pgid > 0) { proc = pfind(pgid); if (proc == NULL) { @@ -720,8 +737,6 @@ fsetown(pid_t pgid, struct sigio **sigiop) error = EPERM; goto done; } - - pgrp = NULL; } else /* if (pgid < 0) */ { pgrp = pgfind(-pgid); if (pgrp == NULL) { @@ -741,27 +756,39 @@ fsetown(pid_t pgid, struct sigio **sigiop) error = EPERM; goto done; } - - proc = NULL; } - funsetown(*sigiop); - sigio = kmalloc(sizeof(struct sigio), M_SIGIO, M_WAITOK); + sigio = kmalloc(sizeof(struct sigio), M_SIGIO, M_WAITOK | M_ZERO); if (pgid > 0) { + KKASSERT(pgrp == NULL); + lwkt_gettoken(&proc->p_token); SLIST_INSERT_HEAD(&proc->p_sigiolst, sigio, sio_pgsigio); sigio->sio_proc = proc; + lwkt_reltoken(&proc->p_token); } else { + KKASSERT(proc == NULL); + lwkt_gettoken(&pgrp->pg_token); SLIST_INSERT_HEAD(&pgrp->pg_sigiolst, sigio, sio_pgsigio); sigio->sio_pgrp = pgrp; + lwkt_reltoken(&pgrp->pg_token); + pgrp = NULL; } sigio->sio_pgid = pgid; sigio->sio_ucred = crhold(curthread->td_ucred); /* It would be convenient if p_ruid was in ucred. */ sigio->sio_ruid = sigio->sio_ucred->cr_ruid; sigio->sio_myref = sigiop; + + lwkt_gettoken(&proc_token); + while (*sigiop) + funsetown(sigiop); *sigiop = sigio; + lwkt_reltoken(&proc_token); error = 0; done: - lwkt_reltoken(&proc_token); + if (pgrp) + pgrel(pgrp); + if (proc) + PRELE(proc); return (error); } diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c index f50bfd36c8..6bc815801c 100644 --- a/sys/kern/kern_event.c +++ b/sys/kern/kern_event.c @@ -209,21 +209,21 @@ filt_procattach(struct knote *kn) int immediate; immediate = 0; - lwkt_gettoken(&proc_token); p = pfind(kn->kn_id); if (p == NULL && (kn->kn_sfflags & NOTE_EXIT)) { p = zpfind(kn->kn_id); immediate = 1; } if (p == NULL) { - lwkt_reltoken(&proc_token); return (ESRCH); } if (!PRISON_CHECK(curthread->td_ucred, p->p_ucred)) { - lwkt_reltoken(&proc_token); + if (p) + PRELE(p); return (EACCES); } + lwkt_gettoken(&p->p_token); kn->kn_ptr.p_proc = p; kn->kn_flags |= EV_CLEAR; /* automatically set */ @@ -245,7 +245,8 @@ filt_procattach(struct knote *kn) */ if (immediate && filt_proc(kn, NOTE_EXIT)) KNOTE_ACTIVATE(kn); - lwkt_reltoken(&proc_token); + lwkt_reltoken(&p->p_token); + PRELE(p); return (0); } @@ -1200,7 +1201,7 @@ kqueue_close(struct file *fp) kqueue_terminate(kq); fp->f_data = NULL; - funsetown(kq->kq_sigio); + funsetown(&kq->kq_sigio); kfree(kq, M_KQUEUE); return (0); diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index c6f6125bd1..e577e1dcfa 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -521,29 +521,34 @@ exit1(int rv) */ if (p->p_pptr->p_sigacts->ps_flag & PS_NOCLDWAIT) { struct proc *pp = p->p_pptr; + + PHOLD(pp); + lwkt_gettoken(&pp->p_token); proc_reparent(p, initproc); + /* * If this was the last child of our parent, notify * parent, so in case he was wait(2)ing, he will - * continue. + * continue. This function interlocks with pptr->p_token. */ if (LIST_EMPTY(&pp->p_children)) wakeup((caddr_t)pp); + lwkt_reltoken(&pp->p_token); + PRELE(pp); } /* lwkt_gettoken(&proc_token); */ q = p->p_pptr; + PHOLD(q); if (p->p_sigparent && q != initproc) { - PHOLD(q); ksignal(q, p->p_sigparent); - PRELE(q); } else { ksignal(q, SIGCHLD); } + wakeup(p->p_pptr); + PRELE(q); /* lwkt_reltoken(&proc_token); */ /* NOTE: p->p_pptr can get ripped out */ - - wakeup(p->p_pptr); /* * cpu_exit is responsible for clearing curproc, since * it is heavily integrated with the thread/switching sequence. @@ -866,12 +871,13 @@ 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))) { + if (p->p_oppid && (t = pfind(p->p_oppid)) != NULL) { p->p_oppid = 0; proc_reparent(p, t); ksignal(t, SIGCHLD); wakeup((caddr_t)t); error = 0; + PRELE(t); goto done; } @@ -948,7 +954,11 @@ loop: error = 0; goto done; } - error = tsleep((caddr_t)q, PCATCH, "wait", 0); + + /* + * Wait for signal - interlocked using q->p_token. + */ + error = tsleep(q, PCATCH, "wait", 0); if (error) { done: lwkt_reltoken(&q->p_token); diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index 89a8658da2..95153cc2ae 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -236,7 +236,8 @@ fork1(struct lwp *lp1, int flags, struct proc **procp) { struct proc *p1 = lp1->lwp_proc; struct proc *p2, *pptr; - struct pgrp *pgrp; + struct pgrp *p1grp; + struct pgrp *plkgrp; uid_t uid; int ok, error; static int curfail = 0; @@ -248,7 +249,7 @@ fork1(struct lwp *lp1, int flags, struct proc **procp) return (EINVAL); lwkt_gettoken(&p1->p_token); - pgrp = NULL; + plkgrp = NULL; /* * Here we don't create a new process, but we divorce @@ -300,8 +301,10 @@ fork1(struct lwp *lp1, int flags, struct proc **procp) * and cause the process group lock to be held indefinitely. If * a STOP occurs, the fork will be restarted after the CONT. */ - if ((flags & RFPGLOCK) && (pgrp = p1->p_pgrp) != NULL) { - lockmgr(&pgrp->pg_lock, LK_SHARED); + p1grp = p1->p_pgrp; + if ((flags & RFPGLOCK) && (plkgrp = p1->p_pgrp) != NULL) { + pgref(plkgrp); + lockmgr(&plkgrp->pg_lock, LK_SHARED); if (CURSIG_NOBLOCK(lp1)) { error = ERESTART; goto done; @@ -483,7 +486,10 @@ fork1(struct lwp *lp1, int flags, struct proc **procp) * race a ^C being sent to the process group by not receiving it * at all prior to this line. */ + pgref(p1grp); + lwkt_gettoken(&p1grp->pg_token); LIST_INSERT_AFTER(p1, p2, p_pglist); + lwkt_reltoken(&p1grp->pg_token); /* * Attach the new process to its parent. @@ -578,8 +584,10 @@ fork1(struct lwp *lp1, int flags, struct proc **procp) error = 0; done: lwkt_reltoken(&p1->p_token); - if (pgrp) - lockmgr(&pgrp->pg_lock, LK_RELEASE); + if (plkgrp) { + lockmgr(&plkgrp->pg_lock, LK_RELEASE); + pgrel(plkgrp); + } return (error); } diff --git a/sys/kern/kern_ktrace.c b/sys/kern/kern_ktrace.c index d159143458..3f63bbd28f 100644 --- a/sys/kern/kern_ktrace.c +++ b/sys/kern/kern_ktrace.c @@ -299,19 +299,25 @@ sys_ktrace(struct ktrace_args *uap) */ if (uap->pid < 0) { /* - * by process group + * By process group. Process group is referenced, preventing + * disposal. */ pg = pgfind(-uap->pid); if (pg == NULL) { error = ESRCH; goto done; } + lwkt_gettoken(&pg->pg_token); LIST_FOREACH(p, &pg->pg_members, p_pglist) { + PHOLD(p); if (descend) ret |= ktrsetchildren(td, p, ops, facs, tracenode); else ret |= ktrops(td, p, ops, facs, tracenode); + PRELE(p); } + lwkt_reltoken(&pg->pg_token); + pgrel(pg); } else { /* * by pid @@ -325,6 +331,7 @@ sys_ktrace(struct ktrace_args *uap) ret |= ktrsetchildren(td, p, ops, facs, tracenode); else ret |= ktrops(td, p, ops, facs, tracenode); + PRELE(p); } if (!ret) error = EPERM; diff --git a/sys/kern/kern_p1003_1b.c b/sys/kern/kern_p1003_1b.c index bf4acbeeab..75d80141b2 100644 --- a/sys/kern/kern_p1003_1b.c +++ b/sys/kern/kern_p1003_1b.c @@ -90,22 +90,26 @@ int p31b_proc(struct proc *p, pid_t pid, struct proc **pp) int ret = 0; struct proc *other_proc = 0; - if (pid == 0) + if (pid == 0) { other_proc = p; - else + if (other_proc) + PHOLD(other_proc); + } else { other_proc = pfind(pid); + /* ref from pfind() */ + } - if (other_proc) - { + if (other_proc) { /* Enforce permission policy. */ if (CAN_AFFECT(p, p->p_ucred, other_proc)) *pp = other_proc; else ret = EPERM; - } - else + PRELE(other_proc); + } else { ret = ESRCH; + } return ret; } diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c index 62bc4884a7..71b2d0bf34 100644 --- a/sys/kern/kern_proc.c +++ b/sys/kern/kern_proc.c @@ -56,6 +56,7 @@ #include #include +#include #include #include @@ -161,12 +162,10 @@ inferior(struct proc *p) } /* - * Locate a process by number - * - * XXX TODO - change API to PHOLD() the returned process ? + * Locate a process by number. The returned process will be referenced and + * must be released with PRELE(). * * No requirements. - * The caller must hold proc_token if the caller wishes a stable result. */ struct proc * pfind(pid_t pid) @@ -176,6 +175,7 @@ pfind(pid_t pid) lwkt_gettoken(&proc_token); LIST_FOREACH(p, PIDHASH(pid), p_hash) { if (p->p_pid == pid) { + PHOLD(p); lwkt_reltoken(&proc_token); return (p); } @@ -185,10 +185,46 @@ pfind(pid_t pid) } /* - * Locate a process group by number + * Locate a process by number. The returned process is NOT referenced. + * The caller should hold proc_token if the caller wishes a stable result. + * + * No requirements. + */ +struct proc * +pfindn(pid_t pid) +{ + struct proc *p; + + lwkt_gettoken(&proc_token); + LIST_FOREACH(p, PIDHASH(pid), p_hash) { + if (p->p_pid == pid) { + lwkt_reltoken(&proc_token); + return (p); + } + } + lwkt_reltoken(&proc_token); + return (NULL); +} + +void +pgref(struct pgrp *pgrp) +{ + refcount_acquire(&pgrp->pg_refs); +} + +void +pgrel(struct pgrp *pgrp) +{ + if (refcount_release(&pgrp->pg_refs)) + pgdelete(pgrp); +} + +/* + * Locate a process group by number. The returned process group will be + * referenced w/pgref() and must be released with pgrel() (or assigned + * somewhere if you wish to keep the reference). * * No requirements. - * The caller must hold proc_token if the caller wishes a stable result. */ struct pgrp * pgfind(pid_t pgid) @@ -198,6 +234,7 @@ pgfind(pid_t pgid) lwkt_gettoken(&proc_token); LIST_FOREACH(pgrp, PGRPHASH(pgid), pg_hash) { if (pgrp->pg_id == pgid) { + refcount_acquire(&pgrp->pg_refs); lwkt_reltoken(&proc_token); return (pgrp); } @@ -215,9 +252,9 @@ int enterpgrp(struct proc *p, pid_t pgid, int mksess) { struct pgrp *pgrp; + struct pgrp *opgrp; int error; - lwkt_gettoken(&proc_token); pgrp = pgfind(pgid); KASSERT(pgrp == NULL || !mksess, @@ -233,7 +270,7 @@ enterpgrp(struct proc *p, pid_t pgid, int mksess) */ KASSERT(p->p_pid == pgid, ("enterpgrp: new pgrp and pid != pgid")); - if ((np = pfind(savepid)) == NULL || np != p) { + if ((np = pfindn(savepid)) == NULL || np != p) { error = ESRCH; goto fatal; } @@ -267,28 +304,38 @@ enterpgrp(struct proc *p, pid_t pgid, int mksess) LIST_INSERT_HEAD(PGRPHASH(pgid), pgrp, pg_hash); pgrp->pg_jobc = 0; SLIST_INIT(&pgrp->pg_sigiolst); + lwkt_token_init(&pgrp->pg_token, "pgrp_token"); + refcount_init(&pgrp->pg_refs, 1); lockinit(&pgrp->pg_lock, "pgwt", 0, 0); } else if (pgrp == p->p_pgrp) { + pgrel(pgrp); goto done; - } + } /* else pgfind() referenced the pgrp */ /* * Adjust eligibility of affected pgrps to participate in job control. * Increment eligibility counts before decrementing, otherwise we * could reach 0 spuriously during the first call. */ + lwkt_gettoken(&pgrp->pg_token); + lwkt_gettoken(&p->p_token); fixjobc(p, pgrp, 1); fixjobc(p, p->p_pgrp, 0); - - LIST_REMOVE(p, p_pglist); - if (LIST_EMPTY(&p->p_pgrp->pg_members)) - pgdelete(p->p_pgrp); + while ((opgrp = p->p_pgrp) != NULL) { + opgrp = p->p_pgrp; + lwkt_gettoken(&opgrp->pg_token); + LIST_REMOVE(p, p_pglist); + p->p_pgrp = NULL; + lwkt_reltoken(&opgrp->pg_token); + pgrel(opgrp); + } p->p_pgrp = pgrp; LIST_INSERT_HEAD(&pgrp->pg_members, p, p_pglist); + lwkt_reltoken(&p->p_token); + lwkt_reltoken(&pgrp->pg_token); done: error = 0; fatal: - lwkt_reltoken(&proc_token); return (error); } @@ -300,19 +347,30 @@ fatal: int leavepgrp(struct proc *p) { - lwkt_gettoken(&proc_token); - LIST_REMOVE(p, p_pglist); - if (LIST_EMPTY(&p->p_pgrp->pg_members)) - pgdelete(p->p_pgrp); - p->p_pgrp = NULL; - lwkt_reltoken(&proc_token); + struct pgrp *pg = p->p_pgrp; + + lwkt_gettoken(&p->p_token); + pg = p->p_pgrp; + if (pg) { + pgref(pg); + lwkt_gettoken(&pg->pg_token); + if (p->p_pgrp == pg) { + p->p_pgrp = NULL; + LIST_REMOVE(p, p_pglist); + pgrel(pg); + } + lwkt_reltoken(&pg->pg_token); + lwkt_reltoken(&p->p_token); /* avoid chaining on rel */ + pgrel(pg); + } else { + lwkt_reltoken(&p->p_token); + } return (0); } /* - * Delete a process group - * - * The caller must hold proc_token. + * Delete a process group. Must be called only after the last ref has been + * released. */ static void pgdelete(struct pgrp *pgrp) @@ -400,8 +458,8 @@ fixjobc(struct proc *p, struct pgrp *pgrp, int entering) * Check p's parent to see whether p qualifies its own process * group; if so, adjust count for p's process group. */ - lwkt_gettoken(&proc_token); lwkt_gettoken(&p->p_token); /* p_children scan */ + lwkt_gettoken(&pgrp->pg_token); mysession = pgrp->pg_session; if ((hispgrp = p->p_pptr->p_pgrp) != pgrp && @@ -418,17 +476,26 @@ fixjobc(struct proc *p, struct pgrp *pgrp, int entering) * process groups. */ LIST_FOREACH(np, &p->p_children, p_sibling) { + PHOLD(np); + lwkt_gettoken(&np->p_token); if ((hispgrp = np->p_pgrp) != pgrp && hispgrp->pg_session == mysession && np->p_stat != SZOMB) { + pgref(hispgrp); + lwkt_gettoken(&hispgrp->pg_token); if (entering) hispgrp->pg_jobc++; else if (--hispgrp->pg_jobc == 0) orphanpg(hispgrp); + lwkt_reltoken(&hispgrp->pg_token); + pgrel(hispgrp); } + lwkt_reltoken(&np->p_token); + PRELE(np); } + KKASSERT(pgrp->pg_refs > 0); + lwkt_reltoken(&pgrp->pg_token); lwkt_reltoken(&p->p_token); - lwkt_reltoken(&proc_token); } /* @@ -436,7 +503,7 @@ fixjobc(struct proc *p, struct pgrp *pgrp, int entering) * if there are any stopped processes in the group, * hang-up all process in that group. * - * The caller must hold proc_token. + * The caller must hold pg_token. */ static void orphanpg(struct pgrp *pg) @@ -700,8 +767,9 @@ DB_SHOW_COMMAND(pgrpdump, pgrpdump) /* * Locate a process on the zombie list. Return a process or NULL. + * The returned process will be referenced and the caller must release + * it with PRELE(). * - * The caller must hold proc_token if a stable result is desired. * No other requirements. */ struct proc * @@ -712,6 +780,7 @@ zpfind(pid_t pid) lwkt_gettoken(&proc_token); LIST_FOREACH(p, &zombproc, p_list) { if (p->p_pid == pid) { + PHOLD(p); lwkt_reltoken(&proc_token); return (p); } @@ -797,7 +866,7 @@ sysctl_kern_proc(SYSCTL_HANDLER_ARGS) lwkt_gettoken(&proc_token); if (oid == KERN_PROC_PID) { - p = pfind((pid_t)name[0]); + p = pfindn((pid_t)name[0]); if (p == NULL) goto post_threads; if (!PRISON_CHECK(cr1, p->p_ucred)) @@ -941,7 +1010,7 @@ sysctl_kern_proc_args(SYSCTL_HANDLER_ARGS) return (EINVAL); lwkt_gettoken(&proc_token); - p = pfind((pid_t)name[0]); + p = pfindn((pid_t)name[0]); if (p == NULL) goto done; @@ -1001,7 +1070,7 @@ sysctl_kern_proc_cwd(SYSCTL_HANDLER_ARGS) return (EINVAL); lwkt_gettoken(&proc_token); - p = pfind((pid_t)name[0]); + p = pfindn((pid_t)name[0]); if (p == NULL) goto done; diff --git a/sys/kern/kern_prot.c b/sys/kern/kern_prot.c index 3811f19bc3..a48ca4fd77 100644 --- a/sys/kern/kern_prot.c +++ b/sys/kern/kern_prot.c @@ -128,19 +128,21 @@ sys_getpgid(struct getpgid_args *uap) struct proc *pt; int error; - lwkt_gettoken(&proc_token); error = 0; if (uap->pid == 0) { pt = p; + PHOLD(pt); } else { pt = pfind(uap->pid); if (pt == NULL) error = ESRCH; } + /* XXX MPSAFE on pgrp? */ if (error == 0) uap->sysmsg_result = pt->p_pgrp->pg_id; - lwkt_reltoken(&proc_token); + if (pt) + PRELE(pt); return (error); } @@ -154,11 +156,11 @@ sys_getsid(struct getsid_args *uap) struct proc *pt; int error; - lwkt_gettoken(&proc_token); error = 0; if (uap->pid == 0) { pt = p; + PHOLD(pt); } else { pt = pfind(uap->pid); if (pt == NULL) @@ -166,7 +168,8 @@ sys_getsid(struct getsid_args *uap) } if (error == 0) uap->sysmsg_result = pt->p_session->s_sid; - lwkt_reltoken(&proc_token); + if (pt) + PRELE(pt); return (error); } @@ -264,17 +267,20 @@ int sys_setsid(struct setsid_args *uap) { struct proc *p = curproc; + struct pgrp *pg = NULL; int error; - lwkt_gettoken(&proc_token); - if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) { + lwkt_gettoken(&p->p_token); + if (p->p_pgid == p->p_pid || (pg = pgfind(p->p_pid)) != NULL) { error = EPERM; + if (pg) + pgrel(pg); } else { enterpgrp(p, p->p_pid, 1); uap->sysmsg_result = p->p_pid; error = 0; } - lwkt_reltoken(&proc_token); + lwkt_reltoken(&p->p_token); return (error); } @@ -296,18 +302,23 @@ sys_setpgid(struct setpgid_args *uap) { struct proc *curp = curproc; struct proc *targp; /* target process */ - struct pgrp *pgrp; /* target pgrp */ + struct pgrp *pgrp = NULL; /* target pgrp */ int error; if (uap->pgid < 0) return (EINVAL); - lwkt_gettoken(&proc_token); if (uap->pid != 0 && uap->pid != curp->p_pid) { - if ((targp = pfind(uap->pid)) == 0 || !inferior(targp)) { + if ((targp = pfind(uap->pid)) == NULL || !inferior(targp)) { + if (targp) + PRELE(targp); error = ESRCH; + targp = NULL; goto done; } + lwkt_gettoken(&targp->p_token); + /* targp now referenced and its token is held */ + if (targp->p_pgrp == NULL || targp->p_session != curp->p_session) { error = EPERM; @@ -319,6 +330,8 @@ sys_setpgid(struct setpgid_args *uap) } } else { targp = curp; + PHOLD(targp); + lwkt_gettoken(&targp->p_token); } if (SESS_LEADER(targp)) { error = EPERM; @@ -327,7 +340,7 @@ sys_setpgid(struct setpgid_args *uap) if (uap->pgid == 0) { uap->pgid = targp->p_pid; } else if (uap->pgid != targp->p_pid) { - if ((pgrp = pgfind(uap->pgid)) == 0 || + if ((pgrp = pgfind(uap->pgid)) == NULL || pgrp->pg_session != curp->p_session) { error = EPERM; goto done; @@ -335,7 +348,12 @@ sys_setpgid(struct setpgid_args *uap) } error = enterpgrp(targp, uap->pgid, 0); done: - lwkt_reltoken(&proc_token); + if (pgrp) + pgrel(pgrp); + if (targp) { + lwkt_reltoken(&targp->p_token); + PRELE(targp); + } return (error); } diff --git a/sys/kern/kern_resource.c b/sys/kern/kern_resource.c index 1f6c0d58f9..afee45fa82 100644 --- a/sys/kern/kern_resource.c +++ b/sys/kern/kern_resource.c @@ -63,7 +63,6 @@ #include #include -#include static int donice (struct proc *chgp, int n); static int doionice (struct proc *chgp, int n); @@ -100,33 +99,40 @@ sys_getpriority(struct getpriority_args *uap) int low = PRIO_MAX + 1; int error; - get_mplock(); - switch (uap->which) { case PRIO_PROCESS: - if (uap->who == 0) + if (uap->who == 0) { p = curp; - else + PHOLD(p); + } else { p = pfind(uap->who); - if (p == 0) - break; - if (!PRISON_CHECK(curp->p_ucred, p->p_ucred)) - break; - low = p->p_nice; + } + if (p) { + if (PRISON_CHECK(curp->p_ucred, p->p_ucred)) { + low = p->p_nice; + } + PRELE(p); + } break; case PRIO_PGRP: { struct pgrp *pg; - if (uap->who == 0) + if (uap->who == 0) { pg = curp->p_pgrp; - else if ((pg = pgfind(uap->who)) == NULL) + pgref(pg); + } else if ((pg = pgfind(uap->who)) == NULL) { break; + } /* else ref held from pgfind */ + LIST_FOREACH(p, &pg->pg_members, p_pglist) { - if ((PRISON_CHECK(curp->p_ucred, p->p_ucred) && p->p_nice < low)) + if (PRISON_CHECK(curp->p_ucred, p->p_ucred) && + p->p_nice < low) { low = p->p_nice; + } } + pgrel(pg); break; } case PRIO_USER: @@ -149,7 +155,6 @@ sys_getpriority(struct getpriority_args *uap) uap->sysmsg_result = low; error = 0; done: - rel_mplock(); return (error); } @@ -191,36 +196,43 @@ sys_setpriority(struct setpriority_args *uap) struct proc *p; int found = 0, error = 0; - get_mplock(); + lwkt_gettoken(&proc_token); switch (uap->which) { case PRIO_PROCESS: - if (uap->who == 0) + if (uap->who == 0) { p = curp; - else + PHOLD(p); + } else { p = pfind(uap->who); - if (p == 0) - break; - if (!PRISON_CHECK(curp->p_ucred, p->p_ucred)) - break; - error = donice(p, uap->prio); - found++; + } + if (p) { + if (PRISON_CHECK(curp->p_ucred, p->p_ucred)) { + error = donice(p, uap->prio); + found++; + } + PRELE(p); + } break; case PRIO_PGRP: { struct pgrp *pg; - if (uap->who == 0) + if (uap->who == 0) { pg = curp->p_pgrp; - else if ((pg = pgfind(uap->who)) == NULL) + pgref(pg); + } else if ((pg = pgfind(uap->who)) == NULL) { break; + } /* else ref held from pgfind */ + LIST_FOREACH(p, &pg->pg_members, p_pglist) { if (PRISON_CHECK(curp->p_ucred, p->p_ucred)) { error = donice(p, uap->prio); found++; } } + pgrel(pg); break; } case PRIO_USER: @@ -241,7 +253,8 @@ sys_setpriority(struct setpriority_args *uap) break; } - rel_mplock(); + lwkt_reltoken(&proc_token); + if (found == 0) error = ESRCH; return (error); @@ -307,33 +320,40 @@ sys_ioprio_get(struct ioprio_get_args *uap) int high = IOPRIO_MIN-2; int error; - get_mplock(); + lwkt_gettoken(&proc_token); switch (uap->which) { case PRIO_PROCESS: - if (uap->who == 0) + if (uap->who == 0) { p = curp; - else + PHOLD(p); + } else { p = pfind(uap->who); - if (p == 0) - break; - if (!PRISON_CHECK(curp->p_ucred, p->p_ucred)) - break; - high = p->p_ionice; + } + if (p) { + if (PRISON_CHECK(curp->p_ucred, p->p_ucred)) + high = p->p_ionice; + PRELE(p); + } break; case PRIO_PGRP: { struct pgrp *pg; - if (uap->who == 0) + if (uap->who == 0) { pg = curp->p_pgrp; - else if ((pg = pgfind(uap->who)) == NULL) + pgref(pg); + } else if ((pg = pgfind(uap->who)) == NULL) { break; + } /* else ref held from pgfind */ + LIST_FOREACH(p, &pg->pg_members, p_pglist) { - if ((PRISON_CHECK(curp->p_ucred, p->p_ucred) && p->p_nice > high)) + if (PRISON_CHECK(curp->p_ucred, p->p_ucred) && + p->p_nice > high) high = p->p_ionice; } + pgrel(pg); break; } case PRIO_USER: @@ -356,7 +376,8 @@ sys_ioprio_get(struct ioprio_get_args *uap) uap->sysmsg_result = high; error = 0; done: - rel_mplock(); + lwkt_reltoken(&proc_token); + return (error); } @@ -399,36 +420,43 @@ sys_ioprio_set(struct ioprio_set_args *uap) struct proc *p; int found = 0, error = 0; - get_mplock(); + lwkt_gettoken(&proc_token); switch (uap->which) { case PRIO_PROCESS: - if (uap->who == 0) + if (uap->who == 0) { p = curp; - else + PHOLD(p); + } else { p = pfind(uap->who); - if (p == 0) - break; - if (!PRISON_CHECK(curp->p_ucred, p->p_ucred)) - break; - error = doionice(p, uap->prio); - found++; + } + if (p) { + if (PRISON_CHECK(curp->p_ucred, p->p_ucred)) { + error = doionice(p, uap->prio); + found++; + } + PRELE(p); + } break; case PRIO_PGRP: { struct pgrp *pg; - if (uap->who == 0) + if (uap->who == 0) { pg = curp->p_pgrp; - else if ((pg = pgfind(uap->who)) == NULL) + pgref(pg); + } else if ((pg = pgfind(uap->who)) == NULL) { break; + } /* else ref held from pgfind */ + LIST_FOREACH(p, &pg->pg_members, p_pglist) { if (PRISON_CHECK(curp->p_ucred, p->p_ucred)) { error = doionice(p, uap->prio); found++; } } + pgrel(pg); break; } case PRIO_USER: @@ -449,7 +477,8 @@ sys_ioprio_set(struct ioprio_set_args *uap) break; } - rel_mplock(); + lwkt_reltoken(&proc_token); + if (found == 0) error = ESRCH; return (error); @@ -500,7 +529,7 @@ doionice(struct proc *chgp, int n) int sys_lwp_rtprio(struct lwp_rtprio_args *uap) { - struct proc *p = curproc; + struct proc *p; struct lwp *lp; struct rtprio rtp; struct ucred *cr = curthread->td_ucred; @@ -512,9 +541,11 @@ sys_lwp_rtprio(struct lwp_rtprio_args *uap) if (uap->pid < 0) return EINVAL; - get_mplock(); + lwkt_gettoken(&proc_token); + if (uap->pid == 0) { - /* curproc already loaded on p */ + p = curproc; + PHOLD(p); } else { p = pfind(uap->pid); } @@ -599,7 +630,10 @@ sys_lwp_rtprio(struct lwp_rtprio_args *uap) } done: - rel_mplock(); + if (p) + PRELE(p); + lwkt_reltoken(&proc_token); + return (error); } @@ -611,7 +645,6 @@ done: int sys_rtprio(struct rtprio_args *uap) { - struct proc *curp = curproc; struct proc *p; struct lwp *lp; struct ucred *cr = curthread->td_ucred; @@ -622,11 +655,14 @@ sys_rtprio(struct rtprio_args *uap) if (error) return (error); - get_mplock(); - if (uap->pid == 0) - p = curp; - else + lwkt_gettoken(&proc_token); + + if (uap->pid == 0) { + p = curproc; + PHOLD(p); + } else { p = pfind(uap->pid); + } if (p == NULL) { error = ESRCH; @@ -691,7 +727,10 @@ sys_rtprio(struct rtprio_args *uap) break; } done: - rel_mplock(); + if (p) + PRELE(p); + lwkt_reltoken(&proc_token); + return (error); } @@ -805,7 +844,7 @@ sys_getrusage(struct getrusage_args *uap) struct rusage *rup; int error; - get_mplock(); + lwkt_gettoken(&proc_token); switch (uap->who) { case RUSAGE_SELF: @@ -823,7 +862,7 @@ sys_getrusage(struct getrusage_args *uap) } if (error == 0) error = copyout(rup, uap->rusage, sizeof(struct rusage)); - rel_mplock(); + lwkt_reltoken(&proc_token); return (error); } diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index 61f21fe809..0e241a59e1 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -692,11 +692,16 @@ dokillpg(int sig, int pgid, int all) * zero pgid means send to my process group. */ pgrp = cp->p_pgrp; + pgref(pgrp); } else { pgrp = pgfind(pgid); if (pgrp == NULL) return (ESRCH); } + + /* + * Must interlock all signals against fork + */ lockmgr(&pgrp->pg_lock, LK_EXCLUSIVE); LIST_FOREACH(p, &pgrp->pg_members, p_pglist) { if (p->p_pid <= 1 || @@ -710,6 +715,7 @@ dokillpg(int sig, int pgid, int all) ksignal(p, sig); } lockmgr(&pgrp->pg_lock, LK_RELEASE); + pgrel(pgrp); } return (info.nfound ? 0 : ESRCH); } @@ -754,7 +760,6 @@ kern_kill(int sig, pid_t pid, lwpid_t tid) lwkt_reltoken(&proc_token); return (ESRCH); } - PHOLD(p); lwkt_gettoken(&p->p_token); if (!CANSIGNAL(p, sig)) { lwkt_reltoken(&p->p_token); @@ -871,13 +876,18 @@ pgsignal(struct pgrp *pgrp, int sig, int checkctty) { struct proc *p; + /* + * Must interlock all signals against fork + */ if (pgrp) { + pgref(pgrp); lockmgr(&pgrp->pg_lock, LK_EXCLUSIVE); LIST_FOREACH(p, &pgrp->pg_members, p_pglist) { if (checkctty == 0 || p->p_flag & P_CONTROLT) ksignal(p, sig); } lockmgr(&pgrp->pg_lock, LK_RELEASE); + pgrel(pgrp); } } @@ -937,9 +947,10 @@ trapsignal(struct lwp *lp, int sig, u_long code) } /* - * Find a suitable lwp to deliver the signal to. + * Find a suitable lwp to deliver the signal to. Returns NULL if all + * lwps hold the signal blocked. * - * Returns NULL if all lwps hold the signal blocked. + * Caller must hold p->p_token. */ static struct lwp * find_lwp_for_signal(struct proc *p, int sig) @@ -955,8 +966,10 @@ find_lwp_for_signal(struct proc *p, int sig) * soon anyways. */ lp = lwkt_preempted_proc(); - if (lp != NULL && lp->lwp_proc == p && !SIGISMEMBER(lp->lwp_sigmask, sig)) + if (lp != NULL && lp->lwp_proc == p && + !SIGISMEMBER(lp->lwp_sigmask, sig)) { return (lp); + } run = sleep = stop = NULL; FOREACH_LWP_IN_PROC(lp, p) { @@ -1037,6 +1050,7 @@ lwpsignal(struct proc *p, struct lwp *lp, int sig) KKASSERT(lp == NULL || lp->lwp_proc == p); + PHOLD(p); lwkt_gettoken(&p->p_token); prop = sigprop(sig); @@ -1056,6 +1070,7 @@ lwpsignal(struct proc *p, struct lwp *lp, int sig) */ if (lp && (lp->lwp_flag & LWP_WEXIT)) { lwkt_reltoken(&p->p_token); + PRELE(p); return; } @@ -1066,6 +1081,7 @@ lwpsignal(struct proc *p, struct lwp *lp, int sig) */ if (SIGISMEMBER(p->p_sigignore, sig)) { lwkt_reltoken(&p->p_token); + PRELE(p); return; } if (SIGISMEMBER(p->p_sigcatch, sig)) @@ -1090,6 +1106,7 @@ lwpsignal(struct proc *p, struct lwp *lp, int sig) if (prop & SA_TTYSTOP && p->p_pgrp->pg_jobc == 0 && action == SIG_DFL) { lwkt_reltoken(&p->p_token); + PRELE(p); return; } SIG_CONTSIGMASK(p->p_siglist); @@ -1252,6 +1269,7 @@ active_process: out: lwkt_reltoken(&p->p_token); + PRELE(p); crit_exit(); } @@ -2268,14 +2286,20 @@ pgsigio(struct sigio *sigio, int sig, int checkctty) ksignal(sigio->sio_proc, sig); } else if (sigio->sio_pgid < 0) { struct proc *p; + struct pgrp *pg = sigio->sio_pgrp; - lockmgr(&sigio->sio_pgrp->pg_lock, LK_EXCLUSIVE); - LIST_FOREACH(p, &sigio->sio_pgrp->pg_members, p_pglist) { + /* + * Must interlock all signals against fork + */ + pgref(pg); + lockmgr(&pg->pg_lock, LK_EXCLUSIVE); + LIST_FOREACH(p, &pg->pg_members, p_pglist) { if (CANSIGIO(sigio->sio_ruid, sigio->sio_ucred, p) && (checkctty == 0 || (p->p_flag & P_CONTROLT))) ksignal(p, sig); } - lockmgr(&sigio->sio_pgrp->pg_lock, LK_RELEASE); + lockmgr(&pg->pg_lock, LK_RELEASE); + pgrel(pg); } } diff --git a/sys/kern/subr_log.c b/sys/kern/subr_log.c index f8d73ade9a..755a33d613 100644 --- a/sys/kern/subr_log.c +++ b/sys/kern/subr_log.c @@ -115,7 +115,7 @@ logclose(struct dev_close_args *ap) log_open = 0; callout_stop(&logsoftc.sc_callout); logsoftc.sc_state = 0; - funsetown(logsoftc.sc_sigio); + funsetown(&logsoftc.sc_sigio); return (0); } diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c index 6e425dec6c..5f14a90e12 100644 --- a/sys/kern/sys_pipe.c +++ b/sys/kern/sys_pipe.c @@ -1018,7 +1018,7 @@ pipe_close(struct file *fp) cpipe = (struct pipe *)fp->f_data; fp->f_ops = &badfileops; fp->f_data = NULL; - funsetown(cpipe->pipe_sigio); + funsetown(&cpipe->pipe_sigio); pipeclose(cpipe); return (0); } diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c index 9673903854..bfb1c8e195 100644 --- a/sys/kern/sys_process.c +++ b/sys/kern/sys_process.c @@ -292,6 +292,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr, write = 0; if (req == PT_TRACE_ME) { p = curp; + PHOLD(p); } else { if ((p = pfind(pid)) == NULL) { lwkt_reltoken(&proc_token); @@ -299,6 +300,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr, } } if (!PRISON_CHECK(curp->p_ucred, p->p_ucred)) { + PRELE(p); lwkt_reltoken(&proc_token); return (ESRCH); } @@ -307,6 +309,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr, /* Can't trace a process that's currently exec'ing. */ if ((p->p_flag & P_INEXEC) != 0) { lwkt_reltoken(&p->p_token); + PRELE(p); lwkt_reltoken(&proc_token); return EAGAIN; } @@ -323,6 +326,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr, /* Self */ if (p->p_pid == curp->p_pid) { lwkt_reltoken(&p->p_token); + PRELE(p); lwkt_reltoken(&proc_token); return EINVAL; } @@ -330,6 +334,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr, /* Already traced */ if (p->p_flag & P_TRACED) { lwkt_reltoken(&p->p_token); + PRELE(p); lwkt_reltoken(&proc_token); return EBUSY; } @@ -338,6 +343,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr, for (pp = curp->p_pptr; pp != NULL; pp = pp->p_pptr) if (pp == p) { lwkt_reltoken(&p->p_token); + PRELE(p); lwkt_reltoken(&proc_token); return (EINVAL); } @@ -347,6 +353,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr, (p->p_flag & P_SUGID)) { if ((error = priv_check_cred(curp->p_ucred, PRIV_ROOT, 0)) != 0) { lwkt_reltoken(&p->p_token); + PRELE(p); lwkt_reltoken(&proc_token); return error; } @@ -355,6 +362,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr, /* can't trace init when securelevel > 0 */ if (securelevel > 0 && p->p_pid == 1) { lwkt_reltoken(&p->p_token); + PRELE(p); lwkt_reltoken(&proc_token); return EPERM; } @@ -392,6 +400,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr, /* not being traced... */ if ((p->p_flag & P_TRACED) == 0) { lwkt_reltoken(&p->p_token); + PRELE(p); lwkt_reltoken(&proc_token); return EPERM; } @@ -399,6 +408,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr, /* not being traced by YOU */ if (p->p_pptr != curp) { lwkt_reltoken(&p->p_token); + PRELE(p); lwkt_reltoken(&proc_token); return EBUSY; } @@ -407,6 +417,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr, if (p->p_stat != SSTOP || (p->p_flag & P_WAITED) == 0) { lwkt_reltoken(&p->p_token); + PRELE(p); lwkt_reltoken(&proc_token); return EBUSY; } @@ -416,6 +427,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr, default: lwkt_reltoken(&p->p_token); + PRELE(p); lwkt_reltoken(&proc_token); return EINVAL; } @@ -441,6 +453,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr, p->p_flag |= P_TRACED; p->p_oppid = p->p_pptr->p_pid; lwkt_reltoken(&p->p_token); + PRELE(p); lwkt_reltoken(&proc_token); return 0; @@ -459,6 +472,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr, /* Zero means do not send any signal */ if (data < 0 || data > _SIG_MAXSIG) { lwkt_reltoken(&p->p_token); + PRELE(p); lwkt_reltoken(&proc_token); return EINVAL; } @@ -469,6 +483,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr, if ((error = ptrace_single_step (lp))) { LWPRELE(lp); lwkt_reltoken(&p->p_token); + PRELE(p); lwkt_reltoken(&proc_token); return error; } @@ -479,6 +494,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr, (u_long)(uintfptr_t)addr))) { LWPRELE(lp); lwkt_reltoken(&p->p_token); + PRELE(p); lwkt_reltoken(&proc_token); return error; } @@ -515,6 +531,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr, } crit_exit(); lwkt_reltoken(&p->p_token); + PRELE(p); lwkt_reltoken(&proc_token); return 0; @@ -559,6 +576,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr, if (!write) *res = tmp; lwkt_reltoken(&p->p_token); + PRELE(p); lwkt_reltoken(&proc_token); return (error); @@ -589,12 +607,14 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr, break; default: lwkt_reltoken(&p->p_token); + PRELE(p); lwkt_reltoken(&proc_token); return (EINVAL); } error = procfs_domem(curp, lp, NULL, &uio); piod->piod_len -= uio.uio_resid; lwkt_reltoken(&p->p_token); + PRELE(p); lwkt_reltoken(&proc_token); return (error); @@ -614,6 +634,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr, #if defined(PT_SETREGS) || defined(PT_GETREGS) if (!procfs_validregs(lp)) { /* no P_SYSTEM procs please */ lwkt_reltoken(&p->p_token); + PRELE(p); lwkt_reltoken(&proc_token); return EINVAL; } else { @@ -628,6 +649,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr, uio.uio_td = curthread; t = procfs_doregs(curp, lp, NULL, &uio); lwkt_reltoken(&p->p_token); + PRELE(p); lwkt_reltoken(&proc_token); return t; } @@ -645,6 +667,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr, #if defined(PT_SETFPREGS) || defined(PT_GETFPREGS) if (!procfs_validfpregs(lp)) { /* no P_SYSTEM procs please */ lwkt_reltoken(&p->p_token); + PRELE(p); lwkt_reltoken(&proc_token); return EINVAL; } else { @@ -659,6 +682,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr, uio.uio_td = curthread; t = procfs_dofpregs(curp, lp, NULL, &uio); lwkt_reltoken(&p->p_token); + PRELE(p); lwkt_reltoken(&proc_token); return t; } @@ -676,6 +700,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr, #if defined(PT_SETDBREGS) || defined(PT_GETDBREGS) if (!procfs_validdbregs(lp)) { /* no P_SYSTEM procs please */ lwkt_reltoken(&p->p_token); + PRELE(p); lwkt_reltoken(&proc_token); return EINVAL; } else { @@ -690,6 +715,7 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr, uio.uio_td = curthread; t = procfs_dodbregs(curp, lp, NULL, &uio); lwkt_reltoken(&p->p_token); + PRELE(p); lwkt_reltoken(&proc_token); return t; } @@ -700,7 +726,9 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr, } lwkt_reltoken(&p->p_token); + PRELE(p); lwkt_reltoken(&proc_token); + return 0; } diff --git a/sys/kern/tty.c b/sys/kern/tty.c index fd86301905..e616e1c4dd 100644 --- a/sys/kern/tty.c +++ b/sys/kern/tty.c @@ -256,7 +256,7 @@ ttyclose(struct tty *tp) { crit_enter(); lwkt_gettoken(&tty_token); - funsetown(tp->t_sigio); + funsetown(&tp->t_sigio); if (constty == tp) constty = NULL; @@ -288,9 +288,16 @@ void ttyclearsession(struct tty *tp) { struct session *sp; + struct pgrp *opgrp; lwkt_gettoken(&tty_token); + opgrp = tp->t_pgrp; tp->t_pgrp = NULL; + if (opgrp) { + pgrel(opgrp); + opgrp = NULL; + } + if ((sp = tp->t_session) != NULL) { tp->t_session = NULL; #ifdef TTY_DO_FULL_CLOSE @@ -845,6 +852,7 @@ ttioctl(struct tty *tp, u_long cmd, void *data, int flag) struct thread *td = curthread; struct lwp *lp = td->td_lwp; struct proc *p = td->td_proc; + struct pgrp *opgrp; struct tty *otp; int error; @@ -1206,12 +1214,18 @@ ttioctl(struct tty *tp, u_long cmd, void *data, int flag) } ttyhold(tp); tp->t_session = p->p_session; + opgrp = tp->t_pgrp; + pgref(p->p_pgrp); tp->t_pgrp = p->p_pgrp; otp = p->p_session->s_ttyp; p->p_session->s_ttyp = tp; + p->p_flag |= P_CONTROLT; if (otp) ttyunhold(otp); - p->p_flag |= P_CONTROLT; + if (opgrp) { + pgrel(opgrp); + opgrp = NULL; + } break; case TIOCSPGRP: { /* set pgrp of tty */ pid_t pgid = *(int *)data; @@ -1228,12 +1242,18 @@ ttioctl(struct tty *tp, u_long cmd, void *data, int flag) } else { struct pgrp *pgrp = pgfind(pgid); if (pgrp == NULL || pgrp->pg_session != p->p_session) { + if (pgrp) + pgrel(pgrp); lwkt_reltoken(&proc_token); lwkt_reltoken(&tty_token); return (EPERM); } - + opgrp = tp->t_pgrp; tp->t_pgrp = pgrp; + if (opgrp) { + pgrel(opgrp); + opgrp = NULL; + } } break; } @@ -2553,7 +2573,7 @@ ttyinfo(struct tty *tp) ttyprintf(tp, "not a controlling terminal\n"); } else if (tp->t_pgrp == NULL) { ttyprintf(tp, "no foreground process group\n"); - } else if ((p = LIST_FIRST(&tp->t_pgrp->pg_members)) == 0) { + } else if ((p = LIST_FIRST(&tp->t_pgrp->pg_members)) == NULL) { ttyprintf(tp, "empty foreground process group\n"); } else { /* @@ -2572,7 +2592,7 @@ ttyinfo(struct tty *tp) /* XXX lwp should compare lwps */ - for (pick = NULL; p != 0; p = LIST_NEXT(p, p_pglist)) { + for (pick = NULL; p != NULL; p = LIST_NEXT(p, p_pglist)) { if (proc_compare(pick, p)) pick = p; } diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c index a3d137dd75..f523a21861 100644 --- a/sys/kern/uipc_socket.c +++ b/sys/kern/uipc_socket.c @@ -386,7 +386,7 @@ soclose(struct socket *so, int fflag) { int error = 0; - funsetown(so->so_sigio); + funsetown(&so->so_sigio); if (so->so_pcb == NULL) goto discard; if (so->so_state & SS_ISCONNECTED) { diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c index 7b763286cd..4950a4cc7d 100644 --- a/sys/kern/uipc_syscalls.c +++ b/sys/kern/uipc_syscalls.c @@ -1372,7 +1372,8 @@ sf_buf_mfree(void *arg) vm_page_t m; m = sf_buf_page(sf); - if (sf_buf_free(sf) == 0) { + if (sf_buf_free(sf)) { + /* sf invalid now */ vm_page_unwire(m, 0); if (m->wire_count == 0 && m->object == NULL) vm_page_try_to_free(m); diff --git a/sys/net/bpf.c b/sys/net/bpf.c index 0924d57a5d..2ff5de64eb 100644 --- a/sys/net/bpf.c +++ b/sys/net/bpf.c @@ -369,7 +369,7 @@ bpfclose(struct dev_close_args *ap) cdev_t dev = ap->a_head.a_dev; struct bpf_d *d = dev->si_drv1; - funsetown(d->bd_sigio); + funsetown(&d->bd_sigio); crit_enter(); if (d->bd_state == BPF_WAITING) callout_stop(&d->bd_callout); diff --git a/sys/net/tap/if_tap.c b/sys/net/tap/if_tap.c index d2d09490e0..7426ca84fc 100644 --- a/sys/net/tap/if_tap.c +++ b/sys/net/tap/if_tap.c @@ -424,12 +424,12 @@ tapclose(struct dev_close_args *ap) rt_ifannouncemsg(ifp, IFAN_DEPARTURE); } - funsetown(tp->tap_sigio); + funsetown(&tp->tap_sigio); tp->tap_sigio = NULL; KNOTE(&tp->tap_rkq.ki_note, 0); tp->tap_flags &= ~TAP_OPEN; - funsetown(tp->tap_sigtd); + funsetown(&tp->tap_sigtd); tp->tap_sigtd = NULL; taprefcnt --; diff --git a/sys/net/tun/if_tun.c b/sys/net/tun/if_tun.c index 5f4e259773..54cb34fdff 100644 --- a/sys/net/tun/if_tun.c +++ b/sys/net/tun/if_tun.c @@ -216,7 +216,7 @@ tunclose(struct dev_close_args *ap) ifp->if_flags &= ~IFF_RUNNING; if_purgeaddrs_nolink(ifp); - funsetown(tp->tun_sigio); + funsetown(&tp->tun_sigio); KNOTE(&tp->tun_rkq.ki_note, 0); TUNDEBUG(ifp, "closed\n"); diff --git a/sys/platform/pc32/i386/db_trace.c b/sys/platform/pc32/i386/db_trace.c index b7b4d4377d..38213a9e62 100644 --- a/sys/platform/pc32/i386/db_trace.c +++ b/sys/platform/pc32/i386/db_trace.c @@ -292,7 +292,7 @@ db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, struct proc *p; struct pcb *pcb; - p = pfind(pid); + p = pfindn(pid); if (p == NULL) { db_printf("pid %d not found\n", pid); return; diff --git a/sys/sys/filedesc.h b/sys/sys/filedesc.h index dd177afa9a..4e77991fa9 100644 --- a/sys/sys/filedesc.h +++ b/sys/sys/filedesc.h @@ -133,8 +133,7 @@ struct sigio { struct pgrp *siu_pgrp; /* process group to receive ... */ } sio_u; SLIST_ENTRY(sigio) sio_pgsigio; /* sigio's for process or group */ - struct sigio **sio_myref; /* location of the pointer that holds - * the reference to this structure */ + struct sigio **sio_myref; /* location of the pointer that holds */ struct ucred *sio_ucred; /* current credentials */ uid_t sio_ruid; /* real user id */ pid_t sio_pgid; /* pgid for signals */ @@ -178,7 +177,7 @@ int fdissequential (struct file *); void fdsequential (struct file *, int); pid_t fgetown (struct sigio **); int fsetown (pid_t, struct sigio **); -void funsetown (struct sigio *); +void funsetown (struct sigio **); void funsetownlst (struct sigiolst *); void setugidsafety (struct proc *p); void allfiles_scan_exclusive(int (*callback)(struct file *, void *), void *data); diff --git a/sys/sys/proc.h b/sys/sys/proc.h index dc24a4e377..d688693ff3 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -106,7 +106,9 @@ struct pgrp { struct sigiolst pg_sigiolst; /* List of sigio sources. */ pid_t pg_id; /* Pgrp id. */ int pg_jobc; /* # procs qualifying pgrp for job control */ - struct lock pg_lock; /* Lock during fork */ + u_int pg_refs; + struct lwkt_token pg_token; + struct lock pg_lock; }; #define PS_NOCLDWAIT 0x0001 /* No zombies if child dies */ @@ -437,7 +439,9 @@ extern void stopevent(struct proc*, unsigned int, unsigned int); } while (0) /* - * Hold process in memory, don't destruct , normally for ptrace/procfs work + * Hold process in memory, don't destruct, used by ktrace, procfs, sigio, + * and signaling code (e.g. ksignal()). + * * MPSAFE */ #define PHOLD(p) atomic_add_int(&(p)->p_lock, 1) @@ -489,9 +493,12 @@ extern u_long ps_arg_cache_limit; extern int ps_argsopen; extern int ps_showallprocs; -struct proc *pfind (pid_t); /* Find process by id. */ -struct pgrp *pgfind (pid_t); /* Find process group by id. */ -struct proc *zpfind (pid_t); /* Find zombie process by id. */ +struct proc *pfind (pid_t); /* Find process by id w/ref */ +struct proc *pfindn (pid_t); /* Find process by id wo/ref */ +struct pgrp *pgfind (pid_t); /* Find process group by id w/ref */ +struct proc *zpfind (pid_t); /* Find zombie process by id w/ref */ +void pgref (struct pgrp *); /* Ref pgrp preventing disposal */ +void pgrel (struct pgrp *); /* Deref pgrp & dispose on 1->0 trans */ struct globaldata; struct lwp_params; diff --git a/sys/vfs/procfs/procfs.h b/sys/vfs/procfs/procfs.h index 1d4d804f46..98ea68c48a 100644 --- a/sys/vfs/procfs/procfs.h +++ b/sys/vfs/procfs/procfs.h @@ -122,8 +122,6 @@ struct reg; struct fpreg; struct dbreg; -#define PFIND(pid) ((pid) ? pfind(pid) : &proc0) - void procfs_exit (struct thread *); int procfs_freevp (struct vnode *); int procfs_allocvp (struct mount *, struct vnode **, long, pfstype); diff --git a/sys/vfs/procfs/procfs_ctl.c b/sys/vfs/procfs/procfs_ctl.c index 3fb9295915..c8f9216c3e 100644 --- a/sys/vfs/procfs/procfs_ctl.c +++ b/sys/vfs/procfs/procfs_ctl.c @@ -218,8 +218,10 @@ procfs_control(struct proc *curp, struct lwp *lp, int op) struct proc *pp; pp = pfind(p->p_oppid); - if (pp) + if (pp) { proc_reparent(p, pp); + PRELE(pp); + } } p->p_oppid = 0; diff --git a/sys/vfs/procfs/procfs_subr.c b/sys/vfs/procfs/procfs_subr.c index ce18058f72..44847a026c 100644 --- a/sys/vfs/procfs/procfs_subr.c +++ b/sys/vfs/procfs/procfs_subr.c @@ -274,13 +274,14 @@ procfs_rw(struct vop_read_args *ap) lwkt_gettoken(&proc_token); - p = PFIND(pfs->pfs_pid); + p = pfind(pfs->pfs_pid); if (p == NULL) { lwkt_reltoken(&proc_token); return (EINVAL); } if (p->p_pid == 1 && securelevel > 0 && uio->uio_rw == UIO_WRITE) { lwkt_reltoken(&proc_token); + PRELE(p); return (EACCES); } /* XXX lwp */ @@ -350,6 +351,7 @@ procfs_rw(struct vop_read_args *ap) pfs->pfs_lockowner = 0; lwkt_reltoken(&proc_token); wakeup(&pfs->pfs_lockowner); + PRELE(p); return rtval; } diff --git a/sys/vfs/procfs/procfs_vnops.c b/sys/vfs/procfs/procfs_vnops.c index cb1b96886c..9ca253edd3 100644 --- a/sys/vfs/procfs/procfs_vnops.c +++ b/sys/vfs/procfs/procfs_vnops.c @@ -172,26 +172,35 @@ procfs_open(struct vop_open_args *ap) { struct pfsnode *pfs = VTOPFS(ap->a_vp); struct proc *p1, *p2; + int error; - p2 = PFIND(pfs->pfs_pid); + p2 = pfind(pfs->pfs_pid); if (p2 == NULL) return (ENOENT); - if (pfs->pfs_pid && !PRISON_CHECK(ap->a_cred, p2->p_ucred)) - return (ENOENT); + if (pfs->pfs_pid && !PRISON_CHECK(ap->a_cred, p2->p_ucred)) { + error = ENOENT; + goto done; + } switch (pfs->pfs_type) { case Pmem: if (((pfs->pfs_flags & FWRITE) && (ap->a_mode & O_EXCL)) || - ((pfs->pfs_flags & O_EXCL) && (ap->a_mode & FWRITE))) - return (EBUSY); + ((pfs->pfs_flags & O_EXCL) && (ap->a_mode & FWRITE))) { + error = EBUSY; + goto done; + } p1 = curproc; KKASSERT(p1); /* Can't trace a process that's currently exec'ing. */ - if ((p2->p_flag & P_INEXEC) != 0) - return EAGAIN; - if (!CHECKIO(p1, p2) || p_trespass(ap->a_cred, p2->p_ucred)) - return (EPERM); + if ((p2->p_flag & P_INEXEC) != 0) { + error = EAGAIN; + goto done; + } + if (!CHECKIO(p1, p2) || p_trespass(ap->a_cred, p2->p_ucred)) { + error = EPERM; + goto done; + } if (ap->a_mode & FWRITE) pfs->pfs_flags = ap->a_mode & (FWRITE|O_EXCL); @@ -201,8 +210,10 @@ procfs_open(struct vop_open_args *ap) default: break; } - - return (vop_stdopen(ap)); + error = vop_stdopen(ap); +done: + PRELE(p2); + return error; } /* @@ -235,6 +246,7 @@ procfs_close(struct vop_close_args *ap) * told to stop on an event, but then the requesting process * has gone away or forgotten about it. */ + p = NULL; if ((ap->a_vp->v_opencount < 2) && (p = pfind(pfs->pfs_pid)) && !(p->p_pfsflags & PF_LINGER)) { @@ -244,6 +256,8 @@ procfs_close(struct vop_close_args *ap) spin_unlock(&p->p_spin); wakeup(&p->p_step); } + if (p) + PRELE(p); break; default: break; @@ -271,14 +285,20 @@ procfs_ioctl(struct vop_ioctl_args *ap) if (procp == NULL) return ENOTTY; p = curproc; - if (p == NULL) - return EINVAL; + if (p == NULL) { + error = EINVAL; + goto done; + } /* Can't trace a process that's currently exec'ing. */ - if ((procp->p_flag & P_INEXEC) != 0) - return EAGAIN; - if (!CHECKIO(p, procp) || p_trespass(ap->a_cred, procp->p_ucred)) - return EPERM; + if ((procp->p_flag & P_INEXEC) != 0) { + error = EAGAIN; + goto done; + } + if (!CHECKIO(p, procp) || p_trespass(ap->a_cred, procp->p_ucred)) { + error = EPERM; + goto done; + } switch (ap->a_command) { case PIOCBIS: @@ -295,7 +315,7 @@ procfs_ioctl(struct vop_ioctl_args *ap) #define NFLAGS (PF_ISUGID) flags = (unsigned char)*(unsigned int*)ap->a_data; if (flags & NFLAGS && (error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0))) - return error; + goto done; procp->p_pfsflags = flags; break; case PIOCGFL: @@ -334,7 +354,7 @@ procfs_ioctl(struct vop_ioctl_args *ap) spin_unlock(&procp->p_spin); error = tsleep(&procp->p_stype, PCATCH | PINTERLOCKED, "piocwait", 0); if (error) - return error; + goto done; spin_lock(&procp->p_spin); } spin_unlock(&procp->p_spin); @@ -350,19 +370,27 @@ procfs_ioctl(struct vop_ioctl_args *ap) * the MP lock. However, the caller is presumably interlocked * by having waited. */ - if (procp->p_step == 0) - return EINVAL; /* Can only start a stopped process */ + if (procp->p_step == 0) { + error = EINVAL; /* Can only start a stopped process */ + goto done; + } if ((signo = *(int*)ap->a_data) != 0) { - if (signo >= NSIG || signo <= 0) - return EINVAL; + if (signo >= NSIG || signo <= 0) { + error = EINVAL; + goto done; + } ksignal(procp, signo); } procp->p_step = 0; wakeup(&procp->p_step); break; default: - return (ENOTTY); + error = ENOTTY; + goto done; } + error = 0; +done: + PRELE(procp); return 0; } @@ -481,13 +509,15 @@ procfs_getattr(struct vop_getattr_args *ap) switch (pfs->pfs_type) { case Proot: case Pcurproc: - procp = 0; + procp = NULL; break; default: - procp = PFIND(pfs->pfs_pid); - if (procp == NULL || procp->p_ucred == NULL) - return (ENOENT); + procp = pfind(pfs->pfs_pid); + if (procp == NULL || procp->p_ucred == NULL) { + error = ENOENT; + goto done; + } } error = 0; @@ -627,7 +657,9 @@ procfs_getattr(struct vop_getattr_args *ap) default: panic("procfs_getattr"); } - +done: + if (procp) + PRELE(procp); return (error); } @@ -699,6 +731,7 @@ procfs_lookup(struct vop_old_lookup_args *ap) if (cnp->cn_nameiop == NAMEI_DELETE || cnp->cn_nameiop == NAMEI_RENAME) return (EROFS); + p = NULL; error = 0; if (cnp->cn_namelen == 1 && *pname == '.') { *vpp = dvp; @@ -721,7 +754,7 @@ procfs_lookup(struct vop_old_lookup_args *ap) if (pid == NO_PID) break; - p = PFIND(pid); + p = pfind(pid); if (p == NULL) break; @@ -741,7 +774,7 @@ procfs_lookup(struct vop_old_lookup_args *ap) goto out; } - p = PFIND(pfs->pfs_pid); + p = pfind(pfs->pfs_pid); if (p == NULL) break; /* XXX lwp */ @@ -787,6 +820,8 @@ out: vn_unlock(dvp); } } + if (p) + PRELE(p); return (error); } @@ -857,18 +892,22 @@ procfs_readdir_proc(struct vop_readdir_args *ap) struct uio *uio = ap->a_uio; pfs = VTOPFS(ap->a_vp); - p = PFIND(pfs->pfs_pid); + p = pfind(pfs->pfs_pid); if (p == NULL) return(0); - if (!PRISON_CHECK(ap->a_cred, p->p_ucred)) - return(0); - /* XXX lwp */ + if (!PRISON_CHECK(ap->a_cred, p->p_ucred)) { + error = 0; + goto done; + } + /* XXX lwp, not MPSAFE */ lp = FIRST_LWP_IN_PROC(p); error = 0; i = (int)uio->uio_offset; - if (i < 0) - return (EINVAL); + if (i < 0) { + error = EINVAL; + goto done; + } for (pt = &proc_targets[i]; !error && uio->uio_resid > 0 && i < nproc_targets; pt++, i++) { @@ -883,8 +922,10 @@ procfs_readdir_proc(struct vop_readdir_args *ap) } uio->uio_offset = (off_t)i; - - return(0); + error = 0; +done: + PRELE(p); + return error; } struct procfs_readdir_root_info { @@ -1032,19 +1073,26 @@ procfs_readlink(struct vop_readlink_args *ap) * from under us... */ case Pfile: - procp = PFIND(pfs->pfs_pid); + procp = pfind(pfs->pfs_pid); if (procp == NULL || procp->p_ucred == NULL) { kprintf("procfs_readlink: pid %d disappeared\n", pfs->pfs_pid); + if (procp) + PRELE(procp); return (uiomove("unknown", sizeof("unknown") - 1, ap->a_uio)); } error = cache_fullpath(procp, &procp->p_textnch, &fullpath, &freepath, 0); - if (error != 0) + if (error != 0) { + if (procp) + PRELE(procp); return (uiomove("unknown", sizeof("unknown") - 1, ap->a_uio)); + } error = uiomove(fullpath, strlen(fullpath), ap->a_uio); kfree(freepath, M_TEMP); + if (procp) + PRELE(procp); return (error); default: return (EINVAL);