cifs: Add fallback for SMB2 CREATE without FILE_READ_ATTRIBUTES
authorPali Rohár <pali@kernel.org>
Mon, 9 Dec 2024 19:44:23 +0000 (20:44 +0100)
committerSteve French <stfrench@microsoft.com>
Tue, 1 Apr 2025 09:58:00 +0000 (04:58 -0500)
Some operations, like WRITE, does not require FILE_READ_ATTRIBUTES access.

So when FILE_READ_ATTRIBUTES is not explicitly requested for
smb2_open_file() then first try to do SMB2 CREATE with FILE_READ_ATTRIBUTES
access (like it was before) and then fallback to SMB2 CREATE without
FILE_READ_ATTRIBUTES access (less common case).

This change allows to complete WRITE operation to a file when it does not
grant FILE_READ_ATTRIBUTES permission and its parent directory does not
grant READ_DATA permission (parent directory READ_DATA is implicit grant of
child FILE_READ_ATTRIBUTES permission).

Signed-off-by: Pali Rohár <pali@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/client/smb2file.c

index d609a20fb98a9c9fe9509e382ce8b4430e7ea682..2d726e9b950cf4069642b376dfd5441d2c2c856a 100644 (file)
@@ -152,16 +152,25 @@ int smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, __u32
        int err_buftype = CIFS_NO_BUFFER;
        struct cifs_fid *fid = oparms->fid;
        struct network_resiliency_req nr_ioctl_req;
+       bool retry_without_read_attributes = false;
 
        smb2_path = cifs_convert_path_to_utf16(oparms->path, oparms->cifs_sb);
        if (smb2_path == NULL)
                return -ENOMEM;
 
-       oparms->desired_access |= FILE_READ_ATTRIBUTES;
+       if (!(oparms->desired_access & FILE_READ_ATTRIBUTES)) {
+               oparms->desired_access |= FILE_READ_ATTRIBUTES;
+               retry_without_read_attributes = true;
+       }
        smb2_oplock = SMB2_OPLOCK_LEVEL_BATCH;
 
        rc = SMB2_open(xid, oparms, smb2_path, &smb2_oplock, smb2_data, NULL, &err_iov,
                       &err_buftype);
+       if (rc == -EACCES && retry_without_read_attributes) {
+               oparms->desired_access &= ~FILE_READ_ATTRIBUTES;
+               rc = SMB2_open(xid, oparms, smb2_path, &smb2_oplock, smb2_data, NULL, &err_iov,
+                              &err_buftype);
+       }
        if (rc && data) {
                struct smb2_hdr *hdr = err_iov.iov_base;