Commit e904d81a authored by Joshua Rogers's avatar Joshua Rogers Committed by Steve French
Browse files

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: default avatarJoshua Rogers <linux@joshua.hu>
Acked-by: default avatarNamjae Jeon <linkinjeon@kernel.org>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent e9a6fb0b
Loading
Loading
Loading
Loading
+10 −1
Original line number Diff line number Diff line
@@ -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,6 +1910,13 @@ static int smb_direct_prepare_negotiation(struct smbdirect_socket *sc)

	return 0;
out_err:
	/*
	 * 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;
}