* FAILED: patch "[PATCH] nvme-tcp: fix host memory disclosure on R2T for a read" failed to apply to 5.10-stable tree
@ 2026-09-03 14:36 gregkh
2026-09-09 10:45 ` [PATCH 5.10.y 1/2] nvme-tcp: validate R2T PDU in nvme_tcp_handle_r2t() Sasha Levin
0 siblings, 1 reply; 3+ messages in thread
From: gregkh @ 2026-09-03 14:36 UTC (permalink / raw)
To: yhlee, kbusch; +Cc: stable
The patch below does not apply to the 5.10-stable tree.
If someone wants it applied there, or to any other stable or longterm
tree, then please email the backport, including the original git commit
id to <stable@vger.kernel.org>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.10.y
git checkout FETCH_HEAD
git cherry-pick -x 6efbc52237facda35d2d874fe1765bb4839275d8
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<stable@vger.kernel.org>' --in-reply-to '2026090304-lazily-cauterize-57c7@gregkh' --subject-prefix 'PATCH 5.10.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 6efbc52237facda35d2d874fe1765bb4839275d8 Mon Sep 17 00:00:00 2001
From: Yehyeong Lee <yhlee@isslab.korea.ac.kr>
Date: Wed, 29 Jul 2026 14:46:02 +0900
Subject: [PATCH] nvme-tcp: fix host memory disclosure on R2T for a read
command
nvme_tcp_handle_r2t() does not check the direction of the request the
R2T refers to. A malicious controller can send an R2T for a READ and
the host will answer it: nvme_tcp_setup_h2c_data_pdu() builds the
H2CData header and nvme_tcp_try_send_data() sends the request's data
buffer. That buffer is the READ destination, so its contents go to the
controller.
The command then completes normally and nothing is logged.
Against a test controller that answers every READ with an R2T, a 4096
byte buffered read returned all 4096 bytes, split over two R2Ts. The
pages contained stale kernel data, including an array of struct page
pointers.
Reject an R2T for a request that is not a write.
Fixes: 3f2304f8c6d6 ("nvme-tcp: add NVMe over TCP host driver")
Cc: stable@vger.kernel.org
Signed-off-by: Yehyeong Lee <yhlee@isslab.korea.ac.kr>
Signed-off-by: Keith Busch <kbusch@kernel.org>
diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
index 46c2acc6abe0..62c5e38f5207 100644
--- a/drivers/nvme/host/tcp.c
+++ b/drivers/nvme/host/tcp.c
@@ -779,6 +779,13 @@ static int nvme_tcp_handle_r2t(struct nvme_tcp_queue *queue,
}
req = blk_mq_rq_to_pdu(rq);
+ if (unlikely(rq_data_dir(rq) != WRITE)) {
+ dev_err(queue->ctrl->ctrl.device,
+ "req %d unexpected r2t for a non-write command\n",
+ rq->tag);
+ return -EPROTO;
+ }
+
if (unlikely(!r2t_length)) {
dev_err(queue->ctrl->ctrl.device,
"req %d r2t len is %u, probably a bug...\n",
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH 5.10.y 1/2] nvme-tcp: validate R2T PDU in nvme_tcp_handle_r2t()
2026-09-03 14:36 FAILED: patch "[PATCH] nvme-tcp: fix host memory disclosure on R2T for a read" failed to apply to 5.10-stable tree gregkh
@ 2026-09-09 10:45 ` Sasha Levin
2026-09-09 10:45 ` [PATCH 5.10.y 2/2] nvme-tcp: fix host memory disclosure on R2T for a read command Sasha Levin
0 siblings, 1 reply; 3+ messages in thread
From: Sasha Levin @ 2026-09-09 10:45 UTC (permalink / raw)
To: stable; +Cc: Varun Prakash, Sagi Grimberg, Christoph Hellwig, Sasha Levin
From: Varun Prakash <varun@chelsio.com>
[ Upstream commit 1d3ef9c3a39e04be31155c27ebf80342350c3abf ]
If maxh2cdata < r2t_length then driver will form multiple
H2CData PDUs, validate R2T PDU in nvme_tcp_handle_r2t() to
reuse nvme_tcp_setup_h2c_data_pdu().
Also set req->state to NVME_TCP_SEND_H2C_PDU in
nvme_tcp_setup_h2c_data_pdu().
Signed-off-by: Varun Prakash <varun@chelsio.com>
Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Stable-dep-of: 6efbc52237fa ("nvme-tcp: fix host memory disclosure on R2T for a read command")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/nvme/host/tcp.c | 55 ++++++++++++++++++-----------------------
1 file changed, 24 insertions(+), 31 deletions(-)
diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
index 7d9ebd4f7947b..01d42b854be2d 100644
--- a/drivers/nvme/host/tcp.c
+++ b/drivers/nvme/host/tcp.c
@@ -598,7 +598,7 @@ static int nvme_tcp_handle_comp(struct nvme_tcp_queue *queue,
return ret;
}
-static int nvme_tcp_setup_h2c_data_pdu(struct nvme_tcp_request *req,
+static void nvme_tcp_setup_h2c_data_pdu(struct nvme_tcp_request *req,
struct nvme_tcp_r2t_pdu *pdu)
{
struct nvme_tcp_data_pdu *data = req->pdu;
@@ -607,32 +607,11 @@ static int nvme_tcp_setup_h2c_data_pdu(struct nvme_tcp_request *req,
u8 hdgst = nvme_tcp_hdgst_len(queue);
u8 ddgst = nvme_tcp_ddgst_len(queue);
+ req->state = NVME_TCP_SEND_H2C_PDU;
+ req->offset = 0;
req->pdu_len = le32_to_cpu(pdu->r2t_length);
req->pdu_sent = 0;
- if (unlikely(!req->pdu_len)) {
- dev_err(queue->ctrl->ctrl.device,
- "req %d r2t len is %u, probably a bug...\n",
- rq->tag, req->pdu_len);
- return -EPROTO;
- }
-
- if (unlikely(req->data_sent + req->pdu_len > req->data_len)) {
- dev_err(queue->ctrl->ctrl.device,
- "req %d r2t len %u exceeded data len %u (%zu sent)\n",
- rq->tag, req->pdu_len, req->data_len,
- req->data_sent);
- return -EPROTO;
- }
-
- if (unlikely(le32_to_cpu(pdu->r2t_offset) < req->data_sent)) {
- dev_err(queue->ctrl->ctrl.device,
- "req %d unexpected r2t offset %u (expected %zu)\n",
- rq->tag, le32_to_cpu(pdu->r2t_offset),
- req->data_sent);
- return -EPROTO;
- }
-
memset(data, 0, sizeof(*data));
data->hdr.type = nvme_tcp_h2c_data;
data->hdr.flags = NVME_TCP_F_DATA_LAST;
@@ -648,7 +627,6 @@ static int nvme_tcp_setup_h2c_data_pdu(struct nvme_tcp_request *req,
data->command_id = nvme_cid(rq);
data->data_offset = pdu->r2t_offset;
data->data_length = cpu_to_le32(req->pdu_len);
- return 0;
}
static int nvme_tcp_handle_r2t(struct nvme_tcp_queue *queue,
@@ -656,7 +634,7 @@ static int nvme_tcp_handle_r2t(struct nvme_tcp_queue *queue,
{
struct nvme_tcp_request *req;
struct request *rq;
- int ret;
+ u32 r2t_length = le32_to_cpu(pdu->r2t_length);
rq = nvme_find_rq(nvme_tcp_tagset(queue), pdu->command_id);
if (!rq) {
@@ -667,13 +645,28 @@ static int nvme_tcp_handle_r2t(struct nvme_tcp_queue *queue,
}
req = blk_mq_rq_to_pdu(rq);
- ret = nvme_tcp_setup_h2c_data_pdu(req, pdu);
- if (unlikely(ret))
- return ret;
+ if (unlikely(!r2t_length)) {
+ dev_err(queue->ctrl->ctrl.device,
+ "req %d r2t len is %u, probably a bug...\n",
+ rq->tag, r2t_length);
+ return -EPROTO;
+ }
- req->state = NVME_TCP_SEND_H2C_PDU;
- req->offset = 0;
+ if (unlikely(req->data_sent + r2t_length > req->data_len)) {
+ dev_err(queue->ctrl->ctrl.device,
+ "req %d r2t len %u exceeded data len %u (%zu sent)\n",
+ rq->tag, r2t_length, req->data_len, req->data_sent);
+ return -EPROTO;
+ }
+
+ if (unlikely(le32_to_cpu(pdu->r2t_offset) < req->data_sent)) {
+ dev_err(queue->ctrl->ctrl.device,
+ "req %d unexpected r2t offset %u (expected %zu)\n",
+ rq->tag, le32_to_cpu(pdu->r2t_offset), req->data_sent);
+ return -EPROTO;
+ }
+ nvme_tcp_setup_h2c_data_pdu(req, pdu);
nvme_tcp_queue_request(req, false, true);
return 0;
--
2.53.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH 5.10.y 2/2] nvme-tcp: fix host memory disclosure on R2T for a read command
2026-09-09 10:45 ` [PATCH 5.10.y 1/2] nvme-tcp: validate R2T PDU in nvme_tcp_handle_r2t() Sasha Levin
@ 2026-09-09 10:45 ` Sasha Levin
0 siblings, 0 replies; 3+ messages in thread
From: Sasha Levin @ 2026-09-09 10:45 UTC (permalink / raw)
To: stable; +Cc: Yehyeong Lee, Keith Busch, Sasha Levin
From: Yehyeong Lee <yhlee@isslab.korea.ac.kr>
[ Upstream commit 6efbc52237facda35d2d874fe1765bb4839275d8 ]
nvme_tcp_handle_r2t() does not check the direction of the request the
R2T refers to. A malicious controller can send an R2T for a READ and
the host will answer it: nvme_tcp_setup_h2c_data_pdu() builds the
H2CData header and nvme_tcp_try_send_data() sends the request's data
buffer. That buffer is the READ destination, so its contents go to the
controller.
The command then completes normally and nothing is logged.
Against a test controller that answers every READ with an R2T, a 4096
byte buffered read returned all 4096 bytes, split over two R2Ts. The
pages contained stale kernel data, including an array of struct page
pointers.
Reject an R2T for a request that is not a write.
Fixes: 3f2304f8c6d6 ("nvme-tcp: add NVMe over TCP host driver")
Cc: stable@vger.kernel.org
Signed-off-by: Yehyeong Lee <yhlee@isslab.korea.ac.kr>
Signed-off-by: Keith Busch <kbusch@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/nvme/host/tcp.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
index 01d42b854be2d..c9436767534a7 100644
--- a/drivers/nvme/host/tcp.c
+++ b/drivers/nvme/host/tcp.c
@@ -645,6 +645,13 @@ static int nvme_tcp_handle_r2t(struct nvme_tcp_queue *queue,
}
req = blk_mq_rq_to_pdu(rq);
+ if (unlikely(rq_data_dir(rq) != WRITE)) {
+ dev_err(queue->ctrl->ctrl.device,
+ "req %d unexpected r2t for a non-write command\n",
+ rq->tag);
+ return -EPROTO;
+ }
+
if (unlikely(!r2t_length)) {
dev_err(queue->ctrl->ctrl.device,
"req %d r2t len is %u, probably a bug...\n",
--
2.53.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-09-09 10:45 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-03 14:36 FAILED: patch "[PATCH] nvme-tcp: fix host memory disclosure on R2T for a read" failed to apply to 5.10-stable tree gregkh
2026-09-09 10:45 ` [PATCH 5.10.y 1/2] nvme-tcp: validate R2T PDU in nvme_tcp_handle_r2t() Sasha Levin
2026-09-09 10:45 ` [PATCH 5.10.y 2/2] nvme-tcp: fix host memory disclosure on R2T for a read command Sasha Levin
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.