Skip to content

Commit fa4cdb8

Browse files
namjaejeonSteve French
authored andcommitted
ksmbd: fix session use-after-free in multichannel connection
There is a race condition between session setup and ksmbd_sessions_deregister. The session can be freed before the connection is added to channel list of session. This patch check reference count of session before freeing it. Cc: stable@vger.kernel.org Reported-by: Sean Heelan <seanheelan@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org> Signed-off-by: Steve French <stfrench@microsoft.com>
1 parent f64a72b commit fa4cdb8

File tree

3 files changed

+14
-11
lines changed

3 files changed

+14
-11
lines changed

fs/smb/server/auth.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1016,9 +1016,9 @@ static int ksmbd_get_encryption_key(struct ksmbd_work *work, __u64 ses_id,
10161016

10171017
ses_enc_key = enc ? sess->smb3encryptionkey :
10181018
sess->smb3decryptionkey;
1019-
if (enc)
1020-
ksmbd_user_session_get(sess);
10211019
memcpy(key, ses_enc_key, SMB3_ENC_DEC_KEY_SIZE);
1020+
if (!enc)
1021+
ksmbd_user_session_put(sess);
10221022

10231023
return 0;
10241024
}

fs/smb/server/mgmt/user_session.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ static void ksmbd_expire_session(struct ksmbd_conn *conn)
181181
down_write(&sessions_table_lock);
182182
down_write(&conn->session_lock);
183183
xa_for_each(&conn->sessions, id, sess) {
184-
if (atomic_read(&sess->refcnt) == 0 &&
184+
if (atomic_read(&sess->refcnt) <= 1 &&
185185
(sess->state != SMB2_SESSION_VALID ||
186186
time_after(jiffies,
187187
sess->last_active + SMB2_SESSION_TIMEOUT))) {
@@ -233,7 +233,8 @@ void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
233233
down_write(&conn->session_lock);
234234
xa_erase(&conn->sessions, sess->id);
235235
up_write(&conn->session_lock);
236-
ksmbd_session_destroy(sess);
236+
if (atomic_dec_and_test(&sess->refcnt))
237+
ksmbd_session_destroy(sess);
237238
}
238239
}
239240
}
@@ -252,7 +253,8 @@ void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
252253
if (xa_empty(&sess->ksmbd_chann_list)) {
253254
xa_erase(&conn->sessions, sess->id);
254255
hash_del(&sess->hlist);
255-
ksmbd_session_destroy(sess);
256+
if (atomic_dec_and_test(&sess->refcnt))
257+
ksmbd_session_destroy(sess);
256258
}
257259
}
258260
up_write(&conn->session_lock);
@@ -328,8 +330,8 @@ void ksmbd_user_session_put(struct ksmbd_session *sess)
328330

329331
if (atomic_read(&sess->refcnt) <= 0)
330332
WARN_ON(1);
331-
else
332-
atomic_dec(&sess->refcnt);
333+
else if (atomic_dec_and_test(&sess->refcnt))
334+
ksmbd_session_destroy(sess);
333335
}
334336

335337
struct preauth_session *ksmbd_preauth_session_alloc(struct ksmbd_conn *conn,
@@ -436,7 +438,7 @@ static struct ksmbd_session *__session_create(int protocol)
436438
xa_init(&sess->rpc_handle_list);
437439
sess->sequence_number = 1;
438440
rwlock_init(&sess->tree_conns_lock);
439-
atomic_set(&sess->refcnt, 1);
441+
atomic_set(&sess->refcnt, 2);
440442

441443
ret = __init_smb2_session(sess);
442444
if (ret)

fs/smb/server/smb2pdu.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2235,13 +2235,14 @@ int smb2_session_logoff(struct ksmbd_work *work)
22352235
return -ENOENT;
22362236
}
22372237

2238-
ksmbd_destroy_file_table(&sess->file_table);
22392238
down_write(&conn->session_lock);
22402239
sess->state = SMB2_SESSION_EXPIRED;
22412240
up_write(&conn->session_lock);
22422241

2243-
ksmbd_free_user(sess->user);
2244-
sess->user = NULL;
2242+
if (sess->user) {
2243+
ksmbd_free_user(sess->user);
2244+
sess->user = NULL;
2245+
}
22452246
ksmbd_all_conn_set_status(sess_id, KSMBD_SESS_NEED_NEGOTIATE);
22462247

22472248
rsp->StructureSize = cpu_to_le16(4);

0 commit comments

Comments
 (0)