]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
smb: server: rdma: avoid unmapping posted recv on accept failure
authorJoshua Rogers <linux@joshua.hu>
Thu, 6 Nov 2025 16:15:37 +0000 (00:15 +0800)
committerSteve French <stfrench@microsoft.com>
Sun, 9 Nov 2025 23:47:49 +0000 (17:47 -0600)
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>
fs/smb/server/transport_rdma.c

index 5d3b48e770125abd4df8994737ff21f0d614b6cd..3d8d8cb456c1146492b86237d68797ef1e58d0fb 100644 (file)
@@ -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;
 }