freebsd-skq/sys/security/lomac/lomacfs_vfsops.c

200 lines
5.9 KiB
C

/*-
* Copyright (c) 2001 Networks Associates Technology, Inc.
* All rights reserved.
*
* This software was developed for the FreeBSD Project by NAI Labs, the
* Security Research Division of Network Associates, Inc. under
* DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA
* CHATS research program.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id$
* $FreeBSD$
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/proc.h>
#include <sys/module.h>
#include <sys/mount.h>
#include <sys/namei.h>
#include <sys/vnode.h>
#include "lomacfs.h"
#include "kernel_mediate.h"
MALLOC_DEFINE(M_LOMACFS, "LOMACFS", "LOMAC filesystem objects");
static int lomacfs_mount(struct mount *mp, char *path, caddr_t data,
struct nameidata *ndp, struct thread *td);
static int lomacfs_statfs(struct mount *mp, struct statfs *sbp,
struct thread *td);
static int lomacfs_unmount(struct mount *mp, int mntflags, struct thread *td);
static int
lomacfs_mount(struct mount *mp, char *path, caddr_t data,
struct nameidata *ndp, struct thread *td) {
if (mp->mnt_flag & MNT_UPDATE || VISLOMAC(mp->mnt_vnodecovered))
return (EOPNOTSUPP);
mp->mnt_flag |= MNT_LOCAL;
mp->mnt_flag &= ~MNT_RDONLY;
mp->mnt_data = malloc(sizeof(struct lomac_mount), M_LOMACFS,
M_WAITOK | M_ZERO);
vfs_getnewfsid(mp);
strncpy(mp->mnt_stat.f_mntfromname, "lomacfs", MNAMELEN);
(void)lomacfs_statfs(mp, &mp->mnt_stat, td);
/*
* Keep around an extra ref for dounmount() to vrele() after the
* VFS_UNMOUNT()... (who knows...)
*/
vref(mp->mnt_vnodecovered);
if (VOP_ISLOCKED(mp->mnt_vnodecovered, NULL))
VOP_UNLOCK(mp->mnt_vnodecovered, 0, td);
return (0);
}
static int
lomacfs_statfs(struct mount *mp, struct statfs *sbp, struct thread *td) {
struct statfs tmpstat;
int error;
bzero(&tmpstat, sizeof(tmpstat));
error = VFS_STATFS(mp->mnt_vnodecovered->v_mount, &tmpstat, td);
if (error)
return (error);
sbp->f_type = tmpstat.f_type;
sbp->f_flags = tmpstat.f_flags;
sbp->f_bsize = tmpstat.f_bsize;
sbp->f_iosize = tmpstat.f_iosize;
sbp->f_blocks = tmpstat.f_blocks;
sbp->f_bfree = tmpstat.f_bfree;
sbp->f_bavail = tmpstat.f_bavail;
sbp->f_files = tmpstat.f_files;
sbp->f_ffree = tmpstat.f_ffree;
if (sbp != &mp->mnt_stat) {
bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
}
return (0);
}
static int
lomacfs_unmount(struct mount *mp, int mntflags, struct thread *td) {
struct vnode *crootvp = VFSTOLOMAC(mp)->lm_rootvp;
int error;
int flags = 0;
if (mntflags & MNT_FORCE)
flags |= FORCECLOSE;
if (VFSTOLOMAC(mp)->lm_flags & LM_TOOKROOT) {
mtx_lock(&crootvp->v_interlock);
crootvp->v_flag |= VROOT;
mtx_unlock(&crootvp->v_interlock);
}
error = vflush(mp, 1, flags); /* have an extra root ref */
if (error)
return (error);
free(VFSTOLOMAC(mp), M_LOMACFS);
/* bye, lomacfs. */
return (0);
}
static int
lomacfs_root(struct mount *mp, struct vnode **vpp) {
int error;
if (VFSTOLOMAC(mp)->lm_rootvp == NULL) {
struct vnode *rootvp, *crootvp;
crootvp = mp->mnt_vnodecovered;
error = lomacfs_node_alloc(mp, NULL, NULL, crootvp, &rootvp);
if (error)
return (error);
/*
* Reference twice to match the rest of the lomacfs vnodes.
*/
vref(crootvp);
vref(crootvp);
VFSTOLOMAC(mp)->lm_rootvp = rootvp;
/*
* This releases the lock on root, but it doesn't release
* the reference so that root won't "disappear" until
* unmount.
*/
error = VOP_UNLOCK(rootvp, 0, curthread);
if (error)
return (error);
/*
* This is some strange magic here... I need to pretend
* that the mounted-on directory isn't a root vnode if I
* want things like __getcwd() to just fail and not crash.
*/
mtx_lock(&crootvp->v_interlock);
if (crootvp->v_flag & VROOT && crootvp == rootvnode) {
crootvp->v_flag &= ~VROOT;
VFSTOLOMAC(mp)->lm_flags |= LM_TOOKROOT;
}
mtx_unlock(&crootvp->v_interlock);
}
*vpp = VFSTOLOMAC(mp)->lm_rootvp;
return (vget(*vpp, LK_EXCLUSIVE, curthread));
}
static struct vfsops lomacfs_vfsops = {
lomacfs_mount,
vfs_stdstart,
lomacfs_unmount,
lomacfs_root,
vfs_stdquotactl,
lomacfs_statfs,
vfs_stdsync,
vfs_stdvget,
vfs_stdfhtovp,
vfs_stdcheckexp,
vfs_stdvptofh,
vfs_stdinit,
vfs_stduninit,
vfs_stdextattrctl
};
VFS_SET(lomacfs_vfsops, lomacfs, VFCF_LOOPBACK);
MODULE_VERSION(lomacfs, 1);
MODULE_DEPEND(lomacfs, lomac_plm, 1, 1, 1);