PR #24590 opened by michaelni URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24590 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24590.patch
The write loop in av_dynamic_hdr_plus_to_t35() nested the color_saturation_mapping_flag and color_saturation_weight put_bits calls inside the tone_mapping_flag block, while the size calculation and the parser treat these fields as unconditional per window. When tone_mapping_flag is 0 and color_saturation_mapping_flag is 1, fewer bits than allocated were written, leaving uninitialized heap bytes in the returned buffer. Move the writes outside the tone_mapping_flag block to match. Fixes: read of uninitialized memory Fixes: Yy1uJcbmyeBp Fixes: AISLE-2026-0100-00011 Found-by: Joshua Rogers <[email protected]> From 4705e4d151c6c00c9546da0eb55419801fe7b432 Mon Sep 17 00:00:00 2001 From: Joshua Rogers <[email protected]> Date: Mon, 31 Aug 2026 15:31:18 +0200 Subject: [PATCH 1/2] avutil/hdr_dynamic_metadata: fix uninitialized bytes when color saturation is set without tone mapping The write loop in av_dynamic_hdr_plus_to_t35() nested the color_saturation_mapping_flag and color_saturation_weight put_bits calls inside the tone_mapping_flag block, while the size calculation and the parser treat these fields as unconditional per window. When tone_mapping_flag is 0 and color_saturation_mapping_flag is 1, fewer bits than allocated were written, leaving uninitialized heap bytes in the returned buffer. Move the writes outside the tone_mapping_flag block to match. Fixes: read of uninitialized memory Fixes: Yy1uJcbmyeBp Fixes: AISLE-2026-0100-00011 Found-by: Joshua Rogers <[email protected]> --- libavutil/hdr_dynamic_metadata.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libavutil/hdr_dynamic_metadata.c b/libavutil/hdr_dynamic_metadata.c index 4c9ac25970..9b46499343 100644 --- a/libavutil/hdr_dynamic_metadata.c +++ b/libavutil/hdr_dynamic_metadata.c @@ -379,11 +379,11 @@ int av_dynamic_hdr_plus_to_t35(const AVDynamicHDRPlus *s, uint8_t **data, size_t for (int i = 0; i < s->params[w].num_bezier_curve_anchors; i++) put_bits(pb, 10, s->params[w].bezier_curve_anchors[i].num * bezier_anchor_den / s->params[w].bezier_curve_anchors[i].den); - put_bits(pb, 1, s->params[w].color_saturation_mapping_flag); - if (s->params[w].color_saturation_mapping_flag) - put_bits(pb, 6, s->params[w].color_saturation_weight.num * saturation_weight_den / - s->params[w].color_saturation_weight.den); } + put_bits(pb, 1, s->params[w].color_saturation_mapping_flag); + if (s->params[w].color_saturation_mapping_flag) + put_bits(pb, 6, s->params[w].color_saturation_weight.num * saturation_weight_den / + s->params[w].color_saturation_weight.den); } flush_put_bits(pb); -- 2.52.0 From ce77b6f53d655fbfc6a48af5e3a90512da1ddf33 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer <[email protected]> Date: Sat, 19 Sep 2026 23:47:13 +0200 Subject: [PATCH 2/2] tests/hdr_dynamic_metadata: Test tone_mapping_flag Found during triage/review of the security report --- libavutil/tests/hdr_dynamic_metadata.c | 25 ++++++++++--------------- tests/ref/fate/hdr_dynamic_metadata | 2 +- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/libavutil/tests/hdr_dynamic_metadata.c b/libavutil/tests/hdr_dynamic_metadata.c index c2126fb45d..e85604e4f0 100644 --- a/libavutil/tests/hdr_dynamic_metadata.c +++ b/libavutil/tests/hdr_dynamic_metadata.c @@ -295,11 +295,7 @@ static void fill_hdr_plus_conforming(AVDynamicHDRPlus *s) /* Deliberately NOT a conforming Version 1 payload: it combines a second * processing window, both actual-peak-luminance matrices and * ColorSaturationWeight, all of which ยง9.4 excludes for Version 1. It exists - * only to drive the optional serializer/parser branches those fields guard. - * - * tone_mapping_flag stays set for every window because the serializer writes - * color_saturation_mapping_flag inside the tone-mapping block while the parser - * reads it outside; only tone_mapping_flag=1 round-trips today. */ + * only to drive the optional serializer/parser branches those fields guard. */ static void fill_hdr_plus_synthetic(AVDynamicHDRPlus *s) { memset(s, 0, sizeof(*s)); @@ -362,17 +358,16 @@ static void fill_hdr_plus_synthetic(AVDynamicHDRPlus *s) s->mastering_display_actual_peak_luminance[i][j] = (AVRational){ 15 - (i * 2 + j), PEAK_LUMINANCE_DEN }; + s->params[0].tone_mapping_flag = 1; + s->params[0].knee_point_x = (AVRational){ 500, KNEE_POINT_DEN }; + s->params[0].knee_point_y = (AVRational){ 800, KNEE_POINT_DEN }; + s->params[0].num_bezier_curve_anchors = 3; + s->params[0].bezier_curve_anchors[0] = (AVRational){ 100, BEZIER_ANCHOR_DEN }; + s->params[0].bezier_curve_anchors[1] = (AVRational){ 500, BEZIER_ANCHOR_DEN }; + s->params[0].bezier_curve_anchors[2] = (AVRational){ 900, BEZIER_ANCHOR_DEN }; + s->params[1].tone_mapping_flag = 0; + for (int w = 0; w < 2; w++) { - s->params[w].tone_mapping_flag = 1; - s->params[w].knee_point_x = (AVRational){ 500 + w, KNEE_POINT_DEN }; - s->params[w].knee_point_y = (AVRational){ 800 + w, KNEE_POINT_DEN }; - s->params[w].num_bezier_curve_anchors = 3; - s->params[w].bezier_curve_anchors[0] = - (AVRational){ 100 + w, BEZIER_ANCHOR_DEN }; - s->params[w].bezier_curve_anchors[1] = - (AVRational){ 500 + w, BEZIER_ANCHOR_DEN }; - s->params[w].bezier_curve_anchors[2] = - (AVRational){ 900 + w, BEZIER_ANCHOR_DEN }; s->params[w].color_saturation_mapping_flag = 1; s->params[w].color_saturation_weight = (AVRational){ 8 + w, SATURATION_DEN }; diff --git a/tests/ref/fate/hdr_dynamic_metadata b/tests/ref/fate/hdr_dynamic_metadata index fbd10e79e9..118f69d7e5 100644 --- a/tests/ref/fate/hdr_dynamic_metadata +++ b/tests/ref/fate/hdr_dynamic_metadata @@ -54,7 +54,7 @@ decoded: maxscl: 20000/100000 30000/100000 40000/100000 average_maxrgb=25000/100000 distribution_maxrgb: n=1 25%=12500/100000 fraction_bright_pixels=100/1000 - tone_mapping_flag=1 knee=501/4095,801/4095 anchors=3: 101/1023 501/1023 901/1023 + tone_mapping_flag=0 color_saturation_mapping_flag=1 weight=9/8 Testing error paths -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
