diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-07-29 14:29:13 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-07-29 14:29:13 -0400 |
commit | b0c4e2acdd6175a07107474f3cd7bdc062cf4d3d (patch) | |
tree | 9b269c5a176175082ce8bd4806901152bb12728c | |
parent | c624c86615fb8aa61fa76ed8c935446d06c80e77 (diff) | |
parent | 7893242e2465aea6f2cbc2639da8fa5ce96e8cc2 (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.h | 4 | ||||
-rw-r--r-- | fs/cifs/cifsencrypt.c | 16 | ||||
-rw-r--r-- | fs/cifs/cifsfs.c | 14 | ||||
-rw-r--r-- | fs/cifs/connect.c | 53 | ||||
-rw-r--r-- | fs/cifs/dir.c | 44 | ||||
-rw-r--r-- | fs/cifs/inode.c | 22 | ||||
-rw-r--r-- | fs/cifs/smb2ops.c | 32 |
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 | ||
50 | struct cifs_sb_info { | 53 | struct 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 | ||
796 | unlock: | ||
797 | mutex_unlock(&ses->server->srv_mutex); | ||
794 | setup_ntlmv2_rsp_ret: | 798 | setup_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 | ||
3488 | static int | ||
3489 | cifs_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 | |||
3486 | int | 3526 | int |
3487 | cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *volume_info) | 3527 | cifs_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 | |||
98 | cifs_bp_rename_retry: | 103 | cifs_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 | |||
441 | out_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 | ||
415 | int | 449 | int |
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 | ||
1018 | iget_no_retry: | 1035 | iget_no_retry: |
1019 | if (!inode) { | 1036 | if (!inode) { |
@@ -1042,6 +1059,7 @@ iget_no_retry: | |||
1042 | } | 1059 | } |
1043 | 1060 | ||
1044 | out: | 1061 | out: |
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 | |||
1047 | static int | 1050 | static int |
1048 | smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, | 1051 | smb2_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, |