Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag '6.1-rc4-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6

Pull cifs fixes from Steve French:
"One symlink handling fix and two fixes foir multichannel issues with
iterating channels, including for oplock breaks when leases are
disabled"

* tag '6.1-rc4-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6:
cifs: fix use-after-free on the link name
cifs: avoid unnecessary iteration of tcp sessions
cifs: always iterate smb sessions using primary channel

+105 -62
+25 -1
fs/cifs/cifsfs.c
··· 1143 1143 .fiemap = cifs_fiemap, 1144 1144 }; 1145 1145 1146 + const char *cifs_get_link(struct dentry *dentry, struct inode *inode, 1147 + struct delayed_call *done) 1148 + { 1149 + char *target_path; 1150 + 1151 + target_path = kmalloc(PATH_MAX, GFP_KERNEL); 1152 + if (!target_path) 1153 + return ERR_PTR(-ENOMEM); 1154 + 1155 + spin_lock(&inode->i_lock); 1156 + if (likely(CIFS_I(inode)->symlink_target)) { 1157 + strscpy(target_path, CIFS_I(inode)->symlink_target, PATH_MAX); 1158 + } else { 1159 + kfree(target_path); 1160 + target_path = ERR_PTR(-EOPNOTSUPP); 1161 + } 1162 + spin_unlock(&inode->i_lock); 1163 + 1164 + if (!IS_ERR(target_path)) 1165 + set_delayed_call(done, kfree_link, target_path); 1166 + 1167 + return target_path; 1168 + } 1169 + 1146 1170 const struct inode_operations cifs_symlink_inode_ops = { 1147 - .get_link = simple_get_link, 1171 + .get_link = cifs_get_link, 1148 1172 .permission = cifs_permission, 1149 1173 .listxattr = cifs_listxattr, 1150 1174 };
-5
fs/cifs/inode.c
··· 215 215 kfree(cifs_i->symlink_target); 216 216 cifs_i->symlink_target = fattr->cf_symlink_target; 217 217 fattr->cf_symlink_target = NULL; 218 - 219 - if (unlikely(!cifs_i->symlink_target)) 220 - inode->i_link = ERR_PTR(-EOPNOTSUPP); 221 - else 222 - inode->i_link = cifs_i->symlink_target; 223 218 } 224 219 spin_unlock(&inode->i_lock); 225 220
+5 -1
fs/cifs/misc.c
··· 400 400 { 401 401 struct smb_hdr *buf = (struct smb_hdr *)buffer; 402 402 struct smb_com_lock_req *pSMB = (struct smb_com_lock_req *)buf; 403 + struct TCP_Server_Info *pserver; 403 404 struct cifs_ses *ses; 404 405 struct cifs_tcon *tcon; 405 406 struct cifsInodeInfo *pCifsInode; ··· 465 464 if (!(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE)) 466 465 return false; 467 466 467 + /* If server is a channel, select the primary channel */ 468 + pserver = CIFS_SERVER_IS_CHAN(srv) ? srv->primary_server : srv; 469 + 468 470 /* look up tcon based on tid & uid */ 469 471 spin_lock(&cifs_tcp_ses_lock); 470 - list_for_each_entry(ses, &srv->smb_ses_list, smb_ses_list) { 472 + list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) { 471 473 list_for_each_entry(tcon, &ses->tcon_list, tcon_list) { 472 474 if (tcon->tid != buf->Tid) 473 475 continue;
+45 -36
fs/cifs/smb2misc.c
··· 135 135 int 136 136 smb2_check_message(char *buf, unsigned int len, struct TCP_Server_Info *server) 137 137 { 138 + struct TCP_Server_Info *pserver; 138 139 struct smb2_hdr *shdr = (struct smb2_hdr *)buf; 139 140 struct smb2_pdu *pdu = (struct smb2_pdu *)shdr; 140 141 int hdr_size = sizeof(struct smb2_hdr); ··· 143 142 int command; 144 143 __u32 calc_len; /* calculated length */ 145 144 __u64 mid; 145 + 146 + /* If server is a channel, select the primary channel */ 147 + pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server; 146 148 147 149 /* 148 150 * Add function to do table lookup of StructureSize by command ··· 159 155 160 156 /* decrypt frame now that it is completely read in */ 161 157 spin_lock(&cifs_tcp_ses_lock); 162 - list_for_each_entry(iter, &server->smb_ses_list, smb_ses_list) { 158 + list_for_each_entry(iter, &pserver->smb_ses_list, smb_ses_list) { 163 159 if (iter->Suid == le64_to_cpu(thdr->SessionId)) { 164 160 ses = iter; 165 161 break; ··· 612 608 } 613 609 614 610 static bool 615 - smb2_is_valid_lease_break(char *buffer) 611 + smb2_is_valid_lease_break(char *buffer, struct TCP_Server_Info *server) 616 612 { 617 613 struct smb2_lease_break *rsp = (struct smb2_lease_break *)buffer; 618 - struct TCP_Server_Info *server; 614 + struct TCP_Server_Info *pserver; 619 615 struct cifs_ses *ses; 620 616 struct cifs_tcon *tcon; 621 617 struct cifs_pending_open *open; 622 618 623 619 cifs_dbg(FYI, "Checking for lease break\n"); 624 620 621 + /* If server is a channel, select the primary channel */ 622 + pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server; 623 + 625 624 /* look up tcon based on tid & uid */ 626 625 spin_lock(&cifs_tcp_ses_lock); 627 - list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) { 628 - list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { 629 - list_for_each_entry(tcon, &ses->tcon_list, tcon_list) { 630 - spin_lock(&tcon->open_file_lock); 631 - cifs_stats_inc( 632 - &tcon->stats.cifs_stats.num_oplock_brks); 633 - if (smb2_tcon_has_lease(tcon, rsp)) { 634 - spin_unlock(&tcon->open_file_lock); 635 - spin_unlock(&cifs_tcp_ses_lock); 636 - return true; 637 - } 638 - open = smb2_tcon_find_pending_open_lease(tcon, 639 - rsp); 640 - if (open) { 641 - __u8 lease_key[SMB2_LEASE_KEY_SIZE]; 642 - struct tcon_link *tlink; 643 - 644 - tlink = cifs_get_tlink(open->tlink); 645 - memcpy(lease_key, open->lease_key, 646 - SMB2_LEASE_KEY_SIZE); 647 - spin_unlock(&tcon->open_file_lock); 648 - spin_unlock(&cifs_tcp_ses_lock); 649 - smb2_queue_pending_open_break(tlink, 650 - lease_key, 651 - rsp->NewLeaseState); 652 - return true; 653 - } 626 + list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) { 627 + list_for_each_entry(tcon, &ses->tcon_list, tcon_list) { 628 + spin_lock(&tcon->open_file_lock); 629 + cifs_stats_inc( 630 + &tcon->stats.cifs_stats.num_oplock_brks); 631 + if (smb2_tcon_has_lease(tcon, rsp)) { 654 632 spin_unlock(&tcon->open_file_lock); 633 + spin_unlock(&cifs_tcp_ses_lock); 634 + return true; 635 + } 636 + open = smb2_tcon_find_pending_open_lease(tcon, 637 + rsp); 638 + if (open) { 639 + __u8 lease_key[SMB2_LEASE_KEY_SIZE]; 640 + struct tcon_link *tlink; 655 641 656 - if (cached_dir_lease_break(tcon, rsp->LeaseKey)) { 657 - spin_unlock(&cifs_tcp_ses_lock); 658 - return true; 659 - } 642 + tlink = cifs_get_tlink(open->tlink); 643 + memcpy(lease_key, open->lease_key, 644 + SMB2_LEASE_KEY_SIZE); 645 + spin_unlock(&tcon->open_file_lock); 646 + spin_unlock(&cifs_tcp_ses_lock); 647 + smb2_queue_pending_open_break(tlink, 648 + lease_key, 649 + rsp->NewLeaseState); 650 + return true; 651 + } 652 + spin_unlock(&tcon->open_file_lock); 653 + 654 + if (cached_dir_lease_break(tcon, rsp->LeaseKey)) { 655 + spin_unlock(&cifs_tcp_ses_lock); 656 + return true; 660 657 } 661 658 } 662 659 } ··· 676 671 smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server) 677 672 { 678 673 struct smb2_oplock_break *rsp = (struct smb2_oplock_break *)buffer; 674 + struct TCP_Server_Info *pserver; 679 675 struct cifs_ses *ses; 680 676 struct cifs_tcon *tcon; 681 677 struct cifsInodeInfo *cinode; ··· 690 684 if (rsp->StructureSize != 691 685 smb2_rsp_struct_sizes[SMB2_OPLOCK_BREAK_HE]) { 692 686 if (le16_to_cpu(rsp->StructureSize) == 44) 693 - return smb2_is_valid_lease_break(buffer); 687 + return smb2_is_valid_lease_break(buffer, server); 694 688 else 695 689 return false; 696 690 } 697 691 698 692 cifs_dbg(FYI, "oplock level 0x%x\n", rsp->OplockLevel); 699 693 694 + /* If server is a channel, select the primary channel */ 695 + pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server; 696 + 700 697 /* look up tcon based on tid & uid */ 701 698 spin_lock(&cifs_tcp_ses_lock); 702 - list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { 699 + list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) { 703 700 list_for_each_entry(tcon, &ses->tcon_list, tcon_list) { 704 701 705 702 spin_lock(&tcon->open_file_lock);
+18 -12
fs/cifs/smb2ops.c
··· 2302 2302 smb2_is_network_name_deleted(char *buf, struct TCP_Server_Info *server) 2303 2303 { 2304 2304 struct smb2_hdr *shdr = (struct smb2_hdr *)buf; 2305 + struct TCP_Server_Info *pserver; 2305 2306 struct cifs_ses *ses; 2306 2307 struct cifs_tcon *tcon; 2307 2308 2308 2309 if (shdr->Status != STATUS_NETWORK_NAME_DELETED) 2309 2310 return; 2310 2311 2312 + /* If server is a channel, select the primary channel */ 2313 + pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server; 2314 + 2311 2315 spin_lock(&cifs_tcp_ses_lock); 2312 - list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { 2316 + list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) { 2313 2317 list_for_each_entry(tcon, &ses->tcon_list, tcon_list) { 2314 2318 if (tcon->tid == le32_to_cpu(shdr->Id.SyncId.TreeId)) { 2315 2319 spin_lock(&tcon->tc_lock); ··· 4268 4264 static int 4269 4265 smb2_get_enc_key(struct TCP_Server_Info *server, __u64 ses_id, int enc, u8 *key) 4270 4266 { 4267 + struct TCP_Server_Info *pserver; 4271 4268 struct cifs_ses *ses; 4272 4269 u8 *ses_enc_key; 4273 4270 4271 + /* If server is a channel, select the primary channel */ 4272 + pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server; 4273 + 4274 4274 spin_lock(&cifs_tcp_ses_lock); 4275 - list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) { 4276 - list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { 4277 - if (ses->Suid == ses_id) { 4278 - spin_lock(&ses->ses_lock); 4279 - ses_enc_key = enc ? ses->smb3encryptionkey : 4280 - ses->smb3decryptionkey; 4281 - memcpy(key, ses_enc_key, SMB3_ENC_DEC_KEY_SIZE); 4282 - spin_unlock(&ses->ses_lock); 4283 - spin_unlock(&cifs_tcp_ses_lock); 4284 - return 0; 4285 - } 4275 + list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) { 4276 + if (ses->Suid == ses_id) { 4277 + spin_lock(&ses->ses_lock); 4278 + ses_enc_key = enc ? ses->smb3encryptionkey : 4279 + ses->smb3decryptionkey; 4280 + memcpy(key, ses_enc_key, SMB3_ENC_DEC_KEY_SIZE); 4281 + spin_unlock(&ses->ses_lock); 4282 + spin_unlock(&cifs_tcp_ses_lock); 4283 + return 0; 4286 4284 } 4287 4285 } 4288 4286 spin_unlock(&cifs_tcp_ses_lock);
+12 -7
fs/cifs/smb2transport.c
··· 77 77 int smb2_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key) 78 78 { 79 79 struct cifs_chan *chan; 80 + struct TCP_Server_Info *pserver; 80 81 struct cifs_ses *ses = NULL; 81 - struct TCP_Server_Info *it = NULL; 82 82 int i; 83 83 int rc = 0; 84 84 85 85 spin_lock(&cifs_tcp_ses_lock); 86 86 87 - list_for_each_entry(it, &cifs_tcp_ses_list, tcp_ses_list) { 88 - list_for_each_entry(ses, &it->smb_ses_list, smb_ses_list) { 89 - if (ses->Suid == ses_id) 90 - goto found; 91 - } 87 + /* If server is a channel, select the primary channel */ 88 + pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server; 89 + 90 + list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) { 91 + if (ses->Suid == ses_id) 92 + goto found; 92 93 } 93 94 cifs_server_dbg(VFS, "%s: Could not find session 0x%llx\n", 94 95 __func__, ses_id); ··· 137 136 static struct cifs_ses * 138 137 smb2_find_smb_ses_unlocked(struct TCP_Server_Info *server, __u64 ses_id) 139 138 { 139 + struct TCP_Server_Info *pserver; 140 140 struct cifs_ses *ses; 141 141 142 - list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { 142 + /* If server is a channel, select the primary channel */ 143 + pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server; 144 + 145 + list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) { 143 146 if (ses->Suid != ses_id) 144 147 continue; 145 148 ++ses->ses_count;