diff options
35 files changed, 1004 insertions, 314 deletions
diff --git a/sys/coda/coda_venus.c b/sys/coda/coda_venus.c index 022009e..e223617 100644 --- a/sys/coda/coda_venus.c +++ b/sys/coda/coda_venus.c @@ -94,13 +94,11 @@ #define INIT_IN(in, op, ident, p) \ (in)->opcode = (op); \ - if (p) \ - PROC_LOCK(p); \ + PGRPSESS_SLOCK(); \ (in)->pid = p ? p->p_pid : -1; \ (in)->pgid = p ? p->p_pgid : -1; \ (in)->sid = (p && p->p_session && p->p_session->s_leader) ? (p->p_session->s_leader->p_pid) : -1; \ - if (p) \ - PROC_UNLOCK(p); \ + PGRPSESS_SUNLOCK(); \ if (ident != NOCRED) { \ (in)->cred.cr_uid = ident->cr_uid; \ (in)->cred.cr_groupid = ident->cr_gid; \ diff --git a/sys/compat/linprocfs/linprocfs.c b/sys/compat/linprocfs/linprocfs.c index 06f0f38..ae21891 100644 --- a/sys/compat/linprocfs/linprocfs.c +++ b/sys/compat/linprocfs/linprocfs.c @@ -494,9 +494,9 @@ linprocfs_doprocstat(PFS_FILL_ARGS) PS_ADD("statr", "%c", '0'); /* XXX */ PROC_LOCK(p); PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0); - PROC_UNLOCK(p); PS_ADD("pgrp", "%d", p->p_pgid); PS_ADD("session", "%d", p->p_session->s_sid); + PROC_UNLOCK(p); PS_ADD("tty", "%d", 0); /* XXX */ PS_ADD("tpgid", "%d", 0); /* XXX */ PS_ADD("flags", "%u", 0); /* XXX */ diff --git a/sys/compat/linux/linux_file.c b/sys/compat/linux/linux_file.c index 1dfa4a1..dd4f219 100644 --- a/sys/compat/linux/linux_file.c +++ b/sys/compat/linux/linux_file.c @@ -144,12 +144,13 @@ linux_open(struct thread *td, struct linux_open_args *args) fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0, td); fdrop(fp, td); } - } else + } else { PROC_UNLOCK(p); #ifdef DEBUG if (ldebug(open)) printf(LMSG("open returns error %d"), error); #endif + } return error; } diff --git a/sys/compat/svr4/svr4_misc.c b/sys/compat/svr4/svr4_misc.c index 4771d90..9dcfa7f 100644 --- a/sys/compat/svr4/svr4_misc.c +++ b/sys/compat/svr4/svr4_misc.c @@ -1017,7 +1017,9 @@ svr4_sys_pgrpsys(td, uap) /*FALLTHROUGH*/ case 0: /* getpgrp() */ + PROC_LOCK(p); *retval = p->p_pgrp->pg_id; + PROC_UNLOCK(p); return 0; case 2: /* getsid(pid) */ @@ -1222,7 +1224,9 @@ svr4_sys_waitsys(td, uap) break; case SVR4_P_PGID: + PROC_LOCK(td->td_proc); SCARG(uap, id) = -td->td_proc->p_pgid; + PROC_UNLOCK(td->td_proc); break; case SVR4_P_ALL: @@ -1283,8 +1287,12 @@ loop: if (q->p_oppid != q->p_pptr->p_pid) { PROC_UNLOCK(q); t = pfind(q->p_oppid); + if (t == NULL) { + t = initproc; + PROC_LOCK(initproc); + } PROC_LOCK(q); - proc_reparent(q, t ? t : initproc); + proc_reparent(q, t); q->p_oppid = 0; q->p_flag &= ~(P_TRACED | P_WAITED); PROC_UNLOCK(q); diff --git a/sys/dev/syscons/scvidctl.c b/sys/dev/syscons/scvidctl.c index b28752b..9e142d0 100644 --- a/sys/dev/syscons/scvidctl.c +++ b/sys/dev/syscons/scvidctl.c @@ -36,6 +36,11 @@ #include <sys/kernel.h> #include <sys/fbio.h> #include <sys/consio.h> +#include <sys/filedesc.h> +#include <sys/lock.h> +#include <sys/sx.h> +#include <sys/mutex.h> +#include <sys/proc.h> #include <dev/fb/fbreg.h> #include <dev/syscons/syscons.h> @@ -228,7 +233,11 @@ sc_set_text_mode(scr_stat *scp, struct tty *tp, int mode, int xsize, int ysize, || tp->t_winsize.ws_row != scp->ysize) { tp->t_winsize.ws_col = scp->xsize; tp->t_winsize.ws_row = scp->ysize; - pgsignal(tp->t_pgrp, SIGWINCH, 1); + if (tp->t_pgrp != NULL) { + PGRP_LOCK(tp->t_pgrp); + pgsignal(tp->t_pgrp, SIGWINCH, 1); + PGRP_UNLOCK(tp->t_pgrp); + } } return 0; @@ -291,7 +300,11 @@ sc_set_graphics_mode(scr_stat *scp, struct tty *tp, int mode) || tp->t_winsize.ws_ypixel != scp->ypixel) { tp->t_winsize.ws_xpixel = scp->xpixel; tp->t_winsize.ws_ypixel = scp->ypixel; - pgsignal(tp->t_pgrp, SIGWINCH, 1); + if (tp->t_pgrp != NULL) { + PGRP_LOCK(tp->t_pgrp); + pgsignal(tp->t_pgrp, SIGWINCH, 1); + PGRP_UNLOCK(tp->t_pgrp); + } } return 0; @@ -423,7 +436,11 @@ sc_set_pixel_mode(scr_stat *scp, struct tty *tp, int xsize, int ysize, || tp->t_winsize.ws_row != scp->ysize) { tp->t_winsize.ws_col = scp->xsize; tp->t_winsize.ws_row = scp->ysize; - pgsignal(tp->t_pgrp, SIGWINCH, 1); + if (tp->t_pgrp != NULL) { + PGRP_LOCK(tp->t_pgrp); + pgsignal(tp->t_pgrp, SIGWINCH, 1); + PGRP_UNLOCK(tp->t_pgrp); + } } return 0; diff --git a/sys/fs/coda/coda_venus.c b/sys/fs/coda/coda_venus.c index 022009e..e223617 100644 --- a/sys/fs/coda/coda_venus.c +++ b/sys/fs/coda/coda_venus.c @@ -94,13 +94,11 @@ #define INIT_IN(in, op, ident, p) \ (in)->opcode = (op); \ - if (p) \ - PROC_LOCK(p); \ + PGRPSESS_SLOCK(); \ (in)->pid = p ? p->p_pid : -1; \ (in)->pgid = p ? p->p_pgid : -1; \ (in)->sid = (p && p->p_session && p->p_session->s_leader) ? (p->p_session->s_leader->p_pid) : -1; \ - if (p) \ - PROC_UNLOCK(p); \ + PGRPSESS_SUNLOCK(); \ if (ident != NOCRED) { \ (in)->cred.cr_uid = ident->cr_uid; \ (in)->cred.cr_groupid = ident->cr_gid; \ diff --git a/sys/fs/procfs/procfs_ctl.c b/sys/fs/procfs/procfs_ctl.c index 154eaa6..3a73980 100644 --- a/sys/fs/procfs/procfs_ctl.c +++ b/sys/fs/procfs/procfs_ctl.c @@ -230,8 +230,10 @@ out: pp = pfind(p->p_oppid); PROC_LOCK(p); - if (pp) + if (pp) { + PROC_UNLOCK(pp); proc_reparent(p, pp); + } } else PROC_LOCK(p); p->p_oppid = 0; diff --git a/sys/fs/procfs/procfs_status.c b/sys/fs/procfs/procfs_status.c index 0f8e343..9238dfe 100644 --- a/sys/fs/procfs/procfs_status.c +++ b/sys/fs/procfs/procfs_status.c @@ -48,6 +48,8 @@ #include <sys/mutex.h> #include <sys/jail.h> #include <sys/malloc.h> +#include <sys/mutex.h> +#include <sys/sx.h> #include <sys/proc.h> #include <sys/resourcevar.h> #include <sys/sbuf.h> @@ -75,9 +77,9 @@ procfs_doprocstatus(PFS_FILL_ARGS) pid = p->p_pid; PROC_LOCK(p); ppid = p->p_pptr ? p->p_pptr->p_pid : 0; - PROC_UNLOCK(p); pgid = p->p_pgrp->pg_id; sess = p->p_pgrp->pg_session; + SESS_LOCK(sess); sid = sess->s_leader ? sess->s_leader->p_pid : 0; /* comm pid ppid pgid sid maj,min ctty,sldr start ut st wmsg @@ -106,6 +108,8 @@ procfs_doprocstatus(PFS_FILL_ARGS) sbuf_printf(sb, "%ssldr", sep); sep = ","; } + SESS_UNLOCK(sess); + PROC_UNLOCK(p); if (*sep != ',') { sbuf_printf(sb, "noflags"); } diff --git a/sys/fs/specfs/spec_vnops.c b/sys/fs/specfs/spec_vnops.c index 9de659c..7887ddb 100644 --- a/sys/fs/specfs/spec_vnops.c +++ b/sys/fs/specfs/spec_vnops.c @@ -35,6 +35,8 @@ */ #include <sys/param.h> +#include <sys/lock.h> +#include <sys/sx.h> #include <sys/proc.h> #include <sys/systm.h> #include <sys/kernel.h> @@ -568,7 +570,7 @@ spec_close(ap) struct thread *a_td; } */ *ap; { - struct vnode *vp = ap->a_vp; + struct vnode *vp = ap->a_vp, *oldvp; struct thread *td = ap->a_td; dev_t dev = vp->v_rdev; @@ -581,11 +583,18 @@ spec_close(ap) * if the reference count is 2 (this last descriptor * plus the session), release the reference from the session. */ + oldvp = NULL; + PGRPSESS_XLOCK(); if (vcount(vp) == 2 && td && (vp->v_flag & VXLOCK) == 0 && vp == td->td_proc->p_session->s_ttyvp) { - vrele(vp); + SESS_LOCK(td->td_proc->p_session); td->td_proc->p_session->s_ttyvp = NULL; + SESS_UNLOCK(td->td_proc->p_session); + oldvp = vp; } + PGRPSESS_XUNLOCK(); + if (oldvp != NULL) + vrele(oldvp); /* * We do not want to really close the device if it * is still in use unless we are trying to close it diff --git a/sys/i386/ibcs2/ibcs2_ioctl.c b/sys/i386/ibcs2/ibcs2_ioctl.c index 2755b01..cb5d5ae 100644 --- a/sys/i386/ibcs2/ibcs2_ioctl.c +++ b/sys/i386/ibcs2/ibcs2_ioctl.c @@ -552,6 +552,7 @@ ibcs2_ioctl(td, uap) } ibcs2_jwinsize; PROC_LOCK(p); + SESS_LOCK(p->p_session); ibcs2_jwinsize.bytex = 80; /* p->p_session->s_ttyp->t_winsize.ws_col; XXX */ ibcs2_jwinsize.bytey = 25; @@ -560,6 +561,7 @@ ibcs2_ioctl(td, uap) p->p_session->s_ttyp->t_winsize.ws_xpixel; ibcs2_jwinsize.bity = p->p_session->s_ttyp->t_winsize.ws_ypixel; + SESS_UNLOCK(p->p_session); PROC_UNLOCK(p); error = copyout((caddr_t)&ibcs2_jwinsize, SCARG(uap, data), sizeof(ibcs2_jwinsize)); diff --git a/sys/i386/isa/pcvt/pcvt_out.c b/sys/i386/isa/pcvt/pcvt_out.c index e891b4c..8c77933 100644 --- a/sys/i386/isa/pcvt/pcvt_out.c +++ b/sys/i386/isa/pcvt/pcvt_out.c @@ -1582,8 +1582,11 @@ set_emulation_mode(struct video_state *svsp, int mode) svsp->scrr_end = svsp->scrr_len - 1; } - if (svsp->vs_tty && svsp->vs_tty->t_pgrp) + if (svsp->vs_tty && svsp->vs_tty->t_pgrp) { + PGRP_LOCK(svsp->vs_tty->t_pgrp); pgsignal(svsp->vs_tty->t_pgrp, SIGWINCH, 1); + PGRP_UNLOCK(svsp->vs_tty->t_pgrp); + } } /*---------------------------------------------------------------------------* @@ -1867,8 +1870,11 @@ vt_col(struct video_state *svsp, int cols) (cols == SCR_COL80)? 720: 1056; svsp->vs_tty->t_winsize.ws_ypixel = 400; - if(svsp->vs_tty->t_pgrp) + if(svsp->vs_tty->t_pgrp) { + PGRP_LOCK(svsp->vs_tty->t_pgrp); pgsignal(svsp->vs_tty->t_pgrp, SIGWINCH, 1); + PGRP_UNLOCK(svsp->vs_tty->t_pgrp); + } } reallocate_scrollbuffer(svsp, svsp->scrollback_pages); diff --git a/sys/i386/isa/pcvt/pcvt_sup.c b/sys/i386/isa/pcvt/pcvt_sup.c index 7fde462..4df2971 100644 --- a/sys/i386/isa/pcvt/pcvt_sup.c +++ b/sys/i386/isa/pcvt/pcvt_sup.c @@ -703,8 +703,11 @@ set_screen_size(struct video_state *svsp, int size) svsp->scrr_len = svsp->screen_rows; svsp->scrr_end = svsp->scrr_len - 1; - if (svsp->vs_tty && svsp->vs_tty->t_pgrp) + if (svsp->vs_tty && svsp->vs_tty->t_pgrp) { + PGRP_LOCK(svsp->vs_tty->t_pgrp); pgsignal(svsp->vs_tty->t_pgrp, SIGWINCH, 1); + PGRP_UNLOCK(svsp->vs_tty->t_pgrp); + } reallocate_scrollbuffer(svsp, svsp->scrollback_pages); break; diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index 6b698e4..6de34ef 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -305,12 +305,14 @@ proc0_init(void *dummy __unused) */ LIST_INSERT_HEAD(&allproc, p, p_list); LIST_INSERT_HEAD(PIDHASH(0), p, p_hash); + mtx_init(&pgrp0.pg_mtx, "process group", MTX_DEF); p->p_pgrp = &pgrp0; LIST_INSERT_HEAD(PGRPHASH(0), &pgrp0, pg_hash); LIST_INIT(&pgrp0.pg_members); LIST_INSERT_HEAD(&pgrp0.pg_members, p, p_pglist); pgrp0.pg_session = &session0; + mtx_init(&session0.s_mtx, "session", MTX_DEF); session0.s_count = 1; session0.s_leader = p; diff --git a/sys/kern/kern_acct.c b/sys/kern/kern_acct.c index cd191d5..e859057 100644 --- a/sys/kern/kern_acct.c +++ b/sys/kern/kern_acct.c @@ -233,10 +233,14 @@ acct_process(td) acct.ac_gid = p->p_ucred->cr_rgid; /* (7) The terminal from which the process was started */ + PROC_LOCK(p); + SESS_LOCK(p->p_session); if ((p->p_flag & P_CONTROLT) && p->p_pgrp->pg_session->s_ttyp) acct.ac_tty = dev2udev(p->p_pgrp->pg_session->s_ttyp->t_dev); else acct.ac_tty = NOUDEV; + SESS_UNLOCK(p->p_session); + PROC_UNLOCK(p); /* (8) The boolean flags that tell how the process terminated, etc. */ acct.ac_flag = p->p_acflag; diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index ea7fa2d..8e4726e 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -535,15 +535,22 @@ funsetown(sigio) if (sigio == NULL) return; + s = splhigh(); *(sigio->sio_myref) = NULL; splx(s); - if (sigio->sio_pgid < 0) { + if ((sigio)->sio_pgid < 0) { + struct pgrp *pg = (sigio)->sio_pgrp; + PGRP_LOCK(pg); SLIST_REMOVE(&sigio->sio_pgrp->pg_sigiolst, sigio, sigio, sio_pgsigio); - } else /* if ((*sigiop)->sio_pgid > 0) */ { + PGRP_UNLOCK(pg); + } else { + struct proc *p = (sigio)->sio_proc; + PROC_LOCK(p); SLIST_REMOVE(&sigio->sio_proc->p_sigiolst, sigio, sigio, sio_pgsigio); + PROC_UNLOCK(p); } crfree(sigio->sio_ucred); FREE(sigio, M_SIGIO); @@ -554,10 +561,52 @@ void funsetownlst(sigiolst) struct sigiolst *sigiolst; { + int s; struct sigio *sigio; + struct proc *p; + struct pgrp *pg; + + sigio = SLIST_FIRST(sigiolst); + if (sigio == NULL) + return; + + p = NULL; + pg = NULL; + + /* + * Every entry of the list should belong + * to a single proc or pgrp. + */ + if (sigio->sio_pgid < 0) { + pg = sigio->sio_pgrp; + PGRP_LOCK_ASSERT(pg, MA_OWNED); + } else /* if (sigio->sio_pgid > 0) */ { + p = sigio->sio_proc; + PROC_LOCK_ASSERT(p, MA_OWNED); + } - while ((sigio = SLIST_FIRST(sigiolst)) != NULL) - funsetown(sigio); + while ((sigio = SLIST_FIRST(sigiolst)) != NULL) { + s = splhigh(); + *(sigio->sio_myref) = NULL; + splx(s); + if (pg != NULL) { + KASSERT(sigio->sio_pgid < 0, ("Proc sigio in pgrp sigio list")); + KASSERT(sigio->sio_pgrp == pg, ("Bogus pgrp in sigio list")); + SLIST_REMOVE(&pg->pg_sigiolst, sigio, sigio, sio_pgsigio); + PGRP_UNLOCK(pg); + crfree(sigio->sio_ucred); + FREE(sigio, M_SIGIO); + PGRP_LOCK(pg); + } else /* if (p != NULL) */ { + KASSERT(sigio->sio_pgid > 0, ("Pgrp sigio in proc sigio list")); + KASSERT(sigio->sio_proc == p, ("Bogus proc in sigio list")); + SLIST_REMOVE(&p->p_sigiolst, sigio, sigio, sio_pgsigio); + PROC_UNLOCK(p); + crfree(sigio->sio_ucred); + FREE(sigio, M_SIGIO); + PROC_LOCK(p); + } + } } /* @@ -574,16 +623,28 @@ fsetown(pgid, sigiop) struct proc *proc; struct pgrp *pgrp; struct sigio *sigio; - int s; + int s, ret; if (pgid == 0) { funsetown(*sigiop); return (0); } + + ret = 0; + + /* Allocate and fill in the new sigio out of locks. */ + MALLOC(sigio, struct sigio *, sizeof(struct sigio), M_SIGIO, M_WAITOK); + sigio->sio_pgid = pgid; + sigio->sio_ucred = crhold(curthread->td_proc->p_ucred); + sigio->sio_myref = sigiop; + + PGRPSESS_SLOCK(); if (pgid > 0) { proc = pfind(pgid); - if (proc == NULL) - return (ESRCH); + if (proc == NULL) { + ret = ESRCH; + goto fail; + } /* * Policy - Don't allow a process to FSETOWN a process @@ -593,17 +654,20 @@ fsetown(pgid, sigiop) * restrict FSETOWN to the current process or process * group for maximum safety. */ + PROC_UNLOCK(proc); if (proc->p_session != curthread->td_proc->p_session) { - PROC_UNLOCK(proc); - return (EPERM); + ret = EPERM; + goto fail; } - PROC_UNLOCK(proc); pgrp = NULL; } else /* if (pgid < 0) */ { pgrp = pgfind(-pgid); - if (pgrp == NULL) - return (ESRCH); + if (pgrp == NULL) { + ret = ESRCH; + goto fail; + } + PGRP_UNLOCK(pgrp); /* * Policy - Don't allow a process to FSETOWN a process @@ -613,27 +677,36 @@ fsetown(pgid, sigiop) * restrict FSETOWN to the current process or process * group for maximum safety. */ - if (pgrp->pg_session != curthread->td_proc->p_session) - return (EPERM); + if (pgrp->pg_session != curthread->td_proc->p_session) { + ret = EPERM; + goto fail; + } proc = NULL; } funsetown(*sigiop); - MALLOC(sigio, struct sigio *, sizeof(struct sigio), M_SIGIO, M_WAITOK); if (pgid > 0) { + PROC_LOCK(proc); SLIST_INSERT_HEAD(&proc->p_sigiolst, sigio, sio_pgsigio); sigio->sio_proc = proc; + PROC_UNLOCK(proc); } else { + PGRP_LOCK(pgrp); SLIST_INSERT_HEAD(&pgrp->pg_sigiolst, sigio, sio_pgsigio); sigio->sio_pgrp = pgrp; + PGRP_UNLOCK(pgrp); } - sigio->sio_pgid = pgid; - sigio->sio_ucred = crhold(curthread->td_proc->p_ucred); - sigio->sio_myref = sigiop; + PGRPSESS_SUNLOCK(); s = splhigh(); *sigiop = sigio; splx(s); return (0); + +fail: + PGRPSESS_SUNLOCK(); + crfree(sigio->sio_ucred); + FREE(sigio, M_SIGIO); + return (ret); } /* diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index c8503ca..37d2ab1 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -125,6 +125,8 @@ exit1(td, rv) register struct vmspace *vm; struct vnode *vtmp; struct exitlist *ep; + struct vnode *ttyvp; + struct tty *tp; GIANT_REQUIRED; @@ -186,7 +188,9 @@ exit1(td, rv) * Reset any sigio structures pointing to us as a result of * F_SETOWN with our pid. */ + PROC_LOCK(p); funsetownlst(&p->p_sigiolst); + PROC_UNLOCK(p); /* * Close open files and release open-file table. @@ -227,11 +231,11 @@ exit1(td, rv) vm->vm_freer = p; } - PROC_LOCK(p); + PGRPSESS_XLOCK(); if (SESS_LEADER(p)) { - register struct session *sp = p->p_session; + register struct session *sp; - PROC_UNLOCK(p); + sp = p->p_session; if (sp->s_ttyvp) { /* * Controlling process. @@ -240,29 +244,48 @@ exit1(td, rv) * and revoke access to controlling terminal. */ if (sp->s_ttyp && (sp->s_ttyp->t_session == sp)) { - if (sp->s_ttyp->t_pgrp) + tp = sp->s_ttyp; + if (sp->s_ttyp->t_pgrp) { + PGRP_LOCK(sp->s_ttyp->t_pgrp); pgsignal(sp->s_ttyp->t_pgrp, SIGHUP, 1); - (void) ttywait(sp->s_ttyp); + PGRP_UNLOCK(sp->s_ttyp->t_pgrp); + } + /* XXX tp should be locked. */ + (void) ttywait(tp); /* * The tty could have been revoked * if we blocked. */ - if (sp->s_ttyvp) - VOP_REVOKE(sp->s_ttyvp, REVOKEALL); + if (sp->s_ttyvp) { + ttyvp = sp->s_ttyvp; + SESS_LOCK(p->p_session); + sp->s_ttyvp = NULL; + SESS_UNLOCK(p->p_session); + PGRPSESS_XUNLOCK(); + VOP_REVOKE(ttyvp, REVOKEALL); + PGRPSESS_XLOCK(); + vrele(ttyvp); + } + } + if (sp->s_ttyvp) { + ttyvp = sp->s_ttyvp; + SESS_LOCK(p->p_session); + sp->s_ttyvp = NULL; + SESS_UNLOCK(p->p_session); + vrele(ttyvp); } - if (sp->s_ttyvp) - vrele(sp->s_ttyvp); - sp->s_ttyvp = NULL; /* * s_ttyp is not zero'd; we use this to indicate * that the session once had a controlling terminal. * (for logging and informational purposes) */ } + SESS_LOCK(p->p_session); sp->s_leader = NULL; - } else - PROC_UNLOCK(p); + SESS_UNLOCK(p->p_session); + } fixjobc(p, p->p_pgrp, 0); + PGRPSESS_XUNLOCK(); (void)acct_process(td); #ifdef KTRACE /* @@ -309,7 +332,7 @@ exit1(td, rv) q->p_flag &= ~P_TRACED; psignal(q, SIGKILL); } - PROC_UNLOCK(q); + PROC_UNLOCK(q); } /* @@ -338,6 +361,7 @@ exit1(td, rv) * notify interested parties of our demise. */ PROC_LOCK(p); + PROC_LOCK(p->p_pptr); KNOTE(&p->p_klist, NOTE_EXIT); /* @@ -347,7 +371,9 @@ exit1(td, rv) */ if (p->p_pptr->p_procsig->ps_flag & PS_NOCLDWAIT) { struct proc *pp = p->p_pptr; + PROC_UNLOCK(pp); proc_reparent(p, initproc); + PROC_LOCK(p->p_pptr); /* * If this was the last child of our parent, notify * parent, so in case he was wait(2)ing, he will @@ -357,7 +383,6 @@ exit1(td, rv) wakeup((caddr_t)pp); } - PROC_LOCK(p->p_pptr); if (p->p_sigparent && p->p_pptr != initproc) psignal(p->p_pptr, p->p_sigparent); else @@ -480,8 +505,11 @@ wait1(td, uap, compat) mtx_lock(&Giant); q = td->td_proc; - if (uap->pid == 0) + if (uap->pid == 0) { + PROC_LOCK(q); uap->pid = -q->p_pgid; + PROC_UNLOCK(q); + } if (uap->options &~ (WUNTRACED|WNOHANG|WLINUXCLONE)) { error = EINVAL; goto done2; @@ -490,9 +518,12 @@ loop: nfound = 0; sx_slock(&proctree_lock); LIST_FOREACH(p, &q->p_children, p_sibling) { + PROC_LOCK(p); if (uap->pid != WAIT_ANY && - p->p_pid != uap->pid && p->p_pgid != -uap->pid) + p->p_pid != uap->pid && p->p_pgid != -uap->pid) { + PROC_UNLOCK(p); continue; + } /* * This special case handles a kthread spawned by linux_clone @@ -502,7 +533,6 @@ loop: * p_sigparent is not SIGCHLD, and the WLINUXCLONE option * signifies we want to wait for threads and not processes. */ - PROC_LOCK(p); if ((p->p_sigparent != SIGCHLD) ^ ((uap->options & WLINUXCLONE) != 0)) { PROC_UNLOCK(p); diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index 8fe1006..69071a1 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -382,12 +382,15 @@ retry: p2 = LIST_FIRST(&allproc); again: for (; p2 != NULL; p2 = LIST_NEXT(p2, p_list)) { + PROC_LOCK(p2); while (p2->p_pid == trypid || p2->p_pgrp->pg_id == trypid || p2->p_session->s_sid == trypid) { trypid++; - if (trypid >= pidchecked) + if (trypid >= pidchecked) { + PROC_UNLOCK(p2); goto retry; + } } if (p2->p_pid > trypid && pidchecked > p2->p_pid) pidchecked = p2->p_pid; @@ -397,6 +400,7 @@ again: if (p2->p_session->s_sid > trypid && pidchecked > p2->p_session->s_sid) pidchecked = p2->p_session->s_sid; + PROC_UNLOCK(p2); } if (!doingzomb) { doingzomb = 1; @@ -559,8 +563,10 @@ again: * been preserved. */ p2->p_flag |= p1->p_flag & (P_SUGID | P_ALTSTACK); + SESS_LOCK(p1->p_session); if (p1->p_session->s_ttyvp != NULL && p1->p_flag & P_CONTROLT) p2->p_flag |= P_CONTROLT; + SESS_UNLOCK(p1->p_session); if (flags & RFPPWAIT) p2->p_flag |= P_PPWAIT; diff --git a/sys/kern/kern_ktrace.c b/sys/kern/kern_ktrace.c index db44873..6fc46d6 100644 --- a/sys/kern/kern_ktrace.c +++ b/sys/kern/kern_ktrace.c @@ -350,16 +350,24 @@ ktrace(td, uap) /* * by process group */ + PGRPSESS_SLOCK(); pg = pgfind(-uap->pid); if (pg == NULL) { + PGRPSESS_SUNLOCK(); error = ESRCH; goto done; } + /* + * ktrops() may call vrele(). Lock pg_members + * by the pgrpsess_lock rather than pg_mtx. + */ + PGRP_UNLOCK(pg); LIST_FOREACH(p, &pg->pg_members, p_pglist) if (descend) ret |= ktrsetchildren(curp, p, ops, facs, vp); else ret |= ktrops(curp, p, ops, facs, vp); + PGRPSESS_SUNLOCK(); } else { /* * by pid diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c index b11c23b..27222fa 100644 --- a/sys/kern/kern_proc.c +++ b/sys/kern/kern_proc.c @@ -55,14 +55,18 @@ #include <vm/vm_map.h> #include <vm/vm_zone.h> -static MALLOC_DEFINE(M_PGRP, "pgrp", "process group header"); +MALLOC_DEFINE(M_PGRP, "pgrp", "process group header"); MALLOC_DEFINE(M_SESSION, "session", "session header"); static MALLOC_DEFINE(M_PROC, "proc", "Proc structures"); MALLOC_DEFINE(M_SUBPROC, "subproc", "Proc sub-structures"); +static struct proc *dopfind __P((register pid_t)); + +static void doenterpgrp __P((struct proc *, struct pgrp *)); + static void pgdelete __P((struct pgrp *)); -static void orphanpg __P((struct pgrp *pg)); +static void orphanpg __P((struct pgrp *pg)); /* * Other process lists @@ -75,6 +79,7 @@ struct proclist allproc; struct proclist zombproc; struct sx allproc_lock; struct sx proctree_lock; +struct sx pgrpsess_lock; vm_zone_t proc_zone; vm_zone_t ithread_zone; @@ -88,6 +93,7 @@ procinit() sx_init(&allproc_lock, "allproc"); sx_init(&proctree_lock, "proctree"); + sx_init(&pgrpsess_lock, "pgrpsess"); LIST_INIT(&allproc); LIST_INIT(&zombproc); pidhashtbl = hashinit(maxproc / 4, M_PROC, &pidhash); @@ -265,17 +271,30 @@ pfind(pid) register struct proc *p; sx_slock(&allproc_lock); + p = dopfind(pid); + sx_sunlock(&allproc_lock); + return (p); +} + +static struct proc * +dopfind(pid) + register pid_t pid; +{ + register struct proc *p; + + sx_assert(&allproc_lock, SX_LOCKED); + LIST_FOREACH(p, PIDHASH(pid), p_hash) if (p->p_pid == pid) { PROC_LOCK(p); break; } - sx_sunlock(&allproc_lock); return (p); } /* - * Locate a process group by number + * Locate a process group by number. + * The caller must hold pgrpsess_lock. */ struct pgrp * pgfind(pgid) @@ -283,77 +302,132 @@ pgfind(pgid) { register struct pgrp *pgrp; - LIST_FOREACH(pgrp, PGRPHASH(pgid), pg_hash) - if (pgrp->pg_id == pgid) + PGRPSESS_LOCK_ASSERT(SX_LOCKED); + + LIST_FOREACH(pgrp, PGRPHASH(pgid), pg_hash) { + if (pgrp->pg_id == pgid) { + PGRP_LOCK(pgrp); return (pgrp); + } + } return (NULL); } /* - * Move p to a new or existing process group (and session) + * Create a new process group. + * pgid must be equal to the pid of p. + * Begin a new session if required. */ int -enterpgrp(p, pgid, mksess) +enterpgrp(p, pgid, pgrp, sess) register struct proc *p; pid_t pgid; - int mksess; + struct pgrp *pgrp; + struct session *sess; { - register struct pgrp *pgrp = pgfind(pgid); - struct pgrp *savegrp; + struct pgrp *pgrp2; - KASSERT(pgrp == NULL || !mksess, - ("enterpgrp: setsid into non-empty pgrp")); + PGRPSESS_LOCK_ASSERT(SX_XLOCKED); + + KASSERT(pgrp != NULL, ("enterpgrp: pgrp == NULL")); + KASSERT(p->p_pid == pgid, + ("enterpgrp: new pgrp and pid != pgid")); + + pgrp2 = pgfind(pgid); + + KASSERT(pgrp2 == NULL, + ("enterpgrp: pgrp with pgid exists")); KASSERT(!SESS_LEADER(p), ("enterpgrp: session leader attempted setpgrp")); - if (pgrp == NULL) { - pid_t savepid = p->p_pid; - struct proc *np; + mtx_init(&pgrp->pg_mtx, "process group", MTX_DEF); + + if (sess != NULL) { /* - * new process group + * new session */ - KASSERT(p->p_pid == pgid, - ("enterpgrp: new pgrp and pid != pgid")); - if ((np = pfind(savepid)) == NULL || np != p) { - if (np != NULL) - PROC_UNLOCK(np); - return (ESRCH); - } - PROC_UNLOCK(np); - MALLOC(pgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP, - M_WAITOK); - if (mksess) { - register struct session *sess; - - /* - * new session - */ - MALLOC(sess, struct session *, sizeof(struct session), - M_SESSION, M_WAITOK); - sess->s_leader = p; - sess->s_sid = p->p_pid; - sess->s_count = 1; - sess->s_ttyvp = NULL; - sess->s_ttyp = NULL; - bcopy(p->p_session->s_login, sess->s_login, + mtx_init(&sess->s_mtx, "session", MTX_DEF); + PROC_LOCK(p); + p->p_flag &= ~P_CONTROLT; + PROC_UNLOCK(p); + PGRP_LOCK(pgrp); + sess->s_leader = p; + sess->s_sid = p->p_pid; + sess->s_count = 1; + sess->s_ttyvp = NULL; + sess->s_ttyp = NULL; + bcopy(p->p_session->s_login, sess->s_login, sizeof(sess->s_login)); - PROC_LOCK(p); - p->p_flag &= ~P_CONTROLT; - PROC_UNLOCK(p); - pgrp->pg_session = sess; - KASSERT(p == curproc, - ("enterpgrp: mksession and p != curproc")); - } else { - pgrp->pg_session = p->p_session; - pgrp->pg_session->s_count++; - } - pgrp->pg_id = pgid; - LIST_INIT(&pgrp->pg_members); - LIST_INSERT_HEAD(PGRPHASH(pgid), pgrp, pg_hash); - pgrp->pg_jobc = 0; - SLIST_INIT(&pgrp->pg_sigiolst); - } else if (pgrp == p->p_pgrp) - return (0); + pgrp->pg_session = sess; + KASSERT(p == curproc, + ("enterpgrp: mksession and p != curproc")); + } else { + pgrp->pg_session = p->p_session; + SESS_LOCK(pgrp->pg_session); + pgrp->pg_session->s_count++; + SESS_UNLOCK(pgrp->pg_session); + PGRP_LOCK(pgrp); + } + pgrp->pg_id = pgid; + LIST_INIT(&pgrp->pg_members); + + /* + * As we have an exclusive lock of pgrpsess_lock, + * this should not deadlock. + */ + LIST_INSERT_HEAD(PGRPHASH(pgid), pgrp, pg_hash); + pgrp->pg_jobc = 0; + SLIST_INIT(&pgrp->pg_sigiolst); + PGRP_UNLOCK(pgrp); + + doenterpgrp(p, pgrp); + + return (0); +} + +/* + * Move p to an existing process group + */ +int +enterthispgrp(p, pgrp) + register struct proc *p; + struct pgrp *pgrp; +{ + PGRPSESS_LOCK_ASSERT(SX_XLOCKED); + PROC_LOCK_ASSERT(p, MA_NOTOWNED); + PGRP_LOCK_ASSERT(pgrp, MA_NOTOWNED); + PGRP_LOCK_ASSERT(p->p_pgrp, MA_NOTOWNED); + SESS_LOCK_ASSERT(p->p_session, MA_NOTOWNED); + KASSERT(pgrp->pg_session == p->p_session, + ("%s: pgrp's session %p, p->p_session %p.\n", + __func__, + pgrp->pg_session, + p->p_session)); + KASSERT(pgrp != p->p_pgrp, + ("%s: p belongs to pgrp.", __func__)); + + doenterpgrp(p, pgrp); + + return (0); +} + +/* + * Move p to a process group + */ +static void +doenterpgrp(p, pgrp) + struct proc *p; + struct pgrp *pgrp; +{ + struct pgrp *savepgrp; + + PGRPSESS_LOCK_ASSERT(SX_XLOCKED); + PROC_LOCK_ASSERT(p, MA_NOTOWNED); + PGRP_LOCK_ASSERT(pgrp, MA_NOTOWNED); + PGRP_LOCK_ASSERT(p->p_pgrp, MA_NOTOWNED); + SESS_LOCK_ASSERT(p->p_session, MA_NOTOWNED); + + savepgrp = p->p_pgrp; /* * Adjust eligibility of affected pgrps to participate in job control. @@ -363,15 +437,17 @@ enterpgrp(p, pgid, mksess) fixjobc(p, pgrp, 1); fixjobc(p, p->p_pgrp, 0); + PGRP_LOCK(pgrp); + PGRP_LOCK(savepgrp); PROC_LOCK(p); LIST_REMOVE(p, p_pglist); - savegrp = p->p_pgrp; p->p_pgrp = pgrp; - LIST_INSERT_HEAD(&pgrp->pg_members, p, p_pglist); PROC_UNLOCK(p); - if (LIST_EMPTY(&savegrp->pg_members)) - pgdelete(savegrp); - return (0); + LIST_INSERT_HEAD(&pgrp->pg_members, p, p_pglist); + PGRP_UNLOCK(savepgrp); + PGRP_UNLOCK(pgrp); + if (LIST_EMPTY(&savepgrp->pg_members)) + pgdelete(savepgrp); } /* @@ -381,15 +457,19 @@ int leavepgrp(p) register struct proc *p; { - struct pgrp *savegrp; + struct pgrp *savepgrp; + PGRPSESS_XLOCK(); + savepgrp = p->p_pgrp; + PGRP_LOCK(savepgrp); PROC_LOCK(p); LIST_REMOVE(p, p_pglist); - savegrp = p->p_pgrp; p->p_pgrp = NULL; PROC_UNLOCK(p); - if (LIST_EMPTY(&savegrp->pg_members)) - pgdelete(savegrp); + PGRP_UNLOCK(savepgrp); + if (LIST_EMPTY(&savepgrp->pg_members)) + pgdelete(savepgrp); + PGRPSESS_XUNLOCK(); return (0); } @@ -400,6 +480,13 @@ static void pgdelete(pgrp) register struct pgrp *pgrp; { + struct session *savesess; + + PGRPSESS_LOCK_ASSERT(SX_XLOCKED); + PGRP_LOCK_ASSERT(pgrp, MA_NOTOWNED); + SESS_LOCK_ASSERT(pgrp->pg_session, MA_NOTOWNED); + + PGRP_LOCK(pgrp); /* * Reset any sigio structures pointing to us as a result of @@ -411,8 +498,16 @@ pgdelete(pgrp) pgrp->pg_session->s_ttyp->t_pgrp == pgrp) pgrp->pg_session->s_ttyp->t_pgrp = NULL; LIST_REMOVE(pgrp, pg_hash); - if (--pgrp->pg_session->s_count == 0) + savesess = pgrp->pg_session; + SESS_LOCK(savesess); + savesess->s_count--; + SESS_UNLOCK(savesess); + PGRP_UNLOCK(pgrp); + if (savesess->s_count == 0) { + mtx_destroy(&savesess->s_mtx); FREE(pgrp->pg_session, M_SESSION); + } + mtx_destroy(&pgrp->pg_mtx); FREE(pgrp, M_PGRP); } @@ -433,19 +528,30 @@ fixjobc(p, pgrp, entering) int entering; { register struct pgrp *hispgrp; - register struct session *mysession = pgrp->pg_session; + register struct session *mysession; + + PGRPSESS_LOCK_ASSERT(SX_LOCKED); + PROC_LOCK_ASSERT(p, MA_NOTOWNED); + PGRP_LOCK_ASSERT(pgrp, MA_NOTOWNED); + SESS_LOCK_ASSERT(pgrp->pg_session, MA_NOTOWNED); /* * Check p's parent to see whether p qualifies its own process * group; if so, adjust count for p's process group. */ + mysession = pgrp->pg_session; sx_slock(&proctree_lock); if ((hispgrp = p->p_pptr->p_pgrp) != pgrp && hispgrp->pg_session == mysession) { + PGRP_LOCK(pgrp); if (entering) pgrp->pg_jobc++; - else if (--pgrp->pg_jobc == 0) - orphanpg(pgrp); + else { + --pgrp->pg_jobc; + if (pgrp->pg_jobc == 0) + orphanpg(pgrp); + } + PGRP_UNLOCK(pgrp); } /* @@ -453,15 +559,21 @@ fixjobc(p, pgrp, entering) * their process groups; if so, adjust counts for children's * process groups. */ - LIST_FOREACH(p, &p->p_children, p_sibling) + LIST_FOREACH(p, &p->p_children, p_sibling) { if ((hispgrp = p->p_pgrp) != pgrp && hispgrp->pg_session == mysession && p->p_stat != SZOMB) { + PGRP_LOCK(hispgrp); if (entering) hispgrp->pg_jobc++; - else if (--hispgrp->pg_jobc == 0) - orphanpg(hispgrp); + else { + --hispgrp->pg_jobc; + if (hispgrp->pg_jobc == 0) + orphanpg(hispgrp); + } + PGRP_UNLOCK(hispgrp); } + } sx_sunlock(&proctree_lock); } @@ -476,6 +588,8 @@ orphanpg(pg) { register struct proc *p; + PGRP_LOCK_ASSERT(pg, MA_OWNED); + mtx_lock_spin(&sched_lock); LIST_FOREACH(p, &pg->pg_members, p_pglist) { if (p->p_stat == SSTOP) { @@ -619,6 +733,7 @@ fill_kinfo_proc(p, kp) /* ^^^ XXXKSE */ mtx_unlock_spin(&sched_lock); sp = NULL; + tp = NULL; if (p->p_pgrp) { kp->ki_pgid = p->p_pgrp->pg_id; kp->ki_jobc = p->p_pgrp->pg_jobc; @@ -626,15 +741,18 @@ fill_kinfo_proc(p, kp) if (sp != NULL) { kp->ki_sid = sp->s_sid; + SESS_LOCK(sp); strncpy(kp->ki_login, sp->s_login, sizeof(kp->ki_login) - 1); if (sp->s_ttyvp) kp->ki_kiflag |= KI_CTTY; if (SESS_LEADER(p)) kp->ki_kiflag |= KI_SLEADER; + tp = sp->s_ttyp; + SESS_UNLOCK(sp); } } - if ((p->p_flag & P_CONTROLT) && sp && ((tp = sp->s_ttyp) != NULL)) { + if ((p->p_flag & P_CONTROLT) && tp != NULL) { kp->ki_tdev = dev2udev(tp->t_dev); kp->ki_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; if (tp->t_session) @@ -768,18 +886,32 @@ sysctl_kern_proc(SYSCTL_HANDLER_ARGS) case KERN_PROC_PGRP: /* could do this by traversing pgrp */ + PROC_LOCK(p); if (p->p_pgrp == NULL || - p->p_pgrp->pg_id != (pid_t)name[0]) + p->p_pgrp->pg_id != (pid_t)name[0]) { + PROC_UNLOCK(p); continue; + } + PROC_UNLOCK(p); break; case KERN_PROC_TTY: + PROC_LOCK(p); if ((p->p_flag & P_CONTROLT) == 0 || - p->p_session == NULL || - p->p_session->s_ttyp == NULL || + p->p_session == NULL) { + PROC_UNLOCK(p); + continue; + } + SESS_LOCK(p->p_session); + if (p->p_session->s_ttyp == NULL || dev2udev(p->p_session->s_ttyp->t_dev) != - (udev_t)name[0]) + (udev_t)name[0]) { + SESS_UNLOCK(p->p_session); + PROC_UNLOCK(p); continue; + } + SESS_UNLOCK(p->p_session); + PROC_UNLOCK(p); break; case KERN_PROC_UID: diff --git a/sys/kern/kern_prot.c b/sys/kern/kern_prot.c index 76b0c72..615709e 100644 --- a/sys/kern/kern_prot.c +++ b/sys/kern/kern_prot.c @@ -51,12 +51,12 @@ #include <sys/acct.h> #include <sys/kernel.h> #include <sys/lock.h> +#include <sys/malloc.h> #include <sys/mutex.h> -#include <sys/proc.h> #include <sys/sx.h> +#include <sys/proc.h> #include <sys/sysproto.h> #include <sys/jail.h> -#include <sys/malloc.h> #include <sys/pioctl.h> #include <sys/resourcevar.h> #include <sys/sysctl.h> @@ -137,10 +137,13 @@ getpgrp(td, uap) struct getpgrp_args *uap; { struct proc *p = td->td_proc; + int s; - mtx_lock(&Giant); + s = mtx_lock_giant(kern_giant_proc); + PROC_LOCK(p); td->td_retval[0] = p->p_pgrp->pg_id; - mtx_unlock(&Giant); + PROC_UNLOCK(p); + mtx_unlock_giant(s); return (0); } @@ -164,9 +167,11 @@ getpgid(td, uap) s = mtx_lock_giant(kern_giant_proc); error = 0; - if (uap->pid == 0) + if (uap->pid == 0) { + PROC_LOCK(p); td->td_retval[0] = p->p_pgrp->pg_id; - else if ((pt = pfind(uap->pid)) == NULL) + PROC_UNLOCK(p); + } else if ((pt = pfind(uap->pid)) == NULL) error = ESRCH; else { error = p_cansee(p, pt); @@ -197,12 +202,15 @@ getsid(td, uap) struct proc *p = td->td_proc; struct proc *pt; int error; + int s; - mtx_lock(&Giant); + s = mtx_lock_giant(kern_giant_proc); error = 0; - if (uap->pid == 0) + if (uap->pid == 0) { + PROC_LOCK(p); td->td_retval[0] = p->p_session->s_sid; - else if ((pt = pfind(uap->pid)) == NULL) + PROC_UNLOCK(p); + } else if ((pt = pfind(uap->pid)) == NULL) error = ESRCH; else { error = p_cansee(p, pt); @@ -210,7 +218,7 @@ getsid(td, uap) td->td_retval[0] = pt->p_session->s_sid; PROC_UNLOCK(pt); } - mtx_unlock(&Giant); + mtx_unlock_giant(s); return (error); } @@ -365,19 +373,44 @@ setsid(td, uap) register struct thread *td; struct setsid_args *uap; { + struct pgrp *pgrp; int error; struct proc *p = td->td_proc; + struct pgrp *newpgrp; + struct session *newsess; + + error = 0; + pgrp = NULL; mtx_lock(&Giant); - if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) + + MALLOC(newpgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO); + MALLOC(newsess, struct session *, sizeof(struct session), M_SESSION, M_WAITOK | M_ZERO); + + PGRPSESS_XLOCK(); + + if (p->p_pgid == p->p_pid || (pgrp = pgfind(p->p_pid)) != NULL) { + if (pgrp != NULL) + PGRP_UNLOCK(pgrp); error = EPERM; - else { - (void)enterpgrp(p, p->p_pid, 1); + goto fail; + } else { + (void)enterpgrp(p, p->p_pid, newpgrp, newsess); td->td_retval[0] = p->p_pid; error = 0; } + PGRPSESS_XUNLOCK(); mtx_unlock(&Giant); - return (error); + return (0); + +fail: + PGRPSESS_XUNLOCK(); + + FREE(newpgrp, M_PGRP); + FREE(newsess, M_SESSION); + + mtx_unlock(&Giant); + return (0); } /* @@ -412,57 +445,92 @@ setpgid(td, uap) register struct proc *targp; /* target process */ register struct pgrp *pgrp; /* target pgrp */ int error; + struct pgrp *newpgrp; if (uap->pgid < 0) return (EINVAL); + + error = 0; + mtx_lock(&Giant); - sx_slock(&proctree_lock); + + MALLOC(newpgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO); + + PGRPSESS_XLOCK(); + if (uap->pid != 0 && uap->pid != curp->p_pid) { - if ((targp = pfind(uap->pid)) == NULL || !inferior(targp)) { + sx_slock(&proctree_lock); + if ((targp = pfind(uap->pid)) == NULL) { if (targp) PROC_UNLOCK(targp); + sx_sunlock(&proctree_lock); error = ESRCH; - goto done2; + goto fail; + } + if (!inferior(targp)) { + PROC_UNLOCK(targp); + sx_sunlock(&proctree_lock); + goto fail; } + sx_sunlock(&proctree_lock); if ((error = p_cansee(curproc, targp))) { PROC_UNLOCK(targp); - goto done2; + goto fail; } if (targp->p_pgrp == NULL || targp->p_session != curp->p_session) { PROC_UNLOCK(targp); error = EPERM; - goto done2; + goto fail; } if (targp->p_flag & P_EXEC) { PROC_UNLOCK(targp); error = EACCES; - goto done2; + goto fail; } - } else { + PROC_UNLOCK(targp); + } else targp = curp; - PROC_LOCK(curp); /* XXX: not needed */ - } if (SESS_LEADER(targp)) { - PROC_UNLOCK(targp); error = EPERM; - goto done2; + goto fail; } if (uap->pgid == 0) uap->pgid = targp->p_pid; - else if (uap->pgid != targp->p_pid) { - if ((pgrp = pgfind(uap->pgid)) == 0 || + if (uap->pgid == targp->p_pid) { + if (targp->p_pgid == uap->pgid) + goto done; + error = enterpgrp(targp, uap->pgid, newpgrp, NULL); + if (error == 0) + newpgrp = NULL; + } else { + if ((pgrp = pgfind(uap->pgid)) == NULL || pgrp->pg_session != curp->p_session) { - PROC_UNLOCK(targp); + if (pgrp != NULL) + PGRP_UNLOCK(pgrp); error = EPERM; - goto done2; + goto fail; + } + if (pgrp == targp->p_pgrp) { + PGRP_UNLOCK(pgrp); + goto done; } + PGRP_UNLOCK(pgrp); + error = enterthispgrp(targp, pgrp); } - /* XXX: We should probably hold the lock across enterpgrp. */ - PROC_UNLOCK(targp); - error = enterpgrp(targp, uap->pgid, 0); -done2: - sx_sunlock(&proctree_lock); +done: + PGRPSESS_XUNLOCK(); + if (newpgrp != NULL) + FREE(newpgrp, M_PGRP); + mtx_unlock(&Giant); + return (0); + +fail: + PGRPSESS_XUNLOCK(); + + KASSERT(newpgrp != NULL, ("setpgid failed and newpgrp is null.")); + FREE(newpgrp, M_PGRP); + mtx_unlock(&Giant); return (error); } @@ -1134,7 +1202,9 @@ issetugid(td, uap) * a user without an exec - programs cannot know *everything* * that libc *might* have put in their data segment. */ + PROC_LOCK(p); td->td_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0; + PROC_UNLOCK(p); return (0); } @@ -1153,10 +1223,14 @@ __setugid(td, uap) error = 0; switch (uap->flag) { case 0: + PROC_LOCK(td->td_proc); td->td_proc->p_flag &= ~P_SUGID; + PROC_UNLOCK(td->td_proc); break; case 1: + PROC_LOCK(td->td_proc); td->td_proc->p_flag |= P_SUGID; + PROC_UNLOCK(td->td_proc); break; default: error = EINVAL; @@ -1725,13 +1799,18 @@ getlogin(td, uap) struct getlogin_args *uap; { int error; + char login[MAXLOGNAME]; struct proc *p = td->td_proc; mtx_lock(&Giant); if (uap->namelen > MAXLOGNAME) uap->namelen = MAXLOGNAME; - error = copyout((caddr_t) p->p_pgrp->pg_session->s_login, - (caddr_t) uap->namebuf, uap->namelen); + PROC_LOCK(p); + SESS_LOCK(p->p_session); + bcopy(p->p_session->s_login, login, uap->namelen); + SESS_UNLOCK(p->p_session); + PROC_UNLOCK(p); + error = copyout((caddr_t) login, (caddr_t) uap->namebuf, uap->namelen); mtx_unlock(&Giant); return(error); } @@ -1764,9 +1843,16 @@ setlogin(td, uap) sizeof(logintmp), (size_t *)0); if (error == ENAMETOOLONG) error = EINVAL; - else if (!error) - (void)memcpy(p->p_pgrp->pg_session->s_login, logintmp, + else if (!error) { + PGRPSESS_XLOCK(); + PROC_LOCK(p); + SESS_LOCK(p->p_session); + (void) memcpy(p->p_session->s_login, logintmp, sizeof(logintmp)); + SESS_UNLOCK(p->p_session); + PROC_UNLOCK(p); + PGRPSESS_XUNLOCK(); + } done2: mtx_unlock(&Giant); return (error); diff --git a/sys/kern/kern_resource.c b/sys/kern/kern_resource.c index ffcd488..c15c631 100644 --- a/sys/kern/kern_resource.c +++ b/sys/kern/kern_resource.c @@ -111,14 +111,25 @@ getpriority(td, uap) case PRIO_PGRP: { register struct pgrp *pg; - if (uap->who == 0) + PGRPSESS_SLOCK(); + if (uap->who == 0) { pg = curp->p_pgrp; - else if ((pg = pgfind(uap->who)) == NULL) - break; + PGRP_LOCK(pg); + } else { + pg = pgfind(uap->who); + if (pg == NULL) { + PGRPSESS_SUNLOCK(); + break; + } + } + PGRPSESS_SUNLOCK(); LIST_FOREACH(p, &pg->pg_members, p_pglist) { + PROC_LOCK(p); if (!p_cansee(curp, p) && p->p_ksegrp.kg_nice /* XXXKSE */ < low) low = p->p_ksegrp.kg_nice /* XXXKSE */ ; + PROC_UNLOCK(p); } + PGRP_UNLOCK(pg); break; } @@ -185,16 +196,27 @@ setpriority(td, uap) case PRIO_PGRP: { register struct pgrp *pg; - if (uap->who == 0) + PGRPSESS_SLOCK(); + if (uap->who == 0) { pg = curp->p_pgrp; - else if ((pg = pgfind(uap->who)) == NULL) - break; + PGRP_LOCK(pg); + } else { + pg = pgfind(uap->who); + if (pg == NULL) { + PGRPSESS_SUNLOCK(); + break; + } + } + PGRPSESS_SUNLOCK(); LIST_FOREACH(p, &pg->pg_members, p_pglist) { + PROC_LOCK(p); if (!p_cansee(curp, p)) { error = donice(curp, p, uap->prio); found++; } + PROC_UNLOCK(p); } + PGRP_UNLOCK(pg); break; } diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index 27acc64..f871cd5 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -1001,16 +1001,21 @@ killpg1(cp, sig, pgid, all) } sx_sunlock(&allproc_lock); } else { - if (pgid == 0) + PGRPSESS_SLOCK(); + if (pgid == 0) { /* * zero pgid means send to my process group. */ pgrp = cp->p_pgrp; - else { + PGRP_LOCK(pgrp); + } else { pgrp = pgfind(pgid); - if (pgrp == NULL) + if (pgrp == NULL) { + PGRPSESS_SUNLOCK(); return (ESRCH); + } } + PGRPSESS_SUNLOCK(); LIST_FOREACH(p, &pgrp->pg_members, p_pglist) { PROC_LOCK(p); if (p->p_pid <= 1 || p->p_flag & P_SYSTEM) { @@ -1031,6 +1036,7 @@ killpg1(cp, sig, pgid, all) } PROC_UNLOCK(p); } + PGRP_UNLOCK(pgrp); } return (nfound ? 0 : ESRCH); } @@ -1124,8 +1130,15 @@ gsignal(pgid, sig) { struct pgrp *pgrp; - if (pgid && (pgrp = pgfind(pgid))) - pgsignal(pgrp, sig, 0); + if (pgid != 0) { + PGRPSESS_SLOCK(); + pgrp = pgfind(pgid); + PGRPSESS_SUNLOCK(); + if (pgrp != NULL) { + pgsignal(pgrp, sig, 0); + PGRP_UNLOCK(pgrp); + } + } } /* @@ -1140,6 +1153,7 @@ pgsignal(pgrp, sig, checkctty) register struct proc *p; if (pgrp) { + PGRP_LOCK_ASSERT(pgrp, MA_OWNED); LIST_FOREACH(p, &pgrp->pg_members, p_pglist) { PROC_LOCK(p); if (checkctty == 0 || p->p_flag & P_CONTROLT) @@ -1351,11 +1365,10 @@ psignal(p, sig) goto out; SIGDELSET(p->p_siglist, sig); p->p_xstat = sig; - if ((p->p_pptr->p_procsig->ps_flag & PS_NOCLDSTOP) == 0) { - PROC_LOCK(p->p_pptr); + PROC_LOCK(p->p_pptr); + if ((p->p_pptr->p_procsig->ps_flag & PS_NOCLDSTOP) == 0) psignal(p->p_pptr, SIGCHLD); - PROC_UNLOCK(p->p_pptr); - } + PROC_UNLOCK(p->p_pptr); mtx_lock_spin(&sched_lock); stop(p); mtx_unlock_spin(&sched_lock); @@ -1629,14 +1642,13 @@ issignal(p) if (prop & SA_STOP) { if (p->p_flag & P_TRACED || (p->p_pgrp->pg_jobc == 0 && - prop & SA_TTYSTOP)) + prop & SA_TTYSTOP)) break; /* == ignore */ p->p_xstat = sig; - if ((p->p_pptr->p_procsig->ps_flag & PS_NOCLDSTOP) == 0) { - PROC_LOCK(p->p_pptr); + PROC_LOCK(p->p_pptr); + if ((p->p_pptr->p_procsig->ps_flag & PS_NOCLDSTOP) == 0) psignal(p->p_pptr, SIGCHLD); - PROC_UNLOCK(p->p_pptr); - } + PROC_UNLOCK(p->p_pptr); mtx_lock_spin(&sched_lock); stop(p); PROC_UNLOCK(p); @@ -2074,7 +2086,7 @@ pgsigio(sigio, sig, checkctty) { if (sigio == NULL) return; - + if (sigio->sio_pgid > 0) { PROC_LOCK(sigio->sio_proc); if (CANSIGIO(sigio->sio_ucred, sigio->sio_proc->p_ucred)) @@ -2083,6 +2095,7 @@ pgsigio(sigio, sig, checkctty) } else if (sigio->sio_pgid < 0) { struct proc *p; + PGRP_LOCK(sigio->sio_pgrp); LIST_FOREACH(p, &sigio->sio_pgrp->pg_members, p_pglist) { PROC_LOCK(p); if (CANSIGIO(sigio->sio_ucred, p->p_ucred) && @@ -2090,6 +2103,7 @@ pgsigio(sigio, sig, checkctty) psignal(p, sig); PROC_UNLOCK(p); } + PGRP_UNLOCK(sigio->sio_pgrp); } } diff --git a/sys/kern/subr_prf.c b/sys/kern/subr_prf.c index daa38e4..034a63c 100644 --- a/sys/kern/subr_prf.c +++ b/sys/kern/subr_prf.c @@ -41,6 +41,9 @@ #include <sys/param.h> #include <sys/systm.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/sx.h> #include <sys/kernel.h> #include <sys/msgbuf.h> #include <sys/malloc.h> @@ -113,16 +116,28 @@ uprintf(const char *fmt, ...) struct proc *p = td->td_proc; va_list ap; struct putchar_arg pca; - int retval = 0; + int retval; + + if (td == NULL || td == PCPU_GET(idlethread)) + return (0); - if (td && td != PCPU_GET(idlethread) && p->p_flag & P_CONTROLT && - p->p_session->s_ttyvp) { - va_start(ap, fmt); - pca.tty = p->p_session->s_ttyp; - pca.flags = TOTTY; - retval = kvprintf(fmt, putchar, &pca, 10, ap); - va_end(ap); + p = td->td_proc; + PROC_LOCK(p); + if ((p->p_flag & P_CONTROLT) == 0) { + PROC_UNLOCK(p); + return (0); } + SESS_LOCK(p->p_session); + pca.tty = p->p_session->s_ttyp; + SESS_UNLOCK(p->p_session); + PROC_UNLOCK(p); + if (pca.tty == NULL) + return (0); + pca.flags = TOTTY; + va_start(ap, fmt); + retval = kvprintf(fmt, putchar, &pca, 10, ap); + va_end(ap); + return (retval); } @@ -141,13 +156,23 @@ tprintf(struct proc *p, int pri, const char *fmt, ...) if (pri != -1) flags |= TOLOG; - if (p && p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) { - SESSHOLD(p->p_session); - shld++; - if (ttycheckoutq(p->p_session->s_ttyp, 0)) { - flags |= TOTTY; + if (p != NULL) { + PGRPSESS_XLOCK(); + PROC_LOCK(p); + if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) { + SESS_LOCK(p->p_session); + SESSHOLD(p->p_session); tp = p->p_session->s_ttyp; - } + SESS_UNLOCK(p->p_session); + PROC_UNLOCK(p); + shld++; + if (ttycheckoutq(tp, 0)) + flags |= TOTTY; + else + tp = NULL; + } else + PROC_UNLOCK(p); + PGRPSESS_XUNLOCK(); } pca.pri = pri; pca.tty = tp; @@ -155,8 +180,13 @@ tprintf(struct proc *p, int pri, const char *fmt, ...) va_start(ap, fmt); retval = kvprintf(fmt, putchar, &pca, 10, ap); va_end(ap); - if (shld) + if (shld) { + PGRPSESS_XLOCK(); + SESS_LOCK(p->p_session); SESSRELE(p->p_session); + SESS_UNLOCK(p->p_session); + PGRPSESS_XUNLOCK(); + } msgbuftrigger = 1; } diff --git a/sys/kern/subr_witness.c b/sys/kern/subr_witness.c index 4bb6a70..39e3243 100644 --- a/sys/kern/subr_witness.c +++ b/sys/kern/subr_witness.c @@ -188,9 +188,12 @@ static struct lock_list_entry w_locklistdata[LOCK_CHILDCOUNT]; static struct witness_order_list_entry order_lists[] = { { "Giant", &lock_class_mtx_sleep }, + { "pgrpsess", &lock_class_sx }, { "proctree", &lock_class_sx }, { "allproc", &lock_class_sx }, + { "process group", &lock_class_mtx_sleep }, { "process lock", &lock_class_mtx_sleep }, + { "session", &lock_class_mtx_sleep }, { "uidinfo hash", &lock_class_mtx_sleep }, { "uidinfo struct", &lock_class_mtx_sleep }, { NULL, NULL }, @@ -227,6 +230,7 @@ static struct witness_order_list_entry order_lists[] = { static const char *dup_list[] = { "process lock", + "process group", NULL }; diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c index 018734e..e15f191 100644 --- a/sys/kern/sys_process.c +++ b/sys/kern/sys_process.c @@ -515,10 +515,10 @@ ptrace(struct thread *td, struct ptrace_args *uap) struct proc *pp; pp = pfind(p->p_oppid); - if (pp != NULL) - PROC_UNLOCK(pp); - else + if (pp == NULL) pp = initproc; + else + PROC_UNLOCK(pp); PROC_LOCK(p); proc_reparent(p, pp); } else diff --git a/sys/kern/tty.c b/sys/kern/tty.c index 5c778b7..2ca162a 100644 --- a/sys/kern/tty.c +++ b/sys/kern/tty.c @@ -75,6 +75,7 @@ #include <sys/filio.h> #include <sys/lock.h> #include <sys/mutex.h> +#include <sys/sx.h> #if defined(COMPAT_43) || defined(COMPAT_SUNOS) #include <sys/ioctl_compat.h> #endif @@ -328,7 +329,11 @@ ttyinput(c, tp) return (0); if (ISSET(iflag, BRKINT)) { ttyflush(tp, FREAD | FWRITE); - pgsignal(tp->t_pgrp, SIGINT, 1); + if (tp->t_pgrp != NULL) { + PGRP_LOCK(tp->t_pgrp); + pgsignal(tp->t_pgrp, SIGINT, 1); + PGRP_UNLOCK(tp->t_pgrp); + } goto endcase; } if (ISSET(iflag, PARMRK)) @@ -406,15 +411,23 @@ parmrk: if (!ISSET(lflag, NOFLSH)) ttyflush(tp, FREAD | FWRITE); ttyecho(c, tp); - pgsignal(tp->t_pgrp, - CCEQ(cc[VINTR], c) ? SIGINT : SIGQUIT, 1); + if (tp->t_pgrp != NULL) { + PGRP_LOCK(tp->t_pgrp); + pgsignal(tp->t_pgrp, + CCEQ(cc[VINTR], c) ? SIGINT : SIGQUIT, 1); + PGRP_UNLOCK(tp->t_pgrp); + } goto endcase; } if (CCEQ(cc[VSUSP], c)) { if (!ISSET(lflag, NOFLSH)) ttyflush(tp, FREAD); ttyecho(c, tp); - pgsignal(tp->t_pgrp, SIGTSTP, 1); + if (tp->t_pgrp != NULL) { + PGRP_LOCK(tp->t_pgrp); + pgsignal(tp->t_pgrp, SIGTSTP, 1); + PGRP_UNLOCK(tp->t_pgrp); + } goto endcase; } } @@ -532,8 +545,11 @@ parmrk: * ^T - kernel info and generate SIGINFO */ if (CCEQ(cc[VSTATUS], c) && ISSET(lflag, IEXTEN)) { - if (ISSET(lflag, ISIG)) + if (ISSET(lflag, ISIG) && tp->t_pgrp != NULL) { + PGRP_LOCK(tp->t_pgrp); pgsignal(tp->t_pgrp, SIGINFO, 1); + PGRP_UNLOCK(tp->t_pgrp); + } if (!ISSET(lflag, NOKERNINFO)) ttyinfo(tp); goto endcase; @@ -752,17 +768,30 @@ ttioctl(tp, cmd, data, flag) case TIOCSETP: case TIOCSLTC: #endif + PGRPSESS_SLOCK(); + PROC_LOCK(p); while (isbackground(p, tp) && !(p->p_flag & P_PPWAIT) && !SIGISMEMBER(p->p_sigignore, SIGTTOU) && !SIGISMEMBER(p->p_sigmask, SIGTTOU)) { - if (p->p_pgrp->pg_jobc == 0) + if (p->p_pgrp->pg_jobc == 0) { + PROC_UNLOCK(p); + PGRPSESS_SUNLOCK(); return (EIO); + } + PROC_UNLOCK(p); + PGRP_LOCK(p->p_pgrp); pgsignal(p->p_pgrp, SIGTTOU, 1); + PGRP_UNLOCK(p->p_pgrp); error = ttysleep(tp, &lbolt, TTOPRI | PCATCH, "ttybg1", 0); - if (error) + if (error) { + PGRPSESS_SUNLOCK(); return (error); + } + PROC_LOCK(p); } + PROC_UNLOCK(p); + PGRPSESS_SUNLOCK(); break; } @@ -1012,22 +1041,44 @@ ttioctl(tp, cmd, data, flag) break; case TIOCSCTTY: /* become controlling tty */ /* Session ctty vnode pointer set in vnode layer. */ + PGRPSESS_XLOCK(); if (!SESS_LEADER(p) || ((p->p_session->s_ttyvp || tp->t_session) && - (tp->t_session != p->p_session))) + (tp->t_session != p->p_session))) { + PGRPSESS_XUNLOCK(); return (EPERM); + } tp->t_session = p->p_session; tp->t_pgrp = p->p_pgrp; + SESS_LOCK(p->p_session); p->p_session->s_ttyp = tp; + SESS_UNLOCK(p->p_session); + PROC_LOCK(p); p->p_flag |= P_CONTROLT; + PROC_UNLOCK(p); + PGRPSESS_XUNLOCK(); break; case TIOCSPGRP: { /* set pgrp of tty */ - register struct pgrp *pgrp = pgfind(*(int *)data); - - if (!isctty(p, tp)) + register struct pgrp *pgrp; + + PGRPSESS_SLOCK(); + pgrp = pgfind(*(int *)data); + if (!isctty(p, tp)) { + if (pgrp != NULL) + PGRP_UNLOCK(pgrp); + PGRPSESS_SUNLOCK(); return (ENOTTY); - else if (pgrp == NULL || pgrp->pg_session != p->p_session) + } + if (pgrp == NULL) { + PGRPSESS_SUNLOCK(); return (EPERM); + } + PGRP_UNLOCK(pgrp); + if (pgrp->pg_session != p->p_session) { + PGRPSESS_SUNLOCK(); + return (EPERM); + } + PGRPSESS_SUNLOCK(); tp->t_pgrp = pgrp; break; } @@ -1040,7 +1091,11 @@ ttioctl(tp, cmd, data, flag) if (bcmp((caddr_t)&tp->t_winsize, data, sizeof (struct winsize))) { tp->t_winsize = *(struct winsize *)data; - pgsignal(tp->t_pgrp, SIGWINCH, 1); + if (tp->t_pgrp != NULL) { + PGRP_LOCK(tp->t_pgrp); + pgsignal(tp->t_pgrp, SIGWINCH, 1); + PGRP_UNLOCK(tp->t_pgrp); + } } break; case TIOCSDRAINWAIT: @@ -1459,13 +1514,17 @@ ttymodem(tp, flag) !ISSET(tp->t_cflag, CLOCAL)) { SET(tp->t_state, TS_ZOMBIE); CLR(tp->t_state, TS_CONNECTED); - if (tp->t_session && tp->t_session->s_leader) { - struct proc *p; - - p = tp->t_session->s_leader; - PROC_LOCK(p); - psignal(p, SIGHUP); - PROC_UNLOCK(p); + if (tp->t_session) { + PGRPSESS_SLOCK(); + if (tp->t_session->s_leader) { + struct proc *p; + + p = tp->t_session->s_leader; + PROC_LOCK(p); + psignal(p, SIGHUP); + PROC_UNLOCK(p); + } + PGRPSESS_SUNLOCK(); } ttyflush(tp, FREAD | FWRITE); return (0); @@ -1549,11 +1608,20 @@ loop: */ if (isbackground(p, tp)) { splx(s); + PGRPSESS_SLOCK(); + PROC_LOCK(p); if (SIGISMEMBER(p->p_sigignore, SIGTTIN) || SIGISMEMBER(p->p_sigmask, SIGTTIN) || - (p->p_flag & P_PPWAIT) || p->p_pgrp->pg_jobc == 0) + (p->p_flag & P_PPWAIT) || p->p_pgrp->pg_jobc == 0) { + PROC_UNLOCK(p); + PGRPSESS_SUNLOCK(); return (EIO); + } + PROC_UNLOCK(p); + PGRP_LOCK(p->p_pgrp); + PGRPSESS_SUNLOCK(); pgsignal(p->p_pgrp, SIGTTIN, 1); + PGRP_UNLOCK(p->p_pgrp); error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, "ttybg2", 0); if (error) return (error); @@ -1727,7 +1795,11 @@ slowcase: */ if (CCEQ(cc[VDSUSP], c) && ISSET(lflag, IEXTEN | ISIG) == (IEXTEN | ISIG)) { - pgsignal(tp->t_pgrp, SIGTSTP, 1); + if (tp->t_pgrp != NULL) { + PGRP_LOCK(tp->t_pgrp); + pgsignal(tp->t_pgrp, SIGTSTP, 1); + PGRP_UNLOCK(tp->t_pgrp); + } if (first) { error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, "ttybg3", 0); @@ -1855,19 +1927,30 @@ loop: * Hang the process if it's in the background. */ p = curproc; + PGRPSESS_SLOCK(); + PROC_LOCK(p); if (isbackground(p, tp) && ISSET(tp->t_lflag, TOSTOP) && !(p->p_flag & P_PPWAIT) && !SIGISMEMBER(p->p_sigignore, SIGTTOU) && !SIGISMEMBER(p->p_sigmask, SIGTTOU)) { if (p->p_pgrp->pg_jobc == 0) { + PROC_UNLOCK(p); + PGRPSESS_SUNLOCK(); error = EIO; goto out; } + PROC_UNLOCK(p); + PGRP_LOCK(p->p_pgrp); + PGRPSESS_SUNLOCK(); pgsignal(p->p_pgrp, SIGTTOU, 1); + PGRP_UNLOCK(p->p_pgrp); error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, "ttybg4", 0); if (error) goto out; goto loop; + } else { + PROC_UNLOCK(p); + PGRPSESS_SUNLOCK(); } /* * Process the user's data in at most OBUFSIZ chunks. Perform any @@ -2328,38 +2411,44 @@ ttyinfo(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) - ttyprintf(tp, "empty foreground process group\n"); else { - mtx_lock_spin(&sched_lock); - - /* Pick interesting process. */ - for (pick = NULL; p != 0; p = LIST_NEXT(p, p_pglist)) - if (proc_compare(pick, p)) - pick = p; - - td = FIRST_THREAD_IN_PROC(pick); - stmp = pick->p_stat == SRUN ? "running" : /* XXXKSE */ - td->td_wmesg ? td->td_wmesg : "iowait"; - calcru(pick, &utime, &stime, NULL); - ltmp = pick->p_stat == SIDL || pick->p_stat == SWAIT || - pick->p_stat == SZOMB ? 0 : - pgtok(vmspace_resident_count(pick->p_vmspace)); - mtx_unlock_spin(&sched_lock); - - ttyprintf(tp, " cmd: %s %d [%s] ", pick->p_comm, pick->p_pid, - stmp); - - /* Print user time. */ - ttyprintf(tp, "%ld.%02ldu ", - (long)utime.tv_sec, utime.tv_usec / 10000); - - /* Print system time. */ - ttyprintf(tp, "%ld.%02lds ", - (long)stime.tv_sec, stime.tv_usec / 10000); - - /* Print percentage cpu, resident set size. */ - ttyprintf(tp, "%d%% %ldk\n", tmp / 100, ltmp); + PGRP_LOCK(tp->t_pgrp); + if ((p = LIST_FIRST(&tp->t_pgrp->pg_members)) == 0) { + PGRP_UNLOCK(tp->t_pgrp); + ttyprintf(tp, "empty foreground process group\n"); + } else { + PGRP_UNLOCK(tp->t_pgrp); + mtx_lock_spin(&sched_lock); + + /* Pick interesting process. */ + for (pick = NULL; p != 0; p = LIST_NEXT(p, p_pglist)) + if (proc_compare(pick, p)) + pick = p; + + td = FIRST_THREAD_IN_PROC(pick); + stmp = pick->p_stat == SRUN ? "running" : /* XXXKSE */ + td->td_wmesg ? td->td_wmesg : "iowait"; + calcru(pick, &utime, &stime, NULL); + ltmp = pick->p_stat == SIDL || pick->p_stat == SWAIT || + pick->p_stat == SZOMB ? 0 : + pgtok(vmspace_resident_count(pick->p_vmspace)); + mtx_unlock_spin(&sched_lock); + + ttyprintf(tp, " cmd: %s %d [%s] ", pick->p_comm, pick->p_pid, + stmp); + + /* Print user time. */ + ttyprintf(tp, "%lld.%02ldu ", + utime.tv_sec, utime.tv_usec / 10000); + + /* Print system time. */ + ttyprintf(tp, "%ld.%02lds ", + (long)stime.tv_sec, stime.tv_usec / 10000); + + /* Print percentage cpu, resident set size. */ + ttyprintf(tp, "%d%% %ldk\n", tmp / 100, ltmp); + + } } tp->t_rocount = 0; /* so pending input will be retyped if BS */ } diff --git a/sys/kern/tty_pty.c b/sys/kern/tty_pty.c index 6f1c0db..b3fcc8d 100644 --- a/sys/kern/tty_pty.c +++ b/sys/kern/tty_pty.c @@ -41,6 +41,9 @@ #include "opt_compat.h" #include <sys/param.h> #include <sys/systm.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/sx.h> #if defined(COMPAT_43) || defined(COMPAT_SUNOS) #include <sys/ioctl_compat.h> #endif @@ -237,11 +240,19 @@ ptsread(dev, uio, flag) again: if (pti->pt_flags & PF_REMOTE) { while (isbackground(p, tp)) { + PGRPSESS_SLOCK(); + PROC_LOCK(p); if (SIGISMEMBER(p->p_sigignore, SIGTTIN) || SIGISMEMBER(p->p_sigmask, SIGTTIN) || - p->p_pgrp->pg_jobc == 0 || p->p_flag & P_PPWAIT) + p->p_pgrp->pg_jobc == 0 || p->p_flag & P_PPWAIT) { + PROC_UNLOCK(p); return (EIO); + } + PROC_UNLOCK(p); + PGRP_LOCK(p->p_pgrp); + PGRPSESS_SUNLOCK(); pgsignal(p->p_pgrp, SIGTTIN, 1); + PGRP_UNLOCK(p->p_pgrp); error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, "ptsbg", 0); if (error) @@ -715,7 +726,11 @@ ptyioctl(dev, cmd, data, flag, td) return(EINVAL); if ((tp->t_lflag&NOFLSH) == 0) ttyflush(tp, FREAD|FWRITE); - pgsignal(tp->t_pgrp, *(unsigned int *)data, 1); + if (tp->t_pgrp != NULL) { + PGRP_LOCK(tp->t_pgrp); + pgsignal(tp->t_pgrp, *(unsigned int *)data, 1); + PGRP_UNLOCK(tp->t_pgrp); + } if ((*(unsigned int *)data == SIGINFO) && ((tp->t_lflag&NOKERNINFO) == 0)) ttyinfo(tp); diff --git a/sys/kern/tty_tty.c b/sys/kern/tty_tty.c index 1c6635c..931da01 100644 --- a/sys/kern/tty_tty.c +++ b/sys/kern/tty_tty.c @@ -43,6 +43,8 @@ #include <sys/conf.h> #include <sys/kernel.h> #include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/sx.h> #include <sys/proc.h> #include <sys/ttycom.h> #include <sys/vnode.h> @@ -80,9 +82,15 @@ cttyopen(dev, flag, mode, td) int flag, mode; struct thread *td; { - struct vnode *ttyvp = cttyvp(td); + struct vnode *ttyvp; int error; + PROC_LOCK(td->td_proc); + SESS_LOCK(td->td_proc->p_session); + ttyvp = cttyvp(td); + SESS_UNLOCK(td->td_proc->p_session); + PROC_UNLOCK(td->td_proc); + if (ttyvp == NULL) return (ENXIO); vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY, td); @@ -99,9 +107,15 @@ cttyread(dev, uio, flag) int flag; { struct thread *td = uio->uio_td; - register struct vnode *ttyvp = cttyvp(td); + register struct vnode *ttyvp; int error; + PROC_LOCK(td->td_proc); + SESS_LOCK(td->td_proc->p_session); + ttyvp = cttyvp(td); + SESS_UNLOCK(td->td_proc->p_session); + PROC_UNLOCK(td->td_proc); + if (ttyvp == NULL) return (EIO); vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY, td); @@ -118,10 +132,16 @@ cttywrite(dev, uio, flag) int flag; { struct thread *td = uio->uio_td; - struct vnode *ttyvp = cttyvp(uio->uio_td); + struct vnode *ttyvp; struct mount *mp; int error; + PROC_LOCK(td->td_proc); + SESS_LOCK(td->td_proc->p_session); + ttyvp = cttyvp(td); + SESS_UNLOCK(td->td_proc->p_session); + PROC_UNLOCK(td->td_proc); + if (ttyvp == NULL) return (EIO); mp = NULL; @@ -144,18 +164,30 @@ cttyioctl(dev, cmd, addr, flag, td) int flag; struct thread *td; { - struct vnode *ttyvp = cttyvp(td); + struct vnode *ttyvp; + int error; + + PROC_LOCK(td->td_proc); + SESS_LOCK(td->td_proc->p_session); + ttyvp = cttyvp(td); + SESS_UNLOCK(td->td_proc->p_session); + PROC_UNLOCK(td->td_proc); if (ttyvp == NULL) return (EIO); if (cmd == TIOCSCTTY) /* don't allow controlling tty to be set */ return EINVAL; /* to controlling tty -- infinite recursion */ if (cmd == TIOCNOTTY) { - if (!SESS_LEADER(td->td_proc)) { + PROC_LOCK(td->td_proc); + SESS_LOCK(td->td_proc->p_session); + error = 0; + if (!SESS_LEADER(td->td_proc)) td->td_proc->p_flag &= ~P_CONTROLT; - return (0); - } else - return (EINVAL); + else + error = EINVAL; + SESS_UNLOCK(td->td_proc->p_session); + PROC_UNLOCK(td->td_proc); + return (error); } return (VOP_IOCTL(ttyvp, cmd, addr, flag, NOCRED, td)); } @@ -167,7 +199,13 @@ cttypoll(dev, events, td) int events; struct thread *td; { - struct vnode *ttyvp = cttyvp(td); + struct vnode *ttyvp; + + PROC_LOCK(td->td_proc); + SESS_LOCK(td->td_proc->p_session); + ttyvp = cttyvp(td); + SESS_UNLOCK(td->td_proc->p_session); + PROC_UNLOCK(td->td_proc); if (ttyvp == NULL) /* try operation to get EOF/failure */ diff --git a/sys/kern/vfs_aio.c b/sys/kern/vfs_aio.c index 3acdf2b..84c1408 100644 --- a/sys/kern/vfs_aio.c +++ b/sys/kern/vfs_aio.c @@ -22,6 +22,7 @@ #include <sys/param.h> #include <sys/systm.h> +#include <sys/malloc.h> #include <sys/bio.h> #include <sys/buf.h> #include <sys/sysproto.h> @@ -741,6 +742,8 @@ aio_daemon(void *uproc) struct proc *curcp, *mycp, *userp; struct vmspace *myvm, *tmpvm; struct thread *td = curthread; + struct pgrp *newpgrp; + struct session *newsess; mtx_lock(&Giant); /* @@ -781,7 +784,12 @@ aio_daemon(void *uproc) mycp->p_fd = NULL; /* The daemon resides in its own pgrp. */ - enterpgrp(mycp, mycp->p_pid, 1); + MALLOC(newpgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO); + MALLOC(newsess, struct session *, sizeof(struct session), M_SESSION, M_WAITOK | M_ZERO); + + PGRPSESS_XLOCK(); + enterpgrp(mycp, mycp->p_pid, newpgrp, newsess); + PGRPSESS_XUNLOCK(); /* Mark special process type. */ mycp->p_flag |= P_SYSTEM; diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index aba87d4..ab3e3c9 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -619,6 +619,7 @@ vn_ioctl(fp, com, data, td) struct thread *td; { register struct vnode *vp = ((struct vnode *)fp->f_data); + struct vnode *vpold; struct vattr vattr; int error; @@ -656,15 +657,23 @@ vn_ioctl(fp, com, data, td) if (error == 0 && com == TIOCSCTTY) { /* Do nothing if reassigning same control tty */ - if (td->td_proc->p_session->s_ttyvp == vp) + PGRPSESS_XLOCK(); + if (td->td_proc->p_session->s_ttyvp == vp) { + PGRPSESS_XUNLOCK(); return (0); + } - /* Get rid of reference to old control tty */ - if (td->td_proc->p_session->s_ttyvp) - vrele(td->td_proc->p_session->s_ttyvp); - - td->td_proc->p_session->s_ttyvp = vp; + vpold = td->td_proc->p_session->s_ttyvp; VREF(vp); + SESS_LOCK(td->td_proc->p_session); + td->td_proc->p_session->s_ttyvp = vp; + SESS_UNLOCK(td->td_proc->p_session); + + PGRPSESS_XUNLOCK(); + + /* Get rid of reference to old control tty */ + if (vpold) + vrele(vpold); } return (error); } diff --git a/sys/net/if_sl.c b/sys/net/if_sl.c index 228f396..c2e0e17 100644 --- a/sys/net/if_sl.c +++ b/sys/net/if_sl.c @@ -83,6 +83,7 @@ #include <sys/kernel.h> #include <sys/conf.h> #include <sys/module.h> +#include <sys/proc.h> #include <net/if.h> #include <net/if_types.h> @@ -1076,9 +1077,13 @@ sl_keepalive(chan) struct sl_softc *sc = chan; if (sc->sc_keepalive) { - if (sc->sc_flags & SC_KEEPALIVE) - pgsignal (sc->sc_ttyp->t_pgrp, SIGURG, 1); - else + if (sc->sc_flags & SC_KEEPALIVE) { + if (sc->sc_ttyp->t_pgrp != NULL) { + PGRP_LOCK(sc->sc_ttyp->t_pgrp); + pgsignal (sc->sc_ttyp->t_pgrp, SIGURG, 1); + PGRP_UNLOCK(sc->sc_ttyp->t_pgrp); + } + } else sc->sc_flags |= SC_KEEPALIVE; sc->sc_kahandle = timeout(sl_keepalive, sc, sc->sc_keepalive); } else { diff --git a/sys/netkey/key.c b/sys/netkey/key.c index 4236081..12b9401 100644 --- a/sys/netkey/key.c +++ b/sys/netkey/key.c @@ -7306,14 +7306,24 @@ key_getuserfqdn() struct proc *p = curproc; char *q; - if (!p || !p->p_pgrp || !p->p_pgrp->pg_session) + if (p == NULL) return NULL; - if (!(host = key_getfqdn())) + bzero(userfqdn, sizeof(userfqdn)); + if (!(host = key_getfqdn())) { + PROC_UNLOCK(p); + return NULL; + } + PROC_LOCK(p); + if (!p->p_pgrp || !p->p_pgrp->pg_session) { + PROC_UNLOCK(p); return NULL; + } /* NOTE: s_login may not be-NUL terminated. */ - bzero(userfqdn, sizeof(userfqdn)); - bcopy(p->p_pgrp->pg_session->s_login, userfqdn, MAXLOGNAME); + SESS_LOCK(p->p_session); + bcopy(p->p_session->s_login, userfqdn, MAXLOGNAME); + SESS_UNLOCK(p->p_session); + PROC_UNLOCK(p); userfqdn[MAXLOGNAME] = '\0'; /* safeguard */ q = userfqdn + strlen(userfqdn); *q++ = '@'; diff --git a/sys/sys/file.h b/sys/sys/file.h index b8a17c2..fac4848 100644 --- a/sys/sys/file.h +++ b/sys/sys/file.h @@ -37,6 +37,10 @@ #ifndef _SYS_FILE_H_ #define _SYS_FILE_H_ +#include <sys/systm.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/sx.h> #ifndef _KERNEL #include <sys/fcntl.h> #include <sys/unistd.h> diff --git a/sys/sys/filedesc.h b/sys/sys/filedesc.h index ae2ea4e..ef833fbf 100644 --- a/sys/sys/filedesc.h +++ b/sys/sys/filedesc.h @@ -110,17 +110,20 @@ struct filedesc0 { * on a device or socket. The structure is placed on an SLIST belonging * to the proc or pgrp so that the entire list may be revoked when the * process exits or the process group disappears. + * + * (c) const + * (pg) locked by either the process or process group lock */ struct sigio { union { - struct proc *siu_proc; /* process to receive SIGIO/SIGURG */ - struct pgrp *siu_pgrp; /* process group to receive ... */ + struct proc *siu_proc; /* (c) process to receive SIGIO/SIGURG */ + struct pgrp *siu_pgrp; /* (c) 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 ucred *sio_ucred; /* current credentials */ - pid_t sio_pgid; /* pgid for signals */ + SLIST_ENTRY(sigio) sio_pgsigio; /* (pg) sigio's for process or group */ + struct sigio **sio_myref; /* (c) location of the pointer that holds + * the reference to this structure */ + struct ucred *sio_ucred; /* (c) current credentials */ + pid_t sio_pgid; /* (c) pgid for signals */ }; #define sio_proc sio_u.siu_proc #define sio_pgrp sio_u.siu_pgrp diff --git a/sys/sys/proc.h b/sys/sys/proc.h index fd18f1b..02ddfe4 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -60,27 +60,39 @@ /* * One structure allocated per session. + * + * List of locks + * (m) locked by s_mtx mtx + * (ps) locked by pgrpsess_lock sx + * (c) const until freeing */ struct session { - int s_count; /* Ref cnt; pgrps in session. */ - struct proc *s_leader; /* Session leader. */ - struct vnode *s_ttyvp; /* Vnode of controlling terminal. */ - struct tty *s_ttyp; /* Controlling terminal. */ - pid_t s_sid; /* Session ID. */ - /* Setlogin() name: */ + int s_count; /* (m) Ref cnt; pgrps in session. */ + struct proc *s_leader; /* (m, ps) Session leader. */ + struct vnode *s_ttyvp; /* (m) Vnode of controlling terminal. */ + struct tty *s_ttyp; /* (m) Controlling terminal. */ + pid_t s_sid; /* (c) Session ID. */ + /* (m) Setlogin() name: */ char s_login[roundup(MAXLOGNAME, sizeof(long))]; + struct mtx s_mtx; /* Mutex to protect members */ }; /* * One structure allocated per process group. + * + * List of locks + * (m) locked by pg_mtx mtx + * (ps) locked by pgrpsess_lock sx + * (c) const until freeing */ struct pgrp { - LIST_ENTRY(pgrp) pg_hash; /* Hash chain. */ - LIST_HEAD(, proc) pg_members; /* Pointer to pgrp members. */ - struct session *pg_session; /* Pointer to session. */ - struct sigiolst pg_sigiolst; /* List of sigio sources. */ - pid_t pg_id; /* Pgrp id. */ - int pg_jobc; /* # procs qualifying pgrp for job control */ + LIST_ENTRY(pgrp) pg_hash; /* (ps) Hash chain. */ + LIST_HEAD(, proc) pg_members; /* (m, ps) Pointer to pgrp members. */ + struct session *pg_session; /* (c) Pointer to session. */ + struct sigiolst pg_sigiolst; /* (m) List of sigio sources. */ + pid_t pg_id; /* (c) Pgrp id. */ + int pg_jobc; /* (m) # procs qualifying pgrp for job control */ + struct mtx pg_mtx; /* Mutex to protect members */ }; struct procsig { @@ -134,6 +146,7 @@ struct pargs { * l - the attaching proc or attaching proc parent * m - Giant * n - not locked, lazy + * o - locked by pgrpsess_lock sx * * If the locking key specifies two identifiers (for example, p_pptr) then * either lock is sufficient for read access, but both locks must be held @@ -388,7 +401,7 @@ struct proc { pid_t p_pid; /* (b) Process identifier. */ LIST_ENTRY(proc) p_hash; /* (d) Hash chain. */ - LIST_ENTRY(proc) p_pglist; /* (c) List of processes in pgrp. */ + LIST_ENTRY(proc) p_pglist; /* (g + o) List of processes in pgrp. */ struct proc *p_pptr; /* (c + e) Pointer to parent process. */ LIST_ENTRY(proc) p_sibling; /* (e) List of sibling processes. */ LIST_HEAD(, proc) p_children; /* (e) Pointer to list of children. */ @@ -406,7 +419,7 @@ struct proc { struct vnode *p_textvp; /* (b) Vnode of executable. */ struct mtx p_mtx; /* (k) Lock for this struct. */ char p_lock; /* (c) Proclock (prevent swap) count. */ - struct klist p_klist; /* (c) Knotes attached to this proc. */ + struct klist p_klist; /* (c) Knotes attached to this proc. */ struct sigiolst p_sigiolst; /* (c) List of sigio sources. */ int p_sigparent; /* (c) Signal to parent on exit. */ sigset_t p_oldsigmask; /* (c) Saved mask from pre sigpause. */ @@ -427,7 +440,7 @@ struct proc { stack_t p_sigstk; /* (c) Stack ptr and on-stack flag. */ int p_magic; /* (b) Magic number. */ char p_comm[MAXCOMLEN + 1]; /* (b) Process name. */ - struct pgrp *p_pgrp; /* (e?/c?) Pointer to process group. */ + struct pgrp *p_pgrp; /* (c + o) Pointer to process group. */ struct sysentvec *p_sysent; /* (b) Syscall dispatch info. */ struct pargs *p_args; /* (c) Process arguments. */ /* End area that is copied on creation. */ @@ -515,6 +528,7 @@ struct proc { #ifdef MALLOC_DECLARE MALLOC_DECLARE(M_PARGS); +MALLOC_DECLARE(M_PGRP); MALLOC_DECLARE(M_SESSION); MALLOC_DECLARE(M_SUBPROC); MALLOC_DECLARE(M_ZOMBIE); @@ -599,6 +613,40 @@ sigonstack(size_t sp) #define PROC_LOCKED(p) mtx_owned(&(p)->p_mtx) #define PROC_LOCK_ASSERT(p, type) mtx_assert(&(p)->p_mtx, (type)) +#define PGRPSESS_SLOCK() sx_slock(&pgrpsess_lock) +#define PGRPSESS_XLOCK() sx_xlock(&pgrpsess_lock) +#define PGRPSESS_SUNLOCK() sx_sunlock(&pgrpsess_lock) +#define PGRPSESS_XUNLOCK() sx_xunlock(&pgrpsess_lock) +#define PGRPSESS_LOCK_ASSERT(type) sx_assert(&pgrpsess_lock, (type)) + +/* Lock and unlock a process group. */ +#define PGRP_LOCK(pg) mtx_lock(&(pg)->pg_mtx) +#define PGRP_UNLOCK(pg) mtx_unlock(&(pg)->pg_mtx) +#define PGRP_UNLOCK_NOSWITCH(pg) \ + mtx_unlock_flags(&(pg)->pg_mtx, MTX_NOSWITCH) +#define PGRP_LOCKED(pg) mtx_owned(&(pg)->pg_mtx) +#define PGRP_LOCK_ASSERT(pg, type) mtx_assert(&(pg)->pg_mtx, (type)) + +#define PGRP_LOCK_PGSIGNAL(pg) \ + do { \ + if ((pg) != NULL) \ + PGRP_LOCK(pg); \ + } while (0); + +#define PGRP_UNLOCK_PGSIGNAL(pg) \ + do { \ + if ((pg) != NULL) \ + PGRP_UNLOCK(pg); \ + } while (0); + +/* Lock and unlock a session. */ +#define SESS_LOCK(s) mtx_lock(&(s)->s_mtx) +#define SESS_UNLOCK(s) mtx_unlock(&(s)->s_mtx) +#define SESS_UNLOCK_NOSWITCH(s) \ + mtx_unlock_flags(&(s)->s_mtx, MTX_NOSWITCH) +#define SESS_LOCKED(s) mtx_owned(&(s)->s_mtx) +#define SESS_LOCK_ASSERT(s, type) mtx_assert(&(s)->s_mtx, (type)) + /* Hold process U-area in memory, normally for ptrace/procfs work. */ #define PHOLD(p) do { \ PROC_LOCK(p); \ @@ -631,6 +679,7 @@ extern u_long pgrphash; extern struct sx allproc_lock; extern struct sx proctree_lock; +extern struct sx pgrpsess_lock; extern struct proc proc0; /* Process slot for swapper. */ extern struct thread thread0; /* Primary thread in proc0 */ extern int hogticks; /* Limit on kernel cpu hogs. */ @@ -672,7 +721,8 @@ struct proc *zpfind(pid_t); /* Find zombie process by id. */ void ast(struct trapframe *framep); struct thread *choosethread(void); int cr_cansignal(struct ucred *cred, struct proc *proc, int signum); -int enterpgrp(struct proc *p, pid_t pgid, int mksess); +int enterpgrp __P((struct proc *p, pid_t pgid, struct pgrp *pgrp, struct session *sess)); +int enterthispgrp __P((struct proc *p, struct pgrp *pgrp)); void faultin(struct proc *p); void fixjobc(struct proc *p, struct pgrp *pgrp, int entering); int fork1(struct thread *, int, struct proc **); |