]> git.proxmox.com Git - mirror_zfs.git/blobdiff - module/os/linux/zfs/zfs_acl.c
Fixed parameter passing error when calling zfs_acl_chmod
[mirror_zfs.git] / module / os / linux / zfs / zfs_acl.c
index 11b5559321adf5f1b354612996c4ccf5714b452f..48abbc010917ff5a749f4d3cb3693bc5f0408110 100644 (file)
@@ -6,7 +6,7 @@
  * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
+ * or https://opensource.org/licenses/CDDL-1.0.
  * See the License for the specific language governing permissions
  * and limitations under the License.
  *
@@ -144,10 +144,10 @@ zfs_ace_v0_set_who(void *acep, uint64_t who)
        ((zfs_oldace_t *)acep)->z_fuid = who;
 }
 
-/*ARGSUSED*/
 static size_t
 zfs_ace_v0_size(void *acep)
 {
+       (void) acep;
        return (sizeof (zfs_oldace_t));
 }
 
@@ -163,15 +163,15 @@ zfs_ace_v0_mask_off(void)
        return (offsetof(zfs_oldace_t, z_access_mask));
 }
 
-/*ARGSUSED*/
 static int
 zfs_ace_v0_data(void *acep, void **datap)
 {
+       (void) acep;
        *datap = NULL;
        return (0);
 }
 
-static acl_ops_t zfs_acl_v0_ops = {
+static const acl_ops_t zfs_acl_v0_ops = {
        .ace_mask_get = zfs_ace_v0_get_mask,
        .ace_mask_set = zfs_ace_v0_set_mask,
        .ace_flags_get = zfs_ace_v0_get_flags,
@@ -269,7 +269,7 @@ zfs_ace_fuid_size(void *acep)
                    entry_type == OWNING_GROUP ||
                    entry_type == ACE_EVERYONE)
                        return (sizeof (zfs_ace_hdr_t));
-               /*FALLTHROUGH*/
+               zfs_fallthrough;
        default:
                return (sizeof (zfs_ace_t));
        }
@@ -307,7 +307,7 @@ zfs_ace_fuid_data(void *acep, void **datap)
        }
 }
 
-static acl_ops_t zfs_acl_fuid_ops = {
+static const acl_ops_t zfs_acl_fuid_ops = {
        .ace_mask_get = zfs_ace_fuid_get_mask,
        .ace_mask_set = zfs_ace_fuid_set_mask,
        .ace_flags_get = zfs_ace_fuid_get_flags,
@@ -493,10 +493,8 @@ zfs_acl_release_nodes(zfs_acl_t *aclp)
 {
        zfs_acl_node_t *aclnode;
 
-       while ((aclnode = list_head(&aclp->z_acl))) {
-               list_remove(&aclp->z_acl, aclnode);
+       while ((aclnode = list_remove_head(&aclp->z_acl)))
                zfs_acl_node_free(aclnode);
-       }
        aclp->z_acl_count = 0;
        aclp->z_acl_bytes = 0;
 }
@@ -525,7 +523,7 @@ zfs_acl_valid_ace_type(uint_t type, uint_t flags)
                    entry_type == ACE_EVERYONE || entry_type == 0 ||
                    entry_type == ACE_IDENTIFIER_GROUP);
        default:
-               if (type >= MIN_ACE_TYPE && type <= MAX_ACE_TYPE)
+               if (type <= MAX_ACE_TYPE)
                        return (B_TRUE);
        }
        return (B_FALSE);
@@ -629,18 +627,18 @@ zfs_acl_next_ace(zfs_acl_t *aclp, void *start, uint64_t *who,
        return (NULL);
 }
 
