diff options
author | phk <phk@FreeBSD.org> | 1999-03-23 14:26:40 +0000 |
---|---|---|
committer | phk <phk@FreeBSD.org> | 1999-03-23 14:26:40 +0000 |
commit | e1c9acedca824cb3a177d665495a51bcebd0763a (patch) | |
tree | e118eebefa3e4bc2de7c8493dee101fd9faa6490 /sys/kern/vfs_syscalls.c | |
parent | a6cff8a40588e5200eaa3635409eaf799058be7d (diff) | |
download | FreeBSD-src-e1c9acedca824cb3a177d665495a51bcebd0763a.zip FreeBSD-src-e1c9acedca824cb3a177d665495a51bcebd0763a.tar.gz |
Add a sysctl variable which can help stop chroot(2) escapes.
kern.chroot_allow_open_directories = 0
chroot(2) fails if there are open directories.
kern.chroot_allow_open_directories = 1 (default)
chroot(2) fails if there are open directories and the process
is subject of a previous chroot(2).
kern.chroot_allow_open_directories = anything else
filedescriptors are not checked. (old behaviour).
I'm very interested in reports about software which breaks when
running with the default setting.
Diffstat (limited to 'sys/kern/vfs_syscalls.c')
-rw-r--r-- | sys/kern/vfs_syscalls.c | 46 |
1 files changed, 45 insertions, 1 deletions
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 54dc30c..e2c75c0 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -36,7 +36,7 @@ * SUCH DAMAGE. * * @(#)vfs_syscalls.c 8.13 (Berkeley) 4/15/94 - * $Id: vfs_syscalls.c,v 1.119 1999/02/27 07:06:05 julian Exp $ + * $Id: vfs_syscalls.c,v 1.120 1999/03/03 02:35:51 julian Exp $ */ /* For 4.3 integer FS ID compatibility */ @@ -71,6 +71,7 @@ static int change_dir __P((struct nameidata *ndp, struct proc *p)); static void checkdirs __P((struct vnode *olddp)); +static int chroot_refuse_vdir_fds __P((struct filedesc *fdp)); static int setfown __P((struct proc *, struct vnode *, uid_t, gid_t)); static int setfmode __P((struct proc *, struct vnode *, int)); static int setfflags __P((struct proc *, struct vnode *, int)); @@ -828,6 +829,44 @@ chdir(p, uap) } /* + * Helper function for raised chroot(2) security function: Refuse if + * any filedescriptors are open directories. + */ +static int +chroot_refuse_vdir_fds(fdp) + struct filedesc *fdp; +{ + struct vnode *vp; + struct file *fp; + int error; + int fd; + + for (fd = 0; fd < fdp->fd_nfiles ; fd++) { + error = getvnode(fdp, fd, &fp); + if (error) + continue; + vp = (struct vnode *)fp->f_data; + if (vp->v_type != VDIR) + continue; + return(EPERM); + } + return (0); +} + +/* + * This sysctl determines if we will allow a process to chroot(2) if it + * has a directory open: + * 0: disallowed for all processes. + * 1: allowed for processes that were not already chroot(2)'ed. + * 2: allowed for all processes. + */ + +static int chroot_allow_open_directories = 1; + +SYSCTL_INT(_kern, OID_AUTO, chroot_allow_open_directories, CTLFLAG_RW, + &chroot_allow_open_directories, 0, ""); + +/* * Change notion of root (``/'') directory. */ #ifndef _SYS_SYSPROTO_H_ @@ -850,6 +889,11 @@ chroot(p, uap) error = suser(p->p_ucred, &p->p_acflag); if (error) return (error); + if (chroot_allow_open_directories == 0 || + (chroot_allow_open_directories == 1 && fdp->fd_rdir != rootvnode)) + error = chroot_refuse_vdir_fds(fdp); + if (error) + return (error); NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, SCARG(uap, path), p); if ((error = change_dir(&nd, p)) != 0) |