1
0
mirror of https://git.ffmpeg.org/ffmpeg.git synced 2026-10-24 02:09:03 +03:00

avformat/iamf_reader: sanitize block and subblock durations and count

Abort earlier if subblock durations are inconsistent with their containing block,
and ensure each subblock duration is at least 1.

Signed-off-by: James Almer <jamrial@gmail.com>
This commit is contained in:
James Almer
2026-02-07 19:26:54 -03:00
parent 34ac6f6b07
commit 8665748584

View File

@@ -102,6 +102,7 @@ static int audio_frame_obu(AVFormatContext *s, const IAMFDemuxContext *c,
static int parameter_block_obu(AVFormatContext *s, IAMFDemuxContext *c,
AVIOContext *pbc, int len)
{
const IAMFAudioElement *audio_element;
const IAMFParamDefinition *param_definition;
const AVIAMFParamDefinition *param;
AVIAMFParamDefinition *out_param = NULL;
@@ -138,6 +139,7 @@ static int parameter_block_obu(AVFormatContext *s, IAMFDemuxContext *c,
goto fail;
}
audio_element = param_definition->audio_element;
param = param_definition->param;
if (!param_definition->mode) {
duration = ffio_read_leb(pb);
@@ -145,10 +147,23 @@ static int parameter_block_obu(AVFormatContext *s, IAMFDemuxContext *c,
ret = AVERROR_INVALIDDATA;
goto fail;
}
if (audio_element) {
const IAMFCodecConfig *codec_config = ff_iamf_get_codec_config(&c->iamf, audio_element->codec_config_id);
if (duration > av_rescale(codec_config->nb_samples, codec_config->sample_rate, param->parameter_rate)) {
av_log(s, AV_LOG_ERROR, "Invalid block duration in parameter_id %u\n", parameter_id);
ret = AVERROR_INVALIDDATA;
goto fail;
}
}
constant_subblock_duration = ffio_read_leb(pb);
if (constant_subblock_duration == 0)
nb_subblocks = ffio_read_leb(pb);
else {
if (constant_subblock_duration > duration) {
av_log(s, AV_LOG_ERROR, "Invalid block duration in parameter_id %u\n", parameter_id);
ret = AVERROR_INVALIDDATA;
goto fail;
}
nb_subblocks = duration / constant_subblock_duration;
total_duration = duration;
}
@@ -158,6 +173,12 @@ static int parameter_block_obu(AVFormatContext *s, IAMFDemuxContext *c,
nb_subblocks = param->nb_subblocks;
}
if (nb_subblocks > duration) {
av_log(s, AV_LOG_ERROR, "Invalid duration or subblock count in parameter_id %u\n", parameter_id);
ret = AVERROR_INVALIDDATA;
goto fail;
}
out_param = av_iamf_param_definition_alloc(param->type, nb_subblocks, &out_param_size);
if (!out_param) {
ret = AVERROR(ENOMEM);
@@ -177,6 +198,11 @@ static int parameter_block_obu(AVFormatContext *s, IAMFDemuxContext *c,
if (!param_definition->mode && !constant_subblock_duration) {
subblock_duration = ffio_read_leb(pb);
if (duration - total_duration > subblock_duration) {
av_log(s, AV_LOG_ERROR, "Invalid subblock durations in parameter_id %u\n", parameter_id);
ret = AVERROR_INVALIDDATA;
goto fail;
}
total_duration += subblock_duration;
} else if (i == nb_subblocks - 1)
subblock_duration = duration - i * constant_subblock_duration;
@@ -211,10 +237,10 @@ static int parameter_block_obu(AVFormatContext *s, IAMFDemuxContext *c,
}
case AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN: {
AVIAMFReconGain *recon = subblock;
const IAMFAudioElement *audio_element = param_definition->audio_element;
const AVIAMFAudioElement *element = audio_element->celement;
const AVIAMFAudioElement *element;
av_assert0(audio_element && element);
av_assert0(audio_element && audio_element->celement);
element = audio_element->celement;
for (int i = 0; i < element->nb_layers; i++) {
const AVIAMFLayer *layer = element->layers[i];
if (layer->flags & AV_IAMF_LAYER_FLAG_RECON_GAIN) {