DF-3987 / fix.diff
--- a/sys/dev/drm/amd/display/dc/core/dc_link_dp.c +++ b/sys/dev/drm/amd/display/dc/core/dc_link_dp.c @@ -1593,7 +1593,11 @@ /*1. Check that Link Status changed, before re-training.*/ /*parse lane status*/ - for (lane = 0; lane < link->cur_link_settings.lane_count; lane++) { + /* DF-3987: cur_link_settings.lane_count is sink-fed state; the + * nibble reads below run off union hpd_irq_data (6 bytes) if it + * ever exceeds LANE_COUNT_DP_MAX. */ + for (lane = 0; lane < LANE_COUNT_DP_MAX && + lane < link->cur_link_settings.lane_count; lane++) { /* check status of lanes 0,1 * changed DpcdAddress_Lane01Status (0x202) */ @@ -1780,6 +1784,33 @@ (unsigned char *)(&link_settings.link_rate), 1); + /* + * DF-1319 / DF-3987: DP_TEST_LANE_COUNT and DP_TEST_LINK_RATE are + * raw sink bytes. A malicious sink can hand back e.g. 0xFF, which + * is persisted into verified_link_cap (below) and into + * link->cur_link_settings by dp_retrain_link_dp_test + * (dc_link_hwss.c:319) and then used as a loop bound by + * dp_test_send_phy_test_pattern and by + * hpd_rx_irq_check_link_loss_status. Reject anything the DP spec + * does not define before it poisons driver state. + */ + if (link_settings.lane_count != LANE_COUNT_ONE && + link_settings.lane_count != LANE_COUNT_TWO && + link_settings.lane_count != LANE_COUNT_FOUR) { + DC_LOG_ERROR("%s: invalid DP_TEST_LANE_COUNT 0x%02x\n", + __func__, link_settings.lane_count); + return; + } + if (link_settings.link_rate != LINK_RATE_LOW && + link_settings.link_rate != LINK_RATE_HIGH && + link_settings.link_rate != LINK_RATE_RBR2 && + link_settings.link_rate != LINK_RATE_HIGH2 && + link_settings.link_rate != LINK_RATE_HIGH3) { + DC_LOG_ERROR("%s: invalid DP_TEST_LINK_RATE 0x%02x\n", + __func__, link_settings.link_rate); + return; + } + /* Set preferred link settings */ link->verified_link_cap.lane_count = link_settings.lane_count; link->verified_link_cap.link_rate = link_settings.link_rate; @@ -1878,8 +1909,10 @@ /* prepare link training settings */ link_settings.link = link->cur_link_settings; - for (lane = 0; lane < - (unsigned int)(link->cur_link_settings.lane_count); + /* DF-3987: cur_link_settings.lane_count is sink-fed state; never + * index lane_settings[LANE_COUNT_DP_MAX] past LANE_COUNT_DP_MAX. */ + for (lane = 0; lane < LANE_COUNT_DP_MAX && + lane < (unsigned int)(link->cur_link_settings.lane_count); lane++) { dpcd_lane_adjust.raw = get_nibble_at_index(&dpcd_lane_adjustment[0].raw, lane); |