Skip to content

Commit 90153f9

Browse files
committed
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
2 parents 8391aa4 + 542228d commit 90153f9

File tree

6 files changed

+105
-62
lines changed

6 files changed

+105
-62
lines changed

fs/cifs/cifsfs.c

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1143,8 +1143,32 @@ const struct inode_operations cifs_file_inode_ops = {
11431143
.fiemap = cifs_fiemap,
11441144
};
11451145

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+
11461170
const struct inode_operations cifs_symlink_inode_ops = {
1147-
.get_link = simple_get_link,
1171+
.get_link = cifs_get_link,
11481172
.permission = cifs_permission,
11491173
.listxattr = cifs_listxattr,
11501174
};

fs/cifs/inode.c

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -215,11 +215,6 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
215215
kfree(cifs_i->symlink_target);
216216
cifs_i->symlink_target = fattr->cf_symlink_target;
217217
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;
223218
}
224219
spin_unlock(&inode->i_lock);
225220

fs/cifs/misc.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,7 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)
400400
{
401401
struct smb_hdr *buf = (struct smb_hdr *)buffer;
402402
struct smb_com_lock_req *pSMB = (struct smb_com_lock_req *)buf;
403+
struct TCP_Server_Info *pserver;
403404
struct cifs_ses *ses;
404405
struct cifs_tcon *tcon;
405406
struct cifsInodeInfo *pCifsInode;
@@ -464,9 +465,12 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)
464465
if (!(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE))
465466
return false;
466467

