aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-07-29 14:29:13 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-07-29 14:29:13 -0400
commitb0c4e2acdd6175a07107474f3cd7bdc062cf4d3d (patch)
tree9b269c5a176175082ce8bd4806901152bb12728c
parentc624c86615fb8aa61fa76ed8c935446d06c80e77 (diff)
parent7893242e2465aea6f2cbc2639da8fa5ce96e8cc2 (diff)
Merge branch 'for-next' of git://git.samba.org/sfrench/cifs-2.6
Pull CIFS/SMB3 fixes from Steve French: "Various CIFS/SMB3 fixes, most for stable" * 'for-next' of git://git.samba.org/sfrench/cifs-2.6: CIFS: Fix a possible invalid memory access in smb2_query_symlink() fs/cifs: make share unaccessible at root level mountable cifs: fix crash due to race in hmac(md5) handling cifs: unbreak TCP session reuse cifs: Check for existing directory when opening file with O_CREAT Add MF-Symlinks support for SMB 2.0
-rw-r--r--fs/cifs/cifs_fs_sb.h4
-rw-r--r--fs/cifs/cifsencrypt.c16
-rw-r--r--fs/cifs/cifsfs.c14
-rw-r--r--fs/cifs/connect.c53
-rw-r--r--fs/cifs/dir.c44
-rw-r--r--fs/cifs/inode.c22
-rw-r--r--fs/cifs/smb2ops.c32
7 files changed, 169 insertions, 16 deletions
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
index 3182273a3407..1418daa03d95 100644
--- a/fs/cifs/cifs_fs_sb.h
+++ b/fs/cifs/cifs_fs_sb.h
@@ -46,6 +46,9 @@
46#define CIFS_MOUNT_CIFS_BACKUPUID 0x200000 /* backup intent bit for a user */ 46#define CIFS_MOUNT_CIFS_BACKUPUID 0x200000 /* backup intent bit for a user */
47#define CIFS_MOUNT_CIFS_BACKUPGID 0x400000 /* backup intent bit for a group */ 47#define CIFS_MOUNT_CIFS_BACKUPGID 0x400000 /* backup intent bit for a group */
48#define CIFS_MOUNT_MAP_SFM_CHR 0x800000 /* SFM/MAC mapping for illegal chars */ 48#define CIFS_MOUNT_MAP_SFM_CHR 0x800000 /* SFM/MAC mapping for illegal chars */
49#define CIFS_MOUNT_USE_PREFIX_PATH 0x1000000 /* make subpath with unaccessible
50 * root mountable
51 */
49 52
50struct cifs_sb_info { 53struct cifs_sb_info {
51 struct rb_root tlink_tree; 54 struct rb_root tlink_tree;
@@ -67,5 +70,6 @@ struct cifs_sb_info {
67 struct backing_dev_info bdi; 70 struct backing_dev_info bdi;
68 struct delayed_work prune_tlinks; 71 struct delayed_work prune_tlinks;
69 struct rcu_head rcu; 72 struct rcu_head rcu;
73 char *prepath;
70}; 74};
71#endif /* _CIFS_FS_SB_H */ 75#endif /* _CIFS_FS_SB_H */
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index 6aeb8d4616a4..8347c90cf483 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -743,24 +743,26 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
743 743
744 memcpy(ses->auth_key.response + baselen, tiblob, tilen); 744 memcpy(ses->auth_key.response + baselen, tiblob, tilen);
745 745
746 mutex_lock(&ses->server->srv_mutex);
747
746 rc = crypto_hmacmd5_alloc(ses->server); 748 rc = crypto_hmacmd5_alloc(ses->server);
747 if (rc) { 749 if (rc) {
748 cifs_dbg(VFS, "could not crypto alloc hmacmd5 rc %d\n", rc); 750 cifs_dbg(VFS, "could not crypto alloc hmacmd5 rc %d\n", rc);
749 goto setup_ntlmv2_rsp_ret; 751 goto unlock;
750 } 752 }
751 753
752 /* calculate ntlmv2_hash */ 754 /* calculate ntlmv2_hash */
753 rc = calc_ntlmv2_hash(ses, ntlmv2_hash, nls_cp); 755 rc = calc_ntlmv2_hash(ses, ntlmv2_hash, nls_cp);
754 if (rc) { 756 if (rc) {
755 cifs_dbg(VFS, "could not get v2 hash rc %d\n", rc); 757 cifs_dbg(VFS, "could not get v2 hash rc %d\n", rc);
756 goto setup_ntlmv2_rsp_ret; 758 goto unlock;
757 } 759 }
758 760
759 /* calculate first part of the client response (CR1) */ 761 /* calculate first part of the client response (CR1) */
760 rc = CalcNTLMv2_response(ses, ntlmv2_hash); 762 rc = CalcNTLMv2_response(ses, ntlmv2_hash);
761 if (rc) { 763 if (rc) {
762 cifs_dbg(VFS, "Could not calculate CR1 rc: %d\n", rc); 764 cifs_dbg(VFS, "Could not calculate CR1 rc: %d\n", rc);
763 goto setup_ntlmv2_rsp_ret; 765 goto unlock;
764 } 766 }
765 767
766 /* now calculate the session key for NTLMv2 */ 768 /* now calculate the session key for NTLMv2 */
@@ -769,13 +771,13 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
769 if (rc) { 771 if (rc) {
770 cifs_dbg(VFS, "%s: Could not set NTLMV2 Hash as a key\n", 772 cifs_dbg(VFS, "%s: Could not set NTLMV2 Hash as a key\n",
771 __func__); 773 __func__);
772 goto setup_ntlmv2_rsp_ret; 774 goto unlock;
773 } 775 }
774 776
775 rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash); 777 rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash);
776 if (rc) { 778 if (rc) {
777 cifs_dbg(VFS, "%s: Could not init hmacmd5\n", __func__); 779 cifs_dbg(VFS, "%s: Could not init hmacmd5\n", __func__);
778 goto setup_ntlmv2_rsp_ret; 780 goto unlock;
779 } 781 }
780 782
781 rc = crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, 783 rc = crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
@@ -783,7 +785,7 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
783 CIFS_HMAC_MD5_HASH_SIZE); 785 CIFS_HMAC_MD5_HASH_SIZE);
784 if (rc) { 786 if (rc) {
785 cifs_dbg(VFS, "%s: Could not update with response\n", __func__); 787 cifs_dbg(VFS, "%s: Could not update with response\n", __func__);
786 goto setup_ntlmv2_rsp_ret; 788 goto unlock;
787 } 789 }
788 790
789 rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash, 791 rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash,
@@ -791,6 +793,8 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
791 if (rc) 793 if (rc)
792 cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__); 794 cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__);
793 795
796unlock:
797 mutex_unlock(&ses->server->srv_mutex);
794setup_ntlmv2_rsp_ret: 798setup_ntlmv2_rsp_ret:
795 kfree(tiblob); 799 kfree(tiblob);
796 800
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 5d841f39c4b7..6bbec5e784cd 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -689,6 +689,14 @@ cifs_do_mount(struct file_system_type *fs_type,
689 goto out_cifs_sb; 689 goto out_cifs_sb;
690 } 690 }
691 691
692 if (volume_info->prepath) {
693 cifs_sb->prepath = kstrdup(volume_info->prepath, GFP_KERNEL);
694 if (cifs_sb->prepath == NULL) {
695 root = ERR_PTR(-ENOMEM);
696 goto out_cifs_sb;
697 }
698 }
699
692 cifs_setup_cifs_sb(volume_info, cifs_sb); 700 cifs_setup_cifs_sb(volume_info, cifs_sb);
693 701
694 rc = cifs_mount(cifs_sb, volume_info); 702 rc = cifs_mount(cifs_sb, volume_info);
@@ -727,7 +735,11 @@ cifs_do_mount(struct file_system_type *fs_type,
727 sb->s_flags |= MS_ACTIVE; 735 sb->s_flags |= MS_ACTIVE;
728 } 736 }
729 737
730 root = cifs_get_root(volume_info, sb); 738 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH)
739 root = dget(sb->s_root);
740 else
741 root = cifs_get_root(volume_info, sb);
742
731 if (IS_ERR(root)) 743 if (IS_ERR(root))
732 goto out_super; 744 goto out_super;
733 745
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 7d2b15c06090..7ae03283bd61 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -1228,6 +1228,8 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
1228 vol->ops = &smb1_operations; 1228 vol->ops = &smb1_operations;
1229 vol->vals = &smb1_values; 1229 vol->vals = &smb1_values;
1230 1230
1231 vol->echo_interval = SMB_ECHO_INTERVAL_DEFAULT;
1232
1231 if (!mountdata) 1233 if (!mountdata)
1232 goto cifs_parse_mount_err; 1234 goto cifs_parse_mount_err;
1233 1235
@@ -2049,7 +2051,7 @@ static int match_server(struct TCP_Server_Info *server, struct smb_vol *vol)
2049 if (!match_security(server, vol)) 2051 if (!match_security(server, vol))
2050 return 0; 2052 return 0;
2051 2053
2052 if (server->echo_interval != vol->echo_interval) 2054 if (server->echo_interval != vol->echo_interval * HZ)
2053 return 0; 2055 return 0;
2054 2056
2055 return 1; 2057 return 1;
@@ -3483,6 +3485,44 @@ cifs_get_volume_info(char *mount_data, const char *devname)
3483 return volume_info; 3485 return volume_info;
3484} 3486}
3485 3487
3488static int
3489cifs_are_all_path_components_accessible(struct TCP_Server_Info *server,
3490 unsigned int xid,
3491 struct cifs_tcon *tcon,
3492 struct cifs_sb_info *cifs_sb,
3493 char *full_path)
3494{
3495 int rc;
3496 char *s;
3497 char sep, tmp;
3498
3499 sep = CIFS_DIR_SEP(cifs_sb);
3500 s = full_path;
3501
3502 rc = server->ops->is_path_accessible(xid, tcon, cifs_sb, "");
3503 while (rc == 0) {
3504 /* skip separators */
3505 while (*s == sep)
3506 s++;
3507 if (!*s)
3508 break;
3509 /* next separator */
3510 while (*s && *s != sep)
3511 s++;
3512
3513 /*
3514 * temporarily null-terminate the path at the end of
3515 * the current component
3516 */
3517 tmp = *s;
3518 *s = 0;
3519 rc = server->ops->is_path_accessible(xid, tcon, cifs_sb,
3520 full_path);
3521 *s = tmp;
3522 }
3523 return rc;
3524}
3525
3486int 3526int
3487cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *volume_info) 3527cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *volume_info)
3488{ 3528{
@@ -3620,6 +3660,16 @@ remote_path_check:
3620 kfree(full_path); 3660 kfree(full_path);
3621 goto mount_fail_check; 3661 goto mount_fail_check;
3622 } 3662 }
3663
3664 rc = cifs_are_all_path_components_accessible(server,
3665 xid, tcon, cifs_sb,
3666 full_path);
3667 if (rc != 0) {
3668 cifs_dbg(VFS, "cannot query dirs between root and final path, "
3669 "enabling CIFS_MOUNT_USE_PREFIX_PATH\n");
3670 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
3671 rc = 0;
3672 }
3623 kfree(full_path); 3673 kfree(full_path);
3624 } 3674 }
3625 3675
@@ -3889,6 +3939,7 @@ cifs_umount(struct cifs_sb_info *cifs_sb)
3889 3939
3890 bdi_destroy(&cifs_sb->bdi); 3940 bdi_destroy(&cifs_sb->bdi);
3891 kfree(cifs_sb->mountdata); 3941 kfree(cifs_sb->mountdata);
3942 kfree(cifs_sb->prepath);
3892 call_rcu(&cifs_sb->rcu, delayed_free); 3943 call_rcu(&cifs_sb->rcu, delayed_free);
3893} 3944}
3894 3945
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 5efd6f1fb8a5..4e532536cbc6 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -84,6 +84,7 @@ build_path_from_dentry(struct dentry *direntry)
84 struct dentry *temp; 84 struct dentry *temp;
85 int namelen; 85 int namelen;
86 int dfsplen; 86 int dfsplen;
87 int pplen = 0;
87 char *full_path; 88 char *full_path;
88 char dirsep; 89 char dirsep;
89 struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb); 90 struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
@@ -95,8 +96,12 @@ build_path_from_dentry(struct dentry *direntry)
95 dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1); 96 dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1);
96 else 97 else
97 dfsplen = 0; 98 dfsplen = 0;
99
100 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH)
101 pplen = cifs_sb->prepath ? strlen(cifs_sb->prepath) + 1 : 0;
102
98cifs_bp_rename_retry: 103cifs_bp_rename_retry:
99 namelen = dfsplen; 104 namelen = dfsplen + pplen;
100 seq = read_seqbegin(&rename_lock); 105 seq = read_seqbegin(&rename_lock);
101 rcu_read_lock(); 106 rcu_read_lock();
102 for (temp = direntry; !IS_ROOT(temp);) { 107 for (temp = direntry; !IS_ROOT(temp);) {
@@ -137,7 +142,7 @@ cifs_bp_rename_retry:
137 } 142 }
138 } 143 }
139 rcu_read_unlock(); 144 rcu_read_unlock();
140 if (namelen != dfsplen || read_seqretry(&rename_lock, seq)) { 145 if (namelen != dfsplen + pplen || read_seqretry(&rename_lock, seq)) {
141 cifs_dbg(FYI, "did not end path lookup where expected. namelen=%ddfsplen=%d\n", 146 cifs_dbg(FYI, "did not end path lookup where expected. namelen=%ddfsplen=%d\n",
142 namelen, dfsplen); 147 namelen, dfsplen);
143 /* presumably this is only possible if racing with a rename 148 /* presumably this is only possible if racing with a rename
@@ -153,6 +158,17 @@ cifs_bp_rename_retry:
153 those safely to '/' if any are found in the middle of the prepath */ 158 those safely to '/' if any are found in the middle of the prepath */
154 /* BB test paths to Windows with '/' in the midst of prepath */ 159 /* BB test paths to Windows with '/' in the midst of prepath */
155 160
161 if (pplen) {
162 int i;
163
164 cifs_dbg(FYI, "using cifs_sb prepath <%s>\n", cifs_sb->prepath);
165 memcpy(full_path+dfsplen+1, cifs_sb->prepath, pplen-1);
166 full_path[dfsplen] = '\\';
167 for (i = 0; i < pplen-1; i++)
168 if (full_path[dfsplen+1+i] == '/')
169 full_path[dfsplen+1+i] = CIFS_DIR_SEP(cifs_sb);
170 }
171
156 if (dfsplen) { 172 if (dfsplen) {
157 strncpy(full_path, tcon->treeName, dfsplen); 173 strncpy(full_path, tcon->treeName, dfsplen);
158 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) { 174 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
@@ -229,6 +245,13 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
229 goto cifs_create_get_file_info; 245 goto cifs_create_get_file_info;
230 } 246 }
231 247
248 if (S_ISDIR(newinode->i_mode)) {
249 CIFSSMBClose(xid, tcon, fid->netfid);
250 iput(newinode);
251 rc = -EISDIR;
252 goto out;
253 }
254
232 if (!S_ISREG(newinode->i_mode)) { 255 if (!S_ISREG(newinode->i_mode)) {
233 /* 256 /*
234 * The server may allow us to open things like 257 * The server may allow us to open things like
@@ -399,10 +422,14 @@ cifs_create_set_dentry:
399 if (rc != 0) { 422 if (rc != 0) {
400 cifs_dbg(FYI, "Create worked, get_inode_info failed rc = %d\n", 423 cifs_dbg(FYI, "Create worked, get_inode_info failed rc = %d\n",
401 rc); 424 rc);
402 if (server->ops->close) 425 goto out_err;
403 server->ops->close(xid, tcon, fid);
404 goto out;
405 } 426 }
427
428 if (S_ISDIR(newinode->i_mode)) {
429 rc = -EISDIR;
430 goto out_err;
431 }
432
406 d_drop(direntry); 433 d_drop(direntry);
407 d_add(direntry, newinode); 434 d_add(direntry, newinode);
408 435
@@ -410,6 +437,13 @@ out:
410 kfree(buf); 437 kfree(buf);
411 kfree(full_path); 438 kfree(full_path);
412 return rc; 439 return rc;
440
441out_err:
442 if (server->ops->close)
443 server->ops->close(xid, tcon, fid);
444 if (newinode)
445 iput(newinode);
446 goto out;
413} 447}
414 448
415int 449int
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 514dadb0575d..b87efd0c92d6 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1002,10 +1002,26 @@ struct inode *cifs_root_iget(struct super_block *sb)
1002 struct inode *inode = NULL; 1002 struct inode *inode = NULL;
1003 long rc; 1003 long rc;
1004 struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); 1004 struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
1005 char *path = NULL;
1006 int len;
1007
1008 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH)
1009 && cifs_sb->prepath) {
1010 len = strlen(cifs_sb->prepath);
1011 path = kzalloc(len + 2 /* leading sep + null */, GFP_KERNEL);
1012 if (path == NULL)
1013 return ERR_PTR(-ENOMEM);
1014 path[0] = '/';
1015 memcpy(path+1, cifs_sb->prepath, len);
1016 } else {
1017 path = kstrdup("", GFP_KERNEL);
1018 if (path == NULL)
1019 return ERR_PTR(-ENOMEM);
1020 }
1005 1021
1006 xid = get_xid(); 1022 xid = get_xid();
1007 if (tcon->unix_ext) { 1023 if (tcon->unix_ext) {
1008 rc = cifs_get_inode_info_unix(&inode, "", sb, xid); 1024 rc = cifs_get_inode_info_unix(&inode, path, sb, xid);
1009 /* some servers mistakenly claim POSIX support */ 1025 /* some servers mistakenly claim POSIX support */
1010 if (rc != -EOPNOTSUPP) 1026 if (rc != -EOPNOTSUPP)
1011 goto iget_no_retry; 1027 goto iget_no_retry;
@@ -1013,7 +1029,8 @@ struct inode *cifs_root_iget(struct super_block *sb)
1013 tcon->unix_ext = false; 1029 tcon->unix_ext = false;
1014 } 1030 }
1015 1031
1016 rc = cifs_get_inode_info(&inode, "", NULL, sb, xid, NULL); 1032 convert_delimiter(path, CIFS_DIR_SEP(cifs_sb));
1033 rc = cifs_get_inode_info(&inode, path, NULL, sb, xid, NULL);
1017 1034
1018iget_no_retry: 1035iget_no_retry:
1019 if (!inode) { 1036 if (!inode) {
@@ -1042,6 +1059,7 @@ iget_no_retry:
1042 } 1059 }
1043 1060
1044out: 1061out:
1062 kfree(path);
1045 /* can not call macro free_xid here since in a void func 1063 /* can not call macro free_xid here since in a void func
1046 * TODO: This is no longer true 1064 * TODO: This is no longer true
1047 */ 1065 */
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 3525ed756173..d203c0329626 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -1044,6 +1044,9 @@ smb2_new_lease_key(struct cifs_fid *fid)
1044 get_random_bytes(fid->lease_key, SMB2_LEASE_KEY_SIZE); 1044 get_random_bytes(fid->lease_key, SMB2_LEASE_KEY_SIZE);
1045} 1045}
1046 1046
1047#define SMB2_SYMLINK_STRUCT_SIZE \
1048 (sizeof(struct smb2_err_rsp) - 1 + sizeof(struct smb2_symlink_err_rsp))
1049
1047static int 1050static int
1048smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, 1051smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
1049 const char *full_path, char **target_path, 1052 const char *full_path, char **target_path,
@@ -1056,7 +1059,10 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
1056 struct cifs_fid fid; 1059 struct cifs_fid fid;
1057 struct smb2_err_rsp *err_buf = NULL; 1060 struct smb2_err_rsp *err_buf = NULL;
1058 struct smb2_symlink_err_rsp *symlink; 1061 struct smb2_symlink_err_rsp *symlink;
1059 unsigned int sub_len, sub_offset; 1062 unsigned int sub_len;
1063 unsigned int sub_offset;
1064 unsigned int print_len;
1065 unsigned int print_offset;
1060 1066
1061 cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path); 1067 cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);
1062 1068
@@ -1077,11 +1083,33 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
1077 kfree(utf16_path); 1083 kfree(utf16_path);
1078 return -ENOENT; 1084 return -ENOENT;
1079 } 1085 }
1086
1087 if (le32_to_cpu(err_buf->ByteCount) < sizeof(struct smb2_symlink_err_rsp) ||
1088 get_rfc1002_length(err_buf) + 4 < SMB2_SYMLINK_STRUCT_SIZE) {
1089 kfree(utf16_path);
1090 return -ENOENT;
1091 }
1092
1080 /* open must fail on symlink - reset rc */ 1093 /* open must fail on symlink - reset rc */
1081 rc = 0; 1094 rc = 0;
1082 symlink = (struct smb2_symlink_err_rsp *)err_buf->ErrorData; 1095 symlink = (struct smb2_symlink_err_rsp *)err_buf->ErrorData;
1083 sub_len = le16_to_cpu(symlink->SubstituteNameLength); 1096 sub_len = le16_to_cpu(symlink->SubstituteNameLength);
1084 sub_offset = le16_to_cpu(symlink->SubstituteNameOffset); 1097 sub_offset = le16_to_cpu(symlink->SubstituteNameOffset);
1098 print_len = le16_to_cpu(symlink->PrintNameLength);
1099 print_offset = le16_to_cpu(symlink->PrintNameOffset);
1100
1101 if (get_rfc1002_length(err_buf) + 4 <
1102 SMB2_SYMLINK_STRUCT_SIZE + sub_offset + sub_len) {
1103 kfree(utf16_path);
1104 return -ENOENT;
1105 }
1106
1107 if (get_rfc1002_length(err_buf) + 4 <
1108 SMB2_SYMLINK_STRUCT_SIZE + print_offset + print_len) {
1109 kfree(utf16_path);
1110 return -ENOENT;
1111 }
1112
1085 *target_path = cifs_strndup_from_utf16( 1113 *target_path = cifs_strndup_from_utf16(
1086 (char *)symlink->PathBuffer + sub_offset, 1114 (char *)symlink->PathBuffer + sub_offset,
1087 sub_len, true, cifs_sb->local_nls); 1115 sub_len, true, cifs_sb->local_nls);
@@ -1515,6 +1543,8 @@ struct smb_version_operations smb20_operations = {
1515 .rename = smb2_rename_path, 1543 .rename = smb2_rename_path,
1516 .create_hardlink = smb2_create_hardlink, 1544 .create_hardlink = smb2_create_hardlink,
1517 .query_symlink = smb2_query_symlink, 1545 .query_symlink = smb2_query_symlink,
1546 .query_mf_symlink = smb3_query_mf_symlink,
1547 .create_mf_symlink = smb3_create_mf_symlink,
1518 .open = smb2_open_file, 1548 .open = smb2_open_file,
1519 .set_fid = smb2_set_fid, 1549 .set_fid = smb2_set_fid,
1520 .close = smb2_close_file, 1550 .close = smb2_close_file,