From: Gabe Teeger <[email protected]>

[Why]
Multiple locations in dml2_0 used num_clk_values-1 as array index
without checking if num_clk_values > 0. When num_clk_values is 0,
this results in accessing array index -1, which wraps to 255 for
unsigned types, causing out-of-bounds memory access and potential
crashes.

[How]
Add proper bounds checking using ternary operators to guard all
num_clk_values-1 array accesses. When num_clk_values is 0, return 0
as fallback value instead of accessing invalid memory. This prevents
buffer overflows while maintaining backward compatibility and provides
sensible default behavior for empty clock tables.

Reviewed-by: Dillon Varone <[email protected]>
Signed-off-by: Gabe Teeger <[email protected]>
Signed-off-by: Chuanyu Tseng <[email protected]>
---
 .../dml21/src/dml2_dpmm/dml2_dpmm_dcn4.c      | 20 +++++++++++++++++++
 .../dml2_0/dml21/src/dml2_mcg/dml2_mcg_dcn4.c |  9 ++++++---
 .../dml21/src/dml2_mcg/dml2_mcg_dcn42.c       |  9 ++++++---
 3 files changed, 32 insertions(+), 6 deletions(-)

diff --git 
a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_dcn4.c 
b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_dcn4.c
index d17e59d684fd..ab0b4a4b5d65 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_dcn4.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_dcn4.c
@@ -279,6 +279,26 @@ static bool round_up_and_copy_to_next_dpm(unsigned long 
min_value, unsigned long
        bool result = false;
        int index = 0;
 
+       /* Guard against empty clock tables (e.g. DTBCLK on DCN42B where the
+        * clock is tied off and num_clk_values == 0).  Without this check the
+        * else-if branch below would evaluate
+        * clk_values_khz[num_clk_values - 1] with num_clk_values == 0, which
+        * wraps the unsigned char index to 255 — a 235-element out-of-bounds
+        * read on an array of DML_MAX_CLK_TABLE_SIZE (20) entries.
+        *
+        * Semantic: if the clock doesn't exist on this ASIC but no frequency
+        * is required (min_value == 0), the request is trivially satisfied.
+        * If a non-zero frequency is required but the clock is absent, the
+        * configuration is unsupportable.
+        */
+       if (clock_table->num_clk_values == 0) {
+               if (min_value == 0) {
+                       *rounded_value = 0;
+                       return true;
+               }
+               return false;
+       }
+
        if (clock_table->num_clk_values > 2) {
                while (index < clock_table->num_clk_values && 
clock_table->clk_values_khz[index] < min_value)
                        index++;
diff --git 
a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_mcg/dml2_mcg_dcn4.c 
b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_mcg/dml2_mcg_dcn4.c
index a265f254152c..eab13e1c96fd 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_mcg/dml2_mcg_dcn4.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_mcg/dml2_mcg_dcn4.c
@@ -178,9 +178,12 @@ static bool build_min_clock_table(const struct dml2_soc_bb 
*soc_bb, struct dml2_
 
        min_table->max_clocks_khz.dispclk = 
soc_bb->clk_table.dispclk.clk_values_khz[soc_bb->clk_table.dispclk.num_clk_values
 - 1];
        min_table->max_clocks_khz.dppclk = 
soc_bb->clk_table.dppclk.clk_values_khz[soc_bb->clk_table.dppclk.num_clk_values 
- 1];
-       min_table->max_clocks_khz.dscclk = 
soc_bb->clk_table.dscclk.clk_values_khz[soc_bb->clk_table.dscclk.num_clk_values 
- 1];
-       min_table->max_clocks_khz.dtbclk = 
soc_bb->clk_table.dtbclk.clk_values_khz[soc_bb->clk_table.dtbclk.num_clk_values 
- 1];
-       min_table->max_clocks_khz.phyclk = 
soc_bb->clk_table.phyclk.clk_values_khz[soc_bb->clk_table.phyclk.num_clk_values 
- 1];
+       min_table->max_clocks_khz.dscclk = 
(soc_bb->clk_table.dscclk.num_clk_values > 0) ?
+               
soc_bb->clk_table.dscclk.clk_values_khz[soc_bb->clk_table.dscclk.num_clk_values 
- 1] : 0;
+       min_table->max_clocks_khz.dtbclk = 
(soc_bb->clk_table.dtbclk.num_clk_values > 0) ?
+               
soc_bb->clk_table.dtbclk.clk_values_khz[soc_bb->clk_table.dtbclk.num_clk_values 
- 1] : 0;
+       min_table->max_clocks_khz.phyclk = 
(soc_bb->clk_table.phyclk.num_clk_values > 0) ?
+               
soc_bb->clk_table.phyclk.clk_values_khz[soc_bb->clk_table.phyclk.num_clk_values 
- 1] : 0;
 
        min_table->max_ss_clocks_khz.dispclk = (unsigned 
int)((double)min_table->max_clocks_khz.dispclk / (1.0 + 
soc_bb->dcn_downspread_percent / 100.0));
        min_table->max_ss_clocks_khz.dppclk = (unsigned 
int)((double)min_table->max_clocks_khz.dppclk / (1.0 + 
soc_bb->dcn_downspread_percent / 100.0));
diff --git 
a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_mcg/dml2_mcg_dcn42.c 
b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_mcg/dml2_mcg_dcn42.c
index 1f67cbc2c236..3eaeff39ee79 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_mcg/dml2_mcg_dcn42.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_mcg/dml2_mcg_dcn42.c
@@ -54,9 +54,12 @@ static bool build_min_clock_table(const struct dml2_soc_bb 
*soc_bb, struct dml2_
 
        min_table->max_clocks_khz.dispclk = 
soc_bb->clk_table.dispclk.clk_values_khz[soc_bb->clk_table.dispclk.num_clk_values
 - 1];
        min_table->max_clocks_khz.dppclk = 
soc_bb->clk_table.dppclk.clk_values_khz[soc_bb->clk_table.dppclk.num_clk_values 
- 1];
-       min_table->max_clocks_khz.dscclk = 
soc_bb->clk_table.dscclk.clk_values_khz[soc_bb->clk_table.dscclk.num_clk_values 
- 1];
-       min_table->max_clocks_khz.dtbclk = 
soc_bb->clk_table.dtbclk.clk_values_khz[soc_bb->clk_table.dtbclk.num_clk_values 
- 1];
-       min_table->max_clocks_khz.phyclk = 
soc_bb->clk_table.phyclk.clk_values_khz[soc_bb->clk_table.phyclk.num_clk_values 
- 1];
+       min_table->max_clocks_khz.dscclk = 
(soc_bb->clk_table.dscclk.num_clk_values > 0) ?
+               
soc_bb->clk_table.dscclk.clk_values_khz[soc_bb->clk_table.dscclk.num_clk_values 
- 1] : 0;
+       min_table->max_clocks_khz.dtbclk = 
(soc_bb->clk_table.dtbclk.num_clk_values > 0) ?
+               
soc_bb->clk_table.dtbclk.clk_values_khz[soc_bb->clk_table.dtbclk.num_clk_values 
- 1] : 0;
+       min_table->max_clocks_khz.phyclk = 
(soc_bb->clk_table.phyclk.num_clk_values > 0) ?
+               
soc_bb->clk_table.phyclk.clk_values_khz[soc_bb->clk_table.phyclk.num_clk_values 
- 1] : 0;
 
        min_table->max_ss_clocks_khz.dispclk = (unsigned 
int)((double)min_table->max_clocks_khz.dispclk / (1.0 + 
soc_bb->dcn_downspread_percent / 100.0));
        min_table->max_ss_clocks_khz.dppclk = (unsigned 
int)((double)min_table->max_clocks_khz.dppclk / (1.0 + 
soc_bb->dcn_downspread_percent / 100.0));
-- 
2.43.0

Reply via email to