FAILED: patch "[PATCH] drm/amd/display: Bound VBIOS record-chain walk loops" failed to apply to 6.6-stable tree
[email protected]
maintainerThe patch below does not apply to the 6.6-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.6.y
git checkout FETCH_HEAD
git cherry-pick -x ff287df16a1a58aca78b08d1f3ee09fc44da0351
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026061552-hatchback-deserving-0abf@gregkh' --subject-prefix 'PATCH 6.6.y' HEAD^..
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From ff287df16a1a58aca78b08d1f3ee09fc44da0351 Mon Sep 17 00:00:00 2001
From: Harry Wentland <[email protected]>
Date: Tue, 12 May 2026 15:24:22 -0400
Subject: [PATCH] drm/amd/display: Bound VBIOS record-chain walk loops
[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.
drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +10 -5
@@ -222,6 +222,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 ;
@@ -234,7 +235,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)
@@ -293,11 +294,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)
@@ -966,6 +968,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 */
@@ -975,7 +978,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)
@@ -1670,6 +1673,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 */
@@ -1679,7 +1683,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)
@@ -2769,6 +2773,7 @@ static enum bp_result update_slot_layout_info(struct dc_bios *dcb, { (void )i;unsigned int j; +unsigned int n;struct bios_parser *bp;ATOM_BRACKET_LAYOUT_RECORD *record;ATOM_COMMON_RECORD_HEADER *record_header;
@@ -2778,7 +2783,7 @@ static enum bp_result update_slot_layout_info(struct dc_bios *dcb, record =NULL ; record_header =NULL ; -for (;;) { +for (n =0 ; n <BIOS_MAX_NUM_RECORD ; n++) { record_header =GET_IMAGE (ATOM_COMMON_RECORD_HEADER , record_offset);if (record_header ==NULL ) {
drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c +18 -9
@@ -396,6 +396,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 ;
@@ -429,7 +430,7 @@ static enum bp_result bios_parser_get_i2c_info(struct dc_bios *dcb,break ; } -for (;;) { +for (i =0 ; i <BIOS_MAX_NUM_RECORD ; i++) { header = GET_IMAGE(struct atom_common_record_header, offset);if (!header)
@@ -534,6 +535,7 @@ static struct atom_hpd_int_record *get_hpd_record_for_path_v3(struct bios_parser {struct atom_common_record_header *header;uint32_t offset; +int i;if (!object) {BREAK_TO_DEBUGGER ();/* Invalid object */
@@ -542,7 +544,7 @@ static struct atom_hpd_int_record *get_hpd_record_for_path_v3(struct bios_parser 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)
@@ -611,6 +613,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 */
@@ -620,7 +623,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)
@@ -2195,6 +2198,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 */
@@ -2203,7 +2207,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)
@@ -2232,6 +2236,7 @@ static struct atom_disp_connector_caps_record *get_disp_connector_caps_record( {struct atom_common_record_header *header;uint32_t offset; +int i;if (!object) {BREAK_TO_DEBUGGER ();/* Invalid object */
@@ -2240,7 +2245,7 @@ static struct atom_disp_connector_caps_record *get_disp_connector_caps_record( 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)
@@ -2268,6 +2273,7 @@ static struct atom_connector_caps_record *get_connector_caps_record(struct bios_ {struct atom_common_record_header *header;uint32_t offset; +int i;if (!object) {BREAK_TO_DEBUGGER ();/* Invalid object */
@@ -2276,7 +2282,7 @@ static struct atom_connector_caps_record *get_connector_caps_record(struct bios_ 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)
@@ -2354,6 +2360,7 @@ static struct atom_connector_speed_record *get_connector_speed_cap_record(struct {struct atom_common_record_header *header;uint32_t offset; +int i;if (!object) {BREAK_TO_DEBUGGER ();/* Invalid object */
@@ -2362,7 +2369,7 @@ static struct atom_connector_speed_record *get_connector_speed_cap_record(struct 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)
@@ -3263,6 +3270,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;
@@ -3284,7 +3292,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,
@@ -3378,6 +3386,7 @@ static enum bp_result update_slot_layout_info_v2( struct slot_layout_info *slot_layout_info) {unsigned int record_offset; +unsigned int n;struct atom_display_object_path_v3 *object;struct atom_bracket_layout_record_v2 *record;struct atom_common_record_header *record_header;
@@ -3400,7 +3409,7 @@ static enum bp_result update_slot_layout_info_v2( (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,
drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.h +5 -0
@@ -37,4 +37,9 @@ void bios_set_scratch_critical_state(struct dc_bios *bios, bool state);#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
Sasha Levin
maintainerPATCH 1/1 drm/amd/display: Bound VBIOS record-chain walk loops
From: Harry Wentland <[email protected]>
[ 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.
--- .../gpu/drm/amd/display/dc/bios/bios_parser.c | 15 +++++++---- .../drm/amd/display/dc/bios/bios_parser2.c | 27 ++++++++++++------- .../amd/display/dc/bios/bios_parser_helper.h | 5 ++++ 3 files changed, 33 insertions(+), 14 deletions(-)
drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +10 -5
@@ -225,6 +225,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 ;
@@ -237,7 +238,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)
@@ -296,11 +297,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)
@@ -873,6 +875,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 */
@@ -882,7 +885,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)
@@ -1577,6 +1580,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 */
@@ -1586,7 +1590,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)
@@ -2675,6 +2679,7 @@ static enum bp_result update_slot_layout_info(struct dc_bios *dcb, 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;
@@ -2684,7 +2689,7 @@ static enum bp_result update_slot_layout_info(struct dc_bios *dcb, record =NULL ; record_header =NULL ; -for (;;) { +for (n =0 ; n <BIOS_MAX_NUM_RECORD ; n++) { record_header =GET_IMAGE (ATOM_COMMON_RECORD_HEADER , record_offset);if (record_header ==NULL ) {
drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c +18 -9
@@ -391,6 +391,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 ;
@@ -424,7 +425,7 @@ static enum bp_result bios_parser_get_i2c_info(struct dc_bios *dcb,break ; } -for (;;) { +for (i =0 ; i <BIOS_MAX_NUM_RECORD ; i++) { header = GET_IMAGE(struct atom_common_record_header, offset);if (!header)
@@ -529,6 +530,7 @@ static struct atom_hpd_int_record *get_hpd_record_for_path_v3(struct bios_parser {struct atom_common_record_header *header;uint32_t offset; +int i;if (!object) {BREAK_TO_DEBUGGER ();/* Invalid object */
@@ -537,7 +539,7 @@ static struct atom_hpd_int_record *get_hpd_record_for_path_v3(struct bios_parser 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)
@@ -607,6 +609,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 */
@@ -616,7 +619,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)
@@ -2123,6 +2126,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 */
@@ -2131,7 +2135,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)
@@ -2160,6 +2164,7 @@ static struct atom_disp_connector_caps_record *get_disp_connector_caps_record( {struct atom_common_record_header *header;uint32_t offset; +int i;if (!object) {BREAK_TO_DEBUGGER ();/* Invalid object */
@@ -2168,7 +2173,7 @@ static struct atom_disp_connector_caps_record *get_disp_connector_caps_record( 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)
@@ -2196,6 +2201,7 @@ static struct atom_connector_caps_record *get_connector_caps_record(struct bios_ {struct atom_common_record_header *header;uint32_t offset; +int i;if (!object) {BREAK_TO_DEBUGGER ();/* Invalid object */
@@ -2204,7 +2210,7 @@ static struct atom_connector_caps_record *get_connector_caps_record(struct bios_ 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)
@@ -2284,6 +2290,7 @@ static struct atom_connector_speed_record *get_connector_speed_cap_record(struct {struct atom_common_record_header *header;uint32_t offset; +int i;if (!object) {BREAK_TO_DEBUGGER ();/* Invalid object */
@@ -2292,7 +2299,7 @@ static struct atom_connector_speed_record *get_connector_speed_cap_record(struct 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)
@@ -3136,6 +3143,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;
@@ -3157,7 +3165,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,
@@ -3251,6 +3259,7 @@ static enum bp_result update_slot_layout_info_v2( struct slot_layout_info *slot_layout_info) {unsigned int record_offset; +unsigned int n;struct atom_display_object_path_v3 *object;struct atom_bracket_layout_record_v2 *record;struct atom_common_record_header *record_header;
@@ -3273,7 +3282,7 @@ static enum bp_result update_slot_layout_info_v2( (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,
drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.h +5 -0
@@ -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
Signature · 1 line
2.53.0