diff options
Diffstat (limited to 'sys/ufs/ufs/ufs_extattr.c')
-rw-r--r-- | sys/ufs/ufs/ufs_extattr.c | 99 |
1 files changed, 59 insertions, 40 deletions
diff --git a/sys/ufs/ufs/ufs_extattr.c b/sys/ufs/ufs/ufs_extattr.c index 84932be..74ed01c 100644 --- a/sys/ufs/ufs/ufs_extattr.c +++ b/sys/ufs/ufs/ufs_extattr.c @@ -49,8 +49,10 @@ 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_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, @@ -84,6 +86,28 @@ ufs_extattr_uepm_unlock(struct ufsmount *ump, struct proc *p) } /* + * Determine whether the name passed is a valid name for an actual + * attribute. + * + * Invalid currently consists of: + * NULL pointer for attrname + * zero-length attrname (used to retrieve application attr list) + * attrname consisting of "$" (used to treive system attr list) + */ +static int +ufs_extattr_valid_attrname(const char *attrname) +{ + + if (attrname == NULL) + return (0); + if (strlen(attrname) == 0) + return (0); + if (strlen(attrname) == 1 && attrname[0] == '$') + return (0); + return (1); +} + +/* * Locate an attribute given a name and mountpoint. * Must be holding uepm lock for the mount point. */ @@ -199,6 +223,8 @@ ufs_extattr_enable(struct ufsmount *ump, const char *attrname, struct uio auio; int error = 0; + if (!ufs_extattr_valid_attrname(attrname)) + return (EINVAL); if (backing_vnode->v_type != VREG) return (EINVAL); @@ -280,6 +306,9 @@ ufs_extattr_disable(struct ufsmount *ump, const char *attrname, struct proc *p) struct ufs_extattr_list_entry *uele; int error = 0; + if (!ufs_extattr_valid_attrname(attrname)) + return (EINVAL); + uele = ufs_extattr_find_attr(ump, attrname); if (!uele) return (ENOENT); @@ -363,41 +392,27 @@ ufs_extattrctl(struct mount *mp, int cmd, const char *attrname, * permissions. */ static int -ufs_extattr_credcheck(struct ufs_extattr_list_entry *uele, u_int32_t fowner, - struct ucred *cred, struct proc *p, int access) +ufs_extattr_credcheck(struct vnode *vp, struct ufs_extattr_list_entry *uele, + 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 */ + int system_namespace; - /* 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); + system_namespace = (strlen(uele->uele_attrname) >= 1 && + uele->uele_attrname[0] == '$'); - /* Allow anyone if appropriate */ - if (uef_perm == UFS_EXTATTR_PERM_ANYONE) + /* + * Kernel-invoked always succeeds + */ + if (cred == NULL) return (0); - return (EACCES); + /* + * XXX What capability should apply here? + */ + if (system_namespace) + return (suser_xxx(cred, p, PRISON_ROOT)); + else + return (VOP_ACCESS(vp, access, cred, p)); } /* @@ -451,12 +466,16 @@ 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] == '$')) { + /* XXX retrieve attribute lists */ + return (EINVAL); + } + attribute = ufs_extattr_find_attr(ump, name); if (!attribute) return (ENOENT); - if ((error = ufs_extattr_credcheck(attribute, ip->i_uid, cred, p, - IREAD))) + if ((error = ufs_extattr_credcheck(vp, attribute, cred, p, IREAD))) return (error); /* @@ -613,16 +632,16 @@ ufs_extattr_set(struct vnode *vp, const char *name, struct uio *uio, if (vp->v_mount->mnt_flag & MNT_RDONLY) return (EROFS); - if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) return (EOPNOTSUPP); + if (!ufs_extattr_valid_attrname(name)) + return (EINVAL); attribute = ufs_extattr_find_attr(ump, name); if (!attribute) return (ENOENT); - if ((error = ufs_extattr_credcheck(attribute, ip->i_uid, cred, - p, IWRITE))) + if ((error = ufs_extattr_credcheck(vp, attribute, cred, p, IWRITE))) return (error); /* @@ -718,16 +737,16 @@ ufs_extattr_rm(struct vnode *vp, const char *name, struct ucred *cred, if (vp->v_mount->mnt_flag & MNT_RDONLY) return (EROFS); - if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) return (EOPNOTSUPP); + if (!ufs_extattr_valid_attrname(name)) + return (EINVAL); attribute = ufs_extattr_find_attr(ump, name); if (!attribute) return (ENOENT); - if ((error = ufs_extattr_credcheck(attribute, ip->i_uid, cred, p, - IWRITE))) + if ((error = ufs_extattr_credcheck(vp, attribute, cred, p, IWRITE))) return (error); /* |