Introduce extended attribute support for FFS, allowing arbitrary

(name, value) pairs to be associated with inodes.  This support is
used for ACLs, MAC labels, and Capabilities in the TrustedBSD
security extensions, which are currently under development.

In this implementation, attributes are backed to data vnodes in the
style of the quota support in FFS.  Support for FFS extended
attributes may be enabled using the FFS_EXTATTR kernel option
(disabled by default).  Userland utilities and man pages will be
committed in the next batch.  VFS interfaces and man pages have
been in the repo since 4.0-RELEASE and are unchanged.

o ufs/ufs/extattr.h: UFS-specific extattr defines
o ufs/ufs/ufs_extattr.c: bulk of support routines
o ufs/{ufs,ffs,mfs}/*.[ch]: hooks and extattr.h includes
o contrib/softupdates/ffs_softdep.c: extattr.h includes
o conf/options, conf/files, i386/conf/LINT: added FFS_EXTATTR

o coda/coda_vfsops.c: XXX required extattr.h due to ufsmount.h
(This should not be the case, and will be fixed in a future commit)

Currently attributes are not supported in MFS.  This will be fixed.

Reviewed by:	adrian, bp, freebsd-fs, other unthanked souls
Obtained from:	TrustedBSD Project
This commit is contained in:
Robert Watson 2000-04-15 03:34:27 +00:00
parent 2192b407ac
commit a64ed08955
27 changed files with 954 additions and 0 deletions

View File

@ -502,6 +502,7 @@ getNewVnode(vpp)
NULL, NULL);
}
#include <ufs/ufs/extattr.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/ufsmount.h>
/* get the mount structure corresponding to a given device. Assume

View File

@ -632,6 +632,11 @@ options DEVFS #devices filesystem
#
#options SOFTUPDATES
# Extended attributes allow additional data to be associated with files,
# and is used for ACLs, Capabilities, and MAC labels
#
options FFS_EXTATTR
# Make space in the kernel for a root filesystem on a md device.
# Define to the number of kilobytes to reserve for the filesystem.
options MD_ROOT_SIZE=10

View File

@ -857,6 +857,7 @@ ufs/mfs/mfs_vfsops.c optional mfs
ufs/mfs/mfs_vnops.c optional mfs
ufs/ufs/ufs_bmap.c standard
ufs/ufs/ufs_disksubr.c standard
ufs/ufs/ufs_extattr.c standard
ufs/ufs/ufs_ihash.c standard
ufs/ufs/ufs_inode.c standard
ufs/ufs/ufs_lookup.c standard

View File

@ -117,6 +117,11 @@ NWFS
# otherwise a STUB module will be compiled in.
SOFTUPDATES opt_ffs.h
# Enabling this option turns on support for extended attributes
# in FFS, which can be used to support high security configurations
# as well as new file system features.
FFS_EXTATTR opt_ffs.h
# The above static dependencies are planned removed, with a
# <filesystem>_ROOT option to control if it usable as root. This list
# allows these options to be present in config files already (though

View File

@ -77,6 +77,7 @@
#include <sys/vnode.h>
#include <sys/conf.h>
#include <ufs/ufs/dir.h>
#include <ufs/ufs/extattr.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>

View File

@ -502,6 +502,7 @@ getNewVnode(vpp)
NULL, NULL);
}
#include <ufs/ufs/extattr.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/ufsmount.h>
/* get the mount structure corresponding to a given device. Assume

View File

@ -48,6 +48,7 @@
#include <sys/resourcevar.h>
#include <sys/conf.h>
#include <ufs/ufs/extattr.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>

View File

@ -69,6 +69,7 @@ struct ucred;
struct uio;
struct vnode;
struct netexport;
struct ufs_extattr_per_mount;
/* This structure describes the UFS specific mount structure data. */
struct ufsmount {
@ -86,6 +87,7 @@ struct ufsmount {
struct vnode *um_quotas[MAXQUOTAS]; /* pointer to quota files */
struct ucred *um_cred[MAXQUOTAS]; /* quota file access cred */
struct ufs_extattr_per_mount um_extattr; /* extended attrs */
u_long um_nindir; /* indirect ptrs per block */
u_long um_bptrtodb; /* indir ptr to disk block */
u_long um_seqinc; /* inc between seq blocks */

View File

@ -48,6 +48,7 @@
#include <sys/resourcevar.h>
#include <sys/conf.h>
#include <ufs/ufs/extattr.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>

View File

@ -69,6 +69,7 @@ struct ucred;
struct uio;
struct vnode;
struct netexport;
struct ufs_extattr_per_mount;
/* This structure describes the UFS specific mount structure data. */
struct ufsmount {
@ -86,6 +87,7 @@ struct ufsmount {
struct vnode *um_quotas[MAXQUOTAS]; /* pointer to quota files */
struct ucred *um_cred[MAXQUOTAS]; /* quota file access cred */
struct ufs_extattr_per_mount um_extattr; /* extended attrs */
u_long um_nindir; /* indirect ptrs per block */
u_long um_bptrtodb; /* indir ptr to disk block */
u_long um_seqinc; /* inc between seq blocks */

View File

@ -632,6 +632,11 @@ options DEVFS #devices filesystem
#
#options SOFTUPDATES
# Extended attributes allow additional data to be associated with files,
# and is used for ACLs, Capabilities, and MAC labels
#
options FFS_EXTATTR
# Make space in the kernel for a root filesystem on a md device.
# Define to the number of kilobytes to reserve for the filesystem.
options MD_ROOT_SIZE=10

View File

@ -632,6 +632,11 @@ options DEVFS #devices filesystem
#
#options SOFTUPDATES
# Extended attributes allow additional data to be associated with files,
# and is used for ACLs, Capabilities, and MAC labels
#
options FFS_EXTATTR
# Make space in the kernel for a root filesystem on a md device.
# Define to the number of kilobytes to reserve for the filesystem.
options MD_ROOT_SIZE=10

View File

@ -47,6 +47,7 @@
#include <sys/sysctl.h>
#include <sys/syslog.h>
#include <ufs/ufs/extattr.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufs_extern.h>

View File

@ -49,6 +49,7 @@
#include <vm/vm.h>
#include <vm/vm_extern.h>
#include <ufs/ufs/extattr.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/ufs/inode.h>

View File

@ -77,6 +77,7 @@
#include <sys/vnode.h>
#include <sys/conf.h>
#include <ufs/ufs/dir.h>
#include <ufs/ufs/extattr.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>

View File

@ -34,6 +34,7 @@
* $FreeBSD$
*/
#include "opt_ffs.h"
#include "opt_quota.h"
#include <sys/param.h>
@ -49,6 +50,7 @@
#include <sys/disklabel.h>
#include <sys/malloc.h>
#include <ufs/ufs/extattr.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/ufs/inode.h>
@ -84,7 +86,11 @@ static struct vfsops ufs_vfsops = {
ffs_vptofh,
ffs_init,
vfs_stduninit,
#ifdef FFS_EXTATTR
ufs_extattrctl,
#else
vfs_stdextattrctl,
#endif
};
VFS_SET(ufs_vfsops, ufs, 0);
@ -710,6 +716,9 @@ ffs_mountfs(devvp, mp, p, malloctype)
ump->um_seqinc = fs->fs_frag;
for (i = 0; i < MAXQUOTAS; i++)
ump->um_quotas[i] = NULLVP;
#ifdef FFS_EXTATTR
ufs_extattr_uepm_init(&ump->um_extattr);
#endif
devvp->v_specmountpoint = mp;
ffs_oldfscompat(fs);
@ -808,6 +817,11 @@ ffs_unmount(mp, mntflags, p)
if (mntflags & MNT_FORCE) {
flags |= FORCECLOSE;
}
#ifdef FFS_EXTATTR
if ((error = ufs_extattr_stop(mp, p))) {
printf("ffs_unmonut: ufs_extattr_stop returned %d\n", error);
}
#endif
if (mp->mnt_flag & MNT_SOFTDEP) {
if ((error = softdep_flushfiles(mp, flags, p)) != 0)
return (error);

View File

@ -34,6 +34,8 @@
* $FreeBSD$
*/
#include "opt_ffs.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/resourcevar.h>
@ -53,6 +55,7 @@
#include <vm/vm_object.h>
#include <vm/vm_extern.h>
#include <ufs/ufs/extattr.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>
@ -78,6 +81,10 @@ static struct vnodeopv_entry_desc ffs_vnodeop_entries[] = {
{ &vop_balloc_desc, (vop_t *) ffs_balloc },
{ &vop_reallocblks_desc, (vop_t *) ffs_reallocblks },
{ &vop_write_desc, (vop_t *) ffs_write },
#ifdef FFS_EXTATTR
{ &vop_getextattr_desc, (vop_t *) ufs_vop_getextattr },
{ &vop_setextattr_desc, (vop_t *) ufs_vop_setextattr },
#endif
{ NULL, NULL }
};
static struct vnodeopv_desc ffs_vnodeop_opv_desc =

View File

@ -49,6 +49,7 @@
#include <sys/malloc.h>
#include <sys/linker.h>
#include <ufs/ufs/extattr.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>

100
sys/ufs/ufs/extattr.h Normal file
View File

@ -0,0 +1,100 @@
/*-
* Copyright (c) 1999, 2000 Robert N. M. Watson
* All rights reserved.
*
* 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.
*
* 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.
*
* $FreeBSD$
*/
/*
* TrustedBSD Project - extended attribute support for UFS-like file systems
*/
#ifndef _UFS_UFS_EXTATTR_H_
#define _UFS_UFS_EXTATTR_H_
#define UFS_EXTATTR_FSROOTSUBDIR ".attributes"
#define UFS_EXTATTR_MAXEXTATTRNAME 33 /* including null */
#define UFS_EXTATTR_MAXEXTATTRSIZE 1024 /* bytes */
#define UFS_EXTATTR_ATTR_FLAG_INUSE 0x00000001 /* attr has been set */
#define UFS_EXTATTR_PERM_KERNEL 0x00000000
#define UFS_EXTATTR_PERM_ROOT 0x00000001
#define UFS_EXTATTR_PERM_OWNER 0x00000002
#define UFS_EXTATTR_PERM_ANYONE 0x00000003
#define UFS_EXTATTR_UEPM_INITIALIZED 0x00000001
#define UFS_EXTATTR_UEPM_STARTED 0x00000002
#define UFS_EXTATTR_CMD_START 0x00000001
#define UFS_EXTATTR_CMD_STOP 0x00000002
#define UFS_EXTATTR_CMD_ENABLE 0x00000003
#define UFS_EXTATTR_CMD_DISABLE 0x00000004
struct ufs_extattr_fileheader {
u_int uef_size; /* size of attributes, w/o header */
u_int uef_read_perm; /* permissions to read attribute */
u_int uef_write_perm; /* permissions to write attribute */
};
struct ufs_extattr_header {
u_int ueh_flags; /* flags for attribute */
u_int ueh_len; /* local defined length; <= uef_size */
/* data follows the header */
};
#ifdef _KERNEL
#ifdef MALLOC_DECLARE
MALLOC_DECLARE(M_EXTATTR);
#endif
struct vnode;
LIST_HEAD(ufs_extattr_list_head, ufs_extattr_list_entry);
struct ufs_extattr_list_entry {
LIST_ENTRY(ufs_extattr_list_entry) uele_entries;
struct ufs_extattr_fileheader uele_fileheader;
char uele_attrname[UFS_EXTATTR_MAXEXTATTRNAME];
struct vnode *uele_backing_vnode;
};
struct lock;
struct ucred;
struct ufs_extattr_per_mount {
struct lock uepm_lock;
struct ufs_extattr_list_head uepm_list;
struct ucred *uepm_ucred;
int uepm_flags;
};
void ufs_extattr_uepm_init(struct ufs_extattr_per_mount *uepm);
int ufs_extattr_start(struct mount *mp, struct proc *p);
int ufs_extattr_stop(struct mount *mp, struct proc *p);
int ufs_extattrctl(struct mount *mp, int cmd, char *attrname,
caddr_t arg, struct proc *p);
int ufs_vop_getextattr(struct vop_getextattr_args *ap);
int ufs_vop_setextattr(struct vop_setextattr_args *ap);
void ufs_extattr_vnode_inactive(struct vnode *vp, struct proc *p);
#endif /* !_KERNEL */
#endif /* !_UFS_UFS_EXTATTR_H_ */

View File

@ -48,6 +48,7 @@
#include <sys/resourcevar.h>
#include <sys/conf.h>
#include <ufs/ufs/extattr.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>

787
sys/ufs/ufs/ufs_extattr.c Normal file
View File

@ -0,0 +1,787 @@
/*-
* Copyright (c) 1999, 2000 Robert N. M. Watson
* All rights reserved.
*
* 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.
*
* 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.
*
* $FreeBSD$
*/
/*
* TrustedBSD Project - extended attribute support for UFS-like file systems
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/namei.h>
#include <sys/malloc.h>
#include <sys/fcntl.h>
#include <sys/proc.h>
#include <sys/vnode.h>
#include <sys/mount.h>
#include <sys/lock.h>
#include <ufs/ufs/extattr.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/ufs/inode.h>
#define MIN(a,b) (((a)<(b))?(a):(b))
static MALLOC_DEFINE(M_UFS_EXTATTR, "ufs_extattr", "ufs extended attribute");
static int ufs_extattr_credcheck(struct ufs_extattr_list_entry *uele,
u_int32_t fowner, struct ucred *cred, struct proc *p, int access);
static int ufs_extattr_enable(struct ufsmount *ump, char *attrname,
struct vnode *backing_vnode, struct proc *p);
static int ufs_extattr_disable(struct ufsmount *ump, char *attrname,
struct proc *p);
static int ufs_extattr_get(struct vnode *vp, char *name, struct uio *uio,
struct ucred *cred, struct proc *p);
static int ufs_extattr_set(struct vnode *vp, char *name, struct uio *uio,
struct ucred *cred, struct proc *p);
static int ufs_extattr_rm(struct vnode *vp, char *name,
struct ucred *cred, struct proc *p);
/*
* Per-FS attribute lock protecting attribute operations
* XXX Right now there is a lot of lock contention due to having a single
* lock per-FS; really, this should be far more fine-grained.
*/
static void
ufs_extattr_uepm_lock(struct ufsmount *ump, struct proc *p)
{
/* ideally, LK_CANRECURSE would not be used, here */
lockmgr(&ump->um_extattr.uepm_lock, LK_EXCLUSIVE | LK_RETRY |
LK_CANRECURSE, 0, p);
}
static void
ufs_extattr_uepm_unlock(struct ufsmount *ump, struct proc *p)
{
lockmgr(&ump->um_extattr.uepm_lock, LK_RELEASE, 0, p);
}
/*
* Locate an attribute given a name and mountpoint.
* Must be holding uepm lock for the mount point.
*/
static struct ufs_extattr_list_entry *
ufs_exttatr_find_attr(struct ufsmount *ump, char *attrname)
{
struct ufs_extattr_list_entry *search_attribute;
for (search_attribute = ump->um_extattr.uepm_list.lh_first;
search_attribute;
search_attribute = search_attribute->uele_entries.le_next) {
if (!(strncmp(attrname, search_attribute->uele_attrname,
UFS_EXTATTR_MAXEXTATTRNAME))) {
return (search_attribute);
}
}
return (0);
}
/*
* Initialize per-FS structures supporting extended attributes. Do not
* start extended attributes yet.
*/
void
ufs_extattr_uepm_init(struct ufs_extattr_per_mount *uepm)
{
uepm->uepm_flags = 0;
LIST_INIT(&uepm->uepm_list);
/* XXX is PVFS right, here? */
lockinit(&uepm->uepm_lock, PVFS, "extattr", 0, 0);
uepm->uepm_flags |= UFS_EXTATTR_UEPM_INITIALIZED;
}
/*
* Start extended attribute support on an FS
*/
int
ufs_extattr_start(struct mount *mp, struct proc *p)
{
struct ufsmount *ump;
int error = 0;
ump = VFSTOUFS(mp);
ufs_extattr_uepm_lock(ump, p);
if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_INITIALIZED)) {
error = EOPNOTSUPP;
goto unlock;
}
if (ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED) {
error = EBUSY;
goto unlock;
}
ump->um_extattr.uepm_flags |= UFS_EXTATTR_UEPM_STARTED;
crhold(p->p_ucred);
ump->um_extattr.uepm_ucred = p->p_ucred;
unlock:
ufs_extattr_uepm_unlock(ump, p);
return (error);
}
/*
* Stop extended attribute support on an FS
*/
int
ufs_extattr_stop(struct mount *mp, struct proc *p)
{
struct ufs_extattr_list_entry *uele;
struct ufsmount *ump = VFSTOUFS(mp);
int error = 0;
ufs_extattr_uepm_lock(ump, p);
if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) {
error = EOPNOTSUPP;
goto unlock;
}
while (ump->um_extattr.uepm_list.lh_first != NULL) {
uele = ump->um_extattr.uepm_list.lh_first;
ufs_extattr_disable(ump, uele->uele_attrname, p);
}
ump->um_extattr.uepm_flags &= ~UFS_EXTATTR_UEPM_STARTED;
crfree(ump->um_extattr.uepm_ucred);
ump->um_extattr.uepm_ucred = NULL;
unlock:
ufs_extattr_uepm_unlock(ump, p);
return (error);
}
/*
* Enable a named attribute on the specified file system; provide a
* backing vnode to hold the attribute data.
*/
static int
ufs_extattr_enable(struct ufsmount *ump, char *attrname,
struct vnode *backing_vnode, struct proc *p)
{
struct ufs_extattr_list_entry *attribute;
struct iovec aiov;
struct uio auio;
int error = 0;
if (backing_vnode->v_type != VREG)
return (EINVAL);
MALLOC(attribute, struct ufs_extattr_list_entry *,
sizeof(struct ufs_extattr_list_entry), M_UFS_EXTATTR, M_WAITOK);
if (attribute == NULL)
return (ENOMEM);
if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) {
error = EOPNOTSUPP;
goto free_exit;
}
if (ufs_exttatr_find_attr(ump, attrname)) {
error = EOPNOTSUPP;
goto free_exit;
}
strncpy(attribute->uele_attrname, attrname, UFS_EXTATTR_MAXEXTATTRNAME);
bzero(&attribute->uele_fileheader,
sizeof(struct ufs_extattr_fileheader));
attribute->uele_backing_vnode = backing_vnode;
backing_vnode->v_flag |= VSYSTEM;
auio.uio_iov = &aiov;
auio.uio_iovcnt = 1;
aiov.iov_base = (caddr_t) &attribute->uele_fileheader;
aiov.iov_len = sizeof(struct ufs_extattr_fileheader);
auio.uio_resid = sizeof(struct ufs_extattr_fileheader);
auio.uio_offset = (off_t) 0;
auio.uio_segflg = UIO_SYSSPACE;
auio.uio_rw = UIO_READ;
auio.uio_procp = (struct proc *) p;
VOP_LEASE(backing_vnode, p, p->p_cred->pc_ucred, LEASE_WRITE);
vn_lock(backing_vnode, LK_SHARED | LK_NOPAUSE | LK_RETRY, p);
error = VOP_READ(backing_vnode, &auio, 0, ump->um_extattr.uepm_ucred);
VOP_UNLOCK(backing_vnode, 0, p);
if (error) {
goto free_exit;
}
if (auio.uio_resid != 0) {
printf("ufs_extattr_enable: malformed attribute header\n");
error = EINVAL;
goto free_exit;
}
LIST_INSERT_HEAD(&ump->um_extattr.uepm_list, attribute, uele_entries);
return (0);
free_exit:
FREE(attribute, M_UFS_EXTATTR);
return (error);
}
/*
* Disable extended attribute support on an FS
*/
static int
ufs_extattr_disable(struct ufsmount *ump, char *attrname, struct proc *p)
{
struct ufs_extattr_list_entry *uele;
int error = 0;
uele = ufs_exttatr_find_attr(ump, attrname);
if (!uele)
return (ENOENT);
LIST_REMOVE(uele, uele_entries);
uele->uele_backing_vnode->v_flag &= ~VSYSTEM;
error = vn_close(uele->uele_backing_vnode, FREAD|FWRITE, p->p_ucred, p);
FREE(uele, M_UFS_EXTATTR);
return (error);
}
/*
* VFS call to manage extended attributes in UFS
* attrname, arg are userspace pointers from the syscall
*/
int
ufs_extattrctl(struct mount *mp, int cmd, char *attrname,
caddr_t arg, struct proc *p)
{
struct nameidata nd;
struct ufsmount *ump = VFSTOUFS(mp);
struct vnode *vp;
char local_attrname[UFS_EXTATTR_MAXEXTATTRNAME]; /* inc null */
char *filename;
int error, len;
if ((error = suser_xxx(p->p_cred->pc_ucred, p, 0)))
return (error);
switch(cmd) {
case UFS_EXTATTR_CMD_START:
error = ufs_extattr_start(mp, p);
return (error);
case UFS_EXTATTR_CMD_STOP:
return (ufs_extattr_stop(mp, p));
case UFS_EXTATTR_CMD_ENABLE:
error = copyinstr(attrname, local_attrname,
UFS_EXTATTR_MAXEXTATTRNAME, &len);
if (error)
return (error);
filename = (char *) arg;
NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, filename, p);
error = vn_open(&nd, FREAD|FWRITE, 0);
if (error)
return (error);
vp = nd.ni_vp;
VOP_UNLOCK(vp, 0, p);
ufs_extattr_uepm_lock(ump, p);
error = ufs_extattr_enable(ump, local_attrname, vp, p);
ufs_extattr_uepm_unlock(ump, p);
return (error);
case UFS_EXTATTR_CMD_DISABLE:
error = copyinstr(attrname, local_attrname,
UFS_EXTATTR_MAXEXTATTRNAME, &len);
ufs_extattr_uepm_lock(ump, p);
error = ufs_extattr_disable(ump, local_attrname, p);
ufs_extattr_uepm_unlock(ump, p);
return (error);
default:
return (EINVAL);
}
}
/*
* Credential check based on process requesting service, and per-attribute
* permissions.
*/
static int
ufs_extattr_credcheck(struct ufs_extattr_list_entry *uele, u_int32_t fowner,
struct ucred *cred, struct proc *p, int access)
{
u_int uef_perm;
switch(access) {
case IREAD:
uef_perm = uele->uele_fileheader.uef_read_perm;
break;
case IWRITE:
uef_perm = uele->uele_fileheader.uef_write_perm;
break;
default:
return (EACCES);
}
/* Kernel sponsoring request does so without passing a cred */
if (!cred)
return (0);
/* XXX there might eventually be a capability check here */
/* If it's set to root-only, check for suser(p) */
if (uef_perm == UFS_EXTATTR_PERM_ROOT && !suser(p))
return (0);
/* Allow the owner if appropriate */
if (uef_perm == UFS_EXTATTR_PERM_OWNER && cred->cr_uid == fowner)
return (0);
/* Allow anyone if appropriate */
if (uef_perm == UFS_EXTATTR_PERM_ANYONE)
return (0);
return (EACCES);
}
/*
* Vnode operating to retrieve a named extended attribute
*/
int
ufs_vop_getextattr(struct vop_getextattr_args *ap)
/*
vop_getextattr {
IN struct vnode *a_vp;
IN char *a_name;
INOUT struct uio *a_uio;
IN struct ucred *a_cred;
IN struct proc *a_p;
};
*/
{
struct mount *mp = ap->a_vp->v_mount;
struct ufsmount *ump = VFSTOUFS(mp);
int error;
ufs_extattr_uepm_lock(ump, ap->a_p);
error = ufs_extattr_get(ap->a_vp, ap->a_name, ap->a_uio, ap->a_cred,
ap->a_p);
ufs_extattr_uepm_unlock(ump, ap->a_p);
return (error);
}
/*
* Real work associated with retrieving a named attribute--assumes that
* the attribute lock has already been grabbed.
*/
static int
ufs_extattr_get(struct vnode *vp, char *name, struct uio *uio,
struct ucred *cred, struct proc *p)
{
struct ufs_extattr_list_entry *attribute;
struct ufs_extattr_header ueh;
struct iovec local_aiov;
struct uio local_aio;
struct mount *mp = vp->v_mount;
struct ufsmount *ump = VFSTOUFS(mp);
struct inode *ip = VTOI(vp);
off_t base_offset, old_offset, offset;
size_t size, old_size;
int error = 0;
if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED))
return (EOPNOTSUPP);
attribute = ufs_exttatr_find_attr(ump, name);
if (!attribute)
return (ENOENT);
if ((error = ufs_extattr_credcheck(attribute, ip->i_uid, cred, p,
IREAD)))
return (error);
/*
* Early rejection of offsets that are invalid
*/
if (uio->uio_offset >= attribute->uele_fileheader.uef_size ||
uio->uio_offset < 0)
return (ENXIO);
/*
* Find base offset of header in file based on file header size, and
* data header size + maximum data size, indexed by inode number
*/
base_offset = sizeof(struct ufs_extattr_fileheader) +
ip->i_number * (sizeof(struct ufs_extattr_header) +
attribute->uele_fileheader.uef_size);
/*
* Read in the data header to see if the data is defined, and if so
* how much.
*/
bzero(&ueh, sizeof(struct ufs_extattr_header));
local_aiov.iov_base = (caddr_t) &ueh;
local_aiov.iov_len = sizeof(struct ufs_extattr_header);
local_aio.uio_iov = &local_aiov;
local_aio.uio_iovcnt = 1;
local_aio.uio_rw = UIO_READ;
local_aio.uio_segflg = UIO_SYSSPACE;
local_aio.uio_procp = p;
local_aio.uio_offset = base_offset;
local_aio.uio_resid = sizeof(struct ufs_extattr_header);
VOP_LEASE(attribute->uele_backing_vnode, p, cred, LEASE_READ);
vn_lock(attribute->uele_backing_vnode, LK_SHARED | LK_NOPAUSE |
LK_RETRY, p);
error = VOP_READ(attribute->uele_backing_vnode, &local_aio, 0,
ump->um_extattr.uepm_ucred);
if (error)
goto vopunlock_exit;
/* defined? */
if ((ueh.ueh_flags & UFS_EXTATTR_ATTR_FLAG_INUSE) == 0) {
error = ENOENT;
goto vopunlock_exit;
}
/* local size consistency check */
if (ueh.ueh_len > attribute->uele_fileheader.uef_size) {
error = ENXIO;
goto vopunlock_exit;
}
if (ueh.ueh_len < uio->uio_offset) {
error = 0;
goto vopunlock_exit;
}
/* allow for offset into the attr data */
offset = base_offset + sizeof(struct ufs_extattr_header) +
uio->uio_offset;
/*
* Figure out maximum to transfer -- use buffer size and local data
* limit.
*/
size = MIN(uio->uio_resid, ueh.ueh_len - uio->uio_offset);
old_offset = uio->uio_offset;
uio->uio_offset = offset;
old_size = uio->uio_resid;
uio->uio_resid = size;
error = VOP_READ(attribute->uele_backing_vnode, uio, 0,
ump->um_extattr.uepm_ucred);
if (error) {
uio->uio_offset = old_offset;
goto vopunlock_exit;
}
uio->uio_offset = old_offset;
uio->uio_resid = old_size - (size - uio->uio_resid);
vopunlock_exit:
VOP_UNLOCK(attribute->uele_backing_vnode, 0, p);
return (error);
}
/*
* Vnode operation to set a named attribute
*/
int
ufs_vop_setextattr(struct vop_setextattr_args *ap)
/*
vop_setextattr {
IN struct vnode *a_vp;
IN char *a_name;
INOUT struct uio *a_uio;
IN struct ucred *a_cred;
IN struct proc *a_p;
};
*/
{
struct mount *mp = ap->a_vp->v_mount;
struct ufsmount *ump = VFSTOUFS(mp);
int error;
ufs_extattr_uepm_lock(ump, ap->a_p);
if (ap->a_uio)
error = ufs_extattr_set(ap->a_vp, ap->a_name, ap->a_uio,
ap->a_cred, ap->a_p);
else
error = ufs_extattr_rm(ap->a_vp, ap->a_name, ap->a_cred,
ap->a_p);
ufs_extattr_uepm_unlock(ump, ap->a_p);
return (error);
}
/*
* Real work associated with setting a vnode's extended attributes;
* assumes that the attribute lock has already been grabbed.
*/
static int
ufs_extattr_set(struct vnode *vp, char *name, struct uio *uio,
struct ucred *cred, struct proc *p)
{
struct ufs_extattr_list_entry *attribute;
struct ufs_extattr_header ueh;
struct iovec local_aiov;
struct uio local_aio;
struct mount *mp = vp->v_mount;
struct ufsmount *ump = VFSTOUFS(mp);
struct inode *ip = VTOI(vp);
off_t base_offset;
int error = 0;
if (vp->v_mount->mnt_flag & MNT_RDONLY)
return (EROFS);
if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED))
return (EOPNOTSUPP);
attribute = ufs_exttatr_find_attr(ump, name);
if (!attribute)
return (ENOENT);
if ((error = ufs_extattr_credcheck(attribute, ip->i_uid, cred,
p, IWRITE)))
return (error);
/*
* Early rejection of invalid offsets/lengths
* Reject: any offset but 0 (replace)
* Any size greater than attribute size limit
*/
if (uio->uio_offset != 0 ||
uio->uio_resid > attribute->uele_fileheader.uef_size)
return (ENXIO);
/*
* Find base offset of header in file based on file header size, and
* data header size + maximum data size, indexed by inode number
*/
base_offset = sizeof(struct ufs_extattr_fileheader) +
ip->i_number * (sizeof(struct ufs_extattr_header) +
attribute->uele_fileheader.uef_size);
/*
* Write out a data header for the data
*/
ueh.ueh_len = uio->uio_resid;
ueh.ueh_flags = UFS_EXTATTR_ATTR_FLAG_INUSE;
local_aiov.iov_base = (caddr_t) &ueh;
local_aiov.iov_len = sizeof(struct ufs_extattr_header);
local_aio.uio_iov = &local_aiov;
local_aio.uio_iovcnt = 1;
local_aio.uio_rw = UIO_WRITE;
local_aio.uio_segflg = UIO_SYSSPACE;
local_aio.uio_procp = p;
local_aio.uio_offset = base_offset;
local_aio.uio_resid = sizeof(struct ufs_extattr_header);
/*
* Acquire locks
*/
VOP_LEASE(attribute->uele_backing_vnode, p, cred, LEASE_WRITE);
/*
* Don't need to get a lock on the backing file if the setattr is
* being applied to the backing file, as the lock is already held
*/
if (attribute->uele_backing_vnode != vp)
vn_lock(attribute->uele_backing_vnode,
LK_EXCLUSIVE | LK_NOPAUSE | LK_RETRY, p);
error = VOP_WRITE(attribute->uele_backing_vnode, &local_aio, 0,
ump->um_extattr.uepm_ucred);
if (error)
goto vopunlock_exit;
if (local_aio.uio_resid != 0)
error = ENXIO;
goto vopunlock_exit;
/*
* Write out user data
*/
uio->uio_offset = base_offset + sizeof(struct ufs_extattr_header);
error = VOP_WRITE(attribute->uele_backing_vnode, uio, 0,
ump->um_extattr.uepm_ucred);
vopunlock_exit:
uio->uio_offset = 0;
VOP_UNLOCK(attribute->uele_backing_vnode, 0, p);
return (error);
}
/*
* Real work associated with removing an extended attribute from a vnode.
* Assumes the attribute lock has already been grabbed.
*/
static int
ufs_extattr_rm(struct vnode *vp, char *name, struct ucred *cred,
struct proc *p)
{
struct ufs_extattr_list_entry *attribute;
struct ufs_extattr_header ueh;
struct iovec local_aiov;
struct uio local_aio;
struct mount *mp = vp->v_mount;
struct ufsmount *ump = VFSTOUFS(mp);
struct inode *ip = VTOI(vp);
off_t base_offset;
int error = 0;
if (vp->v_mount->mnt_flag & MNT_RDONLY)
return (EROFS);
if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED))
return (EOPNOTSUPP);
attribute = ufs_exttatr_find_attr(ump, name);
if (!attribute)
return (ENOENT);
if ((error = ufs_extattr_credcheck(attribute, ip->i_uid, cred, p,
IWRITE)))
return (error);
/*
* Find base offset of header in file based on file header size, and
* data header size + maximum data size, indexed by inode number
*/
base_offset = sizeof(struct ufs_extattr_fileheader) +
ip->i_number * (sizeof(struct ufs_extattr_header) +
attribute->uele_fileheader.uef_size);
/*
* Read in the data header to see if the data is defined
*/
bzero(&ueh, sizeof(struct ufs_extattr_header));
local_aiov.iov_base = (caddr_t) &ueh;
local_aiov.iov_len = sizeof(struct ufs_extattr_header);
local_aio.uio_iov = &local_aiov;
local_aio.uio_iovcnt = 1;
local_aio.uio_rw = UIO_READ;
local_aio.uio_segflg = UIO_SYSSPACE;
local_aio.uio_procp = p;
local_aio.uio_offset = base_offset;
local_aio.uio_resid = sizeof(struct ufs_extattr_header);
VOP_LEASE(attribute->uele_backing_vnode, p, cred, LEASE_WRITE);
/*
* Don't need to get the lock on the backing vnode if the vnode we're
* modifying is it, as we already hold the lock.
*/
if (attribute->uele_backing_vnode != vp)
vn_lock(attribute->uele_backing_vnode,
LK_EXCLUSIVE | LK_NOPAUSE | LK_RETRY, p);
error = VOP_READ(attribute->uele_backing_vnode, &local_aio, 0,
ump->um_extattr.uepm_ucred);
if (error)
goto vopunlock_exit;
/* defined? */
if ((ueh.ueh_flags & UFS_EXTATTR_ATTR_FLAG_INUSE) == 0) {
error = ENOENT;
goto vopunlock_exit;
}
/* flag it as not in use */
ueh.ueh_flags = 0;
error = VOP_WRITE(attribute->uele_backing_vnode, &local_aio, 0,
ump->um_extattr.uepm_ucred);
if (error)
goto vopunlock_exit;
if (local_aio.uio_resid != 0)
error = ENXIO;
vopunlock_exit:
VOP_UNLOCK(attribute->uele_backing_vnode, 0, p);
return (error);
}
/*
* Called by UFS when an inode is no longer active and should have its
* attributes stripped.
*/
void
ufs_extattr_vnode_inactive(struct vnode *vp, struct proc *p)
{
struct ufs_extattr_list_entry *uele;
struct mount *mp = vp->v_mount;
struct ufsmount *ump = VFSTOUFS(mp);
ufs_extattr_uepm_lock(ump, p);
if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) {
ufs_extattr_uepm_unlock(ump, p);
return;
}
for (uele = ump->um_extattr.uepm_list.lh_first; uele != NULL;
uele = uele->uele_entries.le_next)
ufs_extattr_rm(vp, uele->uele_attrname, 0, p);
ufs_extattr_uepm_unlock(ump, p);
}

