From nobody Fri Dec 19 10:47:41 2025 Received: from mx0b-00082601.pphosted.com (mx0b-00082601.pphosted.com [67.231.153.30]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5CDA53469E6 for ; Tue, 28 Oct 2025 16:15:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=67.231.153.30 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761668116; cv=none; b=rdE4g+DYcWwgual2a57x4YTCglmmZDbUod4fkA8J8ZFntFdd4QpTbfw07inHjQgtYlOlikTtnJY1rt/jMndue08dJSY9KcbYGdqgprRRtncQKEQ33tJ9cRuFXeqzQ3kXUMg3Gntnjx9Dpsa5e2VkyS8gpAc6GUgFFqdijEr/G90= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761668116; c=relaxed/simple; bh=5btW7c2QlUBiHj/dljboPvASBr+YBpM7j/wLAfUdHEc=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=uRmCvw8L8lpFnDTgNjU5i46NcYI4orzYGPcbgAW+2lqzrcEdPMKNTzUCNODZgSfwxlcJ4PdDgyA5zKXmXRpYUU0IDaSWLZy5stmI4mUhXpWa1K98Z1c1lcNsEBg0krrwltc9oprWEb4vly5DgPcaXowXliy+HWt23XicgsubUnU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=fb.com; spf=pass smtp.mailfrom=meta.com; dkim=pass (2048-bit key) header.d=fb.com header.i=@fb.com header.b=6vfqoTmE; arc=none smtp.client-ip=67.231.153.30 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=fb.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=meta.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=fb.com header.i=@fb.com header.b="6vfqoTmE" Received: from pps.filterd (m0109332.ppops.net [127.0.0.1]) by mx0a-00082601.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 59SDI1Qe471239 for ; Tue, 28 Oct 2025 09:15:13 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fb.com; h=cc :content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=s2048-2025-q2; bh=iUWPw0RcWFuSEfLHoYV1wEUtZvKNyBm0Cr9wUiHyf7Q=; b=6vfqoTmEV9EF J4LispLKZ0udMKR6O7LKbbI2WAh7AzzFOvhTq9/URftIgEZqJddgadbR/nBZ0bwL yyLU+BQjczzua9iLRNRD2yJh/kg5DGKUQRguiziLzlWXGE7D2d8VUEjw5GWuRNT4 SJOx8HCZ+2ity0GsSShYSEpRje3bNoou1djBm95rbJ0AUMPt9xalof43dUa5iA1c 2EB3IaHdycoLkCxSPAZEBJWmiZNJ6GYJxrM2RT5cJqlDc1n0V7uUVwthdVI2G3jk fenzCUeDY74mCfFAVJIU1Ll7KjOGqugQH63CuWPNmPByQ7r2XnAWHCklNmFqmt6h D/1wtvcOpQ== Received: from mail.thefacebook.com ([163.114.134.16]) by mx0a-00082601.pphosted.com (PPS) with ESMTPS id 4a2xkhhq1h-9 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT) for ; Tue, 28 Oct 2025 09:15:12 -0700 (PDT) Received: from twshared15465.32.frc3.facebook.com (2620:10d:c085:208::7cb7) by mail.thefacebook.com (2620:10d:c08b:78::c78f) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.2.2562.20; Tue, 28 Oct 2025 16:15:07 +0000 Received: by devgpu012.nha5.facebook.com (Postfix, from userid 28580) id F3B97512935; Tue, 28 Oct 2025 09:15:04 -0700 (PDT) From: Alex Mastro Date: Tue, 28 Oct 2025 09:15:00 -0700 Subject: [PATCH v6 1/5] vfio/type1: sanitize for overflow using check_*_overflow() Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-ID: <20251028-fix-unmap-v6-1-2542b96bcc8e@fb.com> References: <20251028-fix-unmap-v6-0-2542b96bcc8e@fb.com> In-Reply-To: <20251028-fix-unmap-v6-0-2542b96bcc8e@fb.com> To: Alex Williamson CC: Jason Gunthorpe , Alejandro Jimenez , David Matlack , , , Alex Mastro , Jason Gunthorpe X-Mailer: b4 0.13.0 X-FB-Internal: Safe X-Proofpoint-Spam-Details-Enc: AW1haW4tMjUxMDI4MDEzNyBTYWx0ZWRfX0ToYcnNJgFzb KnkXVmFYP4ny0zRbepIPW5SvT55TCwqeNZFpgX5qu51doo270+UhsEN5sNdFH8s8c1FRjdIGJpG 9l2hjqtIg5Qs/bsuAzLLdyUAtL9cOrHOoZnk24eVmv1QbgK7W+iHy/A2nhJT16vdVyTg1VG4I5w GuPwlDTnEoMkB8g18VjKp40x/LJR6l4OR1JGKMFjgYwXdFvDPNmrttQZBQvIZBm4D8bY2nJISmr vWC0ZmKxpROY1td+zGSk7CzQsmFgAqObCctvG8T8Jz/hkhfarzxyEsJXG8ESGCJfI1fdGZhMROd gcS5RLpBlGVDdRL7G5bCtH6f0fv2Os2vmMrchYcDBJ78TywI2QQJYwYX6Iz7/qIsilPhsbQamD6 BWPMcqRCuTYTOnodmUJsmussID3vKg== X-Proofpoint-GUID: jDUOkojAFwKBOg7yi24S05NxM_MyRSHQ X-Authority-Analysis: v=2.4 cv=Uspu9uwB c=1 sm=1 tr=0 ts=6900ec10 cx=c_pps a=CB4LiSf2rd0gKozIdrpkBw==:117 a=CB4LiSf2rd0gKozIdrpkBw==:17 a=IkcTkHD0fZMA:10 a=x6icFKpwvdMA:10 a=VkNPw1HP01LnGYTKEx00:22 a=yPCof4ZbAAAA:8 a=Ikd4Dj_1AAAA:8 a=FOH2dFAWAAAA:8 a=kyqc8lFLhbGN_ZoCeBMA:9 a=QEXdDO2ut3YA:10 X-Proofpoint-ORIG-GUID: jDUOkojAFwKBOg7yi24S05NxM_MyRSHQ X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.9,FMLib:17.12.80.40 definitions=2025-10-28_06,2025-10-22_01,2025-03-28_01 Adopt check_*_overflow() functions to clearly express overflow check intent. Tested-by: Alejandro Jimenez Fixes: 73fa0d10d077 ("vfio: Type1 IOMMU implementation") Reviewed-by: Jason Gunthorpe Reviewed-by: Alejandro Jimenez Signed-off-by: Alex Mastro --- drivers/vfio/vfio_iommu_type1.c | 86 ++++++++++++++++++++++++++++++-------= ---- 1 file changed, 63 insertions(+), 23 deletions(-) diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type= 1.c index 916cad80941c..91b1480b7a37 100644 --- a/drivers/vfio/vfio_iommu_type1.c +++ b/drivers/vfio/vfio_iommu_type1.c @@ -38,6 +38,7 @@ #include #include #include +#include #include "vfio.h" =20 #define DRIVER_VERSION "0.2" @@ -182,7 +183,7 @@ static struct vfio_dma *vfio_find_dma(struct vfio_iommu= *iommu, } =20 static struct rb_node *vfio_find_dma_first_node(struct vfio_iommu *iommu, - dma_addr_t start, u64 size) + dma_addr_t start, size_t size) { struct rb_node *res =3D NULL; struct rb_node *node =3D iommu->dma_list.rb_node; @@ -895,14 +896,20 @@ static int vfio_iommu_type1_pin_pages(void *iommu_dat= a, unsigned long remote_vaddr; struct vfio_dma *dma; bool do_accounting; + dma_addr_t iova_end; + size_t iova_size; =20 - if (!iommu || !pages) + if (!iommu || !pages || npage <=3D 0) return -EINVAL; =20 /* Supported for v2 version only */ if (!iommu->v2) return -EACCES; =20 + if (check_mul_overflow(npage, PAGE_SIZE, &iova_size) || + check_add_overflow(user_iova, iova_size - 1, &iova_end)) + return -EOVERFLOW; + mutex_lock(&iommu->lock); =20 if (WARN_ONCE(iommu->vaddr_invalid_count, @@ -1008,12 +1015,21 @@ static void vfio_iommu_type1_unpin_pages(void *iomm= u_data, { struct vfio_iommu *iommu =3D iommu_data; bool do_accounting; + dma_addr_t iova_end; + size_t iova_size; int i; =20 /* Supported for v2 version only */ if (WARN_ON(!iommu->v2)) return; =20 + if (WARN_ON(npage <=3D 0)) + return; + + if (WARN_ON(check_mul_overflow(npage, PAGE_SIZE, &iova_size) || + check_add_overflow(user_iova, iova_size - 1, &iova_end))) + return; + mutex_lock(&iommu->lock); =20 do_accounting =3D list_empty(&iommu->domain_list); @@ -1374,7 +1390,8 @@ static int vfio_dma_do_unmap(struct vfio_iommu *iommu, int ret =3D -EINVAL, retries =3D 0; unsigned long pgshift; dma_addr_t iova =3D unmap->iova; - u64 size =3D unmap->size; + dma_addr_t iova_end; + size_t size =3D unmap->size; bool unmap_all =3D unmap->flags & VFIO_DMA_UNMAP_FLAG_ALL; bool invalidate_vaddr =3D unmap->flags & VFIO_DMA_UNMAP_FLAG_VADDR; struct rb_node *n, *first_n; @@ -1387,6 +1404,11 @@ static int vfio_dma_do_unmap(struct vfio_iommu *iomm= u, goto unlock; } =20 + if (iova !=3D unmap->iova || size !=3D unmap->size) { + ret =3D -EOVERFLOW; + goto unlock; + } + pgshift =3D __ffs(iommu->pgsize_bitmap); pgsize =3D (size_t)1 << pgshift; =20 @@ -1396,10 +1418,15 @@ static int vfio_dma_do_unmap(struct vfio_iommu *iom= mu, if (unmap_all) { if (iova || size) goto unlock; - size =3D U64_MAX; - } else if (!size || size & (pgsize - 1) || - iova + size - 1 < iova || size > SIZE_MAX) { - goto unlock; + size =3D SIZE_MAX; + } else { + if (!size || size & (pgsize - 1)) + goto unlock; + + if (check_add_overflow(iova, size - 1, &iova_end)) { + ret =3D -EOVERFLOW; + goto unlock; + } } =20 /* When dirty tracking is enabled, allow only min supported pgsize */ @@ -1446,7 +1473,7 @@ static int vfio_dma_do_unmap(struct vfio_iommu *iommu, if (dma && dma->iova !=3D iova) goto unlock; =20 - dma =3D vfio_find_dma(iommu, iova + size - 1, 0); + dma =3D vfio_find_dma(iommu, iova_end, 0); if (dma && dma->iova + dma->size !=3D iova + size) goto unlock; } @@ -1648,7 +1675,9 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu, { bool set_vaddr =3D map->flags & VFIO_DMA_MAP_FLAG_VADDR; dma_addr_t iova =3D map->iova; + dma_addr_t iova_end; unsigned long vaddr =3D map->vaddr; + unsigned long vaddr_end; size_t size =3D map->size; int ret =3D 0, prot =3D 0; size_t pgsize; @@ -1656,8 +1685,15 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu, =20 /* Verify that none of our __u64 fields overflow */ if (map->size !=3D size || map->vaddr !=3D vaddr || map->iova !=3D iova) + return -EOVERFLOW; + + if (!size) return -EINVAL; =20 + if (check_add_overflow(iova, size - 1, &iova_end) || + check_add_overflow(vaddr, size - 1, &vaddr_end)) + return -EOVERFLOW; + /* READ/WRITE from device perspective */ if (map->flags & VFIO_DMA_MAP_FLAG_WRITE) prot |=3D IOMMU_WRITE; @@ -1673,13 +1709,7 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu, =20 WARN_ON((pgsize - 1) & PAGE_MASK); =20 - if (!size || (size | iova | vaddr) & (pgsize - 1)) { - ret =3D -EINVAL; - goto out_unlock; - } - - /* Don't allow IOVA or virtual address wrap */ - if (iova + size - 1 < iova || vaddr + size - 1 < vaddr) { + if ((size | iova | vaddr) & (pgsize - 1)) { ret =3D -EINVAL; goto out_unlock; } @@ -1710,7 +1740,7 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu, goto out_unlock; } =20 - if (!vfio_iommu_iova_dma_valid(iommu, iova, iova + size - 1)) { + if (!vfio_iommu_iova_dma_valid(iommu, iova, iova_end)) { ret =3D -EINVAL; goto out_unlock; } @@ -2977,7 +3007,8 @@ static int vfio_iommu_type1_dirty_pages(struct vfio_i= ommu *iommu, struct vfio_iommu_type1_dirty_bitmap_get range; unsigned long pgshift; size_t data_size =3D dirty.argsz - minsz; - size_t iommu_pgsize; + size_t size, iommu_pgsize; + dma_addr_t iova, iova_end; =20 if (!data_size || data_size < sizeof(range)) return -EINVAL; @@ -2986,14 +3017,24 @@ static int vfio_iommu_type1_dirty_pages(struct vfio= _iommu *iommu, sizeof(range))) return -EFAULT; =20 - if (range.iova + range.size < range.iova) + iova =3D range.iova; + size =3D range.size; + + if (iova !=3D range.iova || size !=3D range.size) + return -EOVERFLOW; + + if (!size) return -EINVAL; + + if (check_add_overflow(iova, size - 1, &iova_end)) + return -EOVERFLOW; + if (!access_ok((void __user *)range.bitmap.data, range.bitmap.size)) return -EINVAL; =20 pgshift =3D __ffs(range.bitmap.pgsize); - ret =3D verify_bitmap_size(range.size >> pgshift, + ret =3D verify_bitmap_size(size >> pgshift, range.bitmap.size); if (ret) return ret; @@ -3007,19 +3048,18 @@ static int vfio_iommu_type1_dirty_pages(struct vfio= _iommu *iommu, ret =3D -EINVAL; goto out_unlock; } - if (range.iova & (iommu_pgsize - 1)) { + if (iova & (iommu_pgsize - 1)) { ret =3D -EINVAL; goto out_unlock; } - if (!range.size || range.size & (iommu_pgsize - 1)) { + if (size & (iommu_pgsize - 1)) { ret =3D -EINVAL; goto out_unlock; } =20 if (iommu->dirty_page_tracking) ret =3D vfio_iova_dirty_bitmap(range.bitmap.data, - iommu, range.iova, - range.size, + iommu, iova, size, range.bitmap.pgsize); else ret =3D -EINVAL; --=20 2.47.3 From nobody Fri Dec 19 10:47:41 2025 Received: from mx0a-00082601.pphosted.com (mx0a-00082601.pphosted.com [67.231.145.42]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 871EA285CAD for ; Tue, 28 Oct 2025 16:15:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=67.231.145.42 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761668123; cv=none; b=u/ggIc52DvqrPgRcehRLR6jXU3D8KsoXl5kGaLsuHyJ0o3w0n50nbY/xrEVchj3XsJOzTqf4lYu71fkzQU1VtHrUhB17v59AUY4dZUqQpbzehAR7ks+24ITPQgdCjK+Hx+ngxnTHwr6bbGRzaBgJvmC/etWoIYx27awOfv1td7A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761668123; c=relaxed/simple; bh=zH2bltp5SnxsRbXoUh5UiyX6fJZxfu9t7+eKTgtNKhw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=pxn/j8OPgvWUpReG6yaKJgNnYbAvE7RpIzz/PKd3xIoq2zcrYYGSuLq+yMgFzq2vt4dAqJ2ys5TH4ZQb38v2jrC7Pe0L2dFOnPT9aoU2MtsxmNSFHfnpnzPc9Ue7vSiW9jyGvoYFqSP9NcoEJQVqAwcdfhyWsQY5YCnxOLVKj1A= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=fb.com; spf=pass smtp.mailfrom=meta.com; dkim=pass (2048-bit key) header.d=fb.com header.i=@fb.com header.b=hieX/C1x; arc=none smtp.client-ip=67.231.145.42 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=fb.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=meta.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=fb.com header.i=@fb.com header.b="hieX/C1x" Received: from pps.filterd (m0044010.ppops.net [127.0.0.1]) by mx0a-00082601.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 59SFNowT3079487 for ; Tue, 28 Oct 2025 09:15:20 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fb.com; h=cc :content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=s2048-2025-q2; bh=5Xtgh45PqrJXrHbQeeYqpMNjm28cym0+HxoQQ807OaM=; b=hieX/C1xkhLS e3xzMgmGsFcxcGmdxQUoyVThbPDASo4WmZZyVBxfQY8VBJ+Qv1OEkDysokXAHE79 VM0yU93lNWm2EqBrWJFR/6LxxWWVQ0RC/iDyxbp53rL9YplTSVg0ym3/3Max8Wom SIVjYbZrGKcBNlmvS8XVmJSMIu2U/hvz/Sg1VTwCTgh5lL5apBWLsqslTlCA6i63 GO5UmR6QdF/YOAX3yOD4xoImfAb1BLW5M//5moFdfAR9lSAC410RoFjLfjAVhmZU zx+C5iyMwSVOwnhd7ZoLBOGV6Yhq86xp1Elv7QM3xpPGP4tiZ38x169k6+zLACs+ QK42qPc7gA== Received: from maileast.thefacebook.com ([163.114.135.16]) by mx0a-00082601.pphosted.com (PPS) with ESMTPS id 4a30eggge2-11 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT) for ; Tue, 28 Oct 2025 09:15:20 -0700 (PDT) Received: from twshared82436.15.frc2.facebook.com (2620:10d:c0a8:fe::f072) by mail.thefacebook.com (2620:10d:c0a9:6f::8fd4) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.2.2562.20; Tue, 28 Oct 2025 16:15:18 +0000 Received: by devgpu012.nha5.facebook.com (Postfix, from userid 28580) id 01E18512937; Tue, 28 Oct 2025 09:15:05 -0700 (PDT) From: Alex Mastro Date: Tue, 28 Oct 2025 09:15:01 -0700 Subject: [PATCH v6 2/5] vfio/type1: move iova increment to unmap_unpin_*() caller Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-ID: <20251028-fix-unmap-v6-2-2542b96bcc8e@fb.com> References: <20251028-fix-unmap-v6-0-2542b96bcc8e@fb.com> In-Reply-To: <20251028-fix-unmap-v6-0-2542b96bcc8e@fb.com> To: Alex Williamson CC: Jason Gunthorpe , Alejandro Jimenez , David Matlack , , , Alex Mastro , Jason Gunthorpe X-Mailer: b4 0.13.0 X-FB-Internal: Safe X-Proofpoint-Spam-Details-Enc: AW1haW4tMjUxMDI4MDEzNyBTYWx0ZWRfXzr/fQJ/mstlC S651eubLCU1IpxJH8yPTCEjrmWZ2pSTJnO8Qbb9pKBGOX3hEFYEps3Hi8gmrwMIiAQInXWNONlQ mriisq+NLbfnvN+SmyyLUnvYoNcioemmyZd8j+j2HhDheh5XKt7mAqdMaRsWNkYdaxgkPHE73zO yu23cfBPitOZK6OJSOOOgdy3MjmOhwU90OB5ElRYzPMHH/EPIXL4f7Iut8NYEZNPCQ9DcufmVQF 9glF0F9B7qaRMJFtJ0Z1/1ByOw9CRdy9wS0ysS5Kx5PxSTqGBqRbkGpGw/u4bPnan5nguBq8IKo bVkNDIY1wt60AQ4HWaFBQc9ctMee7e+cJHACGa1T6ZEd8FHsSu5ybRYukzCtdVLl6FjUG+699Bp oGw0AdQA2bu++n51m/Y0kUlR2i8SMw== X-Proofpoint-GUID: Qp0OWSWYqovN7PJmSoLpru5F-0MYnzhj X-Authority-Analysis: v=2.4 cv=PNkCOPqC c=1 sm=1 tr=0 ts=6900ec18 cx=c_pps a=MfjaFnPeirRr97d5FC5oHw==:117 a=MfjaFnPeirRr97d5FC5oHw==:17 a=IkcTkHD0fZMA:10 a=x6icFKpwvdMA:10 a=VkNPw1HP01LnGYTKEx00:22 a=yPCof4ZbAAAA:8 a=Ikd4Dj_1AAAA:8 a=FOH2dFAWAAAA:8 a=PelP7hj50Gaxf9uocr0A:9 a=QEXdDO2ut3YA:10 X-Proofpoint-ORIG-GUID: Qp0OWSWYqovN7PJmSoLpru5F-0MYnzhj X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.9,FMLib:17.12.80.40 definitions=2025-10-28_06,2025-10-22_01,2025-03-28_01 Move incrementing iova to the caller of these functions as part of preparing to handle end of address space map/unmap. Tested-by: Alejandro Jimenez Fixes: 73fa0d10d077 ("vfio: Type1 IOMMU implementation") Reviewed-by: Jason Gunthorpe Reviewed-by: Alejandro Jimenez Signed-off-by: Alex Mastro --- drivers/vfio/vfio_iommu_type1.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type= 1.c index 91b1480b7a37..48bcc0633d44 100644 --- a/drivers/vfio/vfio_iommu_type1.c +++ b/drivers/vfio/vfio_iommu_type1.c @@ -1083,7 +1083,7 @@ static long vfio_sync_unpin(struct vfio_dma *dma, str= uct vfio_domain *domain, #define VFIO_IOMMU_TLB_SYNC_MAX 512 =20 static size_t unmap_unpin_fast(struct vfio_domain *domain, - struct vfio_dma *dma, dma_addr_t *iova, + struct vfio_dma *dma, dma_addr_t iova, size_t len, phys_addr_t phys, long *unlocked, struct list_head *unmapped_list, int *unmapped_cnt, @@ -1093,18 +1093,17 @@ static size_t unmap_unpin_fast(struct vfio_domain *= domain, struct vfio_regions *entry =3D kzalloc(sizeof(*entry), GFP_KERNEL); =20 if (entry) { - unmapped =3D iommu_unmap_fast(domain->domain, *iova, len, + unmapped =3D iommu_unmap_fast(domain->domain, iova, len, iotlb_gather); =20 if (!unmapped) { kfree(entry); } else { - entry->iova =3D *iova; + entry->iova =3D iova; entry->phys =3D phys; entry->len =3D unmapped; list_add_tail(&entry->list, unmapped_list); =20 - *iova +=3D unmapped; (*unmapped_cnt)++; } } @@ -1123,18 +1122,17 @@ static size_t unmap_unpin_fast(struct vfio_domain *= domain, } =20 static size_t unmap_unpin_slow(struct vfio_domain *domain, - struct vfio_dma *dma, dma_addr_t *iova, + struct vfio_dma *dma, dma_addr_t iova, size_t len, phys_addr_t phys, long *unlocked) { - size_t unmapped =3D iommu_unmap(domain->domain, *iova, len); + size_t unmapped =3D iommu_unmap(domain->domain, iova, len); =20 if (unmapped) { - *unlocked +=3D vfio_unpin_pages_remote(dma, *iova, + *unlocked +=3D vfio_unpin_pages_remote(dma, iova, phys >> PAGE_SHIFT, unmapped >> PAGE_SHIFT, false); - *iova +=3D unmapped; cond_resched(); } return unmapped; @@ -1197,16 +1195,18 @@ static long vfio_unmap_unpin(struct vfio_iommu *iom= mu, struct vfio_dma *dma, * First, try to use fast unmap/unpin. In case of failure, * switch to slow unmap/unpin path. */ - unmapped =3D unmap_unpin_fast(domain, dma, &iova, len, phys, + unmapped =3D unmap_unpin_fast(domain, dma, iova, len, phys, &unlocked, &unmapped_region_list, &unmapped_region_cnt, &iotlb_gather); if (!unmapped) { - unmapped =3D unmap_unpin_slow(domain, dma, &iova, len, + unmapped =3D unmap_unpin_slow(domain, dma, iova, len, phys, &unlocked); if (WARN_ON(!unmapped)) break; } + + iova +=3D unmapped; } =20 dma->iommu_mapped =3D false; --=20 2.47.3 From nobody Fri Dec 19 10:47:41 2025 Received: from mx0a-00082601.pphosted.com (mx0a-00082601.pphosted.com [67.231.145.42]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2825E27FB05 for ; Tue, 28 Oct 2025 16:15:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=67.231.145.42 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761668124; cv=none; b=Dq64BoPs0O683sAeXVe/EdMziU0n6v1Np8zFeLljab6cJFSnb7x+b+P1elH+b4gZ5DFVtIvhavvo+p29O0MGvfswdMItKkzg77LhEyECckaGmblcTUPxzYwd5/iP7fLwhKkMkOPI+6hDP8fHpWa5rJjt5WJSJ8MyCUTeqdwlJz0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761668124; c=relaxed/simple; bh=L9hqR11lu9H4XlY3g2ghJUmNvK2Vduby3QCfQC3ufIA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=nVkrNO4L7PLEKyS04+n+kxiJIxxo68KhE1FD+H90on/5KL6wss/c/lRS+VHYqQRxL3W596UnEvM/EbqkwM86780sQsmCI+0MhaWp/oghu08Huc7BPzjMQmhht7dMaAsmb/Ykc4dZ4N/Isif+N/5eXzAugDnAHczXsqYtrIm+4QU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=fb.com; spf=pass smtp.mailfrom=meta.com; dkim=pass (2048-bit key) header.d=fb.com header.i=@fb.com header.b=PgydI/yV; arc=none smtp.client-ip=67.231.145.42 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=fb.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=meta.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=fb.com header.i=@fb.com header.b="PgydI/yV" Received: from pps.filterd (m0109334.ppops.net [127.0.0.1]) by mx0a-00082601.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 59SEo1l6105054 for ; Tue, 28 Oct 2025 09:15:22 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fb.com; h=cc :content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=s2048-2025-q2; bh=/4A/pamM+dW+0rJ6NsCHbv58sh8cFT1xwf3Z2nTc9lE=; b=PgydI/yV5Yjm xBrhwWNVkqKCwFwo/WwIz2qLJF9Aqm6XjD9vmQ1Zu9woPMkXGo1moJ7+pwCVOeBQ oC6v1fJRVyuM6kgELjF6dxQRM7t2FLONNuyd2uxfj8ua+LXYaZqFScAw3bWhJ/l9 jFaKvYSV331/eLnR8PWM9He3C6HbJQYM3ob5lDJIrxyY4RQkP6Dp1ZMUI8wu2cSK yFXypYzQ2A9W4dAi8lo+ZwJVj9xGKr0nPC+q3FgZKVC3BudJ3M10vVs1B9iX53jf 6MHbR8TpXVlYSld0V7HpQdMNTqIgEKvFS9O5kZkKiHBHcrN9E6r75W+VsTMuf/D4 dhqnCc9X8A== Received: from maileast.thefacebook.com ([163.114.135.16]) by mx0a-00082601.pphosted.com (PPS) with ESMTPS id 4a2yxngtu0-6 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT) for ; Tue, 28 Oct 2025 09:15:22 -0700 (PDT) Received: from twshared82436.15.frc2.facebook.com (2620:10d:c0a8:fe::f072) by mail.thefacebook.com (2620:10d:c0a9:6f::237c) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.2.2562.20; Tue, 28 Oct 2025 16:15:18 +0000 Received: by devgpu012.nha5.facebook.com (Postfix, from userid 28580) id 03F41512939; Tue, 28 Oct 2025 09:15:05 -0700 (PDT) From: Alex Mastro Date: Tue, 28 Oct 2025 09:15:02 -0700 Subject: [PATCH v6 3/5] vfio/type1: handle DMA map/unmap up to the addressable limit Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-ID: <20251028-fix-unmap-v6-3-2542b96bcc8e@fb.com> References: <20251028-fix-unmap-v6-0-2542b96bcc8e@fb.com> In-Reply-To: <20251028-fix-unmap-v6-0-2542b96bcc8e@fb.com> To: Alex Williamson CC: Jason Gunthorpe , Alejandro Jimenez , David Matlack , , , Alex Mastro , Jason Gunthorpe X-Mailer: b4 0.13.0 X-FB-Internal: Safe X-Proofpoint-Spam-Details-Enc: AW1haW4tMjUxMDI4MDEzNyBTYWx0ZWRfXySI6I3Idgk2E e7Bi4py34j9l2uv9aWt4YZJxwQNnIHNJfw014yoIZfBZlR9MCdFps3Sjg8DlTfIGP/ZhG/ggsnj qd6i3dy8uUydreBVWBHAzyC0aViEWxPoEXPBTM8unMxK6miaBguiiFl3g1HtLCoakxS2cYi9MjH l4vZm53i709CfT1SIoovHsaQgYR03a6cQgbci/oLgi22FQk5qYnmu8l9zlvZSY6DaivGSgAqjVi AzS90ubvEY3b1jJ+fl0711Qfo9hDP60S0U7wCweuDGfu6QE8dbjTfmomGjzC1ShBCxdF6g4fcwl p6GWMDal36J0hHUrOT4CxI7LdN7FWBiQ7/GMFhn8veoKlKMc5rKNXJhvh9XSqFe7P6us789uB9l oozAbX5+mMM0UdkyqjzLbZpjhBrU9Q== X-Proofpoint-GUID: wDQSGvZ7J4CEO_XeBBEvnuTrmqoGTGUu X-Authority-Analysis: v=2.4 cv=fcWgCkQF c=1 sm=1 tr=0 ts=6900ec1a cx=c_pps a=MfjaFnPeirRr97d5FC5oHw==:117 a=MfjaFnPeirRr97d5FC5oHw==:17 a=IkcTkHD0fZMA:10 a=x6icFKpwvdMA:10 a=VkNPw1HP01LnGYTKEx00:22 a=yPCof4ZbAAAA:8 a=Ikd4Dj_1AAAA:8 a=FOH2dFAWAAAA:8 a=8P58oYQow4jR27pd84AA:9 a=QEXdDO2ut3YA:10 X-Proofpoint-ORIG-GUID: wDQSGvZ7J4CEO_XeBBEvnuTrmqoGTGUu X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.9,FMLib:17.12.80.40 definitions=2025-10-28_06,2025-10-22_01,2025-03-28_01 Before this commit, it was possible to create end of address space mappings, but unmapping them via VFIO_IOMMU_UNMAP_DMA, replaying them for newly added iommu domains, and querying their dirty pages via VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP was broken due to bugs caused by comparisons against (iova + size) expressions, which overflow to zero. Additionally, there appears to be a page pinning leak in the vfio_iommu_type1_release() path, since vfio_unmap_unpin()'s loop body where unmap_unpin_*() are called will never be entered due to overflow of (iova + size) to zero. This commit handles DMA map/unmap operations up to the addressable limit by comparing against inclusive end-of-range limits, and changing iteration to perform relative traversals across range sizes, rather than absolute traversals across addresses. vfio_link_dma() inserts a zero-sized vfio_dma into the rb-tree, and is only used for that purpose, so discard the size from consideration for the insertion point. Tested-by: Alejandro Jimenez Fixes: 73fa0d10d077 ("vfio: Type1 IOMMU implementation") Reviewed-by: Jason Gunthorpe Reviewed-by: Alejandro Jimenez Signed-off-by: Alex Mastro --- drivers/vfio/vfio_iommu_type1.c | 77 ++++++++++++++++++++++---------------= ---- 1 file changed, 42 insertions(+), 35 deletions(-) diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type= 1.c index 48bcc0633d44..5167bec14e36 100644 --- a/drivers/vfio/vfio_iommu_type1.c +++ b/drivers/vfio/vfio_iommu_type1.c @@ -168,12 +168,14 @@ static struct vfio_dma *vfio_find_dma(struct vfio_iom= mu *iommu, { struct rb_node *node =3D iommu->dma_list.rb_node; =20 + WARN_ON(!size); + while (node) { struct vfio_dma *dma =3D rb_entry(node, struct vfio_dma, node); =20 - if (start + size <=3D dma->iova) + if (start + size - 1 < dma->iova) node =3D node->rb_left; - else if (start >=3D dma->iova + dma->size) + else if (start > dma->iova + dma->size - 1) node =3D node->rb_right; else return dma; @@ -183,16 +185,19 @@ static struct vfio_dma *vfio_find_dma(struct vfio_iom= mu *iommu, } =20 static struct rb_node *vfio_find_dma_first_node(struct vfio_iommu *iommu, - dma_addr_t start, size_t size) + dma_addr_t start, + dma_addr_t end) { struct rb_node *res =3D NULL; struct rb_node *node =3D iommu->dma_list.rb_node; struct vfio_dma *dma_res =3D NULL; =20 + WARN_ON(end < start); + while (node) { struct vfio_dma *dma =3D rb_entry(node, struct vfio_dma, node); =20 - if (start < dma->iova + dma->size) { + if (start <=3D dma->iova + dma->size - 1) { res =3D node; dma_res =3D dma; if (start >=3D dma->iova) @@ -202,7 +207,7 @@ static struct rb_node *vfio_find_dma_first_node(struct = vfio_iommu *iommu, node =3D node->rb_right; } } - if (res && size && dma_res->iova >=3D start + size) + if (res && dma_res->iova > end) res =3D NULL; return res; } @@ -212,11 +217,13 @@ static void vfio_link_dma(struct vfio_iommu *iommu, s= truct vfio_dma *new) struct rb_node **link =3D &iommu->dma_list.rb_node, *parent =3D NULL; struct vfio_dma *dma; =20 + WARN_ON(new->size !=3D 0); + while (*link) { parent =3D *link; dma =3D rb_entry(parent, struct vfio_dma, node); =20 - if (new->iova + new->size <=3D dma->iova) + if (new->iova <=3D dma->iova) link =3D &(*link)->rb_left; else link =3D &(*link)->rb_right; @@ -1141,12 +1148,12 @@ static size_t unmap_unpin_slow(struct vfio_domain *= domain, static long vfio_unmap_unpin(struct vfio_iommu *iommu, struct vfio_dma *dm= a, bool do_accounting) { - dma_addr_t iova =3D dma->iova, end =3D dma->iova + dma->size; struct vfio_domain *domain, *d; LIST_HEAD(unmapped_region_list); struct iommu_iotlb_gather iotlb_gather; int unmapped_region_cnt =3D 0; long unlocked =3D 0; + size_t pos =3D 0; =20 if (!dma->size) return 0; @@ -1170,13 +1177,14 @@ static long vfio_unmap_unpin(struct vfio_iommu *iom= mu, struct vfio_dma *dma, } =20 iommu_iotlb_gather_init(&iotlb_gather); - while (iova < end) { + while (pos < dma->size) { size_t unmapped, len; phys_addr_t phys, next; + dma_addr_t iova =3D dma->iova + pos; =20 phys =3D iommu_iova_to_phys(domain->domain, iova); if (WARN_ON(!phys)) { - iova +=3D PAGE_SIZE; + pos +=3D PAGE_SIZE; continue; } =20 @@ -1185,7 +1193,7 @@ static long vfio_unmap_unpin(struct vfio_iommu *iommu= , struct vfio_dma *dma, * may require hardware cache flushing, try to find the * largest contiguous physical memory chunk to unmap. */ - for (len =3D PAGE_SIZE; iova + len < end; len +=3D PAGE_SIZE) { + for (len =3D PAGE_SIZE; pos + len < dma->size; len +=3D PAGE_SIZE) { next =3D iommu_iova_to_phys(domain->domain, iova + len); if (next !=3D phys + len) break; @@ -1206,7 +1214,7 @@ static long vfio_unmap_unpin(struct vfio_iommu *iommu= , struct vfio_dma *dma, break; } =20 - iova +=3D unmapped; + pos +=3D unmapped; } =20 dma->iommu_mapped =3D false; @@ -1298,7 +1306,7 @@ static int update_user_bitmap(u64 __user *bitmap, str= uct vfio_iommu *iommu, } =20 static int vfio_iova_dirty_bitmap(u64 __user *bitmap, struct vfio_iommu *i= ommu, - dma_addr_t iova, size_t size, size_t pgsize) + dma_addr_t iova, dma_addr_t iova_end, size_t pgsize) { struct vfio_dma *dma; struct rb_node *n; @@ -1315,8 +1323,8 @@ static int vfio_iova_dirty_bitmap(u64 __user *bitmap,= struct vfio_iommu *iommu, if (dma && dma->iova !=3D iova) return -EINVAL; =20 - dma =3D vfio_find_dma(iommu, iova + size - 1, 0); - if (dma && dma->iova + dma->size !=3D iova + size) + dma =3D vfio_find_dma(iommu, iova_end, 1); + if (dma && dma->iova + dma->size - 1 !=3D iova_end) return -EINVAL; =20 for (n =3D rb_first(&iommu->dma_list); n; n =3D rb_next(n)) { @@ -1325,7 +1333,7 @@ static int vfio_iova_dirty_bitmap(u64 __user *bitmap,= struct vfio_iommu *iommu, if (dma->iova < iova) continue; =20 - if (dma->iova > iova + size - 1) + if (dma->iova > iova_end) break; =20 ret =3D update_user_bitmap(bitmap, iommu, dma, iova, pgsize); @@ -1418,7 +1426,7 @@ static int vfio_dma_do_unmap(struct vfio_iommu *iommu, if (unmap_all) { if (iova || size) goto unlock; - size =3D SIZE_MAX; + iova_end =3D ~(dma_addr_t)0; } else { if (!size || size & (pgsize - 1)) goto unlock; @@ -1473,17 +1481,17 @@ static int vfio_dma_do_unmap(struct vfio_iommu *iom= mu, if (dma && dma->iova !=3D iova) goto unlock; =20 - dma =3D vfio_find_dma(iommu, iova_end, 0); - if (dma && dma->iova + dma->size !=3D iova + size) + dma =3D vfio_find_dma(iommu, iova_end, 1); + if (dma && dma->iova + dma->size - 1 !=3D iova_end) goto unlock; } =20 ret =3D 0; - n =3D first_n =3D vfio_find_dma_first_node(iommu, iova, size); + n =3D first_n =3D vfio_find_dma_first_node(iommu, iova, iova_end); =20 while (n) { dma =3D rb_entry(n, struct vfio_dma, node); - if (dma->iova >=3D iova + size) + if (dma->iova > iova_end) break; =20 if (!iommu->v2 && iova > dma->iova) @@ -1813,12 +1821,12 @@ static int vfio_iommu_replay(struct vfio_iommu *iom= mu, =20 for (; n; n =3D rb_next(n)) { struct vfio_dma *dma; - dma_addr_t iova; + size_t pos =3D 0; =20 dma =3D rb_entry(n, struct vfio_dma, node); - iova =3D dma->iova; =20 - while (iova < dma->iova + dma->size) { + while (pos < dma->size) { + dma_addr_t iova =3D dma->iova + pos; phys_addr_t phys; size_t size; =20 @@ -1834,14 +1842,14 @@ static int vfio_iommu_replay(struct vfio_iommu *iom= mu, phys =3D iommu_iova_to_phys(d->domain, iova); =20 if (WARN_ON(!phys)) { - iova +=3D PAGE_SIZE; + pos +=3D PAGE_SIZE; continue; } =20 size =3D PAGE_SIZE; p =3D phys + size; i =3D iova + size; - while (i < dma->iova + dma->size && + while (pos + size < dma->size && p =3D=3D iommu_iova_to_phys(d->domain, i)) { size +=3D PAGE_SIZE; p +=3D PAGE_SIZE; @@ -1849,9 +1857,8 @@ static int vfio_iommu_replay(struct vfio_iommu *iommu, } } else { unsigned long pfn; - unsigned long vaddr =3D dma->vaddr + - (iova - dma->iova); - size_t n =3D dma->iova + dma->size - iova; + unsigned long vaddr =3D dma->vaddr + pos; + size_t n =3D dma->size - pos; long npage; =20 npage =3D vfio_pin_pages_remote(dma, vaddr, @@ -1882,7 +1889,7 @@ static int vfio_iommu_replay(struct vfio_iommu *iommu, goto unwind; } =20 - iova +=3D size; + pos +=3D size; } } =20 @@ -1899,29 +1906,29 @@ static int vfio_iommu_replay(struct vfio_iommu *iom= mu, unwind: for (; n; n =3D rb_prev(n)) { struct vfio_dma *dma =3D rb_entry(n, struct vfio_dma, node); - dma_addr_t iova; + size_t pos =3D 0; =20 if (dma->iommu_mapped) { iommu_unmap(domain->domain, dma->iova, dma->size); continue; } =20 - iova =3D dma->iova; - while (iova < dma->iova + dma->size) { + while (pos < dma->size) { + dma_addr_t iova =3D dma->iova + pos; phys_addr_t phys, p; size_t size; dma_addr_t i; =20 phys =3D iommu_iova_to_phys(domain->domain, iova); if (!phys) { - iova +=3D PAGE_SIZE; + pos +=3D PAGE_SIZE; continue; } =20 size =3D PAGE_SIZE; p =3D phys + size; i =3D iova + size; - while (i < dma->iova + dma->size && + while (pos + size < dma->size && p =3D=3D iommu_iova_to_phys(domain->domain, i)) { size +=3D PAGE_SIZE; p +=3D PAGE_SIZE; @@ -3059,7 +3066,7 @@ static int vfio_iommu_type1_dirty_pages(struct vfio_i= ommu *iommu, =20 if (iommu->dirty_page_tracking) ret =3D vfio_iova_dirty_bitmap(range.bitmap.data, - iommu, iova, size, + iommu, iova, iova_end, range.bitmap.pgsize); else ret =3D -EINVAL; --=20 2.47.3 From nobody Fri Dec 19 10:47:41 2025 Received: from mx0b-00082601.pphosted.com (mx0b-00082601.pphosted.com [67.231.153.30]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7DC36346E47 for ; Tue, 28 Oct 2025 16:15:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=67.231.153.30 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761668119; cv=none; b=L7FFcNvjiQk6IolAWEP9fCugKTc+r8O7QTTaWix7P3CA2rRyvizD3bKScJXTnYr2eIWeM0xlTwPP83uN/en6QrFR+f1a+pkEHVzo3evK6DiPuritfx6DQxtvJSvszyotFH6B2MV+6VAiR4JPsOvLgTmMTxGybiChvXWE53TS5PE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761668119; c=relaxed/simple; bh=58UJV8Jomnww3/4xmMaH1WPBBt+aEgJfVLp6+UgTH8U=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=NugMKOgkj+FfDjTLswDkWLgB8Tr81sGx7oYCHuJdueMHWnnCzzD+X+WvBT4IHXwA1ww0BI8S7Y1h5Zmix+/OXzORD/DlzR/ZH8jYhmmNIjnBVaZfn6vjVEIJaF+ccqN4Pz2yUbLYL1VxIIwOQ93BFqRJHCXpKZkdL145396ZmY0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=fb.com; spf=pass smtp.mailfrom=meta.com; dkim=pass (2048-bit key) header.d=fb.com header.i=@fb.com header.b=HLiwrOcF; arc=none smtp.client-ip=67.231.153.30 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=fb.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=meta.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=fb.com header.i=@fb.com header.b="HLiwrOcF" Received: from pps.filterd (m0109332.ppops.net [127.0.0.1]) by mx0a-00082601.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 59SDI1Qk471239 for ; Tue, 28 Oct 2025 09:15:16 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fb.com; h=cc :content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=s2048-2025-q2; bh=GrjI71Ph4wCt61whNKp0lSntFbHA1PCFmc6ms15PM/s=; b=HLiwrOcFib4g mGGEgH2K3x9bZbBu3jeuYEtd/Z1Li290yvlTVi0/6qiiyoZDttQfC+SPA2jqv6EV H9Rjz7ow4dkPDuqVQxAE5vhi/8qQSfdmtQ+0U+/PJW6TdILI8AuvAd4ykcbJ7eL/ Wt7WDEDaj4Gn5iXhttx5lK+HaNm9SjaLQeeNpNYOafvOOcO61XtGrlv/6y1SO0gu Vcm07LrBXh9GFYsYxkVKR2e8sZxuZiiz+KZ1mS1Gg5JZW1OcVMkXAQFZFzmy4E2X NYGTizxmH2l19E6FKq32yqZx89AcnkUsqILjIJHcFz1ThX8wzCemJiHUCwg8NbZ2 2cF2YiCCug== Received: from mail.thefacebook.com ([163.114.134.16]) by mx0a-00082601.pphosted.com (PPS) with ESMTPS id 4a2xkhhq1h-15 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT) for ; Tue, 28 Oct 2025 09:15:16 -0700 (PDT) Received: from twshared15465.32.frc3.facebook.com (2620:10d:c085:208::7cb7) by mail.thefacebook.com (2620:10d:c08b:78::c78f) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.2.2562.20; Tue, 28 Oct 2025 16:15:10 +0000 Received: by devgpu012.nha5.facebook.com (Postfix, from userid 28580) id 05ACF51293B; Tue, 28 Oct 2025 09:15:05 -0700 (PDT) From: Alex Mastro Date: Tue, 28 Oct 2025 09:15:03 -0700 Subject: [PATCH v6 4/5] vfio: selftests: update DMA map/unmap helpers to support more test kinds Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-ID: <20251028-fix-unmap-v6-4-2542b96bcc8e@fb.com> References: <20251028-fix-unmap-v6-0-2542b96bcc8e@fb.com> In-Reply-To: <20251028-fix-unmap-v6-0-2542b96bcc8e@fb.com> To: Alex Williamson CC: Jason Gunthorpe , Alejandro Jimenez , David Matlack , , , Alex Mastro X-Mailer: b4 0.13.0 X-FB-Internal: Safe X-Proofpoint-Spam-Details-Enc: AW1haW4tMjUxMDI4MDEzNyBTYWx0ZWRfXx3wp3MiEn9V2 PWYi9P1Z2++ElYZTyDDpgMwhtzlL/SfMRMh0l6wFNprBAJFuwak95/f0yUt9pxPabyL6StOmT/G hm4eHXCL3y/csIM3qNTx4TAJ3YP8j5btuiKXZ4GPEFMDPRB38ASSevBCR3hB6VY18xnqJuXEHBP S9oEOjNT/l+ZQcIsleXzGxSRn21WwKqrUUknto6XhOVIH2AdfsE/UlNflD9j0yXtf0g27VUFgul PIq9jaPlkf9G98EhDCYeBxDu+UrJ+1WG+kTC5cypFptOdh9En6AvDNGZ7rOb5/MSEovB831kLxk J0NhpRJm2TmgcaKZmUMXhhJ+5BKMczkXOxFfPlQ2nA0pJD3Mc+Z9qayHpeimN9Lil8iggSEU2cO uHsuAEDK0juIrQ4Dv6fdTz45TgI0dA== X-Proofpoint-GUID: xrszek2qg9e2th0_jonv7_jZIKngpikv X-Authority-Analysis: v=2.4 cv=Uspu9uwB c=1 sm=1 tr=0 ts=6900ec14 cx=c_pps a=CB4LiSf2rd0gKozIdrpkBw==:117 a=CB4LiSf2rd0gKozIdrpkBw==:17 a=IkcTkHD0fZMA:10 a=x6icFKpwvdMA:10 a=VkNPw1HP01LnGYTKEx00:22 a=1XWaLZrsAAAA:8 a=FOH2dFAWAAAA:8 a=QPJBnxU05y6f-KHllaYA:9 a=QEXdDO2ut3YA:10 X-Proofpoint-ORIG-GUID: xrszek2qg9e2th0_jonv7_jZIKngpikv X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.9,FMLib:17.12.80.40 definitions=2025-10-28_06,2025-10-22_01,2025-03-28_01 Add __vfio_pci_dma_*() helpers which return -errno from the underlying ioctls. Add __vfio_pci_dma_unmap_all() to test more unmapping code paths. Add an out unmapped arg to report the unmapped byte size. The existing vfio_pci_dma_*() functions, which are intended for happy-path usage (assert on failure) are now thin wrappers on top of the double-underscore helpers. Reviewed-by: David Matlack Signed-off-by: Alex Mastro --- .../testing/selftests/vfio/lib/include/vfio_util.h | 27 +++++- tools/testing/selftests/vfio/lib/vfio_pci_device.c | 104 ++++++++++++++++-= ---- .../testing/selftests/vfio/vfio_dma_mapping_test.c | 5 +- 3 files changed, 108 insertions(+), 28 deletions(-) diff --git a/tools/testing/selftests/vfio/lib/include/vfio_util.h b/tools/t= esting/selftests/vfio/lib/include/vfio_util.h index ed31606e01b7..240409bf5f8a 100644 --- a/tools/testing/selftests/vfio/lib/include/vfio_util.h +++ b/tools/testing/selftests/vfio/lib/include/vfio_util.h @@ -206,10 +206,29 @@ struct vfio_pci_device *vfio_pci_device_init(const ch= ar *bdf, const char *iommu_ void vfio_pci_device_cleanup(struct vfio_pci_device *device); void vfio_pci_device_reset(struct vfio_pci_device *device); =20 -void vfio_pci_dma_map(struct vfio_pci_device *device, - struct vfio_dma_region *region); -void vfio_pci_dma_unmap(struct vfio_pci_device *device, - struct vfio_dma_region *region); +int __vfio_pci_dma_map(struct vfio_pci_device *device, + struct vfio_dma_region *region); +int __vfio_pci_dma_unmap(struct vfio_pci_device *device, + struct vfio_dma_region *region, + u64 *unmapped); +int __vfio_pci_dma_unmap_all(struct vfio_pci_device *device, u64 *unmapped= ); + +static inline void vfio_pci_dma_map(struct vfio_pci_device *device, + struct vfio_dma_region *region) +{ + VFIO_ASSERT_EQ(__vfio_pci_dma_map(device, region), 0); +} + +static inline void vfio_pci_dma_unmap(struct vfio_pci_device *device, + struct vfio_dma_region *region) +{ + VFIO_ASSERT_EQ(__vfio_pci_dma_unmap(device, region, NULL), 0); +} + +static inline void vfio_pci_dma_unmap_all(struct vfio_pci_device *device) +{ + VFIO_ASSERT_EQ(__vfio_pci_dma_unmap_all(device, NULL), 0); +} =20 void vfio_pci_config_access(struct vfio_pci_device *device, bool write, size_t config, size_t size, void *data); diff --git a/tools/testing/selftests/vfio/lib/vfio_pci_device.c b/tools/tes= ting/selftests/vfio/lib/vfio_pci_device.c index 0921b2451ba5..a381fd253aa7 100644 --- a/tools/testing/selftests/vfio/lib/vfio_pci_device.c +++ b/tools/testing/selftests/vfio/lib/vfio_pci_device.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -141,7 +142,7 @@ static void vfio_pci_irq_get(struct vfio_pci_device *de= vice, u32 index, ioctl_assert(device->fd, VFIO_DEVICE_GET_IRQ_INFO, irq_info); } =20 -static void vfio_iommu_dma_map(struct vfio_pci_device *device, +static int vfio_iommu_dma_map(struct vfio_pci_device *device, struct vfio_dma_region *region) { struct vfio_iommu_type1_dma_map args =3D { @@ -152,10 +153,13 @@ static void vfio_iommu_dma_map(struct vfio_pci_device= *device, .size =3D region->size, }; =20 - ioctl_assert(device->container_fd, VFIO_IOMMU_MAP_DMA, &args); + if (ioctl(device->container_fd, VFIO_IOMMU_MAP_DMA, &args)) + return -errno; + + return 0; } =20 -static void iommufd_dma_map(struct vfio_pci_device *device, +static int iommufd_dma_map(struct vfio_pci_device *device, struct vfio_dma_region *region) { struct iommu_ioas_map args =3D { @@ -169,54 +173,108 @@ static void iommufd_dma_map(struct vfio_pci_device *= device, .ioas_id =3D device->ioas_id, }; =20 - ioctl_assert(device->iommufd, IOMMU_IOAS_MAP, &args); + if (ioctl(device->iommufd, IOMMU_IOAS_MAP, &args)) + return -errno; + + return 0; } =20 -void vfio_pci_dma_map(struct vfio_pci_device *device, +int __vfio_pci_dma_map(struct vfio_pci_device *device, struct vfio_dma_region *region) { + int ret; + if (device->iommufd) - iommufd_dma_map(device, region); + ret =3D iommufd_dma_map(device, region); else - vfio_iommu_dma_map(device, region); + ret =3D vfio_iommu_dma_map(device, region); + + if (ret) + return ret; =20 list_add(®ion->link, &device->dma_regions); + + return 0; } =20 -static void vfio_iommu_dma_unmap(struct vfio_pci_device *device, - struct vfio_dma_region *region) +static int vfio_iommu_dma_unmap(int fd, u64 iova, u64 size, u32 flags, + u64 *unmapped) { struct vfio_iommu_type1_dma_unmap args =3D { .argsz =3D sizeof(args), - .iova =3D region->iova, - .size =3D region->size, + .iova =3D iova, + .size =3D size, + .flags =3D flags, }; =20 - ioctl_assert(device->container_fd, VFIO_IOMMU_UNMAP_DMA, &args); + if (ioctl(fd, VFIO_IOMMU_UNMAP_DMA, &args)) + return -errno; + + if (unmapped) + *unmapped =3D args.size; + + return 0; } =20 -static void iommufd_dma_unmap(struct vfio_pci_device *device, - struct vfio_dma_region *region) +static int iommufd_dma_unmap(int fd, u64 iova, u64 length, u32 ioas_id, + u64 *unmapped) { struct iommu_ioas_unmap args =3D { .size =3D sizeof(args), - .iova =3D region->iova, - .length =3D region->size, - .ioas_id =3D device->ioas_id, + .iova =3D iova, + .length =3D length, + .ioas_id =3D ioas_id, }; =20 - ioctl_assert(device->iommufd, IOMMU_IOAS_UNMAP, &args); + if (ioctl(fd, IOMMU_IOAS_UNMAP, &args)) + return -errno; + + if (unmapped) + *unmapped =3D args.length; + + return 0; } =20 -void vfio_pci_dma_unmap(struct vfio_pci_device *device, - struct vfio_dma_region *region) +int __vfio_pci_dma_unmap(struct vfio_pci_device *device, + struct vfio_dma_region *region, u64 *unmapped) { + int ret; + + if (device->iommufd) + ret =3D iommufd_dma_unmap(device->iommufd, region->iova, + region->size, device->ioas_id, + unmapped); + else + ret =3D vfio_iommu_dma_unmap(device->container_fd, region->iova, + region->size, 0, unmapped); + + if (ret) + return ret; + + list_del_init(®ion->link); + + return 0; +} + +int __vfio_pci_dma_unmap_all(struct vfio_pci_device *device, u64 *unmapped) +{ + int ret; + struct vfio_dma_region *curr, *next; + if (device->iommufd) - iommufd_dma_unmap(device, region); + ret =3D iommufd_dma_unmap(device->iommufd, 0, UINT64_MAX, + device->ioas_id, unmapped); else - vfio_iommu_dma_unmap(device, region); + ret =3D vfio_iommu_dma_unmap(device->container_fd, 0, 0, + VFIO_DMA_UNMAP_FLAG_ALL, unmapped); + + if (ret) + return ret; + + list_for_each_entry_safe(curr, next, &device->dma_regions, link) + list_del_init(&curr->link); =20 - list_del(®ion->link); + return 0; } =20 static void vfio_pci_region_get(struct vfio_pci_device *device, int index, diff --git a/tools/testing/selftests/vfio/vfio_dma_mapping_test.c b/tools/t= esting/selftests/vfio/vfio_dma_mapping_test.c index ab19c54a774d..a38966e8e5a6 100644 --- a/tools/testing/selftests/vfio/vfio_dma_mapping_test.c +++ b/tools/testing/selftests/vfio/vfio_dma_mapping_test.c @@ -129,6 +129,7 @@ TEST_F(vfio_dma_mapping_test, dma_map_unmap) struct vfio_dma_region region; struct iommu_mapping mapping; u64 mapping_size =3D size; + u64 unmapped; int rc; =20 region.vaddr =3D mmap(NULL, size, PROT_READ | PROT_WRITE, flags, -1, 0); @@ -184,7 +185,9 @@ TEST_F(vfio_dma_mapping_test, dma_map_unmap) } =20 unmap: - vfio_pci_dma_unmap(self->device, ®ion); + rc =3D __vfio_pci_dma_unmap(self->device, ®ion, &unmapped); + ASSERT_EQ(rc, 0); + ASSERT_EQ(unmapped, region.size); printf("Unmapped IOVA 0x%lx\n", region.iova); ASSERT_EQ(INVALID_IOVA, __to_iova(self->device, region.vaddr)); ASSERT_NE(0, iommu_mapping_get(device_bdf, region.iova, &mapping)); --=20 2.47.3 From nobody Fri Dec 19 10:47:41 2025 Received: from mx0a-00082601.pphosted.com (mx0a-00082601.pphosted.com [67.231.145.42]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4CB3928467D for ; Tue, 28 Oct 2025 16:15:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=67.231.145.42 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761668121; cv=none; b=H1D9J8bYbGNm7IobXIqTENGbE0DPAljByh1+Rn/wR0WjAjmpLNsZ4zc6/V5ydIoM56RDPYiKqVNuOnWggMUfeTWzYjAeVh5XifpC9CcvMmPOeh5z7et5qNq16GDrg3He2es7JIUff0Qb6S3sddq3w1jBaJmwJYkpx/kUsIleorg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761668121; c=relaxed/simple; bh=tzggaxR9FZMIzBPQS8Uhk5DQQIJ5mAFzxbGJIArHuc4=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=C364zHDKjCR+J5UHPpiTXlps/L4StnHI2XSDmvuKOCgYZJx7vPdr8PdLM7c9AUHvifph33/eQ7ff9R+tQVNuVb7W/TvbNmNN8G8FY5jBGZ3N7cpBDDkUkAjrYLk4aRDFT91R2uNhS+j13ayckJWFZRaIMDj9mf8w1m1BN8mWMqM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=fb.com; spf=pass smtp.mailfrom=meta.com; dkim=pass (2048-bit key) header.d=fb.com header.i=@fb.com header.b=HOKKYZtr; arc=none smtp.client-ip=67.231.145.42 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=fb.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=meta.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=fb.com header.i=@fb.com header.b="HOKKYZtr" Received: from pps.filterd (m0044010.ppops.net [127.0.0.1]) by mx0a-00082601.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 59SFNmrj3079406 for ; Tue, 28 Oct 2025 09:15:19 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fb.com; h=cc :content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=s2048-2025-q2; bh=jL27jaMKNMd3868BGcN8P3oHAzLxge4Xak38+P/R528=; b=HOKKYZtrgrl4 TqOmQtT1fJ7qYwIMUqejfa+hMZWFT2/r+0YdM5IzfY2RBNSJ9DlQVqI4XQgRMc36 S2c1E3KCdvyar50lqlSKk7oWPFMyoJKUxfF0RS2/hB0SHnxiq8OmGiDy6Z4l8+yV xheMDaYD3YUP3P5Cl8Nf/K63Z79ixNnyR6jEAAm0/GBSP43FrYBXPrd+lZYBZl/T mTir10MOmaKkycV87BEdwfouqVFxmCpzURfTawcEhNXIciJEPmamly1Jo3O3NEIw IxtCIw1+dWgvcDke4ADhvVICa8Uhn5J6Ojjmo79dP3//FBIdkcg5m5EFnwPZNR/r YkgZs5YC+A== Received: from mail.thefacebook.com ([163.114.134.16]) by mx0a-00082601.pphosted.com (PPS) with ESMTPS id 4a30egggem-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT) for ; Tue, 28 Oct 2025 09:15:19 -0700 (PDT) Received: from twshared15465.32.frc3.facebook.com (2620:10d:c085:208::7cb7) by mail.thefacebook.com (2620:10d:c08b:78::c78f) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.2.2562.20; Tue, 28 Oct 2025 16:15:12 +0000 Received: by devgpu012.nha5.facebook.com (Postfix, from userid 28580) id 0778E51293D; Tue, 28 Oct 2025 09:15:05 -0700 (PDT) From: Alex Mastro Date: Tue, 28 Oct 2025 09:15:04 -0700 Subject: [PATCH v6 5/5] vfio: selftests: add end of address space DMA map/unmap tests Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-ID: <20251028-fix-unmap-v6-5-2542b96bcc8e@fb.com> References: <20251028-fix-unmap-v6-0-2542b96bcc8e@fb.com> In-Reply-To: <20251028-fix-unmap-v6-0-2542b96bcc8e@fb.com> To: Alex Williamson CC: Jason Gunthorpe , Alejandro Jimenez , David Matlack , , , Alex Mastro X-Mailer: b4 0.13.0 X-FB-Internal: Safe X-Proofpoint-Spam-Details-Enc: AW1haW4tMjUxMDI4MDEzNyBTYWx0ZWRfXwd8NAJOk14nK z2ldXud0GkOPtu8yuhuKy9j3La8U8BL9arW9mTUloALm0FqcEqDP1CVgPw0jDCnsFHnkY6ga1rN Dn5/KcVW0LRFithZE20fjtls29dUAMp64kzGdoW69wiKOpOBYbk9eRY0gtmF/PNPkWTHugdvl1e bwahXpbPCFeImEFqn4BtpBf8a7d06FV4iH5ad0qPDTYoAAwEpzftxFFq3f6IgZvM7L9btLusB31 25Imfhw5X7RK7aktkcCfXt6RmX1TWryCQeMPwXo4G7AI3Ds0ZkOOPzT6Ww9rDuRHn46lceC5ZMN R7VoLzTsBoufoNuUFOdtIh3G3J8JlGEi8ApI0ABzjcZkTFtoF7P/6IGj/JmRglnt1vWJXUVXJt4 NG12t7Txo3pRO3d07dVet/iSiQpf5Q== X-Proofpoint-GUID: 421no4rqLIP4UGgGIipuBk3VCLAKaQ7Y X-Authority-Analysis: v=2.4 cv=PNkCOPqC c=1 sm=1 tr=0 ts=6900ec17 cx=c_pps a=CB4LiSf2rd0gKozIdrpkBw==:117 a=CB4LiSf2rd0gKozIdrpkBw==:17 a=IkcTkHD0fZMA:10 a=x6icFKpwvdMA:10 a=VkNPw1HP01LnGYTKEx00:22 a=1XWaLZrsAAAA:8 a=FOH2dFAWAAAA:8 a=wf1ge7rc0ZxdfOmzxhAA:9 a=QEXdDO2ut3YA:10 X-Proofpoint-ORIG-GUID: 421no4rqLIP4UGgGIipuBk3VCLAKaQ7Y X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.9,FMLib:17.12.80.40 definitions=2025-10-28_06,2025-10-22_01,2025-03-28_01 Add tests which validate dma map/unmap at the end of address space. Add negative test cases for checking that overflowing ioctl args fail with the expected errno. Reviewed-by: David Matlack Signed-off-by: Alex Mastro --- .../testing/selftests/vfio/vfio_dma_mapping_test.c | 90 ++++++++++++++++++= ++++ 1 file changed, 90 insertions(+) diff --git a/tools/testing/selftests/vfio/vfio_dma_mapping_test.c b/tools/t= esting/selftests/vfio/vfio_dma_mapping_test.c index a38966e8e5a6..4f1ea79a200c 100644 --- a/tools/testing/selftests/vfio/vfio_dma_mapping_test.c +++ b/tools/testing/selftests/vfio/vfio_dma_mapping_test.c @@ -112,6 +112,8 @@ FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(anonymous, 0, 0); FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(anonymous_hugetlb_2mb, SZ_2M, MAP_HUGE= TLB | MAP_HUGE_2MB); FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(anonymous_hugetlb_1gb, SZ_1G, MAP_HUGE= TLB | MAP_HUGE_1GB); =20 +#undef FIXTURE_VARIANT_ADD_IOMMU_MODE + FIXTURE_SETUP(vfio_dma_mapping_test) { self->device =3D vfio_pci_device_init(device_bdf, variant->iommu_mode); @@ -195,6 +197,94 @@ TEST_F(vfio_dma_mapping_test, dma_map_unmap) ASSERT_TRUE(!munmap(region.vaddr, size)); } =20 +FIXTURE(vfio_dma_map_limit_test) { + struct vfio_pci_device *device; + struct vfio_dma_region region; + size_t mmap_size; +}; + +FIXTURE_VARIANT(vfio_dma_map_limit_test) { + const char *iommu_mode; +}; + +#define FIXTURE_VARIANT_ADD_IOMMU_MODE(_iommu_mode) \ +FIXTURE_VARIANT_ADD(vfio_dma_map_limit_test, _iommu_mode) { \ + .iommu_mode =3D #_iommu_mode, \ +} + +FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(); + +#undef FIXTURE_VARIANT_ADD_IOMMU_MODE + +FIXTURE_SETUP(vfio_dma_map_limit_test) +{ + struct vfio_dma_region *region =3D &self->region; + u64 region_size =3D getpagesize(); + + /* + * Over-allocate mmap by double the size to provide enough backing vaddr + * for overflow tests + */ + self->mmap_size =3D 2 * region_size; + + self->device =3D vfio_pci_device_init(device_bdf, variant->iommu_mode); + region->vaddr =3D mmap(NULL, self->mmap_size, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + ASSERT_NE(region->vaddr, MAP_FAILED); + + /* One page prior to the end of address space */ + region->iova =3D ~(iova_t)0 & ~(region_size - 1); + region->size =3D region_size; +} + +FIXTURE_TEARDOWN(vfio_dma_map_limit_test) +{ + vfio_pci_device_cleanup(self->device); + ASSERT_EQ(munmap(self->region.vaddr, self->mmap_size), 0); +} + +TEST_F(vfio_dma_map_limit_test, unmap_range) +{ + struct vfio_dma_region *region =3D &self->region; + u64 unmapped; + int rc; + + vfio_pci_dma_map(self->device, region); + ASSERT_EQ(region->iova, to_iova(self->device, region->vaddr)); + + rc =3D __vfio_pci_dma_unmap(self->device, region, &unmapped); + ASSERT_EQ(rc, 0); + ASSERT_EQ(unmapped, region->size); +} + +TEST_F(vfio_dma_map_limit_test, unmap_all) +{ + struct vfio_dma_region *region =3D &self->region; + u64 unmapped; + int rc; + + vfio_pci_dma_map(self->device, region); + ASSERT_EQ(region->iova, to_iova(self->device, region->vaddr)); + + rc =3D __vfio_pci_dma_unmap_all(self->device, &unmapped); + ASSERT_EQ(rc, 0); + ASSERT_EQ(unmapped, region->size); +} + +TEST_F(vfio_dma_map_limit_test, overflow) +{ + struct vfio_dma_region *region =3D &self->region; + int rc; + + region->size =3D self->mmap_size; + + rc =3D __vfio_pci_dma_map(self->device, region); + ASSERT_EQ(rc, -EOVERFLOW); + + rc =3D __vfio_pci_dma_unmap(self->device, region, NULL); + ASSERT_EQ(rc, -EOVERFLOW); +} + int main(int argc, char *argv[]) { device_bdf =3D vfio_selftests_get_bdf(&argc, argv); --=20 2.47.3