Blob Blame History Raw
From: Nicolas Morey <nmorey@suse.com>
Date: Wed, 27 Mar 2024 10:49:11 +0100
Subject: [PATCH 1/1] IB/hfi1: Fix bugs with non-PAGE_SIZE-end multi-iovec user
 SDMA requests
Patch-mainline: Never, SUSE specific backport
References: bsc#1220445, CVE-2023-52474

hfi1 user SDMA request processing has two bugs that can cause data
corruption for user SDMA requests that have multiple payload iovecs
where an iovec other than the tail iovec does not run up to the page
boundary for the buffer pointed to by that iovec.a

Here are the specific bugs:
1. user_sdma_txadd() does not use struct user_sdma_iovec->iov.iov_len.
   Rather, user_sdma_txadd() will add up to PAGE_SIZE bytes from iovec
   to the packet, even if some of those bytes are past
   iovec->iov.iov_len and are thus not intended to be in the packet.
2. user_sdma_txadd() and user_sdma_send_pkts() fail to advance to the
   next iovec in user_sdma_request->iovs when the current iovec
   is not PAGE_SIZE and does not contain enough data to complete the
   packet. The transmitted packet will contain the wrong data from the
   iovec pages.

This has not been an issue with SDMA packets from hfi1 Verbs or PSM2
because they only produce iovecs that end short of PAGE_SIZE as the tail
iovec of an SDMA request.

Fixing these bugs exposes other bugs with the SDMA pin cache
(struct mmu_rb_handler) that get in way of supporting user SDMA requests
with multiple payload iovecs whose buffers do not end at PAGE_SIZE.
Upstream commit does fixes these issues but requires mmu_interval_notifier.

Instead of trying to fix the MMU issues in older kernels, simply return
 -EINVAL when an unsupported iovec (where an iovec other than the tail
 iovec does not run up to the page boundary) is provided.
This will not impact currently working use-cases (Verbs, PSM2) but will
prevent data corruption in currently broken cases.

Signed-off-by: Nicolas Morey <nmorey@suse.com>
---
 drivers/infiniband/hw/hfi1/user_sdma.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/drivers/infiniband/hw/hfi1/user_sdma.c b/drivers/infiniband/hw/hfi1/user_sdma.c
index 4a4956f96a7e..993f0a87e679 100644
--- a/drivers/infiniband/hw/hfi1/user_sdma.c
+++ b/drivers/infiniband/hw/hfi1/user_sdma.c
@@ -753,6 +753,16 @@ static int user_sdma_txadd(struct user_sdma_request *req,
 	len = offset + req->info.fragsize > PAGE_SIZE ?
 		PAGE_SIZE - offset : req->info.fragsize;
 	len = min((datalen - queued), len);
+
+	/*
+	 * Make sure we have not overflown the iov_len which may happen if iov_len % PAGE_SIZE != 0
+	 * and another iovec is required to fill the needed (datalen - queued) bytes.
+	 * Prevents both bugs causing CVE-2023-52474
+	 * See 00cbce5cbf88 ("IB/hfi1: Fix bugs with non-PAGE_SIZE-end multi-iovec user SDMA requests")
+	 */
+	if (iov_offset + len > iovec->iov.iov_len)
+		return -EINVAL;
+
 	ret = sdma_txadd_page(pq->dd, &tx->txreq, iovec->pages[pageidx],
 			      offset, len);
 	if (ret) {
-- 
2.44.0.1.gd14cf580c85d