-/*ARGSUSED*/
-static uint64_t
-zfs_ace_walk(void *datap, uint64_t cookie, int aclcnt,
+static uintptr_t
+zfs_ace_walk(void *datap, uintptr_t cookie, int aclcnt,
     uint16_t *flags, uint16_t *type, uint32_t *mask)
 {
+       (void) aclcnt;
        zfs_acl_t *aclp = datap;
-       zfs_ace_hdr_t *acep = (zfs_ace_hdr_t *)(uintptr_t)cookie;
+       zfs_ace_hdr_t *acep = (zfs_ace_hdr_t *)cookie;
        uint64_t who;
 
        acep = zfs_acl_next_ace(aclp, acep, &who, mask,
            flags, type);
-       return ((uint64_t)(uintptr_t)acep);
+       return ((uintptr_t)acep);
 }
 
 /*
@@ -687,10 +685,10 @@ zfs_copy_ace_2_fuid(zfsvfs_t *zfsvfs, umode_t obj_mode, zfs_acl_t *aclp,
                        zobjacep = (zfs_object_ace_t *)aceptr;
                        aceobjp = (ace_object_t *)acep;
 
-                       bcopy(aceobjp->a_obj_type, zobjacep->z_object_type,
+                       memcpy(zobjacep->z_object_type, aceobjp->a_obj_type,
                            sizeof (aceobjp->a_obj_type));
-                       bcopy(aceobjp->a_inherit_obj_type,
-                           zobjacep->z_inherit_type,
+                       memcpy(zobjacep->z_inherit_type,
+                           aceobjp->a_inherit_obj_type,
                            sizeof (aceobjp->a_inherit_obj_type));
                        acep = (ace_t *)((caddr_t)acep + sizeof (ace_object_t));
                        break;
@@ -737,11 +735,11 @@ zfs_copy_fuid_2_ace(zfsvfs_t *zfsvfs, zfs_acl_t *aclp, cred_t *cr,
                        }
                        zobjacep = (zfs_object_ace_t *)zacep;
                        objacep = (ace_object_t *)acep;
-                       bcopy(zobjacep->z_object_type,
-                           objacep->a_obj_type,
+                       memcpy(objacep->a_obj_type,
+                           zobjacep->z_object_type,
                            sizeof (zobjacep->z_object_type));
-                       bcopy(zobjacep->z_inherit_type,
-                           objacep->a_inherit_obj_type,
+                       memcpy(objacep->a_inherit_obj_type,
+                           zobjacep->z_inherit_type,
                            sizeof (zobjacep->z_inherit_type));
                        ace_size = sizeof (ace_object_t);
                        break;
@@ -863,6 +861,26 @@ zfs_unix_to_v4(uint32_t access_mask)
        return (new_mask);
 }
 
+
+static int
+zfs_v4_to_unix(uint32_t access_mask, int *unmapped)
+{
+       int new_mask = 0;
+
+       *unmapped = access_mask &
+           (ACE_WRITE_OWNER | ACE_WRITE_ACL | ACE_DELETE);
+
+       if (access_mask & WRITE_MASK)
+               new_mask |= S_IWOTH;
+       if (access_mask & ACE_READ_DATA)
+               new_mask |= S_IROTH;
+       if (access_mask & ACE_EXECUTE)
+               new_mask |= S_IXOTH;
+
+       return (new_mask);
+}
+
+
 static void
 zfs_set_ace(zfs_acl_t *aclp, void *acep, uint32_t access_mask,
     uint16_t access_type, uint64_t fuid, uint16_t entry_type)
@@ -1102,7 +1120,7 @@ zfs_acl_node_read(struct znode *zp, boolean_t have_lock, zfs_acl_t **aclpp,
                            znode_acl.z_acl_extern_obj, 0, aclnode->z_size,
                            aclnode->z_acldata, DMU_READ_PREFETCH);
                } else {
-                       bcopy(znode_acl.z_ace_data, aclnode->z_acldata,
+                       memcpy(aclnode->z_acldata, znode_acl.z_ace_data,
                            aclnode->z_size);
                }
        } else {
@@ -1130,11 +1148,11 @@ done:
        return (error);
 }
 
-/*ARGSUSED*/
 void
 zfs_acl_data_locator(void **dataptr, uint32_t *length, uint32_t buflen,
     boolean_t start, void *userdata)
 {
+       (void) buflen;
        zfs_acl_locator_cb_t *cb = (zfs_acl_locator_cb_t *)userdata;
 
        if (start) {
@@ -1143,6 +1161,7 @@ zfs_acl_data_locator(void **dataptr, uint32_t *length, uint32_t buflen,
                cb->cb_acl_node = list_next(&cb->cb_aclp->z_acl,
                    cb->cb_acl_node);
        }
+       ASSERT3P(cb->cb_acl_node, !=, NULL);
        *dataptr = cb->cb_acl_node->z_acldata;
        *length = cb->cb_acl_node->z_size;
 }
@@ -1264,7 +1283,7 @@ acl_trivial_access_masks(mode_t mode, boolean_t isdir, trivial_acl_t *masks)
  */
 static int
 ace_trivial_common(void *acep, int aclcnt,
-    uint64_t (*walk)(void *, uint64_t, int aclcnt,
+    uintptr_t (*walk)(void *, uintptr_t, int,
     uint16_t *, uint16_t *, uint32_t *))
 {
        uint16_t flags;
@@ -1447,7 +1466,7 @@ zfs_aclset_common(znode_t *zp, zfs_acl_t *aclp, cred_t *cr, dmu_tx_t *tx)
                            aclnode = list_next(&aclp->z_acl, aclnode)) {
                                if (aclnode->z_ace_count == 0)
                                        continue;
-                               bcopy(aclnode->z_acldata, start,
+                               memcpy(start, aclnode->z_acldata,
                                    aclnode->z_size);
                                start = (caddr_t)start + aclnode->z_size;
                        }
@@ -1727,7 +1746,7 @@ zfs_acl_inherit(zfsvfs_t *zfsvfs, umode_t va_mode, zfs_acl_t *paclp,
                if ((data1sz = paclp->z_ops->ace_data(pacep, &data1)) != 0) {
                        VERIFY((data2sz = aclp->z_ops->ace_data(acep,
                            &data2)) == data1sz);
-                       bcopy(data1, data2, data2sz);
+                       memcpy(data2, data1, data2sz);
                }
 
                aclp->z_acl_count++;
@@ -1781,7 +1800,7 @@ zfs_acl_inherit(zfsvfs_t *zfsvfs, umode_t va_mode, zfs_acl_t *paclp,
  */
 int
 zfs_acl_ids_create(znode_t *dzp, int flag, vattr_t *vap, cred_t *cr,
-    vsecattr_t *vsecp, zfs_acl_ids_t *acl_ids)
+    vsecattr_t *vsecp, zfs_acl_ids_t *acl_ids, zidmap_t *mnt_ns)
 {
        int             error;
        zfsvfs_t        *zfsvfs = ZTOZSB(dzp);
@@ -1791,7 +1810,7 @@ zfs_acl_ids_create(znode_t *dzp, int flag, vattr_t *vap, cred_t *cr,
        boolean_t       trim = B_FALSE;
        boolean_t       inherited = B_FALSE;
 
-       bzero(acl_ids, sizeof (zfs_acl_ids_t));
+       memset(acl_ids, 0, sizeof (zfs_acl_ids_t));
        acl_ids->z_mode = vap->va_mode;
 
        if (vsecp)
@@ -1868,8 +1887,10 @@ zfs_acl_ids_create(znode_t *dzp, int flag, vattr_t *vap, cred_t *cr,
                acl_ids->z_mode |= S_ISGID;
        } else {
                if ((acl_ids->z_mode & S_ISGID) &&
-                   secpolicy_vnode_setids_setgids(cr, gid) != 0)
+                   secpolicy_vnode_setids_setgids(cr, gid, mnt_ns,
+                   zfs_i_user_ns(ZTOI(dzp))) != 0) {
                        acl_ids->z_mode &= ~S_ISGID;
+               }
        }
 
        if (acl_ids->z_aclp == NULL) {
@@ -1900,8 +1921,8 @@ zfs_acl_ids_create(znode_t *dzp, int flag, vattr_t *vap, cred_t *cr,
                            zfsvfs->z_acl_inherit != ZFS_ACL_PASSTHROUGH &&
                            zfsvfs->z_acl_inherit != ZFS_ACL_PASSTHROUGH_X)
                                trim = B_TRUE;
-                       zfs_acl_chmod(vap->va_mode, acl_ids->z_mode, B_FALSE,
-                           trim, acl_ids->z_aclp);
+                       zfs_acl_chmod(S_ISDIR(vap->va_mode), acl_ids->z_mode,
+                           B_FALSE, trim, acl_ids->z_aclp);
                }
        }
 
@@ -1957,7 +1978,8 @@ zfs_getacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr)
        if (mask == 0)
                return (SET_ERROR(ENOSYS));
 
-       if ((error = zfs_zaccess(zp, ACE_READ_ACL, 0, skipaclchk, cr)))
+       if ((error = zfs_zaccess(zp, ACE_READ_ACL, 0, skipaclchk, cr,
+           zfs_init_idmap)))
                return (error);
 
        mutex_enter(&zp->z_acl_lock);
@@ -2016,7 +2038,7 @@ zfs_getacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr)
 
                        for (aclnode = list_head(&aclp->z_acl); aclnode;
                            aclnode = list_next(&aclp->z_acl, aclnode)) {
-                               bcopy(aclnode->z_acldata, start,
+                               memcpy(start, aclnode->z_acldata,
                                    aclnode->z_size);
                                start = (caddr_t)start + aclnode->z_size;
                        }
@@ -2116,7 +2138,8 @@ zfs_setacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr)
        if (zp->z_pflags & ZFS_IMMUTABLE)
                return (SET_ERROR(EPERM));
 
-       if ((error = zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr)))
+       if ((error = zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr,
+           zfs_init_idmap)))
                return (error);
 
        error = zfs_vsec_2_aclp(zfsvfs, ZTOI(zp)->i_mode, vsecp, cr, &fuidp,
@@ -2208,19 +2231,16 @@ static int
 zfs_zaccess_dataset_check(znode_t *zp, uint32_t v4_mode)
 {
        if ((v4_mode & WRITE_MASK) && (zfs_is_readonly(ZTOZSB(zp))) &&
-           (!Z_ISDEV(ZTOI(zp)->i_mode) ||
-           (Z_ISDEV(ZTOI(zp)->i_mode) && (v4_mode & WRITE_MASK_ATTRS)))) {
+           (!Z_ISDEV(ZTOI(zp)->i_mode) || (v4_mode & WRITE_MASK_ATTRS))) {
                return (SET_ERROR(EROFS));
        }
 
        /*
-        * Only check for READONLY on non-directories.
+        * Intentionally allow ZFS_READONLY through here.
+        * See zfs_zaccess_common().
         */
        if ((v4_mode & WRITE_MASK_DATA) &&
-           ((!S_ISDIR(ZTOI(zp)->i_mode) &&
-           (zp->z_pflags & (ZFS_READONLY | ZFS_IMMUTABLE))) ||
-           (S_ISDIR(ZTOI(zp)->i_mode) &&
-           (zp->z_pflags & ZFS_IMMUTABLE)))) {
+           (zp->z_pflags & ZFS_IMMUTABLE)) {
                return (SET_ERROR(EPERM));
        }
 
@@ -2264,7 +2284,7 @@ zfs_zaccess_dataset_check(znode_t *zp, uint32_t v4_mode)
  */
 static int
 zfs_zaccess_aces_check(znode_t *zp, uint32_t *working_mode,
-    boolean_t anyaccess, cred_t *cr)
+    boolean_t anyaccess, cred_t *cr, zidmap_t *mnt_ns)
 {
        zfsvfs_t        *zfsvfs = ZTOZSB(zp);
        zfs_acl_t       *aclp;
@@ -2280,7 +2300,13 @@ zfs_zaccess_aces_check(znode_t *zp, uint32_t *working_mode,
        uid_t           gowner;
        uid_t           fowner;
 
-       zfs_fuid_map_ids(zp, cr, &fowner, &gowner);
+       if (mnt_ns) {
+               fowner = zfs_uid_to_vfsuid(mnt_ns, zfs_i_user_ns(ZTOI(zp)),
+                   KUID_TO_SUID(ZTOI(zp)->i_uid));
+               gowner = zfs_gid_to_vfsgid(mnt_ns, zfs_i_user_ns(ZTOI(zp)),
+                   KGID_TO_SGID(ZTOI(zp)->i_gid));
+       } else
+               zfs_fuid_map_ids(zp, cr, &fowner, &gowner);
 
        mutex_enter(&zp->z_acl_lock);
 
@@ -2319,7 +2345,7 @@ zfs_zaccess_aces_check(znode_t *zp, uint32_t *working_mode,
                        break;
                case OWNING_GROUP:
                        who = gowner;
-                       /*FALLTHROUGH*/
+                       zfs_fallthrough;
                case ACE_IDENTIFIER_GROUP:
                        checkit = zfs_groupmember(zfsvfs, who, cr);
                        break;
@@ -2391,7 +2417,8 @@ zfs_has_access(znode_t *zp, cred_t *cr)
 {
        uint32_t have = ACE_ALL_PERMS;
 
-       if (zfs_zaccess_aces_check(zp, &have, B_TRUE, cr) != 0) {
+       if (zfs_zaccess_aces_check(zp, &have, B_TRUE, cr,
+           zfs_init_idmap) != 0) {
                uid_t owner;
 
                owner = zfs_fuid_map_id(ZTOZSB(zp),
@@ -2401,9 +2428,58 @@ zfs_has_access(znode_t *zp, cred_t *cr)
        return (B_TRUE);
 }
 
+/*
+ * Simplified access check for case where ACL is known to not contain
+ * information beyond what is defined in the mode. In this case, we
+ * can pass along to the kernel / vfs generic_permission() check, which
+ * evaluates the mode and POSIX ACL.
+ *
+ * NFSv4 ACLs allow granting permissions that are usually relegated only
+ * to the file owner or superuser. Examples are ACE_WRITE_OWNER (chown),
+ * ACE_WRITE_ACL(chmod), and ACE_DELETE. ACE_DELETE requests must fail
+ * because with conventional posix permissions, right to delete file
+ * is determined by write bit on the parent dir.
+ *
+ * If unmappable perms are requested, then we must return EPERM
+ * and include those bits in the working_mode so that the caller of
+ * zfs_zaccess_common() can decide whether to perform additional
+ * policy / capability checks. EACCES is used in zfs_zaccess_aces_check()
+ * to indicate access check failed due to explicit DENY entry, and so
+ * we want to avoid that here.
+ */
+static int
+zfs_zaccess_trivial(znode_t *zp, uint32_t *working_mode, cred_t *cr,
+    zidmap_t *mnt_ns)
+{
+       int err, mask;
+       int unmapped = 0;
+
+       ASSERT(zp->z_pflags & ZFS_ACL_TRIVIAL);
+
+       mask = zfs_v4_to_unix(*working_mode, &unmapped);
+       if (mask == 0 || unmapped) {
+               *working_mode = unmapped;
+               return (unmapped ? SET_ERROR(EPERM) : 0);
+       }
+
+#if (defined(HAVE_IOPS_PERMISSION_USERNS) || \
+       defined(HAVE_IOPS_PERMISSION_IDMAP))
+       err = generic_permission(mnt_ns, ZTOI(zp), mask);
+#else
+       err = generic_permission(ZTOI(zp), mask);
+#endif
+       if (err != 0) {
+               return (SET_ERROR(EPERM));
+       }
+
+       *working_mode = unmapped;
+
+       return (0);
+}
+
 static int
 zfs_zaccess_common(znode_t *zp, uint32_t v4_mode, uint32_t *working_mode,
-    boolean_t *check_privs, boolean_t skipaclchk, cred_t *cr)
+    boolean_t *check_privs, boolean_t skipaclchk, cred_t *cr, zidmap_t *mnt_ns)
 {
        zfsvfs_t *zfsvfs = ZTOZSB(zp);
        int err;
@@ -2434,18 +2510,39 @@ zfs_zaccess_common(znode_t *zp, uint32_t v4_mode, uint32_t *working_mode,
                return (0);
        }
 
-       return (zfs_zaccess_aces_check(zp, working_mode, B_FALSE, cr));
+       /*
+        * Note: ZFS_READONLY represents the "DOS R/O" attribute.
+        * When that flag is set, we should behave as if write access
+        * were not granted by anything in the ACL.  In particular:
+        * We _must_ allow writes after opening the file r/w, then
+        * setting the DOS R/O attribute, and writing some more.
+        * (Similar to how you can write after fchmod(fd, 0444).)
+        *
+        * Therefore ZFS_READONLY is ignored in the dataset check
+        * above, and checked here as if part of the ACL check.
+        * Also note: DOS R/O is ignored for directories.
+        */
+       if ((v4_mode & WRITE_MASK_DATA) &&
+           S_ISDIR(ZTOI(zp)->i_mode) &&
+           (zp->z_pflags & ZFS_READONLY)) {
+               return (SET_ERROR(EPERM));
+       }
+
+       if (zp->z_pflags & ZFS_ACL_TRIVIAL)
+               return (zfs_zaccess_trivial(zp, working_mode, cr, mnt_ns));
+
+       return (zfs_zaccess_aces_check(zp, working_mode, B_FALSE, cr, mnt_ns));
 }
 
 static int
 zfs_zaccess_append(znode_t *zp, uint32_t *working_mode, boolean_t *check_privs,
-    cred_t *cr)
+    cred_t *cr, zidmap_t *mnt_ns)
 {
        if (*working_mode != ACE_WRITE_DATA)
                return (SET_ERROR(EACCES));
 
        return (zfs_zaccess_common(zp, ACE_APPEND_DATA, working_mode,
-           check_privs, B_FALSE, cr));
+           check_privs, B_FALSE, cr, mnt_ns));
 }
 
 int
@@ -2480,7 +2577,6 @@ zfs_fastaccesschk_execute(znode_t *zdp, cred_t *cr)
        }
 
        if (uid == KUID_TO_SUID(ZTOI(zdp)->i_uid)) {
-               owner = B_TRUE;
                if (zdp->z_mode & S_IXUSR) {
                        mutex_exit(&zdp->z_acl_lock);
                        return (0);
@@ -2490,7 +2586,6 @@ zfs_fastaccesschk_execute(znode_t *zdp, cred_t *cr)
                }
        }
        if (groupmember(KGID_TO_SGID(ZTOI(zdp)->i_gid), cr)) {
-               groupmbr = B_TRUE;
                if (zdp->z_mode & S_IXGRP) {
                        mutex_exit(&zdp->z_acl_lock);
                        return (0);
@@ -2510,9 +2605,11 @@ zfs_fastaccesschk_execute(znode_t *zdp, cred_t *cr)
 
 slow:
        DTRACE_PROBE(zfs__fastpath__execute__access__miss);
-       ZFS_ENTER(ZTOZSB(zdp));
-       error = zfs_zaccess(zdp, ACE_EXECUTE, 0, B_FALSE, cr);
-       ZFS_EXIT(ZTOZSB(zdp));
+       if ((error = zfs_enter(ZTOZSB(zdp), FTAG)) != 0)
+               return (error);
+       error = zfs_zaccess(zdp, ACE_EXECUTE, 0, B_FALSE, cr,
+           zfs_init_idmap);
+       zfs_exit(ZTOZSB(zdp), FTAG);
        return (error);
 }
 
@@ -2523,7 +2620,8 @@ slow:
  * can define any form of access.
  */
 int
-zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr)
+zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr,
+    zidmap_t *mnt_ns)
 {
        uint32_t        working_mode;
        int             error;
@@ -2562,8 +2660,10 @@ zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr)
                }
        }
 
-       owner = zfs_fuid_map_id(ZTOZSB(zp), KUID_TO_SUID(ZTOI(zp)->i_uid),
-           cr, ZFS_OWNER);
+       owner = zfs_uid_to_vfsuid(mnt_ns, zfs_i_user_ns(ZTOI(zp)),
+           KUID_TO_SUID(ZTOI(zp)->i_uid));
+       owner = zfs_fuid_map_id(ZTOZSB(zp), owner, cr, ZFS_OWNER);
+
        /*
         * Map the bits required to the standard inode flags
         * S_IRUSR|S_IWUSR|S_IXUSR in the needed_bits.  Map the bits
@@ -2588,7 +2688,7 @@ zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr)
                needed_bits |= S_IXUSR;
 
        if ((error = zfs_zaccess_common(check_zp, mode, &working_mode,
-           &check_privs, skipaclchk, cr)) == 0) {
+           &check_privs, skipaclchk, cr, mnt_ns)) == 0) {
                if (is_attr)
                        zrele(xzp);
                return (secpolicy_vnode_access2(cr, ZTOI(zp), owner,
@@ -2602,7 +2702,8 @@ zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr)
        }
 
        if (error && (flags & V_APPEND)) {
-               error = zfs_zaccess_append(zp, &working_mode, &check_privs, cr);
+               error = zfs_zaccess_append(zp, &working_mode, &check_privs, cr,
+                   mnt_ns);
        }
 
        if (error && check_privs) {
@@ -2613,7 +2714,6 @@ zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr)
                 * read_acl/read_attributes
                 */
 
-               error = 0;
                ASSERT(working_mode != 0);
 
                if ((working_mode & (ACE_READ_ACL|ACE_READ_ATTRIBUTES) &&
@@ -2666,27 +2766,29 @@ zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr)
 
 /*
  * Translate traditional unix S_IRUSR/S_IWUSR/S_IXUSR mode into
- * native ACL format and call zfs_zaccess()
+ * NFSv4-style ZFS ACL format and call zfs_zaccess()
  */
 int
-zfs_zaccess_rwx(znode_t *zp, mode_t mode, int flags, cred_t *cr)
+zfs_zaccess_rwx(znode_t *zp, mode_t mode, int flags, cred_t *cr,
+    zidmap_t *mnt_ns)
 {
-       return (zfs_zaccess(zp, zfs_unix_to_v4(mode >> 6), flags, B_FALSE, cr));
+       return (zfs_zaccess(zp, zfs_unix_to_v4(mode >> 6), flags, B_FALSE, cr,
+           mnt_ns));
 }
 
 /*
  * Access function for secpolicy_vnode_setattr
  */
 int
-zfs_zaccess_unix(znode_t *zp, mode_t mode, cred_t *cr)
+zfs_zaccess_unix(void *zp, int mode, cred_t *cr)
 {
        int v4_mode = zfs_unix_to_v4(mode >> 6);
 
-       return (zfs_zaccess(zp, v4_mode, 0, B_FALSE, cr));
+       return (zfs_zaccess(zp, v4_mode, 0, B_FALSE, cr, zfs_init_idmap));
 }
 
 /* See zfs_zaccess_delete() */
-int zfs_write_implies_delete_child = 1;
+static const boolean_t zfs_write_implies_delete_child = B_TRUE;
 
 /*
  * Determine whether delete access should be granted.
@@ -2759,7 +2861,7 @@ int zfs_write_implies_delete_child = 1;
  * zfs_write_implies_delete_child
  */
 int
-zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr)
+zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr, zidmap_t *mnt_ns)
 {
        uint32_t wanted_dirperms;
        uint32_t dzp_working_mode = 0;
@@ -2786,7 +2888,7 @@ zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr)
         * (This is part of why we're checking the target first.)
         */
        zp_error = zfs_zaccess_common(zp, ACE_DELETE, &zp_working_mode,
-           &zpcheck_privs, B_FALSE, cr);
+           &zpcheck_privs, B_FALSE, cr, mnt_ns);
        if (zp_error == EACCES) {
                /* We hit a DENY ACE. */
                if (!zpcheck_privs)
@@ -2808,7 +2910,7 @@ zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr)
        if (zfs_write_implies_delete_child)
                wanted_dirperms |= ACE_WRITE_DATA;
        dzp_error = zfs_zaccess_common(dzp, wanted_dirperms,
-           &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr);
+           &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr, mnt_ns);
        if (dzp_error == EACCES) {
                /* We hit a DENY ACE. */
                if (!dzpcheck_privs)
@@ -2890,7 +2992,7 @@ zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr)
 
 int
 zfs_zaccess_rename(znode_t *sdzp, znode_t *szp, znode_t *tdzp,
-    znode_t *tzp, cred_t *cr)
+    znode_t *tzp, cred_t *cr, zidmap_t *mnt_ns)
 {
        int add_perm;
        int error;
@@ -2912,21 +3014,21 @@ zfs_zaccess_rename(znode_t *sdzp, znode_t *szp, znode_t *tdzp,
         * If that succeeds then check for add_file/add_subdir permissions
         */
 
-       if ((error = zfs_zaccess_delete(sdzp, szp, cr)))
+       if ((error = zfs_zaccess_delete(sdzp, szp, cr, mnt_ns)))
                return (error);
 
        /*
         * If we have a tzp, see if we can delete it?
         */
        if (tzp) {
-               if ((error = zfs_zaccess_delete(tdzp, tzp, cr)))
+               if ((error = zfs_zaccess_delete(tdzp, tzp, cr, mnt_ns)))
                        return (error);
        }
 
        /*
         * Now check for add permissions
         */
-       error = zfs_zaccess(tdzp, add_perm, 0, B_FALSE, cr);
+       error = zfs_zaccess(tdzp, add_perm, 0, B_FALSE, cr, mnt_ns);
 
        return (error);
 }