Index: sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_acl.h =================================================================== --- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_acl.h +++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_acl.h @@ -214,7 +214,10 @@ void zfs_ace_byteswap(void *, size_t, boolean_t); extern boolean_t zfs_has_access(struct znode *zp, cred_t *cr); extern int zfs_zaccess(struct znode *, int, int, boolean_t, cred_t *); +#ifdef illumos int zfs_fastaccesschk_execute(struct znode *, cred_t *); +#endif +int zfs_freebsd_fastaccesschk_execute(struct vnode *, cred_t *); extern int zfs_zaccess_rwx(struct znode *, mode_t, int, cred_t *); extern int zfs_zaccess_unix(struct znode *, mode_t, cred_t *); extern int zfs_acl_access(struct znode *, int, cred_t *); Index: sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_acl.c =================================================================== --- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_acl.c +++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_acl.c @@ -2299,6 +2299,73 @@ check_privs, B_FALSE, cr)); } +/* + * Check if VEXEC is allowed. + * + * This routine is based on zfs_fastaccesschk_execute which has slowpath + * calling zfs_zaccess. This would be incorrect on FreeBSD (see + * zfs_freebsd_access for the difference). Thus this variant let's the + * caller handle the slowpath (if necessary). + * + * On top of that we perform a lockless check for ZFS_NO_EXECS_DENIED. + * + * Safe access to znode_t is provided by the vnode lock. + */ +int +zfs_freebsd_fastaccesschk_execute(struct vnode *vp, cred_t *cr) +{ + boolean_t owner = B_FALSE; + boolean_t groupmbr = B_FALSE; + boolean_t is_attr; + uid_t uid = crgetuid(cr); + znode_t *zdp = VTOZ(vp); + + if (zdp->z_pflags & ZFS_AV_QUARANTINED) + return (1); + + is_attr = ((zdp->z_pflags & ZFS_XATTR) && + (ZTOV(zdp)->v_type == VDIR)); + if (is_attr) + return (1); + + if (zdp->z_pflags & ZFS_NO_EXECS_DENIED) + return (0); + + mutex_enter(&zdp->z_acl_lock); + if (FUID_INDEX(zdp->z_uid) != 0 || FUID_INDEX(zdp->z_gid) != 0) { + goto out_slow; + } + + if (uid == zdp->z_uid) { + owner = B_TRUE; + if (zdp->z_mode & S_IXUSR) { + goto out; + } else { + goto out_slow; + } + } + if (groupmember(zdp->z_gid, cr)) { + groupmbr = B_TRUE; + if (zdp->z_mode & S_IXGRP) { + goto out; + } else { + goto out_slow; + } + } + if (!owner && !groupmbr) { + if (zdp->z_mode & S_IXOTH) { + goto out; + } + } +out: + mutex_exit(&zdp->z_acl_lock); + return (0); +out_slow: + mutex_exit(&zdp->z_acl_lock); + return (1); +} + +#ifdef illumos int zfs_fastaccesschk_execute(znode_t *zdp, cred_t *cr) { @@ -2365,6 +2432,7 @@ ZFS_EXIT(zdp->z_zfsvfs); return (error); } +#endif /* * Determine whether Access should be granted/denied. Index: sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c =================================================================== --- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c +++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c @@ -4860,6 +4860,11 @@ accmode_t accmode; int error = 0; + if (ap->a_accmode == VEXEC) { + if (zfs_freebsd_fastaccesschk_execute(ap->a_vp, ap->a_cred) == 0) + return (0); + } + /* * ZFS itself only knowns about VREAD, VWRITE, VEXEC and VAPPEND, */