View File

@ -39,6 +39,7 @@
* $FreeBSD$
*/
#include "opt_ffs.h"
#include "opt_quota.h"
#include <sys/param.h>
@ -46,6 +47,7 @@
#include <sys/mount.h>
#include <sys/malloc.h>
#include <ufs/ufs/extattr.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>
@ -80,6 +82,9 @@ ufs_inactive(ap)
#ifdef QUOTA
if (!getinoquota(ip))
(void)chkiq(ip, -1, NOCRED, 0);
#endif
#ifdef FFS_EXTATTR
ufs_extattr_vnode_inactive(ap->a_vp, ap->a_p);
#endif
error = UFS_TRUNCATE(vp, (off_t)0, 0, NOCRED, p);
ip->i_rdev = 0;

View File

@ -53,6 +53,7 @@
#include <vm/vm.h>
#include <vm/vm_extern.h>
#include <ufs/ufs/extattr.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/dir.h>

View File

@ -48,6 +48,7 @@
#include <sys/mount.h>
#include <vm/vm_zone.h>
#include <ufs/ufs/extattr.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>

View File

@ -48,6 +48,7 @@
#include <sys/malloc.h>
#include <sys/vnode.h>
#include <ufs/ufs/extattr.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>

View File

@ -65,6 +65,7 @@
#include <miscfs/fifofs/fifo.h>
#include <ufs/ufs/extattr.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/dir.h>

View File

@ -69,6 +69,7 @@ struct ucred;
struct uio;
struct vnode;
struct netexport;
struct ufs_extattr_per_mount;
/* This structure describes the UFS specific mount structure data. */
struct ufsmount {
@ -86,6 +87,7 @@ struct ufsmount {
struct vnode *um_quotas[MAXQUOTAS]; /* pointer to quota files */
struct ucred *um_cred[MAXQUOTAS]; /* quota file access cred */
struct ufs_extattr_per_mount um_extattr; /* extended attrs */
u_long um_nindir; /* indirect ptrs per block */
u_long um_bptrtodb; /* indir ptr to disk block */
u_long um_seqinc; /* inc between seq blocks */