Fix up some session-related races in devfs.

One was introduced with r272596, the rest was there to begin with.

Noted by: jhb
This commit is contained in:
mjg 2014-11-03 03:12:15 +00:00
parent 90a2b12f5f
commit 5c258fe4b9

View File

@ -499,6 +499,7 @@ devfs_access(struct vop_access_args *ap)
{ {
struct vnode *vp = ap->a_vp; struct vnode *vp = ap->a_vp;
struct devfs_dirent *de; struct devfs_dirent *de;
struct proc *p;
int error; int error;
de = vp->v_data; de = vp->v_data;
@ -511,11 +512,16 @@ devfs_access(struct vop_access_args *ap)
return (0); return (0);
if (error != EACCES) if (error != EACCES)
return (error); return (error);
p = ap->a_td->td_proc;
/* We do, however, allow access to the controlling terminal */ /* We do, however, allow access to the controlling terminal */
if (!(ap->a_td->td_proc->p_flag & P_CONTROLT)) PROC_LOCK(p);
if (!(p->p_flag & P_CONTROLT)) {
PROC_UNLOCK(p);
return (error); return (error);
if (ap->a_td->td_proc->p_session->s_ttydp == de->de_cdp) }
return (0); if (p->p_session->s_ttydp == de->de_cdp)
error = 0;
PROC_UNLOCK(p);
return (error); return (error);
} }
@ -525,6 +531,7 @@ devfs_close(struct vop_close_args *ap)
{ {
struct vnode *vp = ap->a_vp, *oldvp; struct vnode *vp = ap->a_vp, *oldvp;
struct thread *td = ap->a_td; struct thread *td = ap->a_td;
struct proc *p;
struct cdev *dev = vp->v_rdev; struct cdev *dev = vp->v_rdev;
struct cdevsw *dsw; struct cdevsw *dsw;
int vp_locked, error, ref; int vp_locked, error, ref;
@ -545,24 +552,30 @@ devfs_close(struct vop_close_args *ap)
* if the reference count is 2 (this last descriptor * if the reference count is 2 (this last descriptor
* plus the session), release the reference from the session. * plus the session), release the reference from the session.
*/ */
if (td && vp == td->td_proc->p_session->s_ttyvp) { if (td != NULL) {
oldvp = NULL; p = td->td_proc;
sx_xlock(&proctree_lock); PROC_LOCK(p);
if (vp == td->td_proc->p_session->s_ttyvp) { if (vp == p->p_session->s_ttyvp) {
SESS_LOCK(td->td_proc->p_session); PROC_UNLOCK(p);
VI_LOCK(vp); oldvp = NULL;
if (count_dev(dev) == 2 && sx_xlock(&proctree_lock);
(vp->v_iflag & VI_DOOMED) == 0) { if (vp == p->p_session->s_ttyvp) {
td->td_proc->p_session->s_ttyvp = NULL; SESS_LOCK(p->p_session);
td->td_proc->p_session->s_ttydp = NULL; VI_LOCK(vp);
oldvp = vp; if (count_dev(dev) == 2 &&
(vp->v_iflag & VI_DOOMED) == 0) {
p->p_session->s_ttyvp = NULL;
p->p_session->s_ttydp = NULL;
oldvp = vp;
}
VI_UNLOCK(vp);
SESS_UNLOCK(p->p_session);
} }
VI_UNLOCK(vp); sx_xunlock(&proctree_lock);
SESS_UNLOCK(td->td_proc->p_session); if (oldvp != NULL)
} vrele(oldvp);
sx_xunlock(&proctree_lock); } else
if (oldvp != NULL) PROC_UNLOCK(p);
vrele(oldvp);
} }
/* /*
* We do not want to really close the device if it * We do not want to really close the device if it
@ -816,6 +829,7 @@ devfs_prison_check(struct devfs_dirent *de, struct thread *td)
{ {
struct cdev_priv *cdp; struct cdev_priv *cdp;
struct ucred *dcr; struct ucred *dcr;
struct proc *p;
int error; int error;
cdp = de->de_cdp; cdp = de->de_cdp;
@ -829,10 +843,15 @@ devfs_prison_check(struct devfs_dirent *de, struct thread *td)
if (error == 0) if (error == 0)
return (0); return (0);
/* We do, however, allow access to the controlling terminal */ /* We do, however, allow access to the controlling terminal */
if (!(td->td_proc->p_flag & P_CONTROLT)) p = td->td_proc;
PROC_LOCK(p);
if (!(p->p_flag & P_CONTROLT)) {
PROC_UNLOCK(p);
return (error); return (error);
if (td->td_proc->p_session->s_ttydp == cdp) }
return (0); if (p->p_session->s_ttydp == cdp)
error = 0;
PROC_UNLOCK(p);
return (error); return (error);
} }