Skip to content

Commit a2809d0

Browse files
Eugene Korenevskysmfrench
authored andcommitted
cifs: quirk for STATUS_OBJECT_NAME_INVALID returned for non-ASCII dfs refs
Windows SMB server responds with STATUS_OBJECT_NAME_INVALID code to SMB2 QUERY_INFO request for "\<server>\<dfsname>\<linkpath>" DFS reference, where <dfsname> contains non-ASCII unicode symbols. Check such DFS reference and emulate -EREMOTE if it is actual. BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=215440 Signed-off-by: Eugene Korenevsky <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent 7eacba3 commit a2809d0

File tree

4 files changed

+65
-0
lines changed

4 files changed

+65
-0
lines changed

fs/cifs/cifsproto.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,11 @@ static inline int get_dfs_path(const unsigned int xid, struct cifs_ses *ses,
647647
int match_target_ip(struct TCP_Server_Info *server,
648648
const char *share, size_t share_len,
649649
bool *result);
650+
651+
int cifs_dfs_query_info_nonascii_quirk(const unsigned int xid,
652+
struct cifs_tcon *tcon,
653+
struct cifs_sb_info *cifs_sb,
654+
const char *dfs_link_path);
650655
#endif
651656

652657
static inline int cifs_create_options(struct cifs_sb_info *cifs_sb, int options)

fs/cifs/connect.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3374,6 +3374,11 @@ static int is_path_remote(struct mount_ctx *mnt_ctx)
33743374

33753375
rc = server->ops->is_path_accessible(xid, tcon, cifs_sb,
33763376
full_path);
3377+
#ifdef CONFIG_CIFS_DFS_UPCALL
3378+
if (rc == -ENOENT && is_tcon_dfs(tcon))
3379+
rc = cifs_dfs_query_info_nonascii_quirk(xid, tcon, cifs_sb,
3380+
full_path);
3381+
#endif
33773382
if (rc != 0 && rc != -EREMOTE) {
33783383
kfree(full_path);
33793384
return rc;

fs/cifs/inode.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -952,6 +952,12 @@ cifs_get_inode_info(struct inode **inode,
952952
rc = server->ops->query_path_info(xid, tcon, cifs_sb,
953953
full_path, tmp_data,
954954
&adjust_tz, &is_reparse_point);
955+
#ifdef CONFIG_CIFS_DFS_UPCALL
956+
if (rc == -ENOENT && is_tcon_dfs(tcon))
957+
rc = cifs_dfs_query_info_nonascii_quirk(xid, tcon,
958+
cifs_sb,
959+
full_path);
960+
#endif
955961
data = tmp_data;
956962
}
957963

fs/cifs/misc.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1302,4 +1302,53 @@ int cifs_update_super_prepath(struct cifs_sb_info *cifs_sb, char *prefix)
13021302
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
13031303
return 0;
13041304
}
1305+
1306+
/** cifs_dfs_query_info_nonascii_quirk
1307+
* Handle weird Windows SMB server behaviour. It responds with
1308+
* STATUS_OBJECT_NAME_INVALID code to SMB2 QUERY_INFO request
1309+
* for "\<server>\<dfsname>\<linkpath>" DFS reference,
1310+
* where <dfsname> contains non-ASCII unicode symbols.
1311+
*
1312+
* Check such DFS reference and emulate -ENOENT if it is actual.
1313+
*/
1314+
int cifs_dfs_query_info_nonascii_quirk(const unsigned int xid,
1315+
struct cifs_tcon *tcon,
1316+
struct cifs_sb_info *cifs_sb,
1317+
const char *linkpath)
1318+
{
1319+
char *treename, *dfspath, sep;
1320+
int treenamelen, linkpathlen, rc;
1321+
1322+
treename = tcon->treeName;
1323+
/* MS-DFSC: All paths in REQ_GET_DFS_REFERRAL and RESP_GET_DFS_REFERRAL
1324+
* messages MUST be encoded with exactly one leading backslash, not two
1325+
* leading backslashes.
1326+
*/
1327+
sep = CIFS_DIR_SEP(cifs_sb);
1328+
if (treename[0] == sep && treename[1] == sep)
1329+
treename++;
1330+
linkpathlen = strlen(linkpath);
1331+
treenamelen = strnlen(treename, MAX_TREE_SIZE + 1);
1332+
dfspath = kzalloc(treenamelen + linkpathlen + 1, GFP_KERNEL);
1333+
if (!dfspath)
1334+
return -ENOMEM;
1335+
if (treenamelen)
1336+
memcpy(dfspath, treename, treenamelen);
1337+
memcpy(dfspath + treenamelen, linkpath, linkpathlen);
1338+
rc = dfs_cache_find(xid, tcon->ses, cifs_sb->local_nls,
1339+
cifs_remap(cifs_sb), dfspath, NULL, NULL);
1340+
if (rc == 0) {
1341+
cifs_dbg(FYI, "DFS ref '%s' is found, emulate -EREMOTE\n",
1342+
dfspath);
1343+
rc = -EREMOTE;
1344+
} else if (rc == -EEXIST) {
1345+
cifs_dbg(FYI, "DFS ref '%s' is not found, emulate -ENOENT\n",
1346+
dfspath);
1347+
rc = -ENOENT;
1348+
} else {
1349+
cifs_dbg(FYI, "%s: dfs_cache_find returned %d\n", __func__, rc);
1350+
}
1351+
kfree(dfspath);
1352+
return rc;
1353+
}
13051354
#endif

0 commit comments

Comments
 (0)