mirror of
https://github.com/opnsense/src.git
synced 2026-05-28 04:12:45 -04:00
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.
This commit is contained in:
parent
7f4173cc09
commit
cc7532aaf0
3 changed files with 119 additions and 4 deletions
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
@ -827,6 +828,44 @@ chdir(p, uap)
|
|||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
|
@ -848,6 +887,11 @@ chroot(p, uap)
|
|||
struct nameidata nd;
|
||||
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
@ -827,6 +828,44 @@ chdir(p, uap)
|
|||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
|
@ -848,6 +887,11 @@ chroot(p, uap)
|
|||
struct nameidata nd;
|
||||
|
||||
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,
|
||||
|
|
|
|||
Loading…
Reference in a new issue