Skip to content

Commit 4f3a06c

Browse files
namjaejeonsmfrench
authored andcommitted
ksmbd: add chann_lock to protect ksmbd_chann_list xarray
ksmbd_chann_list xarray lacks synchronization, allowing use-after-free in multi-channel sessions (between lookup_chann_list() and ksmbd_chann_del). Adds rw_semaphore chann_lock to struct ksmbd_session and protects all xa_load/xa_store/xa_erase accesses. Cc: stable@vger.kernel.org Reported-by: Igor Stepansky <igor.stepansky@orca.security> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org> Signed-off-by: Steve French <stfrench@microsoft.com>
1 parent 164cacd commit 4f3a06c

3 files changed

Lines changed: 17 additions & 1 deletion

File tree

fs/smb/server/mgmt/user_session.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,12 +244,14 @@ static void free_channel_list(struct ksmbd_session *sess)
244244
struct channel *chann;
245245
unsigned long index;
246246

247+
down_write(&sess->chann_lock);
247248
xa_for_each(&sess->ksmbd_chann_list, index, chann) {
248249
xa_erase(&sess->ksmbd_chann_list, index);
249250
kfree(chann);
250251
}
251252

252253
xa_destroy(&sess->ksmbd_chann_list);
254+
up_write(&sess->chann_lock);
253255
}
254256

255257
static void __session_rpc_close(struct ksmbd_session *sess,
@@ -434,7 +436,9 @@ static int ksmbd_chann_del(struct ksmbd_conn *conn, struct ksmbd_session *sess)
434436
{
435437
struct channel *chann;
436438

439+
down_write(&sess->chann_lock);
437440
chann = xa_erase(&sess->ksmbd_chann_list, (long)conn);
441+
up_write(&sess->chann_lock);
438442
if (!chann)
439443
return -ENOENT;
440444

@@ -668,6 +672,7 @@ static struct ksmbd_session *__session_create(int protocol)
668672
rwlock_init(&sess->tree_conns_lock);
669673
atomic_set(&sess->refcnt, 2);
670674
init_rwsem(&sess->rpc_lock);
675+
init_rwsem(&sess->chann_lock);
671676

672677
ret = __init_smb2_session(sess);
673678
if (ret)

fs/smb/server/mgmt/user_session.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ struct ksmbd_session {
4848
char sess_key[CIFS_KEY_SIZE];
4949

5050
struct hlist_node hlist;
51+
struct rw_semaphore chann_lock;
5152
struct xarray ksmbd_chann_list;
5253
struct xarray tree_conns;
5354
struct ida tree_conn_ida;

fs/smb/server/smb2pdu.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,13 @@ static inline bool check_session_id(struct ksmbd_conn *conn, u64 id)
8080

8181
struct channel *lookup_chann_list(struct ksmbd_session *sess, struct ksmbd_conn *conn)
8282
{
83-
return xa_load(&sess->ksmbd_chann_list, (long)conn);
83+
struct channel *chann;
84+
85+
down_read(&sess->chann_lock);
86+
chann = xa_load(&sess->ksmbd_chann_list, (long)conn);
87+
up_read(&sess->chann_lock);
88+
89+
return chann;
8490
}
8591

8692
/**
@@ -1559,8 +1565,10 @@ static int ntlm_authenticate(struct ksmbd_work *work,
15591565
return -ENOMEM;
15601566

15611567
chann->conn = conn;
1568+
down_write(&sess->chann_lock);
15621569
old = xa_store(&sess->ksmbd_chann_list, (long)conn, chann,
15631570
KSMBD_DEFAULT_GFP);
1571+
up_write(&sess->chann_lock);
15641572
if (xa_is_err(old)) {
15651573
kfree(chann);
15661574
return xa_err(old);
@@ -1652,8 +1660,10 @@ static int krb5_authenticate(struct ksmbd_work *work,
16521660
return -ENOMEM;
16531661

16541662
chann->conn = conn;
1663+
down_write(&sess->chann_lock);
16551664
old = xa_store(&sess->ksmbd_chann_list, (long)conn,
16561665
chann, KSMBD_DEFAULT_GFP);
1666+
up_write(&sess->chann_lock);
16571667
if (xa_is_err(old)) {
16581668
kfree(chann);
16591669
return xa_err(old);

0 commit comments

Comments
 (0)