Skip to content

Commit 44e2b63

Browse files
committed
nvme-tcp: fix potential memory corruption in nvme_tcp_recv_pdu()
jira VULN-56026 cve CVE-2025-21927 commit-author Maurizio Lombardi <[email protected]> commit ad95bab upstream-diff Removed `nvme_tcp_c2h_term' case from `nvme_tcp_recv_pdu_supported' for the sake of consistency of `nvme_tcp_recv_pdu''s behavior relative to the upstream version, between the cases of proper and improper header. (What could be considered as "`c2h_term' type support" started with 84e0090 commit, not included in `ciqlts9_2''s history, so `nvme_tcp_recv_pdu_supported' in `ciqlts9_2' shouldn't report the `nvme_tcp_c2h_term' type as supported.) nvme_tcp_recv_pdu() doesn't check the validity of the header length. When header digests are enabled, a target might send a packet with an invalid header length (e.g. 255), causing nvme_tcp_verify_hdgst() to access memory outside the allocated area and cause memory corruptions by overwriting it with the calculated digest. Fix this by rejecting packets with an unexpected header length. Fixes: 3f2304f ("nvme-tcp: add NVMe over TCP host driver") Signed-off-by: Maurizio Lombardi <[email protected]> Reviewed-by: Sagi Grimberg <[email protected]> Signed-off-by: Keith Busch <[email protected]> (cherry picked from commit ad95bab) Signed-off-by: Brett Mastbergen <[email protected]>
1 parent 727af46 commit 44e2b63

File tree

1 file changed

+28
-3
lines changed

1 file changed

+28
-3
lines changed

drivers/nvme/host/tcp.c

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,18 @@ static inline int nvme_tcp_queue_id(struct nvme_tcp_queue *queue)
152152
return queue - queue->ctrl->queues;
153153
}
154154

155+
static inline bool nvme_tcp_recv_pdu_supported(enum nvme_tcp_pdu_type type)
156+
{
157+
switch (type) {
158+
case nvme_tcp_c2h_data:
159+
case nvme_tcp_r2t:
160+
case nvme_tcp_rsp:
161+
return true;
162+
default:
163+
return false;
164+
}
165+
}
166+
155167
static inline struct blk_mq_tags *nvme_tcp_tagset(struct nvme_tcp_queue *queue)
156168
{
157169
u32 queue_idx = nvme_tcp_queue_id(queue);
@@ -674,6 +686,16 @@ static int nvme_tcp_recv_pdu(struct nvme_tcp_queue *queue, struct sk_buff *skb,
674686
return 0;
675687

676688
hdr = queue->pdu;
689+
if (unlikely(hdr->hlen != sizeof(struct nvme_tcp_rsp_pdu))) {
690+
if (!nvme_tcp_recv_pdu_supported(hdr->type))
691+
goto unsupported_pdu;
692+
693+
dev_err(queue->ctrl->ctrl.device,
694+
"pdu type %d has unexpected header length (%d)\n",
695+
hdr->type, hdr->hlen);
696+
return -EPROTO;
697+
}
698+
677699
if (queue->hdr_digest) {
678700
ret = nvme_tcp_verify_hdgst(queue, queue->pdu, hdr->hlen);
679701
if (unlikely(ret))
@@ -697,10 +719,13 @@ static int nvme_tcp_recv_pdu(struct nvme_tcp_queue *queue, struct sk_buff *skb,
697719
nvme_tcp_init_recv_ctx(queue);
698720
return nvme_tcp_handle_r2t(queue, (void *)queue->pdu);
699721
default:
700-
dev_err(queue->ctrl->ctrl.device,
701-
"unsupported pdu type (%d)\n", hdr->type);
702-
return -EINVAL;
722+
goto unsupported_pdu;
703723
}
724+
725+
unsupported_pdu:
726+
dev_err(queue->ctrl->ctrl.device,
727+
"unsupported pdu type (%d)\n", hdr->type);
728+
return -EINVAL;
704729
}
705730

706731
static inline void nvme_tcp_end_request(struct request *rq, u16 status)

0 commit comments

Comments
 (0)