From: Harry Wentland <[email protected]>

[Why & How]
The VBIOS integrated info tables (v1_11 and v2_1) contain HdmiRegNum and
Hdmi6GRegNum fields that are used as loop bounds when copying retimer I2C
register settings into fixed-size arrays (dp*_ext_hdmi_reg_settings[9]
and dp*_ext_hdmi_6g_reg_settings[3]). These u8 fields are not validated
before use, so a malformed VBIOS can specify values up to 255, causing an
out-of-bounds heap write during driver probe.

Clamp each register count to the destination array size using min_t()
before the copy loops, in both get_integrated_info_v11() and
get_integrated_info_v2_1().

Cc: [email protected]
Assisted-by: GitHub Copilot:claude-opus-4.6

Reviewed-by: Alex Hung <[email protected]>
Signed-off-by: Harry Wentland <[email protected]>
Signed-off-by: Ray Wu <[email protected]>
---
 .../drm/amd/display/dc/bios/bios_parser2.c    | 48 ++++++++++++-------
 1 file changed, 32 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c 
b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c
index d19ae67ebfac..6cbdf356b1cd 100644
--- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c
+++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c
@@ -2600,14 +2600,16 @@ static enum bp_result get_integrated_info_v11(
        info_v11->extdispconninfo.checksum;
 
        info->dp0_ext_hdmi_slv_addr = info_v11->dp0_retimer_set.HdmiSlvAddr;
-       info->dp0_ext_hdmi_reg_num = info_v11->dp0_retimer_set.HdmiRegNum;
+       info->dp0_ext_hdmi_reg_num = min_t(u8, 
info_v11->dp0_retimer_set.HdmiRegNum,
+                                           
ARRAY_SIZE(info->dp0_ext_hdmi_reg_settings));
        for (i = 0; i < info->dp0_ext_hdmi_reg_num; i++) {
                info->dp0_ext_hdmi_reg_settings[i].i2c_reg_index =
                                
info_v11->dp0_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
                info->dp0_ext_hdmi_reg_settings[i].i2c_reg_val =
                                
info_v11->dp0_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
        }
-       info->dp0_ext_hdmi_6g_reg_num = info_v11->dp0_retimer_set.Hdmi6GRegNum;
+       info->dp0_ext_hdmi_6g_reg_num = min_t(u8, 
info_v11->dp0_retimer_set.Hdmi6GRegNum,
+                                              
ARRAY_SIZE(info->dp0_ext_hdmi_6g_reg_settings));
        for (i = 0; i < info->dp0_ext_hdmi_6g_reg_num; i++) {
                info->dp0_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
                                
info_v11->dp0_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
@@ -2616,14 +2618,16 @@ static enum bp_result get_integrated_info_v11(
        }
 
        info->dp1_ext_hdmi_slv_addr = info_v11->dp1_retimer_set.HdmiSlvAddr;
-       info->dp1_ext_hdmi_reg_num = info_v11->dp1_retimer_set.HdmiRegNum;
+       info->dp1_ext_hdmi_reg_num = min_t(u8, 
info_v11->dp1_retimer_set.HdmiRegNum,
+                                           
ARRAY_SIZE(info->dp1_ext_hdmi_reg_settings));
        for (i = 0; i < info->dp1_ext_hdmi_reg_num; i++) {
                info->dp1_ext_hdmi_reg_settings[i].i2c_reg_index =
                                
info_v11->dp1_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
                info->dp1_ext_hdmi_reg_settings[i].i2c_reg_val =
                                
info_v11->dp1_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
        }
-       info->dp1_ext_hdmi_6g_reg_num = info_v11->dp1_retimer_set.Hdmi6GRegNum;
+       info->dp1_ext_hdmi_6g_reg_num = min_t(u8, 
info_v11->dp1_retimer_set.Hdmi6GRegNum,
+                                              
ARRAY_SIZE(info->dp1_ext_hdmi_6g_reg_settings));
        for (i = 0; i < info->dp1_ext_hdmi_6g_reg_num; i++) {
                info->dp1_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
                                
info_v11->dp1_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
@@ -2632,14 +2636,16 @@ static enum bp_result get_integrated_info_v11(
        }
 
        info->dp2_ext_hdmi_slv_addr = info_v11->dp2_retimer_set.HdmiSlvAddr;
-       info->dp2_ext_hdmi_reg_num = info_v11->dp2_retimer_set.HdmiRegNum;
+       info->dp2_ext_hdmi_reg_num = min_t(u8, 
info_v11->dp2_retimer_set.HdmiRegNum,
+                                           
ARRAY_SIZE(info->dp2_ext_hdmi_reg_settings));
        for (i = 0; i < info->dp2_ext_hdmi_reg_num; i++) {
                info->dp2_ext_hdmi_reg_settings[i].i2c_reg_index =
                                
info_v11->dp2_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
                info->dp2_ext_hdmi_reg_settings[i].i2c_reg_val =
                                
info_v11->dp2_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
        }
-       info->dp2_ext_hdmi_6g_reg_num = info_v11->dp2_retimer_set.Hdmi6GRegNum;
+       info->dp2_ext_hdmi_6g_reg_num = min_t(u8, 
info_v11->dp2_retimer_set.Hdmi6GRegNum,
+                                              
ARRAY_SIZE(info->dp2_ext_hdmi_6g_reg_settings));
        for (i = 0; i < info->dp2_ext_hdmi_6g_reg_num; i++) {
                info->dp2_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
                                
info_v11->dp2_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
@@ -2648,14 +2654,16 @@ static enum bp_result get_integrated_info_v11(
        }
 
        info->dp3_ext_hdmi_slv_addr = info_v11->dp3_retimer_set.HdmiSlvAddr;
-       info->dp3_ext_hdmi_reg_num = info_v11->dp3_retimer_set.HdmiRegNum;
+       info->dp3_ext_hdmi_reg_num = min_t(u8, 
info_v11->dp3_retimer_set.HdmiRegNum,
+                                           
ARRAY_SIZE(info->dp3_ext_hdmi_reg_settings));
        for (i = 0; i < info->dp3_ext_hdmi_reg_num; i++) {
                info->dp3_ext_hdmi_reg_settings[i].i2c_reg_index =
                                
info_v11->dp3_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
                info->dp3_ext_hdmi_reg_settings[i].i2c_reg_val =
                                
info_v11->dp3_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
        }
-       info->dp3_ext_hdmi_6g_reg_num = info_v11->dp3_retimer_set.Hdmi6GRegNum;
+       info->dp3_ext_hdmi_6g_reg_num = min_t(u8, 
info_v11->dp3_retimer_set.Hdmi6GRegNum,
+                                              
ARRAY_SIZE(info->dp3_ext_hdmi_6g_reg_settings));
        for (i = 0; i < info->dp3_ext_hdmi_6g_reg_num; i++) {
                info->dp3_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
                                
info_v11->dp3_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
@@ -2796,14 +2804,16 @@ static enum bp_result get_integrated_info_v2_1(
        info->ext_disp_conn_info.checksum =
                info_v2_1->extdispconninfo.checksum;
        info->dp0_ext_hdmi_slv_addr = info_v2_1->dp0_retimer_set.HdmiSlvAddr;
-       info->dp0_ext_hdmi_reg_num = info_v2_1->dp0_retimer_set.HdmiRegNum;
+       info->dp0_ext_hdmi_reg_num = min_t(u8, 
info_v2_1->dp0_retimer_set.HdmiRegNum,
+                                           
ARRAY_SIZE(info->dp0_ext_hdmi_reg_settings));
        for (i = 0; i < info->dp0_ext_hdmi_reg_num; i++) {
                info->dp0_ext_hdmi_reg_settings[i].i2c_reg_index =
                                
info_v2_1->dp0_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
                info->dp0_ext_hdmi_reg_settings[i].i2c_reg_val =
                                
info_v2_1->dp0_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
        }
-       info->dp0_ext_hdmi_6g_reg_num = info_v2_1->dp0_retimer_set.Hdmi6GRegNum;
+       info->dp0_ext_hdmi_6g_reg_num = min_t(u8, 
info_v2_1->dp0_retimer_set.Hdmi6GRegNum,
+                                              
ARRAY_SIZE(info->dp0_ext_hdmi_6g_reg_settings));
        for (i = 0; i < info->dp0_ext_hdmi_6g_reg_num; i++) {
                info->dp0_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
                                
info_v2_1->dp0_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
@@ -2811,14 +2821,16 @@ static enum bp_result get_integrated_info_v2_1(
                                
info_v2_1->dp0_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegVal;
        }
        info->dp1_ext_hdmi_slv_addr = info_v2_1->dp1_retimer_set.HdmiSlvAddr;
-       info->dp1_ext_hdmi_reg_num = info_v2_1->dp1_retimer_set.HdmiRegNum;
+       info->dp1_ext_hdmi_reg_num = min_t(u8, 
info_v2_1->dp1_retimer_set.HdmiRegNum,
+                                           
ARRAY_SIZE(info->dp1_ext_hdmi_reg_settings));
        for (i = 0; i < info->dp1_ext_hdmi_reg_num; i++) {
                info->dp1_ext_hdmi_reg_settings[i].i2c_reg_index =
                                
info_v2_1->dp1_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
                info->dp1_ext_hdmi_reg_settings[i].i2c_reg_val =
                                
info_v2_1->dp1_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
        }
-       info->dp1_ext_hdmi_6g_reg_num = info_v2_1->dp1_retimer_set.Hdmi6GRegNum;
+       info->dp1_ext_hdmi_6g_reg_num = min_t(u8, 
info_v2_1->dp1_retimer_set.Hdmi6GRegNum,
+                                              
ARRAY_SIZE(info->dp1_ext_hdmi_6g_reg_settings));
        for (i = 0; i < info->dp1_ext_hdmi_6g_reg_num; i++) {
                info->dp1_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
                                
info_v2_1->dp1_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
@@ -2826,14 +2838,16 @@ static enum bp_result get_integrated_info_v2_1(
                                
info_v2_1->dp1_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegVal;
        }
        info->dp2_ext_hdmi_slv_addr = info_v2_1->dp2_retimer_set.HdmiSlvAddr;
-       info->dp2_ext_hdmi_reg_num = info_v2_1->dp2_retimer_set.HdmiRegNum;
+       info->dp2_ext_hdmi_reg_num = min_t(u8, 
info_v2_1->dp2_retimer_set.HdmiRegNum,
+                                           
ARRAY_SIZE(info->dp2_ext_hdmi_reg_settings));
        for (i = 0; i < info->dp2_ext_hdmi_reg_num; i++) {
                info->dp2_ext_hdmi_reg_settings[i].i2c_reg_index =
                                
info_v2_1->dp2_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
                info->dp2_ext_hdmi_reg_settings[i].i2c_reg_val =
                                
info_v2_1->dp2_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
        }
-       info->dp2_ext_hdmi_6g_reg_num = info_v2_1->dp2_retimer_set.Hdmi6GRegNum;
+       info->dp2_ext_hdmi_6g_reg_num = min_t(u8, 
info_v2_1->dp2_retimer_set.Hdmi6GRegNum,
+                                              
ARRAY_SIZE(info->dp2_ext_hdmi_6g_reg_settings));
        for (i = 0; i < info->dp2_ext_hdmi_6g_reg_num; i++) {
                info->dp2_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
                                
info_v2_1->dp2_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
@@ -2841,14 +2855,16 @@ static enum bp_result get_integrated_info_v2_1(
                                
info_v2_1->dp2_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegVal;
        }
        info->dp3_ext_hdmi_slv_addr = info_v2_1->dp3_retimer_set.HdmiSlvAddr;
-       info->dp3_ext_hdmi_reg_num = info_v2_1->dp3_retimer_set.HdmiRegNum;
+       info->dp3_ext_hdmi_reg_num = min_t(u8, 
info_v2_1->dp3_retimer_set.HdmiRegNum,
+                                           
ARRAY_SIZE(info->dp3_ext_hdmi_reg_settings));
        for (i = 0; i < info->dp3_ext_hdmi_reg_num; i++) {
                info->dp3_ext_hdmi_reg_settings[i].i2c_reg_index =
                                
info_v2_1->dp3_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
                info->dp3_ext_hdmi_reg_settings[i].i2c_reg_val =
                                
info_v2_1->dp3_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
        }
-       info->dp3_ext_hdmi_6g_reg_num = info_v2_1->dp3_retimer_set.Hdmi6GRegNum;
+       info->dp3_ext_hdmi_6g_reg_num = min_t(u8, 
info_v2_1->dp3_retimer_set.Hdmi6GRegNum,
+                                              
ARRAY_SIZE(info->dp3_ext_hdmi_6g_reg_settings));
        for (i = 0; i < info->dp3_ext_hdmi_6g_reg_num; i++) {
                info->dp3_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
                                
info_v2_1->dp3_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
-- 
2.43.0

Reply via email to