mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2026-04-03 12:05:13 +02:00
nvme-tcp: fix potential memory corruption in nvme_tcp_recv_pdu()
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: 3f2304f8c6 ("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>
This commit is contained in:
committed by
Keith Busch
parent
afb41b08c4
commit
ad95bab0cd
@@ -217,6 +217,19 @@ static inline int nvme_tcp_queue_id(struct nvme_tcp_queue *queue)
|
||||
return queue - queue->ctrl->queues;
|
||||
}
|
||||
|
||||
static inline bool nvme_tcp_recv_pdu_supported(enum nvme_tcp_pdu_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case nvme_tcp_c2h_term:
|
||||
case nvme_tcp_c2h_data:
|
||||
case nvme_tcp_r2t:
|
||||
case nvme_tcp_rsp:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the queue is TLS encrypted
|
||||
*/
|
||||
@@ -818,6 +831,16 @@ static int nvme_tcp_recv_pdu(struct nvme_tcp_queue *queue, struct sk_buff *skb,
|
||||
return 0;
|
||||
|
||||
hdr = queue->pdu;
|
||||
if (unlikely(hdr->hlen != sizeof(struct nvme_tcp_rsp_pdu))) {
|
||||
if (!nvme_tcp_recv_pdu_supported(hdr->type))
|
||||
goto unsupported_pdu;
|
||||
|
||||
dev_err(queue->ctrl->ctrl.device,
|
||||
"pdu type %d has unexpected header length (%d)\n",
|
||||
hdr->type, hdr->hlen);
|
||||
return -EPROTO;
|
||||
}
|
||||
|
||||
if (unlikely(hdr->type == nvme_tcp_c2h_term)) {
|
||||
/*
|
||||
* C2HTermReq never includes Header or Data digests.
|
||||
@@ -850,10 +873,13 @@ static int nvme_tcp_recv_pdu(struct nvme_tcp_queue *queue, struct sk_buff *skb,
|
||||
nvme_tcp_init_recv_ctx(queue);
|
||||
return nvme_tcp_handle_r2t(queue, (void *)queue->pdu);
|
||||
default:
|
||||
dev_err(queue->ctrl->ctrl.device,
|
||||
"unsupported pdu type (%d)\n", hdr->type);
|
||||
return -EINVAL;
|
||||
goto unsupported_pdu;
|
||||
}
|
||||
|
||||
unsupported_pdu:
|
||||
dev_err(queue->ctrl->ctrl.device,
|
||||
"unsupported pdu type (%d)\n", hdr->type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline void nvme_tcp_end_request(struct request *rq, u16 status)
|
||||
|
||||
Reference in New Issue
Block a user