* [PATCH 6.6.y] ksmbd: add chann_lock to protect ksmbd_chann_list xarray
@ 2026-05-01 22:51 Kai Aizen
2026-05-01 22:51 ` [PATCH 6.1.y] " Kai Aizen
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Kai Aizen @ 2026-05-01 22:51 UTC (permalink / raw)
To: stable; +Cc: gregkh, linkinjeon, linux-cifs, samba-technical
From: Namjae Jeon <linkinjeon@kernel.org>
[ 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
Cc: stable@vger.kernel.org # 6.6.y
Reported-by: Igor Stepansky <igor.stepansky@orca.security>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
[backport for linux-6.6.y, verified 2026-05-01]
---
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(-)
diff --git a/fs/smb/server/mgmt/user_session.c b/fs/smb/server/mgmt/user_session.c
--- a/fs/smb/server/mgmt/user_session.c
+++ b/fs/smb/server/mgmt/user_session.c
@@ -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)
diff --git a/fs/smb/server/mgmt/user_session.h b/fs/smb/server/mgmt/user_session.h
--- a/fs/smb/server/mgmt/user_session.h
+++ b/fs/smb/server/mgmt/user_session.h
@@ -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;
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -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
^ permalink raw reply [flat|nested] 4+ messages in thread* [PATCH 6.1.y] ksmbd: add chann_lock to protect ksmbd_chann_list xarray
2026-05-01 22:51 [PATCH 6.6.y] ksmbd: add chann_lock to protect ksmbd_chann_list xarray Kai Aizen
@ 2026-05-01 22:51 ` Kai Aizen
2026-05-01 22:51 ` [PATCH 5.15.y] " Kai Aizen
2026-05-03 18:17 ` [PATCH 6.6.y] " Sasha Levin
2 siblings, 0 replies; 4+ messages in thread
From: Kai Aizen @ 2026-05-01 22:51 UTC (permalink / raw)
To: stable; +Cc: gregkh, linkinjeon, linux-cifs, samba-technical
From: Namjae Jeon <linkinjeon@kernel.org>
[ 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
Cc: stable@vger.kernel.org # 6.1.y
Reported-by: Igor Stepansky <igor.stepansky@orca.security>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
[backport for linux-6.1.y, verified 2026-05-01]
---
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(-)
diff --git a/fs/smb/server/mgmt/user_session.c b/fs/smb/server/mgmt/user_session.c
--- a/fs/smb/server/mgmt/user_session.c
+++ b/fs/smb/server/mgmt/user_session.c
@@ -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)
diff --git a/fs/smb/server/mgmt/user_session.h b/fs/smb/server/mgmt/user_session.h
--- a/fs/smb/server/mgmt/user_session.h
+++ b/fs/smb/server/mgmt/user_session.h
@@ -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;
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -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
^ permalink raw reply [flat|nested] 4+ messages in thread* [PATCH 5.15.y] ksmbd: add chann_lock to protect ksmbd_chann_list xarray
2026-05-01 22:51 [PATCH 6.6.y] ksmbd: add chann_lock to protect ksmbd_chann_list xarray Kai Aizen
2026-05-01 22:51 ` [PATCH 6.1.y] " Kai Aizen
@ 2026-05-01 22:51 ` Kai Aizen
2026-05-03 18:17 ` [PATCH 6.6.y] " Sasha Levin
2 siblings, 0 replies; 4+ messages in thread
From: Kai Aizen @ 2026-05-01 22:51 UTC (permalink / raw)
To: stable; +Cc: gregkh, linkinjeon, linux-cifs, samba-technical
From: Namjae Jeon <linkinjeon@kernel.org>
[ 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
Cc: stable@vger.kernel.org # 5.15.y
Reported-by: Igor Stepansky <igor.stepansky@orca.security>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
[backport for linux-5.15.y, verified 2026-05-01]
---
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(-)
diff --git a/fs/ksmbd/mgmt/user_session.c b/fs/ksmbd/mgmt/user_session.c
--- a/fs/ksmbd/mgmt/user_session.c
+++ b/fs/ksmbd/mgmt/user_session.c
@@ -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)
diff --git a/fs/ksmbd/mgmt/user_session.h b/fs/ksmbd/mgmt/user_session.h
--- a/fs/ksmbd/mgmt/user_session.h
+++ b/fs/ksmbd/mgmt/user_session.h
@@ -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;
diff --git a/fs/ksmbd/smb2pdu.c b/fs/ksmbd/smb2pdu.c
--- a/fs/ksmbd/smb2pdu.c
+++ b/fs/ksmbd/smb2pdu.c
@@ -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
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [PATCH 6.6.y] ksmbd: add chann_lock to protect ksmbd_chann_list xarray
2026-05-01 22:51 [PATCH 6.6.y] ksmbd: add chann_lock to protect ksmbd_chann_list xarray Kai Aizen
2026-05-01 22:51 ` [PATCH 6.1.y] " Kai Aizen
2026-05-01 22:51 ` [PATCH 5.15.y] " Kai Aizen
@ 2026-05-03 18:17 ` Sasha Levin
2 siblings, 0 replies; 4+ messages in thread
From: Sasha Levin @ 2026-05-03 18:17 UTC (permalink / raw)
To: stable; +Cc: gregkh, linkinjeon, linux-cifs, samba-technical, Kai Aizen
On Sat, May 02, 2026 at 01:51:50AM +0300, Kai Aizen wrote:
> From: Namjae Jeon <linkinjeon@kernel.org>
>
> [ 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.
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
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-05-03 18:17 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-01 22:51 [PATCH 6.6.y] ksmbd: add chann_lock to protect ksmbd_chann_list xarray Kai Aizen
2026-05-01 22:51 ` [PATCH 6.1.y] " Kai Aizen
2026-05-01 22:51 ` [PATCH 5.15.y] " Kai Aizen
2026-05-03 18:17 ` [PATCH 6.6.y] " Sasha Levin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox