Let access overriding to TTYs depend on the cdev_priv, not the vnode.

Basically this commit changes two things, which improves access to TTYs
in exceptional conditions. Basically the problem was that when you ran
jexec(8) to attach to a jail, you couldn't use /dev/tty (well, also the
node of the actual TTY, e.g. /dev/pts/X). This is very inconvenient if
you want to attach to screens quickly, use ssh(1), etc.

The fixes:

- Cache the cdev_priv of the controlling TTY in struct session. Change
  devfs_access() to compare against the cdev_priv instead of the vnode.
  This allows you to bypass UNIX permissions, even across different
  mounts of devfs.

- Extend devfs_prison_check() to unconditionally expose the device node
  of the controlling TTY, even if normal prison nesting rules normally
  don't allow this. This actually allows you to interact with this
  device node.

To be honest, I'm not really happy with this solution. We now have to
store three pointers to a controlling TTY (s_ttyp, s_ttyvp, s_ttydp).
In an ideal world, we should just get rid of the latter two and only use
s_ttyp, but this makes certian pieces of code very impractical (e.g.
devfs, kern_exit.c).

Reported by:	Many people
This commit is contained in:
ed 2009-12-19 18:42:12 +00:00
parent 74382eba8c
commit 449c6ac843
4 changed files with 21 additions and 7 deletions

View File

@ -436,14 +436,14 @@ devfs_access(struct vop_access_args *ap)
error = vaccess(vp->v_type, de->de_mode, de->de_uid, de->de_gid,
ap->a_accmode, ap->a_cred, NULL);
if (!error)
return (error);
if (error == 0)
return (0);
if (error != EACCES)
return (error);
/* We do, however, allow access to the controlling terminal */
if (!(ap->a_td->td_proc->p_flag & P_CONTROLT))
return (error);
if (ap->a_td->td_proc->p_session->s_ttyvp == de->de_vnode)
if (ap->a_td->td_proc->p_session->s_ttydp == de->de_cdp)
return (0);
return (error);
}
@ -474,6 +474,7 @@ devfs_close(struct vop_close_args *ap)
VI_LOCK(vp);
if (count_dev(dev) == 2 && (vp->v_iflag & VI_DOOMED) == 0) {
td->td_proc->p_session->s_ttyvp = NULL;
td->td_proc->p_session->s_ttydp = NULL;
oldvp = vp;
}
VI_UNLOCK(vp);
@ -675,6 +676,7 @@ devfs_ioctl_f(struct file *fp, u_long com, void *data, struct ucred *cred, struc
VREF(vp);
SESS_LOCK(td->td_proc->p_session);
td->td_proc->p_session->s_ttyvp = vp;
td->td_proc->p_session->s_ttydp = cdev2priv(dev);
SESS_UNLOCK(td->td_proc->p_session);
sx_sunlock(&proctree_lock);
@ -708,10 +710,11 @@ devfs_kqfilter_f(struct file *fp, struct knote *kn)
}
static inline int
devfs_prison_check(struct devfs_dirent *de, struct ucred *tcr)
devfs_prison_check(struct devfs_dirent *de, struct thread *td)
{
struct cdev_priv *cdp;
struct ucred *dcr;
int error;
cdp = de->de_cdp;
if (cdp == NULL)
@ -720,7 +723,15 @@ devfs_prison_check(struct devfs_dirent *de, struct ucred *tcr)
if (dcr == NULL)
return (0);
return (prison_check(tcr, dcr));
error = prison_check(td->td_ucred, dcr);
if (error == 0)
return (0);
/* We do, however, allow access to the controlling terminal */
if (!(td->td_proc->p_flag & P_CONTROLT))
return (error);
if (td->td_proc->p_session->s_ttydp == cdp)
return (0);
return (error);
}
static int
@ -848,7 +859,7 @@ devfs_lookupx(struct vop_lookup_args *ap, int *dm_unlock)
return (ENOENT);
}
if (devfs_prison_check(de, td->td_ucred))
if (devfs_prison_check(de, td))
return (ENOENT);
if ((cnp->cn_nameiop == DELETE) && (flags & ISLASTCN)) {
@ -1126,7 +1137,7 @@ devfs_readdir(struct vop_readdir_args *ap)
KASSERT(dd->de_cdp != (void *)0xdeadc0de, ("%s %d\n", __func__, __LINE__));
if (dd->de_flags & DE_WHITEOUT)
continue;
if (devfs_prison_check(dd, ap->a_cred))
if (devfs_prison_check(dd, uio->uio_td))
continue;
if (dd->de_dirent->d_type == DT_DIR)
de = dd->de_dir;

View File

@ -316,6 +316,7 @@ exit1(struct thread *td, int rv)
ttyvp = sp->s_ttyvp;
tp = sp->s_ttyp;
sp->s_ttyvp = NULL;
sp->s_ttydp = NULL;
sp->s_leader = NULL;
SESS_UNLOCK(sp);

View File

@ -358,6 +358,7 @@ enterpgrp(p, pgid, pgrp, sess)
sess->s_sid = p->p_pid;
refcount_init(&sess->s_count, 1);
sess->s_ttyvp = NULL;
sess->s_ttydp = NULL;
sess->s_ttyp = NULL;
bcopy(p->p_session->s_login, sess->s_login,
sizeof(sess->s_login));

View File

@ -77,6 +77,7 @@ struct session {
u_int s_count; /* Ref cnt; pgrps in session - atomic. */
struct proc *s_leader; /* (m + e) Session leader. */
struct vnode *s_ttyvp; /* (m) Vnode of controlling tty. */
struct cdev_priv *s_ttydp; /* (m) Device of controlling tty. */
struct tty *s_ttyp; /* (e) Controlling tty. */
pid_t s_sid; /* (c) Session ID. */
/* (m) Setlogin() name: */