⬢ DragonFlyBSD Kernel Audit
DF-3869 / fix.diff
← back to finding ↓ download raw
--- dce_calcs.c -----------------------------------------------------------
Guard the two reachable zero divisors and stop computing the
horizontal_blank_and_chunk_granularity_factor when its denominator collapses
to zero (degenerate-but-UABI-legal modes: hdisplay=1/htotal=3 etc.).
Also guard the u32 division at the stutter burst computation.

--- a/sys/dev/drm/amd/display/dc/calcs/dce_calcs.c
+++ b/sys/dev/drm/amd/display/dc/calcs/dce_calcs.c
@@ -836,7 +836,15 @@ static void calculate_bandwidth(
 			if (data->line_buffer_prefetch[i] == 1 || bw_equ(data->lb_lines_in_per_line_out_in_middle_of_frame[i], bw_int_to_fixed(2)) || bw_equ(data->lb_lines_in_per_line_out_in_middle_of_frame[i], bw_int_to_fixed(4))) {
 				data->horizontal_blank_and_chunk_granularity_factor[i] = bw_int_to_fixed(1);
 			}
-			else {
+			else {
+				struct bw_fixed granularity_denominator =
+					bw_div((bw_add(data->h_total[i],
+						bw_div((bw_sub(data->source_width_pixels[i],
+							bw_int_to_fixed(dceip->chunk_width))),
+							data->hsr[i]))), bw_int_to_fixed(2));
+				if (granularity_denominator.value == 0) {
+					/* degenerate mode: avoid #DE in bw_frc_to_fixed */
+					data->horizontal_blank_and_chunk_granularity_factor[i] = bw_int_to_fixed(1);
+					continue;
+				}
 				data->horizontal_blank_and_chunk_granularity_factor[i] = bw_div(data->h_total[i], (bw_div((bw_add(data->h_total[i], bw_div((bw_sub(data->source_width_pixels[i], bw_int_to_fixed(dceip->chunk_width))), data->hsr[i]))), bw_int_to_fixed(2))));
 			}
@@ -1942,7 +1950,9 @@ static void calculate_bandwidth(
 	data->stutter_burst_time = bw_div(bw_int_to_fixed(data->total_stutter_dmif_buffer_size), bw_mul(sclk[data->sclk_level], vbios->data_return_bus_width));
-	data->num_stutter_bursts = data->total_bytes_requested / data->min_stutter_dmif_buffer_size;
+	data->num_stutter_bursts = data->min_stutter_dmif_buffer_size != 0 ?
+		data->total_bytes_requested / data->min_stutter_dmif_buffer_size : 0;

--- bw_fixed.c -----------------------------------------------------------
Defense in depth: honor the existing ASSERT contract instead of faulting.

--- a/sys/dev/drm/amd/display/dc/calcs/bw_fixed.c
+++ b/sys/dev/drm/amd/display/dc/calcs/bw_fixed.c
@@ -66,7 +66,12 @@ struct bw_fixed bw_frc_to_fixed(int64_t numerator, int64_t denominator)
 	/* determine integer part */
 	uint64_t res_value;
 
-	ASSERT(denominator != 0);
+	if (denominator == 0) {
+		/* release builds compile ASSERT to WARN_ON; a zero divisor
+		 * would raise #DE in div64_u64_rem and panic the kernel */
+		ASSERT(0);
+		return numerator >= 0 ?
+			(struct bw_fixed){ BW_FIXED_MAX_I32 << BW_FIXED_BITS_PER_FRACTIONAL_PART } :
+			(struct bw_fixed){ BW_FIXED_MIN_I32 << BW_FIXED_BITS_PER_FRACTIONAL_PART };
+	}