* [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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.