]> git.proxmox.com Git - mirror_zfs.git/commitdiff
Intentionally allow ZFS_READONLY in zfs_write
authorRyan Moeller <ryan@iXsystems.com>
Sun, 7 Mar 2021 17:31:52 +0000 (12:31 -0500)
committerGitHub <noreply@github.com>
Sun, 7 Mar 2021 17:31:52 +0000 (09:31 -0800)
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).)

Restore these semantics which were lost on FreeBSD when refactoring
zfs_write.  To my knowledge Linux does not actually expose this flag,
but we'll need it to eventually so I've added the supporting checks.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Ryan Moeller <ryan@iXsystems.com>
Closes #11693

module/os/linux/zfs/zfs_acl.c
module/zfs/zfs_vnops.c

index 2628325c0ba9d755e9d6d8aab8a0331e32c1ceb5..f8bf55f75e97fd21a23f4ea6237fa56297e78d85 100644 (file)
@@ -2214,13 +2214,11 @@ zfs_zaccess_dataset_check(znode_t *zp, uint32_t v4_mode)
        }
 
        /*
-        * 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));
        }
 
@@ -2434,6 +2432,24 @@ zfs_zaccess_common(znode_t *zp, uint32_t v4_mode, uint32_t *working_mode,
                return (0);
        }
 
+       /*
+        * 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));
+       }
+
        return (zfs_zaccess_aces_check(zp, working_mode, B_FALSE, cr));
 }
 
index a35c17f86f932d2143ea92d51956864576582968..0af03e9233b3438e932906183db47286922acbc6 100644 (file)
@@ -350,9 +350,11 @@ zfs_write(znode_t *zp, zfs_uio_t *uio, int ioflag, cred_t *cr)
        }
 
        /*
-        * If immutable or not appending then return EPERM
+        * If immutable or not appending then return EPERM.
+        * Intentionally allow ZFS_READONLY through here.
+        * See zfs_zaccess_common()
         */
-       if ((zp->z_pflags & (ZFS_IMMUTABLE | ZFS_READONLY)) ||
+       if ((zp->z_pflags & ZFS_IMMUTABLE) ||
            ((zp->z_pflags & ZFS_APPENDONLY) && !(ioflag & O_APPEND) &&
            (zfs_uio_offset(uio) < zp->z_size))) {
                ZFS_EXIT(zfsvfs);