Index: sys/jail.h =================================================================== RCS file: /private/FreeBSD/src/sys/sys/jail.h,v retrieving revision 1.21 diff -u -p -r1.21 jail.h --- sys/jail.h 26 Apr 2004 19:46:52 -0000 1.21 +++ sys/jail.h 27 Jun 2004 09:08:55 -0000 @@ -93,10 +93,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); Index: kern/kern_jail.c =================================================================== RCS file: /private/FreeBSD/src/sys/kern/kern_jail.c,v retrieving revision 1.44 diff -u -p -r1.44 kern_jail.c --- kern/kern_jail.c 27 Jun 2004 09:03:21 -0000 1.44 +++ kern/kern_jail.c 27 Jun 2004 10:14:31 -0000 @@ -26,6 +26,7 @@ __FBSDID("$FreeBSD: src/sys/kern/kern_ja #include #include #include +#include #include #include #include @@ -57,10 +58,10 @@ SYSCTL_INT(_security_jail, OID_AUTO, sys &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 = 1; +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, @@ -431,19 +432,72 @@ getcredhostname(struct ucred *cred, char strlcpy(buf, hostname, 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 statfs *sp; + size_t len; + + if (!jailed(cred) || !jail_enforce_statfs) + return (0); + if (cred->cr_prison->pr_root->v_mount == mp) + return (0); + len = strlen(cred->cr_prison->pr_path); + sp = &mp->mnt_stat; + if (strncmp(cred->cr_prison->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]; + 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) + return; + if (prison_canseemount(cred, mp) != 0) { + /* Should never happen. */ + strlcpy(sp->f_mntonname, "[restricted]", + sizeof(sp->f_mntonname)); + return; + } + if (cred->cr_prison->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; + } + len = strlen(cred->cr_prison->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 Index: kern/vfs_syscalls.c =================================================================== RCS file: /private/FreeBSD/src/sys/kern/vfs_syscalls.c,v retrieving revision 1.354 diff -u -p -r1.354 vfs_syscalls.c --- kern/vfs_syscalls.c 24 Jun 2004 17:22:29 -0000 1.354 +++ kern/vfs_syscalls.c 27 Jun 2004 19:27:05 -0000 @@ -232,6 +232,9 @@ statfs(td, uap) sp = &mp->mnt_stat; NDFREE(&nd, NDF_ONLY_PNBUF); vrele(nd.ni_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) @@ -249,6 +252,7 @@ statfs(td, uap) 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; } return (copyout(sp, uap->buf, sizeof(*sp))); @@ -282,6 +286,9 @@ fstatfs(td, uap) fdrop(fp, td); if (mp == NULL) return (EBADF); + error = prison_canseemount(td->td_ucred, mp); + if (error) + return (error); #ifdef MAC error = mac_check_mount_stat(td->td_ucred, mp); if (error) @@ -300,6 +307,7 @@ fstatfs(td, uap) 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; } return (copyout(sp, uap->buf, sizeof(*sp))); @@ -334,7 +342,7 @@ getfsstat(td, uap) count = 0; 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; } @@ -373,6 +381,7 @@ getfsstat(td, uap) 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; } error = copyout(sp, sfsp, sizeof(*sp)); @@ -399,7 +408,8 @@ getfsstat(td, uap) /* * Get old format filesystem statistics. */ -static void cvtstatfs(struct thread *, struct statfs *, struct ostatfs *); +static void cvtstatfs(struct thread *, struct mount *mp, struct statfs *, + struct ostatfs *); #ifndef _SYS_SYSPROTO_H_ struct freebsd4_statfs_args { @@ -428,6 +438,9 @@ freebsd4_statfs(td, uap) sp = &mp->mnt_stat; NDFREE(&nd, NDF_ONLY_PNBUF); vrele(nd.ni_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) @@ -437,7 +450,7 @@ freebsd4_statfs(td, uap) if (error) return (error); sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; - cvtstatfs(td, sp, &osb); + cvtstatfs(td, mp, sp, &osb); return (copyout(&osb, uap->buf, sizeof(osb))); } @@ -470,6 +483,9 @@ freebsd4_fstatfs(td, uap) fdrop(fp, td); if (mp == NULL) return (EBADF); + error = prison_canseemount(td->td_ucred, mp); + if (error) + return (error); #ifdef MAC error = mac_check_mount_stat(td->td_ucred, mp); if (error) @@ -480,7 +496,7 @@ freebsd4_fstatfs(td, uap) if (error) return (error); sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; - cvtstatfs(td, sp, &osb); + cvtstatfs(td, mp, sp, &osb); return (copyout(&osb, uap->buf, sizeof(osb))); } @@ -514,7 +530,7 @@ freebsd4_getfsstat(td, uap) count = 0; 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; } @@ -544,7 +560,7 @@ freebsd4_getfsstat(td, uap) continue; } sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; - cvtstatfs(td, sp, &osb); + cvtstatfs(td, mp, sp, &osb); error = copyout(&osb, sfsp, sizeof(osb)); if (error) { vfs_unbusy(mp, td); @@ -601,6 +617,9 @@ freebsd4_fhstatfs(td, uap) 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) @@ -609,7 +628,7 @@ freebsd4_fhstatfs(td, uap) if ((error = VFS_STATFS(mp, sp, td)) != 0) return (error); sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; - cvtstatfs(td, sp, &osb); + cvtstatfs(td, mp, sp, &osb); return (copyout(&osb, uap->buf, sizeof(osb))); } @@ -617,12 +636,20 @@ freebsd4_fhstatfs(td, uap) * Convert a new format statfs structure to an old format statfs structure. */ static void -cvtstatfs(td, nsp, osp) +cvtstatfs(td, mp, nsp, osp) struct thread *td; + struct mount *mp; struct statfs *nsp; struct ostatfs *osp; { + struct statfs sb; + if (suser(td)) { + bcopy(nsp, &sb, sizeof(sb)); + sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; + prison_enforce_statfs(td->td_ucred, mp, &sb); + nsp = &sb; + } bzero(osp, sizeof(*osp)); osp->f_bsize = MIN(nsp->f_bsize, LONG_MAX); osp->f_iosize = MIN(nsp->f_iosize, LONG_MAX); @@ -644,11 +671,7 @@ cvtstatfs(td, nsp, osp) MIN(MFSNAMELEN, OMNAMELEN)); bcopy(nsp->f_mntfromname, osp->f_mntfromname, MIN(MFSNAMELEN, OMNAMELEN)); - if (suser(td)) { - osp->f_fsid.val[0] = osp->f_fsid.val[1] = 0; - } else { - osp->f_fsid = nsp->f_fsid; - } + osp->f_fsid = nsp->f_fsid; } #endif /* COMPAT_FREEBSD4 */ @@ -4107,7 +4130,7 @@ fhstatfs(td, uap) struct statfs *buf; } */ *uap; { - struct statfs *sp; + struct statfs *sp, sb; struct mount *mp; struct vnode *vp; fhandle_t fh; @@ -4125,6 +4148,9 @@ fhstatfs(td, uap) 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) @@ -4138,6 +4164,15 @@ fhstatfs(td, uap) sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; if ((error = VFS_STATFS(mp, sp, td)) != 0) return (error); + if (suser(td)) { + /* + * XXX: This is impossible, but keep it for consistency. + */ + 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; + } return (copyout(sp, uap->buf, sizeof(*sp))); } Index: compat/linux/linux_stats.c =================================================================== RCS file: /private/FreeBSD/src/sys/compat/linux/linux_stats.c,v retrieving revision 1.60 diff -u -p -r1.60 linux_stats.c --- compat/linux/linux_stats.c 17 Jun 2004 17:16:41 -0000 1.60 +++ compat/linux/linux_stats.c 27 Jun 2004 09:41:37 -0000 @@ -37,6 +37,7 @@ __FBSDID("$FreeBSD: src/sys/compat/linux #include #include #include +#include #include #include #include @@ -230,7 +231,7 @@ linux_statfs(struct thread *td, struct l { struct mount *mp; struct nameidata *ndp; - struct statfs *bsd_statfs; + struct statfs *bsd_statfs, sb; struct nameidata nd; struct l_statfs linux_statfs; char *path; @@ -252,6 +253,9 @@ linux_statfs(struct thread *td, struct l mp = ndp->ni_vp->v_mount; bsd_statfs = &mp->mnt_stat; vrele(ndp->ni_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) @@ -261,6 +265,12 @@ linux_statfs(struct thread *td, struct l if (error) return error; bsd_statfs->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; + if (suser(td)) { + bcopy(bsd_statfs, &sb, sizeof(sb)); + sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; + prison_enforce_statfs(td->td_ucred, mp, &sb); + bsd_statfs = &sb; + } linux_statfs.f_type = bsd_to_linux_ftype(bsd_statfs->f_fstypename); linux_statfs.f_bsize = bsd_statfs->f_bsize; linux_statfs.f_blocks = bsd_statfs->f_blocks; @@ -268,13 +278,8 @@ linux_statfs(struct thread *td, struct l linux_statfs.f_bavail = bsd_statfs->f_bavail; linux_statfs.f_ffree = bsd_statfs->f_ffree; linux_statfs.f_files = bsd_statfs->f_files; - if (suser(td)) { - linux_statfs.f_fsid.val[0] = 0; - linux_statfs.f_fsid.val[1] = 0; - } else { - linux_statfs.f_fsid.val[0] = bsd_statfs->f_fsid.val[0]; - linux_statfs.f_fsid.val[1] = bsd_statfs->f_fsid.val[1]; - } + linux_statfs.f_fsid.val[0] = bsd_statfs->f_fsid.val[0]; + linux_statfs.f_fsid.val[1] = bsd_statfs->f_fsid.val[1]; linux_statfs.f_namelen = MAXNAMLEN; return copyout(&linux_statfs, args->buf, sizeof(linux_statfs)); } @@ -284,7 +289,7 @@ linux_fstatfs(struct thread *td, struct { struct file *fp; struct mount *mp; - struct statfs *bsd_statfs; + struct statfs *bsd_statfs, sb; struct l_statfs linux_statfs; int error; @@ -296,6 +301,11 @@ linux_fstatfs(struct thread *td, struct if (error) return error; mp = fp->f_vnode->v_mount; + error = prison_canseemount(td->td_ucred, mp); + if (error) { + fdrop(fp, td); + return (error); + } #ifdef MAC error = mac_check_mount_stat(td->td_ucred, mp); if (error) { @@ -310,6 +320,12 @@ linux_fstatfs(struct thread *td, struct return error; } bsd_statfs->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; + if (suser(td)) { + bcopy(bsd_statfs, &sb, sizeof(sb)); + sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; + prison_enforce_statfs(td->td_ucred, mp, &sb); + bsd_statfs = &sb; + } linux_statfs.f_type = bsd_to_linux_ftype(bsd_statfs->f_fstypename); linux_statfs.f_bsize = bsd_statfs->f_bsize; linux_statfs.f_blocks = bsd_statfs->f_blocks; @@ -317,13 +333,8 @@ linux_fstatfs(struct thread *td, struct linux_statfs.f_bavail = bsd_statfs->f_bavail; linux_statfs.f_ffree = bsd_statfs->f_ffree; linux_statfs.f_files = bsd_statfs->f_files; - if (suser(td)) { - linux_statfs.f_fsid.val[0] = 0; - linux_statfs.f_fsid.val[1] = 0; - } else { - linux_statfs.f_fsid.val[0] = bsd_statfs->f_fsid.val[0]; - linux_statfs.f_fsid.val[1] = bsd_statfs->f_fsid.val[1]; - } + linux_statfs.f_fsid.val[0] = bsd_statfs->f_fsid.val[0]; + linux_statfs.f_fsid.val[1] = bsd_statfs->f_fsid.val[1]; linux_statfs.f_namelen = MAXNAMLEN; error = copyout(&linux_statfs, args->buf, sizeof(linux_statfs)); fdrop(fp, td); @@ -369,6 +380,9 @@ linux_ustat(struct thread *td, struct li if (dev != NULL && vfinddev(dev, &vp)) { if (vp->v_mount == NULL) 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) Index: alpha/osf1/osf1_mount.c =================================================================== RCS file: /private/FreeBSD/src/sys/alpha/osf1/osf1_mount.c,v retrieving revision 1.18 diff -u -p -r1.18 osf1_mount.c --- alpha/osf1/osf1_mount.c 16 Nov 2003 21:53:05 -0000 1.18 +++ alpha/osf1/osf1_mount.c 27 Jun 2004 09:42:04 -0000 @@ -47,6 +47,7 @@ __FBSDID("$FreeBSD: src/sys/alpha/osf1/o #include #include #include +#include #include #include #include @@ -71,7 +72,8 @@ __FBSDID("$FreeBSD: src/sys/alpha/osf1/o #include -void bsd2osf_statfs(struct statfs *, struct osf1_statfs *); +void bsd2osf_statfs(struct thread *td, struct mount *mp, struct statfs *, + struct osf1_statfs *); int osf1_mount_mfs(struct thread *, struct osf1_mount_args *, struct mount_args *); int osf1_mount_nfs(struct thread *, struct osf1_mount_args *, @@ -82,13 +84,22 @@ static const char *fsnames[OSF1_MOUNT_MA #endif void -bsd2osf_statfs(bsfs, osfs) +bsd2osf_statfs(td, mp, bsfs, osfs) + struct thread *td; + struct mount *mp; struct statfs *bsfs; struct osf1_statfs *osfs; { - #ifdef notanymore -bzero(osfs, sizeof (struct osf1_statfs)); + struct statfs sb; + + if (suser(td)) { + bcopy(bsfs, &sb, sizeof(sb)); + sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; + prison_enforce_statfs(td->td_ucred, mp, &sb); + bsfs = &sb; + } + bzero(osfs, sizeof (struct osf1_statfs)); if (!strncmp(fsnames[MOUNT_UFS], bsfs->f_fstypename, MFSNAMELEN)) osfs->f_type = OSF1_MOUNT_UFS; else if (!strncmp(fsnames[MOUNT_NFS], bsfs->f_fstypename, MFSNAMELEN)) @@ -134,6 +145,9 @@ osf1_statfs(td, uap) mp = nd.ni_vp->v_mount; sp = &mp->mnt_stat; vrele(nd.ni_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) @@ -142,7 +156,7 @@ osf1_statfs(td, uap) if ((error = VFS_STATFS(mp, sp, td))) return (error); sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; - bsd2osf_statfs(sp, &osfs); + bsd2osf_statfs(td, mp, sp, &osfs); return copyout(&osfs, uap->buf, min(sizeof osfs, uap->len)); } @@ -161,6 +175,11 @@ osf1_fstatfs(td, uap) if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp))) return (error); mp = fp->f_vnode->v_mount; + error = prison_canseemount(td->td_ucred, mp); + if (error) { + fdrop(fp, td); + return (error); + } #ifdef MAC error = mac_check_mount_stat(td->td_ucred, mp); if (error) { @@ -174,7 +193,7 @@ osf1_fstatfs(td, uap) if (error) return (error); sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; - bsd2osf_statfs(sp, &osfs); + bsd2osf_statfs(td, mp, sp, &osfs); return copyout(&osfs, uap->buf, min(sizeof osfs, uap->len)); } @@ -198,6 +217,9 @@ osf1_getfsstat(td, uap) for (count = 0, mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) { nmp = TAILQ_NEXT(mp, mnt_list); if (osf_sfsp && count < maxcount) { + error = prison_canseemount(td->td_ucred, mp); + if (error) + continue; #ifdef MAC error = mac_check_mount_stat(td->td_ucred, mp); if (error) @@ -214,7 +236,7 @@ osf1_getfsstat(td, uap) (error = VFS_STATFS(mp, sp, td))) continue; sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; - bsd2osf_statfs(sp, &osfs); + bsd2osf_statfs(td, mp, sp, &osfs); if ((error = copyout(&osfs, osf_sfsp, sizeof (struct osf1_statfs)))) return (error);