diff --git a/sys/cddl/compat/opensolaris/kern/opensolaris_policy.c b/sys/cddl/compat/opensolaris/kern/opensolaris_policy.c index 040f27d6e5fa..865fba337f5a 100644 --- a/sys/cddl/compat/opensolaris/kern/opensolaris_policy.c +++ b/sys/cddl/compat/opensolaris/kern/opensolaris_policy.c @@ -358,8 +358,11 @@ secpolicy_fs_mount_clearopts(cred_t *cr, struct mount *vfsp) * Check privileges for setting xvattr attributes */ int -secpolicy_xvattr(xvattr_t *xvap, uid_t owner, cred_t *cr, vtype_t vtype) +secpolicy_xvattr(struct vnode *vp, xvattr_t *xvap, uid_t owner, cred_t *cr, + vtype_t vtype) { + if (secpolicy_fs_owner(vp->v_mount, cr) == 0) + return (0); return (priv_check_cred(cr, PRIV_VFS_SYSFLAGS, 0)); } diff --git a/sys/cddl/compat/opensolaris/sys/policy.h b/sys/cddl/compat/opensolaris/sys/policy.h index 08db5ca763d7..6731d7cbcd4c 100644 --- a/sys/cddl/compat/opensolaris/sys/policy.h +++ b/sys/cddl/compat/opensolaris/sys/policy.h @@ -70,7 +70,8 @@ int secpolicy_setid_setsticky_clear(struct vnode *vp, struct vattr *vap, int secpolicy_fs_owner(struct mount *vfsp, struct ucred *cred); int secpolicy_fs_mount(cred_t *cr, vnode_t *mvp, struct mount *vfsp); void secpolicy_fs_mount_clearopts(cred_t *cr, struct mount *vfsp); -int secpolicy_xvattr(xvattr_t *xvap, uid_t owner, cred_t *cr, vtype_t vtype); +int secpolicy_xvattr(struct vnode *vp, xvattr_t *xvap, uid_t owner, + cred_t *cr, vtype_t vtype); #endif /* _KERNEL */ diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c index 4136e7d66c85..6d9ec9cd4a70 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c @@ -1306,7 +1306,7 @@ zfs_create(vnode_t *dvp, char *name, vattr_t *vap, int excl, int mode, } if (vap->va_mask & AT_XVATTR) { - if ((error = secpolicy_xvattr((xvattr_t *)vap, + if ((error = secpolicy_xvattr(dvp, (xvattr_t *)vap, crgetuid(cr), cr, vap->va_type)) != 0) { ZFS_EXIT(zfsvfs); return (error); @@ -1758,7 +1758,7 @@ zfs_mkdir(vnode_t *dvp, char *dirname, vattr_t *vap, vnode_t **vpp, cred_t *cr, zf |= ZCILOOK; if (vap->va_mask & AT_XVATTR) - if ((error = secpolicy_xvattr((xvattr_t *)vap, + if ((error = secpolicy_xvattr(dvp, (xvattr_t *)vap, crgetuid(cr), cr, vap->va_type)) != 0) { ZFS_EXIT(zfsvfs); return (error); @@ -4205,12 +4205,6 @@ zfs_freebsd_setattr(ap) fflags = vap->va_flags; if ((fflags & ~(SF_IMMUTABLE|SF_APPEND|SF_NOUNLINK|UF_NODUMP)) != 0) return (EOPNOTSUPP); - /* - * Callers may only modify the file flags on objects they - * have VADMIN rights for. - */ - if ((error = VOP_ACCESS(vp, VADMIN, cred, curthread)) != 0) - return (error); /* * Unprivileged processes are not permitted to unset system * flags, or modify flags if any system flags are set. @@ -4221,14 +4215,21 @@ zfs_freebsd_setattr(ap) * is non-zero; otherwise, they behave like unprivileged * processes. */ - if (priv_check_cred(cred, PRIV_VFS_SYSFLAGS, 0) == 0) { + if (secpolicy_fs_owner(vp->v_mount, cred) == 0 || + priv_check_cred(cred, PRIV_VFS_SYSFLAGS, 0) == 0) { if (zflags & (ZFS_IMMUTABLE | ZFS_APPENDONLY | ZFS_NOUNLINK)) { error = securelevel_gt(cred, 0); - if (error) + if (error != 0) return (error); } } else { + /* + * Callers may only modify the file flags on objects they + * have VADMIN rights for. + */ + if ((error = VOP_ACCESS(vp, VADMIN, cred, curthread)) != 0) + return (error); if (zflags & (ZFS_IMMUTABLE | ZFS_APPENDONLY | ZFS_NOUNLINK)) { return (EPERM);