Rename sysctl security.jail.getfsstatroot_only to security.jail.enforce_statfs
and extend its functionality: value policy 0 show all mount-points without any restrictions 1 show only mount-points below jail's chroot and show only part of the mount-point's path (if jail's chroot directory is /jails/foo and mount-point is /jails/foo/usr/home only /usr/home will be shown) 2 show only mount-point where jail's chroot directory is placed. Default value is 2. Discussed with: rwatson
This commit is contained in:
parent
591223e66b
commit
820a0de9a9
@ -331,8 +331,9 @@ linux_ustat(struct thread *td, struct linux_ustat_args *args)
|
||||
if (dev != NULL && vfinddev(dev, &vp)) {
|
||||
if (vp->v_mount == NULL)
|
||||
return (EINVAL);
|
||||
if (!prison_check_mount(td->td_ucred, vp->v_mount))
|
||||
return (EINVAL);
|
||||
error = prison_canseemount(td->td_ucred, vp->v_mount);
|
||||
if (error)
|
||||
return (error);
|
||||
#ifdef MAC
|
||||
error = mac_check_mount_stat(td->td_ucred, vp->v_mount);
|
||||
if (error)
|
||||
|
@ -26,6 +26,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/namei.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/syscallsubr.h>
|
||||
@ -55,10 +56,10 @@ SYSCTL_INT(_security_jail, OID_AUTO, sysvipc_allowed, CTLFLAG_RW,
|
||||
&jail_sysvipc_allowed, 0,
|
||||
"Processes in jail can use System V IPC primitives");
|
||||
|
||||
int jail_getfsstatroot_only = 1;
|
||||
SYSCTL_INT(_security_jail, OID_AUTO, getfsstatroot_only, CTLFLAG_RW,
|
||||
&jail_getfsstatroot_only, 0,
|
||||
"Processes see only their root file system in getfsstat()");
|
||||
static int jail_enforce_statfs = 2;
|
||||
SYSCTL_INT(_security_jail, OID_AUTO, enforce_statfs, CTLFLAG_RW,
|
||||
&jail_enforce_statfs, 0,
|
||||
"Processes in jail cannot see all mounted file systems");
|
||||
|
||||
int jail_allow_raw_sockets = 0;
|
||||
SYSCTL_INT(_security_jail, OID_AUTO, allow_raw_sockets, CTLFLAG_RW,
|
||||
@ -435,18 +436,92 @@ getcredhostname(struct ucred *cred, char *buf, size_t size)
|
||||
}
|
||||
|
||||
/*
|
||||
* Return 1 if the passed credential can "see" the passed mountpoint
|
||||
* when performing a getfsstat(); otherwise, 0.
|
||||
* Determine whether the subject represented by cred can "see"
|
||||
* status of a mount point.
|
||||
* Returns: 0 for permitted, ENOENT otherwise.
|
||||
* XXX: This function should be called cr_canseemount() and should be
|
||||
* placed in kern_prot.c.
|
||||
*/
|
||||
int
|
||||
prison_check_mount(struct ucred *cred, struct mount *mp)
|
||||
prison_canseemount(struct ucred *cred, struct mount *mp)
|
||||
{
|
||||
struct prison *pr;
|
||||
struct statfs *sp;
|
||||
size_t len;
|
||||
|
||||
if (jail_getfsstatroot_only && cred->cr_prison != NULL) {
|
||||
if (cred->cr_prison->pr_root->v_mount != mp)
|
||||
return (0);
|
||||
if (!jailed(cred) || jail_enforce_statfs == 0)
|
||||
return (0);
|
||||
pr = cred->cr_prison;
|
||||
if (pr->pr_root->v_mount == mp)
|
||||
return (0);
|
||||
if (jail_enforce_statfs == 2)
|
||||
return (ENOENT);
|
||||
/*
|
||||
* If jail's chroot directory is set to "/" we should be able to see
|
||||
* all mount-points from inside a jail.
|
||||
* This is ugly check, but this is the only situation when jail's
|
||||
* directory ends with '/'.
|
||||
*/
|
||||
if (strcmp(pr->pr_path, "/") == 0)
|
||||
return (0);
|
||||
len = strlen(pr->pr_path);
|
||||
sp = &mp->mnt_stat;
|
||||
if (strncmp(pr->pr_path, sp->f_mntonname, len) != 0)
|
||||
return (ENOENT);
|
||||
/*
|
||||
* Be sure that we don't have situation where jail's root directory
|
||||
* is "/some/path" and mount point is "/some/pathpath".
|
||||
*/
|
||||
if (sp->f_mntonname[len] != '\0' && sp->f_mntonname[len] != '/')
|
||||
return (ENOENT);
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
prison_enforce_statfs(struct ucred *cred, struct mount *mp, struct statfs *sp)
|
||||
{
|
||||
char jpath[MAXPATHLEN];
|
||||
struct prison *pr;
|
||||
size_t len;
|
||||
|
||||
if (!jailed(cred) || jail_enforce_statfs == 0)
|
||||
return;
|
||||
pr = cred->cr_prison;
|
||||
if (prison_canseemount(cred, mp) != 0) {
|
||||
/* Should never happen. */
|
||||
bzero(sp->f_mntonname, sizeof(sp->f_mntonname));
|
||||
strlcpy(sp->f_mntonname, "[restricted]",
|
||||
sizeof(sp->f_mntonname));
|
||||
return;
|
||||
}
|
||||
if (pr->pr_root->v_mount == mp) {
|
||||
/*
|
||||
* Clear current buffer data, so we are sure nothing from
|
||||
* the valid path left there.
|
||||
*/
|
||||
bzero(sp->f_mntonname, sizeof(sp->f_mntonname));
|
||||
*sp->f_mntonname = '/';
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* If jail's chroot directory is set to "/" we should be able to see
|
||||
* all mount-points from inside a jail.
|
||||
*/
|
||||
if (strcmp(pr->pr_path, "/") == 0)
|
||||
return;
|
||||
len = strlen(pr->pr_path);
|
||||
strlcpy(jpath, sp->f_mntonname + len, sizeof(jpath));
|
||||
/*
|
||||
* Clear current buffer data, so we are sure nothing from
|
||||
* the valid path left there.
|
||||
*/
|
||||
bzero(sp->f_mntonname, sizeof(sp->f_mntonname));
|
||||
if (*jpath == '\0') {
|
||||
/* Should never happen. */
|
||||
*sp->f_mntonname = '/';
|
||||
} else {
|
||||
strlcpy(sp->f_mntonname, jpath, sizeof(sp->f_mntonname));
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -257,6 +257,11 @@ kern_statfs(struct thread *td, char *path, enum uio_seg pathseg,
|
||||
sp = &mp->mnt_stat;
|
||||
NDFREE(&nd, NDF_ONLY_PNBUF);
|
||||
vrele(nd.ni_vp);
|
||||
error = prison_canseemount(td->td_ucred, mp);
|
||||
if (error) {
|
||||
mtx_unlock(&Giant);
|
||||
return (error);
|
||||
}
|
||||
#ifdef MAC
|
||||
error = mac_check_mount_stat(td->td_ucred, mp);
|
||||
if (error) {
|
||||
@ -271,14 +276,17 @@ kern_statfs(struct thread *td, char *path, enum uio_seg pathseg,
|
||||
sp->f_namemax = NAME_MAX;
|
||||
sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
|
||||
error = VFS_STATFS(mp, sp, td);
|
||||
mtx_unlock(&Giant);
|
||||
if (error)
|
||||
if (error) {
|
||||
mtx_unlock(&Giant);
|
||||
return (error);
|
||||
}
|
||||
if (suser(td)) {
|
||||
bcopy(sp, &sb, sizeof(sb));
|
||||
sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
|
||||
prison_enforce_statfs(td->td_ucred, mp, &sb);
|
||||
sp = &sb;
|
||||
}
|
||||
mtx_unlock(&Giant);
|
||||
*buf = *sp;
|
||||
return (0);
|
||||
}
|
||||
@ -327,6 +335,11 @@ kern_fstatfs(struct thread *td, int fd, struct statfs *buf)
|
||||
mtx_unlock(&Giant);
|
||||
return (EBADF);
|
||||
}
|
||||
error = prison_canseemount(td->td_ucred, mp);
|
||||
if (error) {
|
||||
mtx_unlock(&Giant);
|
||||
return (error);
|
||||
}
|
||||
#ifdef MAC
|
||||
error = mac_check_mount_stat(td->td_ucred, mp);
|
||||
if (error) {
|
||||
@ -342,14 +355,17 @@ kern_fstatfs(struct thread *td, int fd, struct statfs *buf)
|
||||
sp->f_namemax = NAME_MAX;
|
||||
sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
|
||||
error = VFS_STATFS(mp, sp, td);
|
||||
mtx_unlock(&Giant);
|
||||
if (error)
|
||||
if (error) {
|
||||
mtx_unlock(&Giant);
|
||||
return (error);
|
||||
}
|
||||
if (suser(td)) {
|
||||
bcopy(sp, &sb, sizeof(sb));
|
||||
sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
|
||||
prison_enforce_statfs(td->td_ucred, mp, &sb);
|
||||
sp = &sb;
|
||||
}
|
||||
mtx_unlock(&Giant);
|
||||
*buf = *sp;
|
||||
return (0);
|
||||
}
|
||||
@ -393,7 +409,7 @@ kern_getfsstat(struct thread *td, struct statfs *buf, size_t bufsize,
|
||||
mtx_lock(&Giant);
|
||||
mtx_lock(&mountlist_mtx);
|
||||
for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) {
|
||||
if (!prison_check_mount(td->td_ucred, mp)) {
|
||||
if (prison_canseemount(td->td_ucred, mp) != 0) {
|
||||
nmp = TAILQ_NEXT(mp, mnt_list);
|
||||
continue;
|
||||
}
|
||||
@ -432,6 +448,7 @@ kern_getfsstat(struct thread *td, struct statfs *buf, size_t bufsize,
|
||||
if (suser(td)) {
|
||||
bcopy(sp, &sb, sizeof(sb));
|
||||
sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
|
||||
prison_enforce_statfs(td->td_ucred, mp, &sb);
|
||||
sp = &sb;
|
||||
}
|
||||
if (bufseg == UIO_USERSPACE) {
|
||||
@ -4221,6 +4238,9 @@ kern_fhstatfs(struct thread *td, fhandle_t fh, struct statfs *buf)
|
||||
mp = vp->v_mount;
|
||||
sp = &mp->mnt_stat;
|
||||
vput(vp);
|
||||
error = prison_canseemount(td->td_ucred, mp);
|
||||
if (error)
|
||||
return (error);
|
||||
#ifdef MAC
|
||||
error = mac_check_mount_stat(td->td_ucred, mp);
|
||||
if (error) {
|
||||
|
@ -257,6 +257,11 @@ kern_statfs(struct thread *td, char *path, enum uio_seg pathseg,
|
||||
sp = &mp->mnt_stat;
|
||||
NDFREE(&nd, NDF_ONLY_PNBUF);
|
||||
vrele(nd.ni_vp);
|
||||
error = prison_canseemount(td->td_ucred, mp);
|
||||
if (error) {
|
||||
mtx_unlock(&Giant);
|
||||
return (error);
|
||||
}
|
||||
#ifdef MAC
|
||||
error = mac_check_mount_stat(td->td_ucred, mp);
|
||||
if (error) {
|
||||
@ -271,14 +276,17 @@ kern_statfs(struct thread *td, char *path, enum uio_seg pathseg,
|
||||
sp->f_namemax = NAME_MAX;
|
||||
sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
|
||||
error = VFS_STATFS(mp, sp, td);
|
||||
mtx_unlock(&Giant);
|
||||
if (error)
|
||||
if (error) {
|
||||
mtx_unlock(&Giant);
|
||||
return (error);
|
||||
}
|
||||
if (suser(td)) {
|
||||
bcopy(sp, &sb, sizeof(sb));
|
||||
sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
|
||||
prison_enforce_statfs(td->td_ucred, mp, &sb);
|
||||
sp = &sb;
|
||||
}
|
||||
mtx_unlock(&Giant);
|
||||
*buf = *sp;
|
||||
return (0);
|
||||
}
|
||||
@ -327,6 +335,11 @@ kern_fstatfs(struct thread *td, int fd, struct statfs *buf)
|
||||
mtx_unlock(&Giant);
|
||||
return (EBADF);
|
||||
}
|
||||
error = prison_canseemount(td->td_ucred, mp);
|
||||
if (error) {
|
||||
mtx_unlock(&Giant);
|
||||
return (error);
|
||||
}
|
||||
#ifdef MAC
|
||||
error = mac_check_mount_stat(td->td_ucred, mp);
|
||||
if (error) {
|
||||
@ -342,14 +355,17 @@ kern_fstatfs(struct thread *td, int fd, struct statfs *buf)
|
||||
sp->f_namemax = NAME_MAX;
|
||||
sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
|
||||
error = VFS_STATFS(mp, sp, td);
|
||||
mtx_unlock(&Giant);
|
||||
if (error)
|
||||
if (error) {
|
||||
mtx_unlock(&Giant);
|
||||
return (error);
|
||||
}
|
||||
if (suser(td)) {
|
||||
bcopy(sp, &sb, sizeof(sb));
|
||||
sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
|
||||
prison_enforce_statfs(td->td_ucred, mp, &sb);
|
||||
sp = &sb;
|
||||
}
|
||||
mtx_unlock(&Giant);
|
||||
*buf = *sp;
|
||||
return (0);
|
||||
}
|
||||
@ -393,7 +409,7 @@ kern_getfsstat(struct thread *td, struct statfs *buf, size_t bufsize,
|
||||
mtx_lock(&Giant);
|
||||
mtx_lock(&mountlist_mtx);
|
||||
for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) {
|
||||
if (!prison_check_mount(td->td_ucred, mp)) {
|
||||
if (prison_canseemount(td->td_ucred, mp) != 0) {
|
||||
nmp = TAILQ_NEXT(mp, mnt_list);
|
||||
continue;
|
||||
}
|
||||
@ -432,6 +448,7 @@ kern_getfsstat(struct thread *td, struct statfs *buf, size_t bufsize,
|
||||
if (suser(td)) {
|
||||
bcopy(sp, &sb, sizeof(sb));
|
||||
sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
|
||||
prison_enforce_statfs(td->td_ucred, mp, &sb);
|
||||
sp = &sb;
|
||||
}
|
||||
if (bufseg == UIO_USERSPACE) {
|
||||
@ -4221,6 +4238,9 @@ kern_fhstatfs(struct thread *td, fhandle_t fh, struct statfs *buf)
|
||||
mp = vp->v_mount;
|
||||
sp = &mp->mnt_stat;
|
||||
vput(vp);
|
||||
error = prison_canseemount(td->td_ucred, mp);
|
||||
if (error)
|
||||
return (error);
|
||||
#ifdef MAC
|
||||
error = mac_check_mount_stat(td->td_ucred, mp);
|
||||
if (error) {
|
||||
|
@ -98,10 +98,13 @@ extern struct prisonlist allprison;
|
||||
struct ucred;
|
||||
struct mount;
|
||||
struct sockaddr;
|
||||
struct statfs;
|
||||
int jailed(struct ucred *cred);
|
||||
void getcredhostname(struct ucred *cred, char *, size_t);
|
||||
int prison_check(struct ucred *cred1, struct ucred *cred2);
|
||||
int prison_check_mount(struct ucred *cred, struct mount *mp);
|
||||
int prison_canseemount(struct ucred *cred, struct mount *mp);
|
||||
void prison_enforce_statfs(struct ucred *cred, struct mount *mp,
|
||||
struct statfs *sp);
|
||||
void prison_free(struct prison *pr);
|
||||
u_int32_t prison_getip(struct ucred *cred);
|
||||
void prison_hold(struct prison *pr);
|
||||
|
Loading…
Reference in New Issue
Block a user