summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/libc/sys/chroot.231
-rw-r--r--sys/kern/vfs_extattr.c46
-rw-r--r--sys/kern/vfs_syscalls.c46
3 files changed, 119 insertions, 4 deletions
diff --git a/lib/libc/sys/chroot.2 b/lib/libc/sys/chroot.2
index 10a9b5e..01258da 100644
--- a/lib/libc/sys/chroot.2
+++ b/lib/libc/sys/chroot.2
@@ -60,7 +60,33 @@ It should be noted that
has no effect on the process's current directory.
.Pp
This call is restricted to the super-user.
-.Sh RETURN VALUES
+.Pp
+Depending on the setting of the
+.Ql kern.chroot_allow_open_directories
+sysctl variable, open filedescriptors which reference directories
+will make the
+.Fn chroot
+fail as follows:
+.Pp
+If
+.Ql kern.chroot_allow_open_directories
+is set to zero,
+.Fn chroot
+will always fail with EPERM if there are any directories open.
+.Pp
+If
+.Ql kern.chroot_allow_open_directories
+is set to one (the default),
+.Fn chroot
+will fail with EPERM if there are any directories open and the
+process is already subject to a
+.Fn chroot
+call.
+.Pp
+Any other value for
+.Ql kern.chroot_allow_open_directories
+will bypass the check for open directories
+.Pp
Upon successful completion, a value of 0 is returned. Otherwise,
a value of -1 is returned and
.Va errno
@@ -72,7 +98,8 @@ will fail and the root directory will be unchanged if:
.It Bq Er ENOTDIR
A component of the path name is not a directory.
.It Bq Er EPERM
-The effective user ID is not the super-user.
+The effective user ID is not the super-user, or one or more
+filedescriptors are open directories.
.It Bq Er ENAMETOOLONG
A component of a pathname exceeded 255 characters,
or an entire path name exceeded 1023 characters.
diff --git a/sys/kern/vfs_extattr.c b/sys/kern/vfs_extattr.c
index 54dc30c..e2c75c0 100644
--- a/sys/kern/vfs_extattr.c
+++ b/sys/kern/vfs_extattr.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)
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)
OpenPOWER on IntegriCloud