ksmbd: add chann_lock to protect ksmbd_chann_list xarray
Subsystems (3)
PATCH 1/1 ksmbd: add chann_lock to protect ksmbd_chann_list xarray
From: Namjae Jeon <[email protected]>
[ Upstream commit 4f3a06cc57976cafa8c6f716646be6c79a99e485 ]
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.
Backport notes for linux-6.6.y:
- File paths and surrounding context are identical to mainline at the time of the fix. The xa_store call sites in ntlm_authenticate / krb5_authenticate use the older form xa_store(..., GFP_KERNEL) rather than the newer
old = xa_store(..., KSMBD_DEFAULT_GFP); the lock-wrap is structurally identical.
CVE: CVE-2026-23226
--- fs/smb/server/mgmt/user_session.c | 5 +++++ fs/smb/server/mgmt/user_session.h | 1 + fs/smb/server/smb2pdu.c | 12 +++++++++++- 3 files changed, 17 insertions(+), 1 deletion(-)
fs/smb/server/mgmt/user_session.c +5 -0
@@ -30,12 +30,14 @@ static void free_channel_list(struct ksmbd_session *sess)struct channel *chann;unsigned long index; +down_write (&sess->chann_lock);xa_for_each (&sess->ksmbd_chann_list, index, chann) {xa_erase (&sess->ksmbd_chann_list, index);kfree (chann); }xa_destroy (&sess->ksmbd_chann_list); +up_write (&sess->chann_lock); } static void __session_rpc_close(struct ksmbd_session *sess,
@@ -218,7 +220,9 @@ static int ksmbd_chann_del(struct ksmbd_conn *conn, struct ksmbd_session *sess) {struct channel *chann; +down_write (&sess->chann_lock); chann =xa_erase (&sess->ksmbd_chann_list, (long )conn); +up_write (&sess->chann_lock);if (!chann)return -ENOENT ;
@@ -451,6 +455,7 @@ static struct ksmbd_session *__session_create(int protocol)rwlock_init (&sess->tree_conns_lock);atomic_set (&sess->refcnt,2 );init_rwsem (&sess->rpc_lock); +init_rwsem (&sess->chann_lock); ret =__init_smb2_session (sess);if (ret)
fs/smb/server/mgmt/user_session.h +1 -0
@@ -48,6 +48,7 @@ struct ksmbd_session {char sess_key[CIFS_KEY_SIZE ];struct hlist_node hlist; +struct rw_semaphore chann_lock;struct xarray ksmbd_chann_list;struct xarray tree_conns;struct ida tree_conn_ida;
fs/smb/server/smb2pdu.c +11 -1
@@ -80,7 +80,13 @@ static inline bool check_session_id(struct ksmbd_conn *conn, u64 id)struct channel *lookup_chann_list (struct ksmbd_session *sess,struct ksmbd_conn *conn) { -return xa_load (&sess->ksmbd_chann_list, (long )conn); +struct channel *chann; + +down_read (&sess->chann_lock); + chann =xa_load (&sess->ksmbd_chann_list, (long )conn); +up_read (&sess->chann_lock); + +return chann; }/**
@@ -1559,7 +1565,9 @@ static int ntlm_authenticate(struct ksmbd_work *work,return -ENOMEM ; chann->conn = conn; +down_write (&sess->chann_lock);xa_store (&sess->ksmbd_chann_list, (long )conn, chann,GFP_KERNEL ); +up_write (&sess->chann_lock); } }
@@ -1652,7 +1660,9 @@ static int krb5_authenticate(struct ksmbd_work *work,return -ENOMEM ; chann->conn = conn; +down_write (&sess->chann_lock);xa_store (&sess->ksmbd_chann_list, (long )conn, chann,GFP_KERNEL ); +up_write (&sess->chann_lock); } }
--
2.43.0
PATCH 1/1 ksmbd: add chann_lock to protect ksmbd_chann_list xarray
From: Namjae Jeon <[email protected]>
[ Upstream commit 4f3a06cc57976cafa8c6f716646be6c79a99e485 ]
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.
Backport notes for linux-6.1.y:
- The smb client/server consolidation has already happened by 6.1.y; file paths are fs/smb/server/, identical to mainline.
- The xa_store call sites use the older form xa_store(..., GFP_KERNEL) with no captured old, but the surrounding context for the lock-wrap is identical.
CVE: CVE-2026-23226
--- fs/smb/server/mgmt/user_session.c | 5 +++++ fs/smb/server/mgmt/user_session.h | 1 + fs/smb/server/smb2pdu.c | 12 +++++++++++- 3 files changed, 17 insertions(+), 1 deletion(-)
fs/smb/server/mgmt/user_session.c +5 -0
@@ -30,12 +30,14 @@ static void free_channel_list(struct ksmbd_session *sess)struct channel *chann;unsigned long index; +down_write (&sess->chann_lock);xa_for_each (&sess->ksmbd_chann_list, index, chann) {xa_erase (&sess->ksmbd_chann_list, index);kfree (chann); }xa_destroy (&sess->ksmbd_chann_list); +up_write (&sess->chann_lock); } static void __session_rpc_close(struct ksmbd_session *sess,
@@ -218,7 +220,9 @@ static int ksmbd_chann_del(struct ksmbd_conn *conn, struct ksmbd_session *sess) {struct channel *chann; +down_write (&sess->chann_lock); chann =xa_erase (&sess->ksmbd_chann_list, (long )conn); +up_write (&sess->chann_lock);if (!chann)return -ENOENT ;
@@ -417,6 +421,7 @@ static struct ksmbd_session *__session_create(int protocol)rwlock_init (&sess->tree_conns_lock);atomic_set (&sess->refcnt,2 );init_rwsem (&sess->rpc_lock); +init_rwsem (&sess->chann_lock); ret =__init_smb2_session (sess);if (ret)
fs/smb/server/mgmt/user_session.h +1 -0
@@ -48,6 +48,7 @@ struct ksmbd_session {char sess_key[CIFS_KEY_SIZE ];struct hlist_node hlist; +struct rw_semaphore chann_lock;struct xarray ksmbd_chann_list;struct xarray tree_conns;struct ida tree_conn_ida;
fs/smb/server/smb2pdu.c +11 -1
@@ -79,7 +79,13 @@ static inline bool check_session_id(struct ksmbd_conn *conn, u64 id)struct channel *lookup_chann_list (struct ksmbd_session *sess,struct ksmbd_conn *conn) { -return xa_load (&sess->ksmbd_chann_list, (long )conn); +struct channel *chann; + +down_read (&sess->chann_lock); + chann =xa_load (&sess->ksmbd_chann_list, (long )conn); +up_read (&sess->chann_lock); + +return chann; }/**
@@ -1567,7 +1573,9 @@ static int ntlm_authenticate(struct ksmbd_work *work,return -ENOMEM ; chann->conn = conn; +down_write (&sess->chann_lock);xa_store (&sess->ksmbd_chann_list, (long )conn, chann,GFP_KERNEL ); +up_write (&sess->chann_lock); } }
@@ -1660,7 +1668,9 @@ static int krb5_authenticate(struct ksmbd_work *work,return -ENOMEM ; chann->conn = conn; +down_write (&sess->chann_lock);xa_store (&sess->ksmbd_chann_list, (long )conn, chann,GFP_KERNEL ); +up_write (&sess->chann_lock); } }
--
2.43.0
PATCH 1/1 ksmbd: add chann_lock to protect ksmbd_chann_list xarray
In reply to Kai AizenFrom: Namjae Jeon <[email protected]>
[ Upstream commit 4f3a06cc57976cafa8c6f716646be6c79a99e485 ]
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.
Backport notes for linux-5.15.y:
- 5.15 still uses fs/ksmbd/ paths (the smb client/server consolidation
landed in 6.1).
- struct ksmbd_session does not yet have rpc_lock; init_rwsem for chann_lock is added directly after the refcnt initialisation.
- Function bodies for free_channel_list, ksmbd_chann_del, lookup_chann_list, and the two xa_store sites in ntlm_authenticate / krb5_authenticate are byte-identical to mainline at the time of the fix.
CVE: CVE-2026-23226
--- fs/ksmbd/mgmt/user_session.c | 5 +++++ fs/ksmbd/mgmt/user_session.h | 1 + fs/ksmbd/smb2pdu.c | 12 +++++++++++- 3 files changed, 17 insertions(+), 1 deletion(-)
fs/ksmbd/mgmt/user_session.c +5 -0
@@ -30,12 +30,14 @@ static void free_channel_list(struct ksmbd_session *sess)struct channel *chann;unsigned long index; +down_write (&sess->chann_lock);xa_for_each (&sess->ksmbd_chann_list, index, chann) {xa_erase (&sess->ksmbd_chann_list, index);kfree (chann); }xa_destroy (&sess->ksmbd_chann_list); +up_write (&sess->chann_lock); } static void __session_rpc_close(struct ksmbd_session *sess,
@@ -201,7 +203,9 @@ static int ksmbd_chann_del(struct ksmbd_conn *conn, struct ksmbd_session *sess) {struct channel *chann; +down_write (&sess->chann_lock); chann =xa_erase (&sess->ksmbd_chann_list, (long )conn); +up_write (&sess->chann_lock);if (!chann)return -ENOENT ;
@@ -395,6 +399,7 @@ static struct ksmbd_session *__session_create(int protocol) sess->sequence_number =1 ;rwlock_init (&sess->tree_conns_lock);atomic_set (&sess->refcnt,1 ); +init_rwsem (&sess->chann_lock); ret =__init_smb2_session (sess);if (ret)
fs/ksmbd/mgmt/user_session.h +1 -0
@@ -48,6 +48,7 @@ struct ksmbd_session {char sess_key[CIFS_KEY_SIZE ];struct hlist_node hlist; +struct rw_semaphore chann_lock;struct xarray ksmbd_chann_list;struct xarray tree_conns;struct ida tree_conn_ida;
fs/ksmbd/smb2pdu.c +11 -1
@@ -78,7 +78,13 @@ static inline bool check_session_id(struct ksmbd_conn *conn, u64 id)struct channel *lookup_chann_list (struct ksmbd_session *sess,struct ksmbd_conn *conn) { -return xa_load (&sess->ksmbd_chann_list, (long )conn); +struct channel *chann; + +down_read (&sess->chann_lock); + chann =xa_load (&sess->ksmbd_chann_list, (long )conn); +up_read (&sess->chann_lock); + +return chann; }/**
@@ -1570,7 +1576,9 @@ static int ntlm_authenticate(struct ksmbd_work *work,return -ENOMEM ; chann->conn = conn; +down_write (&sess->chann_lock);xa_store (&sess->ksmbd_chann_list, (long )conn, chann,GFP_KERNEL ); +up_write (&sess->chann_lock); } }
@@ -1667,7 +1675,9 @@ static int krb5_authenticate(struct ksmbd_work *work,return -ENOMEM ; chann->conn = conn; +down_write (&sess->chann_lock);xa_store (&sess->ksmbd_chann_list, (long )conn, chann,GFP_KERNEL ); +up_write (&sess->chann_lock); } }
--
2.43.0
Sasha Levin
maintainerQuoted 9 lines · Kai Aizen
From: Namjae Jeon <[email protected]>
[ Upstream commit
4f3a06cc57976cafa8c6f716646be6c79a99e485]
ksmbd_chann_listxarray lacks synchronization, allowing use-after-free in multi-channel sessions (betweenlookup_chann_list()andksmbd_chann_del).Adds
rw_semaphorechann_lockto structksmbd_sessionand protects all xa_load/xa_store/xa_erase accesses.
Thanks for the backport. Unfortunately I'm holding off on queuing this (and the 6.1.y / 5.15.y siblings) for now.
The backport is faithful to upstream, but on closer review the upstream commit 4f3a06cc5797 itself does not fully cover the race: there are xa_for_each() / xa_empty() / xa_load() call sites that remain unprotected after the patch. Shipping just this commit to the LTS trees would leave the same UAF window open.
--
Thanks,
Sasha