⬢ DragonFlyBSD Kernel Audit
DF-4980 / fix.diff
← back to finding ↓ download raw
fix.diff — DF-4980 (authored after verification; never applied to sys/)
1) Clamp the untrusted VBIOS-driven scratch size to the driver's own default.
2) Stop ignoring the allocation error in amdgpu_atombios_init() (both the
   atomfirmware and legacy variants).

diff --git a/sys/dev/drm/amd/amdgpu/amdgpu_atomfirmware.c b/sys/dev/drm/amd/amdgpu/amdgpu_atomfirmware.c
--- a/sys/dev/drm/amd/amdgpu/amdgpu_atomfirmware.c
+++ b/sys/dev/drm/amd/amdgpu/amdgpu_atomfirmware.c
@@ -100,6 +100,15 @@ int amdgpu_atomfirmware_allocate_fb_scratch(struct amdgpu_device *adev)
 			usage_bytes = le16_to_cpu(firmware_usage->used_by_driver_in_kb) << 10;
 		}
 	}
+	/*
+	 * used_by_driver_in_kb is untrusted VBIOS data.  Don't let a garbage
+	 * table drive a huge kernel allocation (and, on allocators that can
+	 * return NULL, don't leave ctx->scratch NULL with the error ignored
+	 * by the caller).  Anything beyond the driver's own 20 KB default is
+	 * nonsense.
+	 */
+	if (usage_bytes > 20 * 1024)
+		usage_bytes = 20 * 1024;
 	ctx->scratch_size_bytes = 0;
 	if (usage_bytes == 0)
 		usage_bytes = 20 * 1024;
diff --git a/sys/dev/drm/amd/amdgpu/amdgpu_atombios.c b/sys/dev/drm/amd/amdgpu/amdgpu_atombios.c
--- a/sys/dev/drm/amd/amdgpu/amdgpu_atombios.c
+++ b/sys/dev/drm/amd/amdgpu/amdgpu_atombios.c
@@ -2008,6 +2008,7 @@ int amdgpu_atombios_init(struct amdgpu_device *adev)
 {
 	struct card_info *atom_card_info =
 	    kzalloc(sizeof(struct card_info), GFP_KERNEL);
+	int r;
 #if 0
 	int ret;
 #endif
@@ -2042,10 +2043,14 @@ int amdgpu_atombios_init(struct amdgpu_device *adev)
 	lockinit(&adev->mode_info.atom_context->mutex, "agmiacm", 0, LK_CANRECURSE);
 	if (adev->is_atom_fw) {
 		amdgpu_atomfirmware_scratch_regs_init(adev);
-		amdgpu_atomfirmware_allocate_fb_scratch(adev);
+		r = amdgpu_atomfirmware_allocate_fb_scratch(adev);
 	} else {
 		amdgpu_atombios_scratch_regs_init(adev);
-		amdgpu_atombios_allocate_fb_scratch(adev);
+		r = amdgpu_atombios_allocate_fb_scratch(adev);
+	}
+	if (r) {
+		amdgpu_atombios_fini(adev);
+		return r;
 	}
 
 #if 0