Skip to content

Commit 326cfbf

Browse files
pvts-matPlaidCat
authored andcommitted
nvme-tcp: fix potential memory corruption in nvme_tcp_recv_pdu()
jira VULN-56028 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: Marcin Wcisło <[email protected]>
1 parent 35c80df commit 326cfbf

File tree

1 file changed

+28
-3
lines changed

1 file changed

+28
-3
lines changed

drivers/nvme/host/tcp.c

+28-3
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);
@@ -716,6 +728,16 @@ static int nvme_tcp_recv_pdu(struct nvme_tcp_queue *queue, struct sk_buff *skb,
716728
return 0;
717729

718730
hdr = queue->pdu;
731+
if (unlikely(hdr->hlen != sizeof(struct nvme_tcp_rsp_pdu))) {
732+
if (!nvme_tcp_recv_pdu_supported(hdr->type))
733+
goto unsupported_pdu;
734+
735+
dev_err(queue->ctrl->ctrl.device,
736+
"pdu type %d has unexpected header length (%d)\n",
737+
hdr->type, hdr->hlen);
738+
return -EPROTO;
739+
}
740+
719741
if (queue->hdr_digest) {
720742
ret = nvme_tcp_verify_hdgst(queue, queue->pdu, hdr->hlen);
721743
if (unlikely(ret))
@@ -739,10 +761,13 @@ static int nvme_tcp_recv_pdu(struct nvme_tcp_queue *queue, struct sk_buff *skb,
739761
nvme_tcp_init_recv_ctx(queue);
740762
return nvme_tcp_handle_r2t(queue, (void *)queue->pdu);
741763
default:
742-
dev_err(queue->ctrl->ctrl.device,
743-
"unsupported pdu type (%d)\n", hdr->type);
744-
return -EINVAL;
764+
goto unsupported_pdu;
745765
}
766+
767+
unsupported_pdu:
768+
dev_err(queue->ctrl->ctrl.device,
769+
"unsupported pdu type (%d)\n", hdr->type);
770+
return -EINVAL;
746771
}
747772

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

0 commit comments

Comments
 (0)