⬢ DragonFlyBSD Kernel Audit
DF-5004 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/drm/amd/amdgpu/amdgpu_pll.c b/sys/dev/drm/amd/amdgpu/amdgpu_pll.c
index 1111111..2222222 100644
--- a/sys/dev/drm/amd/amdgpu/amdgpu_pll.c
+++ b/sys/dev/drm/amd/amdgpu/amdgpu_pll.c
@@ -48,11 +48,19 @@ static void amdgpu_pll_reduce_ratio(unsigned *nom, unsigned *den,
 	unsigned tmp;
 
 	/* reduce the numbers to a simpler ratio */
 	tmp = gcd(*nom, *den);
+	if (tmp == 0)		/* gcd(0,0) == 0 -> would divide by zero */
+		tmp = 1;
 	*nom /= tmp;
 	*den /= tmp;
+	/* degenerate inputs (fb_div/ref_div/reference_freq under-ran to 0):
+	 * keep the ratio well-defined instead of dividing by zero below */
+	if (*nom == 0)
+		*nom = 1;
+	if (*den == 0)
+		*den = 1;
 
 	/* make sure nominator is large enough */
 	if (*nom < nom_min) {
@@ -85,9 +93,14 @@ static void amdgpu_pll_get_fb_ref_div(unsigned nom, unsigned den, unsigned post_d
 				      unsigned *fb_div, unsigned *ref_div)
 {
+	if (post_div == 0)	/* defense in depth (DF-2037 family) */
+		post_div = 1;
+
 	/* limit reference * post divider to a maximum */
-	ref_div_max = min(128 / post_div, ref_div_max);
+	/* post_div > 128 (e.g. firmware-supplied AMDGPU_PLL_USE_POST_DIV value
+	 * of 129..255) drives this to 0 and forces ref_div = 0 -> 0/0 */
+	ref_div_max = max(min(128 / post_div, ref_div_max), 1u);
 
 	/* get matching reference and feedback divider */
 	*ref_div = min(max(DIV_ROUND_CLOSEST(den, post_div), 1u), ref_div_max);