[PATCH 3/6] nvme-tcp: require the R2T offset to match the data sent
From: shao.mingyin
Date: Tue Nov 10 2026 - 11:17:03 EST
From: Shao Mingyin <shao.mingyin@xxxxxxxxxx>
nvme_tcp_handle_r2t() rejects offsets below data_sent but accepts
larger offsets. The send iterator still points at data_sent, so the
next H2CData PDU carries bytes from that position while advertising the
larger offset. A target that accepts the PDU can place the data at the
wrong position; the Linux target rejects it and fails the connection.
Require the R2T offset to equal data_sent, rejecting the invalid request
before transmitting data with a mismatched offset.
Fixes: 3f2304f8c6d6 ("nvme-tcp: add NVMe over TCP host driver")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Shao Mingyin <shao.mingyin@xxxxxxxxxx>
---
Tested on 7.3.0-next-20261030 (QEMU/TCG guest) with the nvmet-tcp
target on 127.0.0.1; no extra hardware is needed.
A test-only hook in the nvmet-tcp target shifts the R2T offset by one
4 KiB block. The 4 KiB write to a loopback namespace is then answered
with an R2T at offset 4096 although the host has sent 0 bytes, so the
host either transmits an H2CData PDU with the wrong offset (unpatched)
or rejects the R2T (patched):
unpatched patched
nvmet_tcp: ttag 2 unexpected data nvme nvme0: req 99 unexpected
offset 4096 (expected 0) r2t offset 4096 (expected 0)
In the unpatched case the target detects the mismatched H2CData offset
and rejects it. This test demonstrates transmission of an incorrect
offset, not a successful corrupted write. With the patch the host
rejects the R2T before transmitting H2CData.
diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
index bc46e5f3eaa7..2672aeae086a 100644
--- a/drivers/nvme/host/tcp.c
+++ b/drivers/nvme/host/tcp.c
@@ -846,7 +846,7 @@ static int nvme_tcp_handle_r2t(struct nvme_tcp_queue *queue,
return -EPROTO;
}
- if (unlikely(r2t_offset < req->data_sent)) {
+ if (unlikely(r2t_offset != req->data_sent)) {
dev_err(queue->ctrl->ctrl.device,
"req %d unexpected r2t offset %u (expected %zu)\n",
rq->tag, r2t_offset, req->data_sent);