Skip to content

Commit a8ca78a

Browse files
pvts-matPlaidCat
authored andcommitted
nvme-tcp: fix potential memory corruption in nvme_tcp_recv_pdu()
jira VULN-56029 cve CVE-2025-21927 commit-author Maurizio Lombardi <mlombard@redhat.com> 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_4''s history, so `nvme_tcp_recv_pdu_supported' in `ciqlts9_4' 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 <mlombard@redhat.com> Reviewed-by: Sagi Grimberg <sagi@grimberg.me> Signed-off-by: Keith Busch <kbusch@kernel.org> (cherry picked from commit ad95bab) Signed-off-by: Marcin Wcisło <marcin.wcislo@conclusive.pl>
1 parent be2f55f commit a8ca78a

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
@@ -189,6 +189,18 @@ static inline int nvme_tcp_queue_id(struct nvme_tcp_queue *queue)
189189
return queue - queue->ctrl->queues;
190190
}
191191

192+
static inline bool nvme_tcp_recv_pdu_supported(enum nvme_tcp_pdu_type type)
193+
{
194+
switch (type) {
195+
case nvme_tcp_c2h_data:
196+
case nvme_tcp_r2t:
197+
case nvme_tcp_rsp:
198+
return true;
199+
default:
200+
return false;
201+
}
202+
}
203+
192204
static inline struct blk_mq_tags *nvme_tcp_tagset(struct nvme_tcp_queue *queue)
193205
{
194206
u32 queue_idx = nvme_tcp_queue_id(queue);
@@ -728,6 +740,16 @@ static int nvme_tcp_recv_pdu(struct nvme_tcp_queue *queue, struct sk_buff *skb,
728740
return 0;
729741

730742
hdr = queue->pdu;
743+
if (unlikely(hdr->hlen != sizeof(struct nvme_tcp_rsp_pdu))) {
744+
if (!nvme_tcp_recv_pdu_supported(hdr->type))
745+
goto unsupported_pdu;
746+
747+
dev_err(queue->ctrl->ctrl.device,
748+
"pdu type %d has unexpected header length (%d)\n",
749+
hdr->type, hdr->hlen);
750+
return -EPROTO;
751+
}
752+
731753
if (queue->hdr_digest) {
732754
ret = nvme_tcp_verify_hdgst(queue, queue->pdu, hdr->hlen);
733755
if (unlikely(ret))
@@ -751,10 +773,13 @@ static int nvme_tcp_recv_pdu(struct nvme_tcp_queue *queue, struct sk_buff *skb,
751773
nvme_tcp_init_recv_ctx(queue);
752774
return nvme_tcp_handle_r2t(queue, (void *)queue->pdu);
753775
default:
754-
dev_err(queue->ctrl->ctrl.device,
755-
"unsupported pdu type (%d)\n", hdr->type);
756-
return -EINVAL;
776+
goto unsupported_pdu;
757777
}
778+
779+
unsupported_pdu:
780+
dev_err(queue->ctrl->ctrl.device,
781+
"unsupported pdu type (%d)\n", hdr->type);
782+
return -EINVAL;
758783
}
759784

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

0 commit comments

Comments
 (0)