diff options
| author | Harry Wentland <harry.wentland@amd.com> | 2026-05-12 15:24:22 -0400 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2026-07-04 13:38:37 +0200 |
| commit | e94f5323c41f32a74160378c3b19850d1f203ad5 (patch) | |
| tree | 31dfe102646a89272d3cc42fcac8a0c5e190a434 | |
| parent | 946b97d632f0f58a705dafac644c1e9346e01f35 (diff) | |
| download | linux-stable-e94f5323c41f32a74160378c3b19850d1f203ad5.tar.gz linux-stable-e94f5323c41f32a74160378c3b19850d1f203ad5.zip | |
drm/amd/display: Bound VBIOS record-chain walk loops
[ Upstream commit ff287df16a1a58aca78b08d1f3ee09fc44da0351 ]
[Why & How]
All record-chain walk loops in bios_parser.c and bios_parser2.c use
for(;;) and only terminate on a 0xFF record_type sentinel or zero
record_size. A malformed VBIOS image missing the terminator record
causes unbounded iteration at probe time, potentially hundreds of
thousands of iterations with record_size=1. In the final iterations
near the BIOS image boundary, struct casts beyond the 2-byte header
validated by GET_IMAGE can also read out of bounds.
Cap all 14 record-chain walk loops to BIOS_MAX_NUM_RECORD (256)
iterations. The atombios.h defines up to 22 distinct record types
and atomfirmware.h has 13. Assuming an average of less than 10
records per type (which is reasonable since most are connector-
based) 256 is a generous upper bound.
Fixes: 4562236b3bc0 ("drm/amd/dc: Add dc display driver (v2)")
Assisted-by: Copilot:claude-opus-4.6 Mythos
Reviewed-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Harry Wentland <harry.wentland@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
(cherry picked from commit 95700a3d660287ed657d6892f7be9ffc0e294a93)
Cc: stable@vger.kernel.org
Signed-off-by: Sasha Levin <sashal@kernel.org>
| -rw-r--r-- | drivers/gpu/drm/amd/display/dc/bios/bios_parser.c | 15 | ||||
| -rw-r--r-- | drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c | 12 | ||||
| -rw-r--r-- | drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.h | 5 |
3 files changed, 23 insertions, 9 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c index d37ee8277480..b7b9e4c99537 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c @@ -223,6 +223,7 @@ static enum bp_result bios_parser_get_i2c_info(struct dc_bios *dcb, ATOM_COMMON_RECORD_HEADER *header; ATOM_I2C_RECORD *record; struct bios_parser *bp = BP_FROM_DCB(dcb); + int i; if (!info) return BP_RESULT_BADINPUT; @@ -235,7 +236,7 @@ static enum bp_result bios_parser_get_i2c_info(struct dc_bios *dcb, offset = le16_to_cpu(object->usRecordOffset) + bp->object_info_tbl_offset; - for (;;) { + for (i = 0; i < BIOS_MAX_NUM_RECORD; i++) { header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset); if (!header) @@ -294,11 +295,12 @@ static enum bp_result bios_parser_get_device_tag_record( { ATOM_COMMON_RECORD_HEADER *header; uint32_t offset; + int i; offset = le16_to_cpu(object->usRecordOffset) + bp->object_info_tbl_offset; - for (;;) { + for (i = 0; i < BIOS_MAX_NUM_RECORD; i++) { header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset); if (!header) @@ -870,6 +872,7 @@ static ATOM_HPD_INT_RECORD *get_hpd_record(struct bios_parser *bp, { ATOM_COMMON_RECORD_HEADER *header; uint32_t offset; + int i; if (!object) { BREAK_TO_DEBUGGER(); /* Invalid object */ @@ -879,7 +882,7 @@ static ATOM_HPD_INT_RECORD *get_hpd_record(struct bios_parser *bp, offset = le16_to_cpu(object->usRecordOffset) + bp->object_info_tbl_offset; - for (;;) { + for (i = 0; i < BIOS_MAX_NUM_RECORD; i++) { header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset); if (!header) @@ -1576,6 +1579,7 @@ static ATOM_ENCODER_CAP_RECORD_V2 *get_encoder_cap_record( { ATOM_COMMON_RECORD_HEADER *header; uint32_t offset; + int i; if (!object) { BREAK_TO_DEBUGGER(); /* Invalid object */ @@ -1585,7 +1589,7 @@ static ATOM_ENCODER_CAP_RECORD_V2 *get_encoder_cap_record( offset = le16_to_cpu(object->usRecordOffset) + bp->object_info_tbl_offset; - for (;;) { + for (i = 0; i < BIOS_MAX_NUM_RECORD; i++) { header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset); if (!header) @@ -2667,6 +2671,7 @@ enum bp_result update_slot_layout_info( unsigned int record_offset) { unsigned int j; + unsigned int n; struct bios_parser *bp; ATOM_BRACKET_LAYOUT_RECORD *record; ATOM_COMMON_RECORD_HEADER *record_header; @@ -2676,7 +2681,7 @@ enum bp_result update_slot_layout_info( record = NULL; record_header = NULL; - for (;;) { + for (n = 0; n < BIOS_MAX_NUM_RECORD; n++) { record_header = (ATOM_COMMON_RECORD_HEADER *) GET_IMAGE(ATOM_COMMON_RECORD_HEADER, record_offset); 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 2ad367212124..9e9476f87f61 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c @@ -296,6 +296,7 @@ static enum bp_result bios_parser_get_i2c_info(struct dc_bios *dcb, struct atom_i2c_record *record; struct atom_i2c_record dummy_record = {0}; struct bios_parser *bp = BP_FROM_DCB(dcb); + int i; if (!info) return BP_RESULT_BADINPUT; @@ -316,7 +317,7 @@ static enum bp_result bios_parser_get_i2c_info(struct dc_bios *dcb, offset = object->disp_recordoffset + bp->object_info_tbl_offset; - for (;;) { + for (i = 0; i < BIOS_MAX_NUM_RECORD; i++) { header = GET_IMAGE(struct atom_common_record_header, offset); if (!header) @@ -446,6 +447,7 @@ static struct atom_hpd_int_record *get_hpd_record( { struct atom_common_record_header *header; uint32_t offset; + int i; if (!object) { BREAK_TO_DEBUGGER(); /* Invalid object */ @@ -455,7 +457,7 @@ static struct atom_hpd_int_record *get_hpd_record( offset = le16_to_cpu(object->disp_recordoffset) + bp->object_info_tbl_offset; - for (;;) { + for (i = 0; i < BIOS_MAX_NUM_RECORD; i++) { header = GET_IMAGE(struct atom_common_record_header, offset); if (!header) @@ -1423,6 +1425,7 @@ static struct atom_encoder_caps_record *get_encoder_cap_record( { struct atom_common_record_header *header; uint32_t offset; + int i; if (!object) { BREAK_TO_DEBUGGER(); /* Invalid object */ @@ -1431,7 +1434,7 @@ static struct atom_encoder_caps_record *get_encoder_cap_record( offset = object->encoder_recordoffset + bp->object_info_tbl_offset; - for (;;) { + for (i = 0; i < BIOS_MAX_NUM_RECORD; i++) { header = GET_IMAGE(struct atom_common_record_header, offset); if (!header) @@ -1870,6 +1873,7 @@ static enum bp_result update_slot_layout_info( { unsigned int record_offset; unsigned int j; + unsigned int n; struct atom_display_object_path_v2 *object; struct atom_bracket_layout_record *record; struct atom_common_record_header *record_header; @@ -1891,7 +1895,7 @@ static enum bp_result update_slot_layout_info( (object->disp_recordoffset) + (unsigned int)(bp->object_info_tbl_offset); - for (;;) { + for (n = 0; n < BIOS_MAX_NUM_RECORD; n++) { record_header = (struct atom_common_record_header *) GET_IMAGE(struct atom_common_record_header, diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.h b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.h index 75a29e68fb27..991bbca95097 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.h +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.h @@ -38,4 +38,9 @@ uint32_t bios_get_vga_enabled_displays(struct dc_bios *bios); #define GET_IMAGE(type, offset) ((type *) bios_get_image(&bp->base, offset, sizeof(type))) +/* Upper bound on the number of records in a VBIOS record chain. Prevents + * unbounded looping if the VBIOS image is malformed and lacks a terminator. + */ +#define BIOS_MAX_NUM_RECORD 256 + #endif |
