]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
cifs: Fix querying of WSL CHR and BLK reparse points over SMB1
authorPali Rohár <pali@kernel.org>
Thu, 26 Dec 2024 16:12:09 +0000 (17:12 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 2 May 2025 06:02:09 +0000 (08:02 +0200)
[ Upstream commit ef86ab131d9127dfbfa8f06e12441d05fdfb090b ]

When reparse point in SMB1 query_path_info() callback was detected then
query also for EA $LXDEV. In this EA are stored device major and minor
numbers used by WSL CHR and BLK reparse points. Without major and minor
numbers, stat() syscall does not work for char and block devices.

Similar code is already in SMB2+ query_path_info() callback function.

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

index d6e2fb669c401f9181ff1c9f55c7f28d2b934876..808970e4a7142fd84a3080c1e4e197cbdb6517a7 100644 (file)
@@ -573,6 +573,42 @@ static int cifs_query_path_info(const unsigned int xid,
                data->reparse_point = le32_to_cpu(fi.Attributes) & ATTR_REPARSE;
        }
 
+#ifdef CONFIG_CIFS_XATTR
+       /*
+        * For WSL CHR and BLK reparse points it is required to fetch
+        * EA $LXDEV which contains major and minor device numbers.
+        */
+       if (!rc && data->reparse_point) {
+               struct smb2_file_full_ea_info *ea;
+
+               ea = (struct smb2_file_full_ea_info *)data->wsl.eas;
+               rc = CIFSSMBQAllEAs(xid, tcon, full_path, SMB2_WSL_XATTR_DEV,
+                                   &ea->ea_data[SMB2_WSL_XATTR_NAME_LEN + 1],
+                                   SMB2_WSL_XATTR_DEV_SIZE, cifs_sb);
+               if (rc == SMB2_WSL_XATTR_DEV_SIZE) {
+                       ea->next_entry_offset = cpu_to_le32(0);
+                       ea->flags = 0;
+                       ea->ea_name_length = SMB2_WSL_XATTR_NAME_LEN;
+                       ea->ea_value_length = cpu_to_le16(SMB2_WSL_XATTR_DEV_SIZE);
+                       memcpy(&ea->ea_data[0], SMB2_WSL_XATTR_DEV, SMB2_WSL_XATTR_NAME_LEN + 1);
+                       data->wsl.eas_len = sizeof(*ea) + SMB2_WSL_XATTR_NAME_LEN + 1 +
+                                           SMB2_WSL_XATTR_DEV_SIZE;
+                       rc = 0;
+               } else if (rc >= 0) {
+                       /* It is an error if EA $LXDEV has wrong size. */
+                       rc = -EINVAL;
+               } else {
+                       /*
+                        * In all other cases ignore error if fetching
+                        * of EA $LXDEV failed. It is needed only for
+                        * WSL CHR and BLK reparse points and wsl_to_fattr()
+                        * handle the case when EA is missing.
+                        */
+                       rc = 0;
+               }
+       }
+#endif
+
        return rc;
 }