]> git.hungrycats.org Git - linux/commitdiff
smb3: fix incorrect mode displayed for read-only files
authorSteve French <stfrench@microsoft.com>
Sun, 22 Sep 2024 04:28:32 +0000 (23:28 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 10 Oct 2024 10:01:02 +0000 (12:01 +0200)
commit 2f3017e7cc7515e0110a3733d8dca84de2a1d23d upstream.

Commands like "chmod 0444" mark a file readonly via the attribute flag
(when mapping of mode bits into the ACL are not set, or POSIX extensions
are not negotiated), but they were not reported correctly for stat of
directories (they were reported ok for files and for "ls").  See example
below:

    root:~# ls /mnt2 -l
    total 12
    drwxr-xr-x 2 root root         0 Sep 21 18:03 normaldir
    -rwxr-xr-x 1 root root         0 Sep 21 23:24 normalfile
    dr-xr-xr-x 2 root root         0 Sep 21 17:55 readonly-dir
    -r-xr-xr-x 1 root root 209716224 Sep 21 18:15 readonly-file
    root:~# stat -c %a /mnt2/readonly-dir
    755
    root:~# stat -c %a /mnt2/readonly-file
    555

This fixes the stat of directories when ATTR_READONLY is set
(in cases where the mode can not be obtained other ways).

    root:~# stat -c %a /mnt2/readonly-dir
    555

Cc: stable@vger.kernel.org
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/smb/client/inode.c

index 73e2e6c230b735b9f97a1991626b7a38d22c5453..54579a2003ac6a80ba6937fe40bbbf77dfb521b3 100644 (file)
@@ -800,10 +800,6 @@ static void cifs_open_info_to_fattr(struct cifs_fattr *fattr,
                fattr->cf_mode = S_IFREG | cifs_sb->ctx->file_mode;
                fattr->cf_dtype = DT_REG;
 
-               /* clear write bits if ATTR_READONLY is set */
-               if (fattr->cf_cifsattrs & ATTR_READONLY)
-                       fattr->cf_mode &= ~(S_IWUGO);
-
                /*
                 * Don't accept zero nlink from non-unix servers unless
                 * delete is pending.  Instead mark it as unknown.
@@ -816,6 +812,10 @@ static void cifs_open_info_to_fattr(struct cifs_fattr *fattr,
                }
        }
 
+       /* clear write bits if ATTR_READONLY is set */
+       if (fattr->cf_cifsattrs & ATTR_READONLY)
+               fattr->cf_mode &= ~(S_IWUGO);
+
 out_reparse:
        if (S_ISLNK(fattr->cf_mode)) {
                if (likely(data->symlink_target))
@@ -1233,11 +1233,14 @@ handle_mnt_opt:
                                 __func__, rc);
                        goto out;
                }
-       }
-
-       /* fill in remaining high mode bits e.g. SUID, VTX */
-       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
+       } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
+               /* fill in remaining high mode bits e.g. SUID, VTX */
                cifs_sfu_mode(fattr, full_path, cifs_sb, xid);
+       else if (!(tcon->posix_extensions))
+               /* clear write bits if ATTR_READONLY is set */
+               if (fattr->cf_cifsattrs & ATTR_READONLY)
+                       fattr->cf_mode &= ~(S_IWUGO);
+
 
        /* check for Minshall+French symlinks */
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {