--- a/sys/dev/drm/amd/display/dc/dce80/dce80_resource.c +++ b/sys/dev/drm/amd/display/dc/dce80/dce80_resource.c @@ -659,12 +659,28 @@ static const struct encoder_feature_support link_enc_feature = { static struct link_encoder *dce80_link_encoder_create( const struct encoder_init_data *enc_init_data) { + enum transmitter transmitter = enc_init_data->transmitter; + enum channel_id channel = enc_init_data->channel; + enum hpd_source_id hpd_source = enc_init_data->hpd_source; struct dce110_link_encoder *enc110 = kzalloc(sizeof(struct dce110_link_encoder), GFP_KERNEL); if (!enc110) return NULL; + /* + * The transmitter/channel/hpd_source values come from the VBIOS + * object tables; UNKNOWN/Travis/UNIPHY_G/VGA variants index past + * the register tables below. Reject them instead of forming OOB + * pointers that later dereference as register addresses. + */ + if (transmitter < TRANSMITTER_UNIPHY_A || + transmitter > TRANSMITTER_NUTMEG_CRT || /* link_enc_regs[7] */ + channel < CHANNEL_ID_DDC1 || + channel > CHANNEL_ID_DDC6 || /* aux table is channel-1 */ + hpd_source < HPD_SOURCEID1 || + hpd_source > HPD_SOURCEID6) { /* hpd table [6] */ + kfree(enc110); + return NULL; + } + dce110_link_encoder_construct(enc110, enc_init_data, &link_enc_feature, - &link_enc_regs[enc_init_data->transmitter], - &link_enc_aux_regs[enc_init_data->channel - 1], - &link_enc_hpd_regs[enc_init_data->hpd_source]); + &link_enc_regs[transmitter], + &link_enc_aux_regs[channel - 1], + &link_enc_hpd_regs[hpd_source]); return &enc110->base; }