diff options
author | Pali Rohár <pali@kernel.org> | 2025-01-02 12:02:23 +0100 |
---|---|---|
committer | Pali Rohár <pali@kernel.org> | 2025-05-05 20:27:45 +0200 |
commit | a3e09f97f8c2a78f22f89f8af10c18db2d3a7393 (patch) | |
tree | c50e8c7368c6dcb78703c12566b2d88b43cdf6e6 | |
parent | 888ddc5f5351ddc1f90e9cf2b68f885ea8234e44 (diff) | |
download | linux-cifs.tar.gz |
cifs: Remove cifs_backup_query_path_info() and replace it by cifs_query_path_info()cifs
Response handling of cifs_backup_query_path_info() function in
cifs_get_fattr() is broken and can cause buffer overflows because
cifs_backup_query_path_info() prepares request with different info levels
but the response parser in cifs_get_fattr() always expects response
structure FILE_DIRECTORY_INFO.
Code which queries file/dir attributes via CIFSFindFirst() is already
implemented in cifs_query_path_info() function, so extend it for
backup_cred(), which is the only missing functionality compared to
cifs_backup_query_path_info().
With this change the cifs_query_path_info() would do everything which is
open-coded in cifs_set_fattr_ino() and cifs_backup_query_path_info()
functions for SMB1. So remove that SMB1 code from cifs_set_fattr_ino() and
also remove whole cifs_backup_query_path_info() function.
Signed-off-by: Pali Rohár <pali@kernel.org>
-rw-r--r-- | fs/smb/client/inode.c | 97 | ||||
-rw-r--r-- | fs/smb/client/smb1ops.c | 7 |
2 files changed, 5 insertions, 99 deletions
diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c index 75be4b46bc6f18..cd06598eacbdb1 100644 --- a/fs/smb/client/inode.c +++ b/fs/smb/client/inode.c @@ -1046,61 +1046,6 @@ static __u64 simple_hashstr(const char *str) return hash; } -#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY -/** - * cifs_backup_query_path_info - SMB1 fallback code to get ino - * - * Fallback code to get file metadata when we don't have access to - * full_path (EACCES) and have backup creds. - * - * @xid: transaction id used to identify original request in logs - * @tcon: information about the server share we have mounted - * @sb: the superblock stores info such as disk space available - * @full_path: name of the file we are getting the metadata for - * @resp_buf: will be set to cifs resp buf and needs to be freed with - * cifs_buf_release() when done with @data - * @data: will be set to search info result buffer - */ -static int -cifs_backup_query_path_info(int xid, - struct cifs_tcon *tcon, - struct super_block *sb, - const char *full_path, - void **resp_buf, - FILE_ALL_INFO **data) -{ - struct cifs_sb_info *cifs_sb = CIFS_SB(sb); - struct cifs_search_info info = {0}; - u16 flags; - int rc; - - *resp_buf = NULL; - info.endOfSearch = false; - if (tcon->unix_ext) - info.info_level = SMB_FIND_FILE_UNIX; - else if ((tcon->ses->capabilities & - tcon->ses->server->vals->cap_nt_find) == 0) - info.info_level = SMB_FIND_FILE_INFO_STANDARD; - else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) - info.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO; - else /* no srvino useful for fallback to some netapp */ - info.info_level = SMB_FIND_FILE_DIRECTORY_INFO; - - flags = CIFS_SEARCH_CLOSE_ALWAYS | - CIFS_SEARCH_CLOSE_AT_END | - CIFS_SEARCH_BACKUP_SEARCH; - - rc = CIFSFindFirst(xid, tcon, full_path, - cifs_sb, NULL, flags, &info, false); - if (rc) - return rc; - - *resp_buf = (void *)info.ntwrk_buf_start; - *data = (FILE_ALL_INFO *)info.srch_entries_start; - return 0; -} -#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ - static void cifs_set_fattr_ino(int xid, struct cifs_tcon *tcon, struct super_block *sb, struct inode **inode, const char *full_path, struct cifs_open_info_data *data, struct cifs_fattr *fattr) @@ -1314,45 +1259,6 @@ static int cifs_get_fattr(struct cifs_open_info_data *data, cifs_create_junction_fattr(fattr, sb); rc = 0; break; - case -EACCES: -#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY - /* - * perm errors, try again with backup flags if possible - * - * For SMB2 and later the backup intent flag - * is already sent if needed on open and there - * is no path based FindFirst operation to use - * to retry with - */ - if (backup_cred(cifs_sb) && is_smb1_server(server)) { - /* for easier reading */ - FILE_ALL_INFO *fi; - FILE_DIRECTORY_INFO *fdi; - SEARCH_ID_FULL_DIR_INFO *si; - - rc = cifs_backup_query_path_info(xid, tcon, sb, - full_path, - &smb1_backup_rsp_buf, - &fi); - if (rc) - goto out; - - move_cifs_info_to_smb2(&data->fi, fi); - fdi = (FILE_DIRECTORY_INFO *)fi; - si = (SEARCH_ID_FULL_DIR_INFO *)fi; - - cifs_dir_info_to_fattr(fattr, fdi, cifs_sb); - fattr->cf_uniqueid = le64_to_cpu(si->UniqueId); - /* uniqueid set, skip get inum step */ - goto handle_mnt_opt; - } else { - /* nothing we can do, bail out */ - goto out; - } -#else - goto out; -#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ - break; default: cifs_dbg(FYI, "%s: unhandled err rc %d\n", __func__, rc); goto out; @@ -1367,9 +1273,6 @@ static int cifs_get_fattr(struct cifs_open_info_data *data, /* * 4. Tweak fattr based on mount options */ -#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY -handle_mnt_opt: -#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ /* query for SFU type info if supported and needed */ if ((fattr->cf_cifsattrs & ATTR_SYSTEM) && (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) { diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c index ac7cb4989b0e66..df955cecdd4c68 100644 --- a/fs/smb/client/smb1ops.c +++ b/fs/smb/client/smb1ops.c @@ -583,15 +583,18 @@ static int cifs_query_path_info(const unsigned int xid, /* * Then fallback to CIFSFindFirst() which works also with non-NT servers * but does not does not provide NumberOfLinks. + * Can be used with backup intent flag to overcome -EACCES error. */ - if ((rc == -EOPNOTSUPP || rc == -EINVAL) && + if ((rc == -EOPNOTSUPP || rc == -EINVAL || + (backup_cred(cifs_sb) && rc == -EACCES)) && !non_unicode_wildcard) { if (!(tcon->ses->capabilities & tcon->ses->server->vals->cap_nt_find)) search_info.info_level = SMB_FIND_FILE_INFO_STANDARD; else search_info.info_level = SMB_FIND_FILE_FULL_DIRECTORY_INFO; rc = CIFSFindFirst(xid, tcon, full_path, cifs_sb, NULL, - CIFS_SEARCH_CLOSE_ALWAYS | CIFS_SEARCH_CLOSE_AT_END, + CIFS_SEARCH_CLOSE_ALWAYS | CIFS_SEARCH_CLOSE_AT_END | + (backup_cred(cifs_sb) ? CIFS_SEARCH_BACKUP_SEARCH : 0), &search_info, false); if (rc == 0) { if (!(tcon->ses->capabilities & tcon->ses->server->vals->cap_nt_find)) { |