⬢ DragonFlyBSD Kernel Audit
DF-5008 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/drm/amd/amdgpu/amdgpu_vram_mgr.c
+++ b/sys/dev/drm/amd/amdgpu/amdgpu_vram_mgr.c
@@ -180,8 +180,21 @@
 		pages_per_node = ~0ul;
 		num_nodes = 1;
 	} else {
+		/*
+		 * The node-count bound num_nodes = DIV_ROUND_UP(num_pages,
+		 * pages_per_node) and the rounddown_pow_of_two() split in the
+		 * loop below both assume pages_per_node is a power of two.
+		 * mem->page_alignment is not guaranteed to be one: it derives
+		 * from user GEM_CREATE in.alignment via
+		 * amdgpu_gem_object_create()/amdgpu_bo_do_create(), which only
+		 * clamp alignment < PAGE_SIZE.  With a non-power-of-two
+		 * pages_per_node, loop 1 can insert nodes smaller than
+		 * pages_per_node and index past the kvmalloc_array()-allocated
+		 * node array.
+		 */
 		pages_per_node = max((uint32_t)amdgpu_vram_page_split,
 				     mem->page_alignment);
+		pages_per_node = rounddown_pow_of_two(pages_per_node);
 		num_nodes = DIV_ROUND_UP(mem->num_pages, pages_per_node);
 	}