diff options
Diffstat (limited to 'sys/ufs')
-rw-r--r-- | sys/ufs/ufs/extattr.h | 11 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_extattr.c | 222 |
2 files changed, 138 insertions, 95 deletions
diff --git a/sys/ufs/ufs/extattr.h b/sys/ufs/ufs/extattr.h index 849e632..f7cbfaa 100644 --- a/sys/ufs/ufs/extattr.h +++ b/sys/ufs/ufs/extattr.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1999, 2000 Robert N. M. Watson + * Copyright (c) 1999, 2000, 2001 Robert N. M. Watson * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -73,8 +73,9 @@ MALLOC_DECLARE(M_EXTATTR); 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; + LIST_ENTRY(ufs_extattr_list_entry) uele_entries; + struct ufs_extattr_fileheader uele_fileheader; + int uele_namespace; char uele_attrname[UFS_EXTATTR_MAXEXTATTRNAME]; struct vnode *uele_backing_vnode; }; @@ -93,8 +94,8 @@ void ufs_extattr_uepm_destroy(struct ufs_extattr_per_mount *uepm); int ufs_extattr_start(struct mount *mp, struct proc *p); int ufs_extattr_autostart(struct mount *mp, struct proc *p); int ufs_extattr_stop(struct mount *mp, struct proc *p); -int ufs_extattrctl(struct mount *mp, int cmd, const char *attrname, - caddr_t arg, struct proc *p); +int ufs_extattrctl(struct mount *mp, int cmd, struct vnode *filename, + int namespace, const char *attrname, 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); diff --git a/sys/ufs/ufs/ufs_extattr.c b/sys/ufs/ufs/ufs_extattr.c index 2c00b95..24d4a03 100644 --- a/sys/ufs/ufs/ufs_extattr.c +++ b/sys/ufs/ufs/ufs_extattr.c @@ -40,6 +40,7 @@ #include <sys/mount.h> #include <sys/lock.h> #include <sys/dirent.h> +#include <sys/extattr.h> #include <vm/vm_zone.h> @@ -52,6 +53,8 @@ #include "opt_ffs.h" +#ifdef FFS_EXTATTR + #define MIN(a,b) (((a)<(b))?(a):(b)) static MALLOC_DEFINE(M_UFS_EXTATTR, "ufs_extattr", "ufs extended attribute"); @@ -60,16 +63,18 @@ static int ufs_extattr_valid_attrname(const char *attrname); static int ufs_extattr_credcheck(struct vnode *vp, struct ufs_extattr_list_entry *uele, struct ucred *cred, struct proc *p, int access); -static int ufs_extattr_enable(struct ufsmount *ump, const char *attrname, - struct vnode *backing_vnode, struct proc *p); -static int ufs_extattr_disable(struct ufsmount *ump, const char *attrname, - struct proc *p); -static int ufs_extattr_get(struct vnode *vp, const char *name, - struct uio *uio, struct ucred *cred, struct proc *p); -static int ufs_extattr_set(struct vnode *vp, const char *name, - struct uio *uio, struct ucred *cred, struct proc *p); -static int ufs_extattr_rm(struct vnode *vp, const char *name, - struct ucred *cred, struct proc *p); +static int ufs_extattr_enable_with_open(struct ufsmount *ump, + struct vnode *vp, int namespace, const char *attrname, struct proc *p); +static int ufs_extattr_enable(struct ufsmount *ump, int namespace, + const char *attrname, struct vnode *backing_vnode, struct proc *p); +static int ufs_extattr_disable(struct ufsmount *ump, int namespace, + const char *attrname, struct proc *p); +static int ufs_extattr_get(struct vnode *vp, int namespace, + const char *name, struct uio *uio, struct ucred *cred, struct proc *p); +static int ufs_extattr_set(struct vnode *vp, int namespace, + const char *name, struct uio *uio, struct ucred *cred, struct proc *p); +static int ufs_extattr_rm(struct vnode *vp, int namespace, + const char *name, struct ucred *cred, struct proc *p); /* * Per-FS attribute lock protecting attribute operations. @@ -119,7 +124,8 @@ ufs_extattr_valid_attrname(const char *attrname) * Must be holding uepm lock for the mount point. */ static struct ufs_extattr_list_entry * -ufs_extattr_find_attr(struct ufsmount *ump, const char *attrname) +ufs_extattr_find_attr(struct ufsmount *ump, int namespace, + const char *attrname) { struct ufs_extattr_list_entry *search_attribute; @@ -127,7 +133,8 @@ ufs_extattr_find_attr(struct ufsmount *ump, const char *attrname) search_attribute; search_attribute = LIST_NEXT(search_attribute, uele_entries)) { if (!(strncmp(attrname, search_attribute->uele_attrname, - UFS_EXTATTR_MAXEXTATTRNAME))) { + UFS_EXTATTR_MAXEXTATTRNAME)) && + (namespace == search_attribute->uele_namespace)) { return (search_attribute); } } @@ -291,17 +298,18 @@ ufs_extattr_lookup(struct vnode *start_dvp, int lockparent, char *dirname, *vp = target_vp; return (0); } +#endif /* !FFS_EXTATTR_AUTOSTART */ /* * Enable an EA using the passed file system, backing vnode, attribute name, - * and proc. Will perform a VOP_OPEN() on the vp, so expects vp to be locked - * when passed in. Will unlock vp, and grab its own reference, so the caller - * needs to vrele(), just not vput(). If the call fails, the lock is not - * released. + * namespace, and proc. Will perform a VOP_OPEN() on the vp, so expects vp + * to be locked when passed in. Will unlock vp, and grab its own reference, + * so the caller needs to vrele(), just not vput(). The unlock the vnode + * regardless of call success or failure. */ static int ufs_extattr_enable_with_open(struct ufsmount *ump, struct vnode *vp, - char *attrname, struct proc *p) + int namespace, const char *attrname, struct proc *p) { int error; @@ -309,6 +317,7 @@ ufs_extattr_enable_with_open(struct ufsmount *ump, struct vnode *vp, if (error) { printf("ufs_extattr_enable_with_open.VOP_OPEN(): failed " "with %d\n", error); + VOP_UNLOCK(vp, 0, p); return (error); } @@ -322,6 +331,7 @@ ufs_extattr_enable_with_open(struct ufsmount *ump, struct vnode *vp, * XXX: bug replicated from vn_open(): should * VOP_CLOSE() here. */ + VOP_UNLOCK(vp, 0, p); return (error); } @@ -331,9 +341,10 @@ ufs_extattr_enable_with_open(struct ufsmount *ump, struct vnode *vp, VOP_UNLOCK(vp, 0, p); - return (ufs_extattr_enable(ump, attrname, vp, p)); + return (ufs_extattr_enable(ump, namespace, attrname, vp, p)); } +#ifdef FFS_EXTATTR_AUTOSTART /* * Given a locked directory vnode, iterate over the names in the directory * and use ufs_extattr_lookup() to retrieve locked vnodes of potential @@ -344,7 +355,7 @@ ufs_extattr_enable_with_open(struct ufsmount *ump, struct vnode *vp, */ static int ufs_extattr_iterate_directory(struct ufsmount *ump, struct vnode *dvp, - struct proc *p) + int namespace, struct proc *p) { struct vop_readdir_args vargs; struct dirent *dp, *edp; @@ -412,19 +423,18 @@ ufs_extattr_iterate_directory(struct ufsmount *ump, struct vnode *dvp, vput(attr_vp); } else { error = ufs_extattr_enable_with_open(ump, - attr_vp, dp->d_name, p); + attr_vp, namespace, dp->d_name, p); + vrele(attr_vp); if (error) { printf("ufs_extattr_iterate_directory: " "enable %s %d\n", dp->d_name, error); - vput(attr_vp); } else { /* * While it's nice to have some visual output here, skip for the time-being. * Probably should be enabled by -v at boot. printf("Autostarted %s\n", dp->d_name); */ - vrele(attr_vp); } } dp = (struct dirent *) ((char *)dp + dp->d_reclen); @@ -448,8 +458,8 @@ ufs_extattr_autostart(struct mount *mp, struct proc *p) int error; /* - * Does ".attribute" exist off the file system root? If so, - * automatically start EA's. + * Does UFS_EXTATTR_FSROOTSUBDIR exist off the file system root? + * If so, automatically start EA's. */ error = VFS_ROOT(mp, &rvp); if (error) { @@ -458,7 +468,7 @@ ufs_extattr_autostart(struct mount *mp, struct proc *p) } error = ufs_extattr_lookup(rvp, UE_GETDIR_LOCKPARENT_DONT, - ".attribute", &attr_dvp, p); + UFS_EXTATTR_FSROOTSUBDIR, &attr_dvp, p); if (error) { /* rvp ref'd but now unlocked */ vrele(rvp); @@ -473,7 +483,8 @@ ufs_extattr_autostart(struct mount *mp, struct proc *p) vrele(rvp); if (attr_dvp->v_type != VDIR) { - printf("ufs_extattr_autostart: .attribute != VDIR\n"); + printf("ufs_extattr_autostart: %s != VDIR\n", + UFS_EXTATTR_FSROOTSUBDIR); goto return_vput; } @@ -485,10 +496,15 @@ ufs_extattr_autostart(struct mount *mp, struct proc *p) } /* - * Iterate over the directory. Eventually we may lookup sub-directories - * and iterate over them independently. + * Iterate over the directory. Eventually we will lookup sub- + * directories and iterate over them independently with different + * EA namespaces. + * + * XXX: Right now, assert that all attributes are in the system + * namespace. */ - error = ufs_extattr_iterate_directory(VFSTOUFS(mp), attr_dvp, p); + error = ufs_extattr_iterate_directory(VFSTOUFS(mp), attr_dvp, + EXTATTR_NAMESPACE_SYSTEM, p); if (error) printf("ufs_extattr_iterate_directory returned %d\n", error); @@ -521,7 +537,8 @@ ufs_extattr_stop(struct mount *mp, struct proc *p) while (LIST_FIRST(&ump->um_extattr.uepm_list) != NULL) { uele = LIST_FIRST(&ump->um_extattr.uepm_list); - ufs_extattr_disable(ump, uele->uele_attrname, p); + ufs_extattr_disable(ump, uele->uele_namespace, + uele->uele_attrname, p); } ump->um_extattr.uepm_flags &= ~UFS_EXTATTR_UEPM_STARTED; @@ -536,11 +553,11 @@ unlock: } /* - * Enable a named attribute on the specified file system; provide a - * backing vnode to hold the attribute data. + * Enable a named attribute on the specified file system; provide an + * unlocked backing vnode to hold the attribute data. */ static int -ufs_extattr_enable(struct ufsmount *ump, const char *attrname, +ufs_extattr_enable(struct ufsmount *ump, int namespace, const char *attrname, struct vnode *backing_vnode, struct proc *p) { struct ufs_extattr_list_entry *attribute; @@ -563,12 +580,13 @@ ufs_extattr_enable(struct ufsmount *ump, const char *attrname, goto free_exit; } - if (ufs_extattr_find_attr(ump, attrname)) { + if (ufs_extattr_find_attr(ump, namespace, attrname)) { error = EEXIST; goto free_exit; } strncpy(attribute->uele_attrname, attrname, UFS_EXTATTR_MAXEXTATTRNAME); + attribute->uele_namespace = namespace; bzero(&attribute->uele_fileheader, sizeof(struct ufs_extattr_fileheader)); @@ -590,9 +608,8 @@ ufs_extattr_enable(struct ufsmount *ump, const char *attrname, ump->um_extattr.uepm_ucred); VOP_UNLOCK(backing_vnode, 0, p); - if (error) { + if (error) goto free_exit; - } if (auio.uio_resid != 0) { printf("ufs_extattr_enable: malformed attribute header\n"); @@ -627,7 +644,8 @@ free_exit: * Disable extended attribute support on an FS. */ static int -ufs_extattr_disable(struct ufsmount *ump, const char *attrname, struct proc *p) +ufs_extattr_disable(struct ufsmount *ump, int namespace, const char *attrname, + struct proc *p) { struct ufs_extattr_list_entry *uele; int error = 0; @@ -635,7 +653,7 @@ ufs_extattr_disable(struct ufsmount *ump, const char *attrname, struct proc *p) if (!ufs_extattr_valid_attrname(attrname)) return (EINVAL); - uele = ufs_extattr_find_attr(ump, attrname); + uele = ufs_extattr_find_attr(ump, namespace, attrname); if (!uele) return (ENOENT); @@ -650,65 +668,83 @@ ufs_extattr_disable(struct ufsmount *ump, const char *attrname, struct proc *p) } /* - * VFS call to manage extended attributes in UFS. - * attrname, arg are userspace pointers from the syscall. + * VFS call to manage extended attributes in UFS. If filename_vp is + * non-NULL, it must be passed in locked, and regardless of errors in + * processing, will be unlocked. */ int -ufs_extattrctl(struct mount *mp, int cmd, const char *attrname, - caddr_t arg, struct proc *p) +ufs_extattrctl(struct mount *mp, int cmd, struct vnode *filename_vp, + int namespace, const char *attrname, struct proc *p) { - struct nameidata nd; struct ufsmount *ump = VFSTOUFS(mp); - struct vnode *vp; - char local_attrname[UFS_EXTATTR_MAXEXTATTRNAME]; /* Incl. null. */ - char *filename; - int error, flags; - size_t len; + int error; /* * Processes with privilege, but in jail, are not allowed to * configure extended attributes. */ - if ((error = suser_xxx(p->p_cred->pc_ucred, p, 0))) + if ((error = suser_xxx(p->p_cred->pc_ucred, p, 0))) { + if (filename_vp != NULL) + VOP_UNLOCK(filename_vp, 0, p); return (error); + } switch(cmd) { case UFS_EXTATTR_CMD_START: + if (filename_vp != NULL) { + VOP_UNLOCK(filename_vp, 0, p); + return (EINVAL); + } + if (attrname != NULL) + return (EINVAL); + error = ufs_extattr_start(mp, p); return (error); case UFS_EXTATTR_CMD_STOP: - return (ufs_extattr_stop(mp, p)); + if (filename_vp != NULL) { + VOP_UNLOCK(filename_vp, 0, p); + return (EINVAL); + } + if (attrname != NULL) + return (EINVAL); + + error = ufs_extattr_stop(mp, p); + + return (error); 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); - flags = FREAD | FWRITE; - error = vn_open(&nd, &flags, 0); - if (error) - return (error); + if (filename_vp == NULL) + return (EINVAL); + if (attrname == NULL) { + VOP_UNLOCK(filename_vp, 0, p); + return (EINVAL); + } - vp = nd.ni_vp; - VOP_UNLOCK(vp, 0, p); - + /* + * ufs_extattr_enable_with_open() will always unlock the + * vnode, regardless of failure. + */ ufs_extattr_uepm_lock(ump, p); - error = ufs_extattr_enable(ump, local_attrname, vp, p); + error = ufs_extattr_enable_with_open(ump, filename_vp, + namespace, attrname, p); ufs_extattr_uepm_unlock(ump, p); return (error); case UFS_EXTATTR_CMD_DISABLE: - error = copyinstr(attrname, local_attrname, - UFS_EXTATTR_MAXEXTATTRNAME, &len); + + if (filename_vp != NULL) { + VOP_UNLOCK(filename_vp, 0, p); + return (EINVAL); + } + if (attrname == NULL) + return (EINVAL); ufs_extattr_uepm_lock(ump, p); - error = ufs_extattr_disable(ump, local_attrname, p); + error = ufs_extattr_disable(ump, namespace, attrname, p); ufs_extattr_uepm_unlock(ump, p); return (error); @@ -726,10 +762,6 @@ static int ufs_extattr_credcheck(struct vnode *vp, struct ufs_extattr_list_entry *uele, struct ucred *cred, struct proc *p, int access) { - int system_namespace; - - system_namespace = (strlen(uele->uele_attrname) >= 1 && - uele->uele_attrname[0] == '$'); /* * Kernel-invoked always succeeds. @@ -744,10 +776,14 @@ ufs_extattr_credcheck(struct vnode *vp, struct ufs_extattr_list_entry *uele, * XXX What capability should apply here? * Probably CAP_SYS_SETFFLAG. */ - if (system_namespace) + switch (uele->uele_namespace) { + case EXTATTR_NAMESPACE_SYSTEM: return (suser_xxx(cred, p, 0)); - else + case EXTATTR_NAMESPACE_USER: return (VOP_ACCESS(vp, access, cred, p)); + default: + return (EPERM); + } } /* @@ -758,6 +794,7 @@ ufs_vop_getextattr(struct vop_getextattr_args *ap) /* vop_getextattr { IN struct vnode *a_vp; + IN int a_namespace; IN const char *a_name; INOUT struct uio *a_uio; IN struct ucred *a_cred; @@ -771,8 +808,8 @@ vop_getextattr { 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); + error = ufs_extattr_get(ap->a_vp, ap->a_namespace, ap->a_name, + ap->a_uio, ap->a_cred, ap->a_p); ufs_extattr_uepm_unlock(ump, ap->a_p); @@ -784,8 +821,8 @@ vop_getextattr { * the attribute lock has already been grabbed. */ static int -ufs_extattr_get(struct vnode *vp, const char *name, struct uio *uio, - struct ucred *cred, struct proc *p) +ufs_extattr_get(struct vnode *vp, int namespace, const char *name, + struct uio *uio, struct ucred *cred, struct proc *p) { struct ufs_extattr_list_entry *attribute; struct ufs_extattr_header ueh; @@ -801,12 +838,13 @@ ufs_extattr_get(struct vnode *vp, const char *name, struct uio *uio, if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) return (EOPNOTSUPP); - if (strlen(name) == 0 || (strlen(name) == 1 && name[0] == '$')) { + if (strlen(name) == 0) { /* XXX retrieve attribute lists. */ + /* XXX should probably be checking for name == NULL? */ return (EINVAL); } - attribute = ufs_extattr_find_attr(ump, name); + attribute = ufs_extattr_find_attr(ump, namespace, name); if (!attribute) return (ENOENT); @@ -923,6 +961,7 @@ ufs_vop_setextattr(struct vop_setextattr_args *ap) /* vop_setextattr { IN struct vnode *a_vp; + IN int a_namespace; IN const char *a_name; INOUT struct uio *a_uio; IN struct ucred *a_cred; @@ -938,11 +977,11 @@ vop_setextattr { ufs_extattr_uepm_lock(ump, ap->a_p); if (ap->a_uio != NULL) - error = ufs_extattr_set(ap->a_vp, ap->a_name, ap->a_uio, - ap->a_cred, ap->a_p); + error = ufs_extattr_set(ap->a_vp, ap->a_namespace, 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); + error = ufs_extattr_rm(ap->a_vp, ap->a_namespace, ap->a_name, + ap->a_cred, ap->a_p); ufs_extattr_uepm_unlock(ump, ap->a_p); @@ -954,8 +993,8 @@ vop_setextattr { * assumes that the attribute lock has already been grabbed. */ static int -ufs_extattr_set(struct vnode *vp, const char *name, struct uio *uio, - struct ucred *cred, struct proc *p) +ufs_extattr_set(struct vnode *vp, int namespace, const char *name, + struct uio *uio, struct ucred *cred, struct proc *p) { struct ufs_extattr_list_entry *attribute; struct ufs_extattr_header ueh; @@ -974,7 +1013,7 @@ ufs_extattr_set(struct vnode *vp, const char *name, struct uio *uio, if (!ufs_extattr_valid_attrname(name)) return (EINVAL); - attribute = ufs_extattr_find_attr(ump, name); + attribute = ufs_extattr_find_attr(ump, namespace, name); if (!attribute) return (ENOENT); @@ -1059,8 +1098,8 @@ vopunlock_exit: * Assumes the attribute lock has already been grabbed. */ static int -ufs_extattr_rm(struct vnode *vp, const char *name, struct ucred *cred, - struct proc *p) +ufs_extattr_rm(struct vnode *vp, int namespace, const char *name, + struct ucred *cred, struct proc *p) { struct ufs_extattr_list_entry *attribute; struct ufs_extattr_header ueh; @@ -1079,7 +1118,7 @@ ufs_extattr_rm(struct vnode *vp, const char *name, struct ucred *cred, if (!ufs_extattr_valid_attrname(name)) return (EINVAL); - attribute = ufs_extattr_find_attr(ump, name); + attribute = ufs_extattr_find_attr(ump, namespace, name); if (!attribute) return (ENOENT); @@ -1191,7 +1230,10 @@ ufs_extattr_vnode_inactive(struct vnode *vp, struct proc *p) } LIST_FOREACH(uele, &ump->um_extattr.uepm_list, uele_entries) - ufs_extattr_rm(vp, uele->uele_attrname, NULL, p); + ufs_extattr_rm(vp, uele->uele_namespace, uele->uele_attrname, + NULL, p); ufs_extattr_uepm_unlock(ump, p); } + +#endif /* !FFS_EXTATTR */ |