DragonFlyBSD Kernel Audit
DF-2012 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/drm/amd/amdgpu/amdgpu_gart.c b/sys/dev/drm/amd/amdgpu/amdgpu_gart.c
--- a/sys/dev/drm/amd/amdgpu/amdgpu_gart.c
+++ b/sys/dev/drm/amd/amdgpu/amdgpu_gart.c
@@ -116,7 +116,16 @@
 		struct amdgpu_bo_param bp;
 
 		memset(&bp, 0, sizeof(bp));
-		bp.size = adev->gart.table_size;
+		/* Validate table_size against num_gpu_pages: a wrapped 32-bit multiply
+	 * in gmc_v{7,8,9}_0_gart_init would allocate a far-too-small BO and
+	 * amdgpu_gart_bind/unbind would write PTEs past it. */
+	if (adev->gart.num_gpu_pages == 0 ||
+	    adev->gart.table_size < adev->gart.num_gpu_pages * sizeof(uint64_t)) {
+		dev_err(adev->dev, "GART table_size %u too small for %u pages\n",
+			adev->gart.table_size, adev->gart.num_gpu_pages);
+		return -EOVERFLOW;
+	}
+	bp.size = adev->gart.table_size;
 		bp.byte_align = PAGE_SIZE;
 		bp.domain = AMDGPU_GEM_DOMAIN_VRAM;
 		bp.flags = AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED |
@@ -355,6 +364,12 @@
 		DRM_ERROR("Page size is smaller than GPU page size!\n");
 		return -EINVAL;
 	}
+	/* Reject gart_size whose page count overflows the unsigned int fields. */
+	if (adev->gmc.gart_size > (uint64_t)UINT_MAX * AMDGPU_GPU_PAGE_SIZE) {
+		DRM_ERROR("GART size %llu too large for 32-bit page count\n",
+			  (unsigned long long)adev->gmc.gart_size);
+		return -EOVERFLOW;
+	}
 	r = amdgpu_gart_dummy_page_init(adev);
 	if (r)
 		return r;