* [PATCH 0/4] smb:server: fix possible use after free problems
@ 2025-08-04 12:15 Stefan Metzmacher
2025-08-04 12:15 ` [PATCH 1/4] smb: server: remove separate empty_recvmsg_queue Stefan Metzmacher
` (4 more replies)
0 siblings, 5 replies; 6+ messages in thread
From: Stefan Metzmacher @ 2025-08-04 12:15 UTC (permalink / raw)
To: linux-cifs, samba-technical; +Cc: metze, Namjae Jeon, Steve French, Tom Talpey
While refactoring the client and server smbdirect code I
noticed a few problems where we might hit use after free
style problems.
In order to allow backports I decided to fix the problems
before trying to move things to common code.
The client has similar problems, I've sent a separate
patchset for the client already.
Stefan Metzmacher (4):
smb: server: remove separate empty_recvmsg_queue
smb: server: make sure we call ib_dma_unmap_single() only if we called
ib_dma_map_single already
smb: server: let recv_done() consitently call
put_recvmsg/smb_direct_disconnect_rdma_connection
smb: server: let recv_done() avoid touching data_transfer after
cleanup/move
fs/smb/server/transport_rdma.c | 97 ++++++++++++----------------------
1 file changed, 35 insertions(+), 62 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 1/4] smb: server: remove separate empty_recvmsg_queue
2025-08-04 12:15 [PATCH 0/4] smb:server: fix possible use after free problems Stefan Metzmacher
@ 2025-08-04 12:15 ` Stefan Metzmacher
2025-08-04 12:15 ` [PATCH 2/4] smb: server: make sure we call ib_dma_unmap_single() only if we called ib_dma_map_single already Stefan Metzmacher
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Stefan Metzmacher @ 2025-08-04 12:15 UTC (permalink / raw)
To: linux-cifs, samba-technical; +Cc: metze, Namjae Jeon, Steve French, Tom Talpey
There's no need to maintain two lists, we can just
have a single list of receive buffers, which are free to use.
Cc: Namjae Jeon <linkinjeon@kernel.org>
Cc: Steve French <smfrench@gmail.com>
Cc: Tom Talpey <tom@talpey.com>
Cc: linux-cifs@vger.kernel.org
Cc: samba-technical@lists.samba.org
Fixes: 0626e6641f6b ("cifsd: add server handler for central processing and tranport layers")
Signed-off-by: Stefan Metzmacher <metze@samba.org>
---
fs/smb/server/transport_rdma.c | 60 +++++-----------------------------
1 file changed, 8 insertions(+), 52 deletions(-)
diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c
index c6cbe0d56e32..393254109fc4 100644
--- a/fs/smb/server/transport_rdma.c
+++ b/fs/smb/server/transport_rdma.c
@@ -129,9 +129,6 @@ struct smb_direct_transport {
spinlock_t recvmsg_queue_lock;
struct list_head recvmsg_queue;
- spinlock_t empty_recvmsg_queue_lock;
- struct list_head empty_recvmsg_queue;
-
int send_credit_target;
atomic_t send_credits;
spinlock_t lock_new_recv_credits;
@@ -276,32 +273,6 @@ static void put_recvmsg(struct smb_direct_transport *t,
spin_unlock(&t->recvmsg_queue_lock);
}
-static struct
-smb_direct_recvmsg *get_empty_recvmsg(struct smb_direct_transport *t)
-{
- struct smb_direct_recvmsg *recvmsg = NULL;
-
- spin_lock(&t->empty_recvmsg_queue_lock);
- if (!list_empty(&t->empty_recvmsg_queue)) {
- recvmsg = list_first_entry(&t->empty_recvmsg_queue,
- struct smb_direct_recvmsg, list);
- list_del(&recvmsg->list);
- }
- spin_unlock(&t->empty_recvmsg_queue_lock);
- return recvmsg;
-}
-
-static void put_empty_recvmsg(struct smb_direct_transport *t,
- struct smb_direct_recvmsg *recvmsg)
-{
- ib_dma_unmap_single(t->cm_id->device, recvmsg->sge.addr,
- recvmsg->sge.length, DMA_FROM_DEVICE);
-
- spin_lock(&t->empty_recvmsg_queue_lock);
- list_add_tail(&recvmsg->list, &t->empty_recvmsg_queue);
- spin_unlock(&t->empty_recvmsg_queue_lock);
-}
-
static void enqueue_reassembly(struct smb_direct_transport *t,
struct smb_direct_recvmsg *recvmsg,
int data_length)
@@ -386,9 +357,6 @@ static struct smb_direct_transport *alloc_transport(struct rdma_cm_id *cm_id)
spin_lock_init(&t->recvmsg_queue_lock);
INIT_LIST_HEAD(&t->recvmsg_queue);
- spin_lock_init(&t->empty_recvmsg_queue_lock);
- INIT_LIST_HEAD(&t->empty_recvmsg_queue);
-
init_waitqueue_head(&t->wait_send_pending);
atomic_set(&t->send_pending, 0);
@@ -554,7 +522,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc)
wc->opcode);
smb_direct_disconnect_rdma_connection(t);
}
- put_empty_recvmsg(t, recvmsg);
+ put_recvmsg(t, recvmsg);
return;
}
@@ -568,7 +536,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc)
switch (recvmsg->type) {
case SMB_DIRECT_MSG_NEGOTIATE_REQ:
if (wc->byte_len < sizeof(struct smb_direct_negotiate_req)) {
- put_empty_recvmsg(t, recvmsg);
+ put_recvmsg(t, recvmsg);
return;
}
t->negotiation_requested = true;
@@ -585,7 +553,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc)
if (wc->byte_len <
offsetof(struct smb_direct_data_transfer, padding)) {
- put_empty_recvmsg(t, recvmsg);
+ put_recvmsg(t, recvmsg);
return;
}
@@ -593,7 +561,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc)
if (data_length) {
if (wc->byte_len < sizeof(struct smb_direct_data_transfer) +
(u64)data_length) {
- put_empty_recvmsg(t, recvmsg);
+ put_recvmsg(t, recvmsg);
return;
}
@@ -613,7 +581,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc)
avail_recvmsg_count = t->count_avail_recvmsg;
spin_unlock(&t->receive_credit_lock);
} else {
- put_empty_recvmsg(t, recvmsg);
+ put_recvmsg(t, recvmsg);
spin_lock(&t->receive_credit_lock);
receive_credits = --(t->recv_credits);
@@ -811,7 +779,6 @@ static void smb_direct_post_recv_credits(struct work_struct *work)
struct smb_direct_recvmsg *recvmsg;
int receive_credits, credits = 0;
int ret;
- int use_free = 1;
spin_lock(&t->receive_credit_lock);
receive_credits = t->recv_credits;
@@ -819,18 +786,9 @@ static void smb_direct_post_recv_credits(struct work_struct *work)
if (receive_credits < t->recv_credit_target) {
while (true) {
- if (use_free)
- recvmsg = get_free_recvmsg(t);
- else
- recvmsg = get_empty_recvmsg(t);
- if (!recvmsg) {
- if (use_free) {
- use_free = 0;
- continue;
- } else {
- break;
- }
- }
+ recvmsg = get_free_recvmsg(t);
+ if (!recvmsg)
+ break;
recvmsg->type = SMB_DIRECT_MSG_DATA_TRANSFER;
recvmsg->first_segment = false;
@@ -1806,8 +1764,6 @@ static void smb_direct_destroy_pools(struct smb_direct_transport *t)
while ((recvmsg = get_free_recvmsg(t)))
mempool_free(recvmsg, t->recvmsg_mempool);
- while ((recvmsg = get_empty_recvmsg(t)))
- mempool_free(recvmsg, t->recvmsg_mempool);
mempool_destroy(t->recvmsg_mempool);
t->recvmsg_mempool = NULL;
--
2.43.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 2/4] smb: server: make sure we call ib_dma_unmap_single() only if we called ib_dma_map_single already
2025-08-04 12:15 [PATCH 0/4] smb:server: fix possible use after free problems Stefan Metzmacher
2025-08-04 12:15 ` [PATCH 1/4] smb: server: remove separate empty_recvmsg_queue Stefan Metzmacher
@ 2025-08-04 12:15 ` Stefan Metzmacher
2025-08-04 12:15 ` [PATCH 3/4] smb: server: let recv_done() consitently call put_recvmsg/smb_direct_disconnect_rdma_connection Stefan Metzmacher
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Stefan Metzmacher @ 2025-08-04 12:15 UTC (permalink / raw)
To: linux-cifs, samba-technical; +Cc: metze, Namjae Jeon, Steve French, Tom Talpey
In case of failures either ib_dma_map_single() might not be called yet
or ib_dma_unmap_single() was already called.
We should make sure put_recvmsg() only calls ib_dma_unmap_single() if needed.
Cc: Namjae Jeon <linkinjeon@kernel.org>
Cc: Steve French <smfrench@gmail.com>
Cc: Tom Talpey <tom@talpey.com>
Cc: linux-cifs@vger.kernel.org
Cc: samba-technical@lists.samba.org
Fixes: 0626e6641f6b ("cifsd: add server handler for central processing and tranport layers")
Signed-off-by: Stefan Metzmacher <metze@samba.org>
---
fs/smb/server/transport_rdma.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c
index 393254109fc4..fac82e60ff80 100644
--- a/fs/smb/server/transport_rdma.c
+++ b/fs/smb/server/transport_rdma.c
@@ -265,8 +265,13 @@ smb_direct_recvmsg *get_free_recvmsg(struct smb_direct_transport *t)
static void put_recvmsg(struct smb_direct_transport *t,
struct smb_direct_recvmsg *recvmsg)
{
- ib_dma_unmap_single(t->cm_id->device, recvmsg->sge.addr,
- recvmsg->sge.length, DMA_FROM_DEVICE);
+ if (likely(recvmsg->sge.length != 0)) {
+ ib_dma_unmap_single(t->cm_id->device,
+ recvmsg->sge.addr,
+ recvmsg->sge.length,
+ DMA_FROM_DEVICE);
+ recvmsg->sge.length = 0;
+ }
spin_lock(&t->recvmsg_queue_lock);
list_add(&recvmsg->list, &t->recvmsg_queue);
@@ -638,6 +643,7 @@ static int smb_direct_post_recv(struct smb_direct_transport *t,
ib_dma_unmap_single(t->cm_id->device,
recvmsg->sge.addr, recvmsg->sge.length,
DMA_FROM_DEVICE);
+ recvmsg->sge.length = 0;
smb_direct_disconnect_rdma_connection(t);
return ret;
}
@@ -1819,6 +1825,7 @@ static int smb_direct_create_pools(struct smb_direct_transport *t)
if (!recvmsg)
goto err;
recvmsg->transport = t;
+ recvmsg->sge.length = 0;
list_add(&recvmsg->list, &t->recvmsg_queue);
}
t->count_avail_recvmsg = t->recv_credit_max;
--
2.43.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 3/4] smb: server: let recv_done() consitently call put_recvmsg/smb_direct_disconnect_rdma_connection
2025-08-04 12:15 [PATCH 0/4] smb:server: fix possible use after free problems Stefan Metzmacher
2025-08-04 12:15 ` [PATCH 1/4] smb: server: remove separate empty_recvmsg_queue Stefan Metzmacher
2025-08-04 12:15 ` [PATCH 2/4] smb: server: make sure we call ib_dma_unmap_single() only if we called ib_dma_map_single already Stefan Metzmacher
@ 2025-08-04 12:15 ` Stefan Metzmacher
2025-08-04 12:15 ` [PATCH 4/4] smb: server: let recv_done() avoid touching data_transfer after cleanup/move Stefan Metzmacher
2025-08-05 8:48 ` [PATCH 0/4] smb:server: fix possible use after free problems Namjae Jeon
4 siblings, 0 replies; 6+ messages in thread
From: Stefan Metzmacher @ 2025-08-04 12:15 UTC (permalink / raw)
To: linux-cifs, samba-technical; +Cc: metze, Namjae Jeon, Steve French, Tom Talpey
We should call put_recvmsg() before smb_direct_disconnect_rdma_connection()
in order to call it before waking up the callers.
In all error cases we should call smb_direct_disconnect_rdma_connection()
in order to avoid stale connections.
Cc: Namjae Jeon <linkinjeon@kernel.org>
Cc: Steve French <smfrench@gmail.com>
Cc: Tom Talpey <tom@talpey.com>
Cc: linux-cifs@vger.kernel.org
Cc: samba-technical@lists.samba.org
Fixes: 0626e6641f6b ("cifsd: add server handler for central processing and tranport layers")
Signed-off-by: Stefan Metzmacher <metze@samba.org>
---
fs/smb/server/transport_rdma.c | 18 +++++++++++++-----
1 file changed, 13 insertions(+), 5 deletions(-)
diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c
index fac82e60ff80..cd8a92fe372b 100644
--- a/fs/smb/server/transport_rdma.c
+++ b/fs/smb/server/transport_rdma.c
@@ -521,13 +521,13 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc)
t = recvmsg->transport;
if (wc->status != IB_WC_SUCCESS || wc->opcode != IB_WC_RECV) {
+ put_recvmsg(t, recvmsg);
if (wc->status != IB_WC_WR_FLUSH_ERR) {
pr_err("Recv error. status='%s (%d)' opcode=%d\n",
ib_wc_status_msg(wc->status), wc->status,
wc->opcode);
smb_direct_disconnect_rdma_connection(t);
}
- put_recvmsg(t, recvmsg);
return;
}
@@ -542,6 +542,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc)
case SMB_DIRECT_MSG_NEGOTIATE_REQ:
if (wc->byte_len < sizeof(struct smb_direct_negotiate_req)) {
put_recvmsg(t, recvmsg);
+ smb_direct_disconnect_rdma_connection(t);
return;
}
t->negotiation_requested = true;
@@ -549,7 +550,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc)
t->status = SMB_DIRECT_CS_CONNECTED;
enqueue_reassembly(t, recvmsg, 0);
wake_up_interruptible(&t->wait_status);
- break;
+ return;
case SMB_DIRECT_MSG_DATA_TRANSFER: {
struct smb_direct_data_transfer *data_transfer =
(struct smb_direct_data_transfer *)recvmsg->packet;
@@ -559,6 +560,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc)
if (wc->byte_len <
offsetof(struct smb_direct_data_transfer, padding)) {
put_recvmsg(t, recvmsg);
+ smb_direct_disconnect_rdma_connection(t);
return;
}
@@ -567,6 +569,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc)
if (wc->byte_len < sizeof(struct smb_direct_data_transfer) +
(u64)data_length) {
put_recvmsg(t, recvmsg);
+ smb_direct_disconnect_rdma_connection(t);
return;
}
@@ -609,11 +612,16 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc)
if (is_receive_credit_post_required(receive_credits, avail_recvmsg_count))
mod_delayed_work(smb_direct_wq,
&t->post_recv_credits_work, 0);
- break;
+ return;
}
- default:
- break;
}
+
+ /*
+ * This is an internal error!
+ */
+ WARN_ON_ONCE(recvmsg->type != SMB_DIRECT_MSG_DATA_TRANSFER);
+ put_recvmsg(t, recvmsg);
+ smb_direct_disconnect_rdma_connection(t);
}
static int smb_direct_post_recv(struct smb_direct_transport *t,
--
2.43.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 4/4] smb: server: let recv_done() avoid touching data_transfer after cleanup/move
2025-08-04 12:15 [PATCH 0/4] smb:server: fix possible use after free problems Stefan Metzmacher
` (2 preceding siblings ...)
2025-08-04 12:15 ` [PATCH 3/4] smb: server: let recv_done() consitently call put_recvmsg/smb_direct_disconnect_rdma_connection Stefan Metzmacher
@ 2025-08-04 12:15 ` Stefan Metzmacher
2025-08-05 8:48 ` [PATCH 0/4] smb:server: fix possible use after free problems Namjae Jeon
4 siblings, 0 replies; 6+ messages in thread
From: Stefan Metzmacher @ 2025-08-04 12:15 UTC (permalink / raw)
To: linux-cifs, samba-technical; +Cc: metze, Namjae Jeon, Steve French, Tom Talpey
Calling enqueue_reassembly() and wake_up_interruptible(&t->wait_reassembly_queue)
or put_receive_buffer() means the recvmsg/data_transfer pointer might
get re-used by another thread, which means these should be
the last operations before calling return.
Cc: Namjae Jeon <linkinjeon@kernel.org>
Cc: Steve French <smfrench@gmail.com>
Cc: Tom Talpey <tom@talpey.com>
Cc: linux-cifs@vger.kernel.org
Cc: samba-technical@lists.samba.org
Fixes: 0626e6641f6b ("cifsd: add server handler for central processing and tranport layers")
Signed-off-by: Stefan Metzmacher <metze@samba.org>
---
fs/smb/server/transport_rdma.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c
index cd8a92fe372b..8d366db5f605 100644
--- a/fs/smb/server/transport_rdma.c
+++ b/fs/smb/server/transport_rdma.c
@@ -581,16 +581,11 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc)
else
t->full_packet_received = true;
- enqueue_reassembly(t, recvmsg, (int)data_length);
- wake_up_interruptible(&t->wait_reassembly_queue);
-
spin_lock(&t->receive_credit_lock);
receive_credits = --(t->recv_credits);
avail_recvmsg_count = t->count_avail_recvmsg;
spin_unlock(&t->receive_credit_lock);
} else {
- put_recvmsg(t, recvmsg);
-
spin_lock(&t->receive_credit_lock);
receive_credits = --(t->recv_credits);
avail_recvmsg_count = ++(t->count_avail_recvmsg);
@@ -612,6 +607,13 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc)
if (is_receive_credit_post_required(receive_credits, avail_recvmsg_count))
mod_delayed_work(smb_direct_wq,
&t->post_recv_credits_work, 0);
+
+ if (data_length) {
+ enqueue_reassembly(t, recvmsg, (int)data_length);
+ wake_up_interruptible(&t->wait_reassembly_queue);
+ } else
+ put_recvmsg(t, recvmsg);
+
return;
}
}
--
2.43.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH 0/4] smb:server: fix possible use after free problems
2025-08-04 12:15 [PATCH 0/4] smb:server: fix possible use after free problems Stefan Metzmacher
` (3 preceding siblings ...)
2025-08-04 12:15 ` [PATCH 4/4] smb: server: let recv_done() avoid touching data_transfer after cleanup/move Stefan Metzmacher
@ 2025-08-05 8:48 ` Namjae Jeon
4 siblings, 0 replies; 6+ messages in thread
From: Namjae Jeon @ 2025-08-05 8:48 UTC (permalink / raw)
To: Stefan Metzmacher; +Cc: linux-cifs, samba-technical, Steve French, Tom Talpey
On Mon, Aug 4, 2025 at 9:16 PM Stefan Metzmacher via samba-technical
<samba-technical@lists.samba.org> wrote:
>
> While refactoring the client and server smbdirect code I
> noticed a few problems where we might hit use after free
> style problems.
>
> In order to allow backports I decided to fix the problems
> before trying to move things to common code.
>
> The client has similar problems, I've sent a separate
> patchset for the client already.
>
> Stefan Metzmacher (4):
> smb: server: remove separate empty_recvmsg_queue
> smb: server: make sure we call ib_dma_unmap_single() only if we called
> ib_dma_map_single already
> smb: server: let recv_done() consitently call
> put_recvmsg/smb_direct_disconnect_rdma_connection
> smb: server: let recv_done() avoid touching data_transfer after
> cleanup/move
I have directly fixed a typo : consitently -> consistently
Applied 4 patches into #ksmbd-for-next-next.
Thanks!
>
> fs/smb/server/transport_rdma.c | 97 ++++++++++++----------------------
> 1 file changed, 35 insertions(+), 62 deletions(-)
>
> --
> 2.43.0
>
>
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2025-08-05 8:48 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-04 12:15 [PATCH 0/4] smb:server: fix possible use after free problems Stefan Metzmacher
2025-08-04 12:15 ` [PATCH 1/4] smb: server: remove separate empty_recvmsg_queue Stefan Metzmacher
2025-08-04 12:15 ` [PATCH 2/4] smb: server: make sure we call ib_dma_unmap_single() only if we called ib_dma_map_single already Stefan Metzmacher
2025-08-04 12:15 ` [PATCH 3/4] smb: server: let recv_done() consitently call put_recvmsg/smb_direct_disconnect_rdma_connection Stefan Metzmacher
2025-08-04 12:15 ` [PATCH 4/4] smb: server: let recv_done() avoid touching data_transfer after cleanup/move Stefan Metzmacher
2025-08-05 8:48 ` [PATCH 0/4] smb:server: fix possible use after free problems Namjae Jeon
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).