Skip to content

Commit 5caedf4

Browse files
Paulo AlcantaraSasha Levin
authored andcommitted
smb: client: fix use-after-free of signing key
[ Upstream commit 343d7fe ] Customers have reported use-after-free in @ses->auth_key.response with SMB2.1 + sign mounts which occurs due to following race: task A task B cifs_mount() dfs_mount_share() get_session() cifs_mount_get_session() cifs_send_recv() cifs_get_smb_ses() compound_send_recv() cifs_setup_session() smb2_setup_request() kfree_sensitive() smb2_calc_signature() crypto_shash_setkey() *UAF* Fix this by ensuring that we have a valid @ses->auth_key.response by checking whether @ses->ses_status is SES_GOOD or SES_EXITING with @ses->ses_lock held. After commit 24a9799 ("smb: client: fix UAF in smb2_reconnect_server()"), we made sure to call ->logoff() only when @SES was known to be good (e.g. valid ->auth_key.response), so it's safe to access signing key when @ses->ses_status == SES_EXITING. Cc: stable@vger.kernel.org Reported-by: Jay Shin <jaeshin@redhat.com> Signed-off-by: Paulo Alcantara (Red Hat) <pc@manguebit.com> Signed-off-by: Steve French <stfrench@microsoft.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 31c0376 commit 5caedf4

File tree

2 files changed

+40
-18
lines changed

2 files changed

+40
-18
lines changed

fs/smb/client/smb2proto.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@ extern struct mid_q_entry *smb2_setup_request(struct cifs_ses *ses,
3737
struct smb_rqst *rqst);
3838
extern struct mid_q_entry *smb2_setup_async_request(
3939
struct TCP_Server_Info *server, struct smb_rqst *rqst);
40-
extern struct cifs_ses *smb2_find_smb_ses(struct TCP_Server_Info *server,
41-
__u64 ses_id);
4240
extern struct cifs_tcon *smb2_find_smb_tcon(struct TCP_Server_Info *server,
4341
__u64 ses_id, __u32 tid);
4442
extern int smb2_calc_signature(struct smb_rqst *rqst,

fs/smb/client/smb2transport.c

Lines changed: 40 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ smb311_crypto_shash_allocate(struct TCP_Server_Info *server)
7474

7575

7676
static
77-
int smb2_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key)
77+
int smb3_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key)
7878
{
7979
struct cifs_chan *chan;
8080
struct TCP_Server_Info *pserver;
@@ -168,16 +168,41 @@ smb2_find_smb_ses_unlocked(struct TCP_Server_Info *server, __u64 ses_id)
168168
return NULL;
169169
}
170170

171-
struct cifs_ses *
172-
smb2_find_smb_ses(struct TCP_Server_Info *server, __u64 ses_id)
171+
static int smb2_get_sign_key(struct TCP_Server_Info *server,
172+
__u64 ses_id, u8 *key)
173173
{
174174
struct cifs_ses *ses;
175+
int rc = -ENOENT;
176+
177+
if (SERVER_IS_CHAN(server))
178+
server = server->primary_server;
175179

176180
spin_lock(&cifs_tcp_ses_lock);
177-
ses = smb2_find_smb_ses_unlocked(server, ses_id);
178-
spin_unlock(&cifs_tcp_ses_lock);
181+
list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
182+
if (ses->Suid != ses_id)
183+
continue;
179184

180-
return ses;
185+
rc = 0;
186+
spin_lock(&ses->ses_lock);
187+
switch (ses->ses_status) {
188+
case SES_EXITING: /* SMB2_LOGOFF */
189+
case SES_GOOD:
190+
if (likely(ses->auth_key.response)) {
191+
memcpy(key, ses->auth_key.response,
192+
SMB2_NTLMV2_SESSKEY_SIZE);
193+
} else {
194+
rc = -EIO;
195+
}
196+
break;
197+
default:
198+
rc = -EAGAIN;
199+
break;
200+
}
201+
spin_unlock(&ses->ses_lock);
202+
break;
203+
}
204+
spin_unlock(&cifs_tcp_ses_lock);
205+
return rc;
181206
}
182207

183208
static struct cifs_tcon *
@@ -236,14 +261,16 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
236261
unsigned char *sigptr = smb2_signature;
237262
struct kvec *iov = rqst->rq_iov;
238263
struct smb2_hdr *shdr = (struct smb2_hdr *)iov[0].iov_base;
239-
struct cifs_ses *ses;
240264
struct shash_desc *shash = NULL;
241265
struct smb_rqst drqst;
266+
__u64 sid = le64_to_cpu(shdr->SessionId);
267+
u8 key[SMB2_NTLMV2_SESSKEY_SIZE];
242268

243-
ses = smb2_find_smb_ses(server, le64_to_cpu(shdr->SessionId));
244-
if (unlikely(!ses)) {
245-
cifs_server_dbg(FYI, "%s: Could not find session\n", __func__);
246-
return -ENOENT;
269+
rc = smb2_get_sign_key(server, sid, key);
270+
if (unlikely(rc)) {
271+
cifs_server_dbg(FYI, "%s: [sesid=0x%llx] couldn't find signing key: %d\n",
272+
__func__, sid, rc);
273+
return rc;
247274
}
248275

249276
memset(smb2_signature, 0x0, SMB2_HMACSHA256_SIZE);
@@ -260,8 +287,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
260287
shash = server->secmech.hmacsha256;
261288
}
262289

263-
rc = crypto_shash_setkey(shash->tfm, ses->auth_key.response,
264-
SMB2_NTLMV2_SESSKEY_SIZE);
290+
rc = crypto_shash_setkey(shash->tfm, key, sizeof(key));
265291
if (rc) {
266292
cifs_server_dbg(VFS,
267293
"%s: Could not update with response\n",
@@ -303,8 +329,6 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
303329
out:
304330
if (allocate_crypto)
305331
cifs_free_hash(&shash);
306-
if (ses)
307-
cifs_put_smb_ses(ses);
308332
return rc;
309333
}
310334

@@ -570,7 +594,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
570594
struct smb_rqst drqst;
571595
u8 key[SMB3_SIGN_KEY_SIZE];
572596

573-
rc = smb2_get_sign_key(le64_to_cpu(shdr->SessionId), server, key);
597+
rc = smb3_get_sign_key(le64_to_cpu(shdr->SessionId), server, key);
574598
if (unlikely(rc)) {
575599
cifs_server_dbg(FYI, "%s: Could not get signing key\n", __func__);
576600
return rc;

0 commit comments

Comments
 (0)