aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorJoshua Rogers <linux@joshua.hu>2025-11-07 00:15:37 +0800
committerSteve French <stfrench@microsoft.com>2025-11-09 17:47:49 -0600
commite904d81ad1c04394e1cda4610de799a006cc141c (patch)
tree09f004a98b2725bc7fdda9b4ed8f3c8fa43520c1
parentLinux 6.18-rc5 (diff)
downloadwireguard-linux-e904d81ad1c04394e1cda4610de799a006cc141c.tar.xz
wireguard-linux-e904d81ad1c04394e1cda4610de799a006cc141c.zip
smb: server: rdma: avoid unmapping posted recv on accept failure
smb_direct_prepare_negotiation() posts a recv and then, if smb_direct_accept_client() fails, calls put_recvmsg() on the same buffer. That unmaps and recycles a buffer that is still posted on the QP., which can lead to device DMA into unmapped or reused memory. Track whether the recv was posted and only return it if it was never posted. If accept fails after a post, leave it for teardown to drain and complete safely. Signed-off-by: Joshua Rogers <linux@joshua.hu> Acked-by: Namjae Jeon <linkinjeon@kernel.org> Signed-off-by: Steve French <stfrench@microsoft.com>
-rw-r--r--fs/smb/server/transport_rdma.c11
1 files changed, 10 insertions, 1 deletions
diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c
index 5d3b48e77012..3d8d8cb456c1 100644
--- a/fs/smb/server/transport_rdma.c
+++ b/fs/smb/server/transport_rdma.c
@@ -1883,6 +1883,7 @@ static int smb_direct_accept_client(struct smbdirect_socket *sc)
static int smb_direct_prepare_negotiation(struct smbdirect_socket *sc)
{
struct smbdirect_recv_io *recvmsg;
+ bool recv_posted = false;
int ret;
WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_CREATED);
@@ -1899,6 +1900,7 @@ static int smb_direct_prepare_negotiation(struct smbdirect_socket *sc)
pr_err("Can't post recv: %d\n", ret);
goto out_err;
}
+ recv_posted = true;
ret = smb_direct_accept_client(sc);
if (ret) {
@@ -1908,7 +1910,14 @@ static int smb_direct_prepare_negotiation(struct smbdirect_socket *sc)
return 0;
out_err:
- put_recvmsg(sc, recvmsg);
+ /*
+ * If the recv was never posted, return it to the free list.
+ * If it was posted, leave it alone so disconnect teardown can
+ * drain the QP and complete it (flush) and the completion path
+ * will unmap it exactly once.
+ */
+ if (!recv_posted)
+ put_recvmsg(sc, recvmsg);
return ret;
}