468+
/* If server is a channel, select the primary channel */
469+
pserver = CIFS_SERVER_IS_CHAN(srv) ? srv->primary_server : srv;
470+
467471
/* look up tcon based on tid & uid */
468472
spin_lock(&cifs_tcp_ses_lock);
469-
list_for_each_entry(ses, &srv->smb_ses_list, smb_ses_list) {
473+
list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
470474
list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
471475
if (tcon->tid != buf->Tid)
472476
continue;

fs/cifs/smb2misc.c

Lines changed: 45 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ static __u32 get_neg_ctxt_len(struct smb2_hdr *hdr, __u32 len,
135135
int
136136
smb2_check_message(char *buf, unsigned int len, struct TCP_Server_Info *server)
137137
{
138+
struct TCP_Server_Info *pserver;
138139
struct smb2_hdr *shdr = (struct smb2_hdr *)buf;
139140
struct smb2_pdu *pdu = (struct smb2_pdu *)shdr;
140141
int hdr_size = sizeof(struct smb2_hdr);
@@ -143,6 +144,9 @@ smb2_check_message(char *buf, unsigned int len, struct TCP_Server_Info *server)
143144
__u32 calc_len; /* calculated length */
144145
__u64 mid;
145146

147+
/* If server is a channel, select the primary channel */
148+
pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
149+
146150
/*
147151
* Add function to do table lookup of StructureSize by command
148152
* ie Validate the wct via smb2_struct_sizes table above
@@ -155,7 +159,7 @@ smb2_check_message(char *buf, unsigned int len, struct TCP_Server_Info *server)
155159

156160
/* decrypt frame now that it is completely read in */
157161
spin_lock(&cifs_tcp_ses_lock);
158-
list_for_each_entry(iter, &server->smb_ses_list, smb_ses_list) {
162+
list_for_each_entry(iter, &pserver->smb_ses_list, smb_ses_list) {
159163
if (iter->Suid == le64_to_cpu(thdr->SessionId)) {
160164
ses = iter;
161165
break;
@@ -608,51 +612,52 @@ smb2_tcon_find_pending_open_lease(struct cifs_tcon *tcon,
608612
}
609613

610614
static bool
611-
smb2_is_valid_lease_break(char *buffer)
615+
smb2_is_valid_lease_break(char *buffer, struct TCP_Server_Info *server)
612616
{
613617
struct smb2_lease_break *rsp = (struct smb2_lease_break *)buffer;
614-
struct TCP_Server_Info *server;
618+
struct TCP_Server_Info *pserver;
615619
struct cifs_ses *ses;
616620
struct cifs_tcon *tcon;
617621
struct cifs_pending_open *open;
618622

619623
cifs_dbg(FYI, "Checking for lease break\n");
620624

625+
/* If server is a channel, select the primary channel */
626+
pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
627+
621628
/* look up tcon based on tid & uid */
622629
spin_lock(&cifs_tcp_ses_lock);
623-
list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
624-
list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
625-
list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
626-
spin_lock(&tcon->open_file_lock);
627-
cifs_stats_inc(
628-
&tcon->stats.cifs_stats.num_oplock_brks);
629-
if (smb2_tcon_has_lease(tcon, rsp)) {
630-
spin_unlock(&tcon->open_file_lock);
631-
spin_unlock(&cifs_tcp_ses_lock);
632-
return true;
633-
}
634-
open = smb2_tcon_find_pending_open_lease(tcon,
635-
rsp);
636-
if (open) {
637-
__u8 lease_key[SMB2_LEASE_KEY_SIZE];
638-
struct tcon_link *tlink;
639-
640-
tlink = cifs_get_tlink(open->tlink);
641-
memcpy(lease_key, open->lease_key,
642-
SMB2_LEASE_KEY_SIZE);
643-
spin_unlock(&tcon->open_file_lock);
644-
spin_unlock(&cifs_tcp_ses_lock);
645-
smb2_queue_pending_open_break(tlink,
646-
lease_key,
647-
rsp->NewLeaseState);
648-
return true;
649-
}
630+
list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
631+
list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
632+
spin_lock(&tcon->open_file_lock);
633+
cifs_stats_inc(
634+
&tcon->stats.cifs_stats.num_oplock_brks);
635+
if (smb2_tcon_has_lease(tcon, rsp)) {
650636
spin_unlock(&tcon->open_file_lock);
637+
spin_unlock(&cifs_tcp_ses_lock);
638+
return true;
639+
}
640+
open = smb2_tcon_find_pending_open_lease(tcon,
641+
rsp);
642+
if (open) {
643+
__u8 lease_key[SMB2_LEASE_KEY_SIZE];
644+
struct tcon_link *tlink;
645+
646+
tlink = cifs_get_tlink(open->tlink);
647+
memcpy(lease_key, open->lease_key,
648+
SMB2_LEASE_KEY_SIZE);
649+
spin_unlock(&tcon->open_file_lock);
650+
spin_unlock(&cifs_tcp_ses_lock);
651+
smb2_queue_pending_open_break(tlink,
652+
lease_key,
653+
rsp->NewLeaseState);
654+
return true;
655+
}
656+
spin_unlock(&tcon->open_file_lock);
651657

652-
if (cached_dir_lease_break(tcon, rsp->LeaseKey)) {
653-
spin_unlock(&cifs_tcp_ses_lock);
654-
return true;
655-
}
658+
if (cached_dir_lease_break(tcon, rsp->LeaseKey)) {
659+
spin_unlock(&cifs_tcp_ses_lock);
660+
return true;
656661
}
657662
}
658663
}
@@ -671,6 +676,7 @@ bool
671676
smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
672677
{
673678
struct smb2_oplock_break *rsp = (struct smb2_oplock_break *)buffer;
679+
struct TCP_Server_Info *pserver;
674680
struct cifs_ses *ses;
675681
struct cifs_tcon *tcon;
676682
struct cifsInodeInfo *cinode;
@@ -684,16 +690,19 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
684690
if (rsp->StructureSize !=
685691
smb2_rsp_struct_sizes[SMB2_OPLOCK_BREAK_HE]) {
686692
if (le16_to_cpu(rsp->StructureSize) == 44)
687-
return smb2_is_valid_lease_break(buffer);
693+
return smb2_is_valid_lease_break(buffer, server);
688694
else
689695
return false;
690696
}
691697

692698
cifs_dbg(FYI, "oplock level 0x%x\n", rsp->OplockLevel);
693699

700+
/* If server is a channel, select the primary channel */
701+
pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
702+
694703
/* look up tcon based on tid & uid */
695704
spin_lock(&cifs_tcp_ses_lock);
696-
list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
705+
list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
697706
list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
698707

699708
spin_lock(&tcon->open_file_lock);

fs/cifs/smb2ops.c

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2302,14 +2302,18 @@ static void
23022302
smb2_is_network_name_deleted(char *buf, struct TCP_Server_Info *server)
23032303
{
23042304
struct smb2_hdr *shdr = (struct smb2_hdr *)buf;
2305+
struct TCP_Server_Info *pserver;
23052306
struct cifs_ses *ses;
23062307
struct cifs_tcon *tcon;
23072308

23082309
if (shdr->Status != STATUS_NETWORK_NAME_DELETED)
23092310
return;
23102311

2312+
/* If server is a channel, select the primary channel */
2313+
pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
2314+
23112315
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) {
23132317
list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
23142318
if (tcon->tid == le32_to_cpu(shdr->Id.SyncId.TreeId)) {
23152319
spin_lock(&tcon->tc_lock);
@@ -4264,21 +4268,23 @@ init_sg(int num_rqst, struct smb_rqst *rqst, u8 *sign)
42644268
static int
42654269
smb2_get_enc_key(struct TCP_Server_Info *server, __u64 ses_id, int enc, u8 *key)
42664270
{
4271+
struct TCP_Server_Info *pserver;
42674272
struct cifs_ses *ses;
42684273
u8 *ses_enc_key;
42694274

4275+
/* If server is a channel, select the primary channel */
4276+
pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
4277+
42704278
spin_lock(&cifs_tcp_ses_lock);
4271-
list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
4272-
list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
4273-
if (ses->Suid == ses_id) {
4274-
spin_lock(&ses->ses_lock);
4275-
ses_enc_key = enc ? ses->smb3encryptionkey :
4276-
ses->smb3decryptionkey;
4277-
memcpy(key, ses_enc_key, SMB3_ENC_DEC_KEY_SIZE);
4278-
spin_unlock(&ses->ses_lock);
4279-
spin_unlock(&cifs_tcp_ses_lock);
4280-
return 0;
4281-
}
4279+
list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
4280+
if (ses->Suid == ses_id) {
4281+
spin_lock(&ses->ses_lock);
4282+
ses_enc_key = enc ? ses->smb3encryptionkey :
4283+
ses->smb3decryptionkey;
4284+
memcpy(key, ses_enc_key, SMB3_ENC_DEC_KEY_SIZE);
4285+
spin_unlock(&ses->ses_lock);
4286+
spin_unlock(&cifs_tcp_ses_lock);
4287+
return 0;
42824288
}
42834289
}
42844290
spin_unlock(&cifs_tcp_ses_lock);

fs/cifs/smb2transport.c

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -77,18 +77,19 @@ static
7777
int smb2_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key)
7878
{
7979
struct cifs_chan *chan;
80+
struct TCP_Server_Info *pserver;
8081
struct cifs_ses *ses = NULL;
81-
struct TCP_Server_Info *it = NULL;
8282
int i;
8383
int rc = 0;
8484

8585
spin_lock(&cifs_tcp_ses_lock);
8686

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;
9293
}
9394
cifs_server_dbg(VFS, "%s: Could not find session 0x%llx\n",
9495
__func__, ses_id);
@@ -136,9 +137,13 @@ int smb2_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key)
136137
static struct cifs_ses *
137138
smb2_find_smb_ses_unlocked(struct TCP_Server_Info *server, __u64 ses_id)
138139
{
140+
struct TCP_Server_Info *pserver;
139141
struct cifs_ses *ses;
140142

141-
list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
143+
/* If server is a channel, select the primary channel */
144+
pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
145+
146+
list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
142147
if (ses->Suid != ses_id)
143148
continue;
144149
++ses->ses_count;

0 commit comments

Comments
 (0)