CVE-2025-60481
Description
A NULL pointer dereference in GPAC's MP4Box allows attackers to cause a Denial of Service via a crafted AC4 audio file.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
A NULL pointer dereference in GPAC's MP4Box allows attackers to cause a Denial of Service via a crafted AC4 audio file.
Vulnerability
A NULL pointer dereference vulnerability exists in the gf_odf_ac4_cfg_dsi_v1 function within odf/descriptors.c of GPAC Project/MP4Box. The issue arises due to insufficient validation of pointers when processing AC4 audio stream configurations, specifically when handling malformed or crafted DSI (Decoder Specific Info) substructures. This vulnerability affects versions prior to 26.02 [1][2].
Exploitation
An attacker can trigger this vulnerability by providing a specially crafted AC4 file to the MP4Box utility. No special privileges or network access are required beyond the ability to supply a malicious file to the application, which then triggers the vulnerable code path during the parsing or information extraction process [2].
Impact
Successful exploitation of this vulnerability results in a segmentation fault, leading to a Denial of Service (DoS) of the MP4Box application. This crash occurs during the processing of the media file, potentially disrupting services or workflows that rely on the utility for media analysis or conversion [2].
Mitigation
This issue is addressed in GPAC/MP4Box versions 26.02 and later. Users are advised to update their installations to the latest version to incorporate the necessary pointer validation checks [1].
AI Insight generated on Jun 1, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected products
1Patches
1e02d1fd24cdcfix several ac4 fuzzing issues:
2 files changed · +117 −34
src/media_tools/av_parsers.c+50 −3 modified@@ -15277,6 +15277,9 @@ static Bool gf_ac4_substream_group_info(GF_BitStream *bs, gf_ac4_oamd_substream_info(bs, ginfo->b_substreams_present); } + if (ginfo->substreams) { + gf_list_del(ginfo->substreams); + } ginfo->substreams = gf_list_new(); for (i = 0; i < ginfo->n_lf_substreams; i++) { @@ -15508,7 +15511,7 @@ static Bool gf_ac4_presentation_v1_info(GF_BitStream *bs, if (pinfo->n_add_emdf_substreams == 0) { pinfo->n_add_emdf_substreams = gf_ac4_variable_bits(bs, 2) + 4; } - for (i = 0; i < pinfo->n_add_emdf_substreams; i++) { + for (i = 0; i < pinfo->n_add_emdf_substreams && i < MIN(GF_ARRAY_LENGTH(pinfo->substream_emdf_version), GF_ARRAY_LENGTH(pinfo->substream_key_id)); i++) { gf_ac4_emdf_info(bs, &emdf_version, &key_id); // ETSI TS 103 190-2 V1.2.1 (2018-02) E.8.16 & E.8.17 @@ -15532,7 +15535,7 @@ static GF_AC4PresentationV1* gf_ac4_get_presentation_by_substreamgroup(GF_AC4Str p = gf_list_get(stream->presentations, i); for (j = 0; j < p->n_substream_groups; j++) { x = gf_list_get(p->substream_group_indexs, j); - if(idx == *x) { + if(x && idx == *x) { return p; } } @@ -15638,8 +15641,10 @@ static s32 gf_ac4_presentation_ch_mode(GF_AC4PresentationV1 *p) // ETSI TS 103 190-2 V1.2.1 (2018-02) 6.3.3.1.27 Table 91 for (i = 0; i < p->n_substream_groups; i++){ group = gf_list_get(p->substream_groups, i); + if (!group) continue; for (j = 0; j < group->n_lf_substreams; j++){ substream = gf_list_get(group->substreams, j); + if (!substream) continue; if (group->b_channel_coded){ pres_ch_mode = gf_ac4_cfg_super_set(pres_ch_mode, substream->ch_mode); }else { @@ -15663,6 +15668,7 @@ static u32 gf_ac4_presentation_channel_mask_v1(GF_AC4PresentationV1 *p) // ETSI TS 103 190-2 V1.2.1 (2018-02) E.10.14 for (i = 0; i < p->n_substream_groups; i++){ group = gf_list_get(p->substream_groups, i); + if (!group) continue; for (j = 0; j < group->n_lf_substreams; j++){ substream = gf_list_get(group->substreams, j); if (group->b_channel_coded){ @@ -15766,8 +15772,10 @@ static s32 gf_ac4_get_b_presentation_core_differs(GF_AC4PresentationV1 *p, s32 p // ETSI TS 103 190-2 V1.2.1 (2018-02) Table 93 for (i = 0; i < p->n_substream_groups; i ++){ group = gf_list_get(p->substream_groups, i); + if (!group) continue; for (j = 0; j < group->n_lf_substreams; j++){ substream = gf_list_get(group->substreams, j); + if (!substream) continue; if (group->b_channel_coded){ ch_mode_core = gf_ac4_get_ch_mode_core(group->b_channel_coded, substream->b_ajoc, @@ -15957,10 +15965,13 @@ static Bool gf_ac4_raw_frame(GF_BitStream *bs, GF_AC4Config* hdr, Bool full_pars for (i = 0; i < n_presentations; i++) { GF_AC4PresentationV1 *p = (GF_AC4PresentationV1*)gf_list_get(hdr_p_list, i); + // calloc the space for GF_LIST<GF_AC4SubStreamGroupV1> p->substream_groups = gf_list_new(); + for (j = 0; j < p->n_substream_groups; j++) { idx = gf_list_get(p->substream_group_indexs, j); + if (!idx) continue; group = (GF_AC4SubStreamGroupV1*)gf_list_get(temp_groups, *idx); if (group) { gf_list_add(p->substream_groups, group); @@ -15970,6 +15981,13 @@ static Bool gf_ac4_raw_frame(GF_BitStream *bs, GF_AC4Config* hdr, Bool full_pars break; } } + // remove added groups from temp to avoid double frees + for (j=0; j < gf_list_count(p->substream_groups); j++) { + group = (GF_AC4SubStreamGroupV1*)gf_list_get(p->substream_groups, j); + if (group) { + gf_list_del_item(temp_groups, group); + } + } // ETSI TS 103 190-2 V1.2.1 (2018-02) E.10 // other elements in GF_AC4PresentationV1 for Sample Description Box @@ -16007,7 +16025,17 @@ static Bool gf_ac4_raw_frame(GF_BitStream *bs, GF_AC4Config* hdr, Bool full_pars gf_list_del(p->substream_group_indexs); } - // free auxiliary information temp_groups, don't delete the memory of GF_AC4SubStreamGroupV1 + // free auxiliary information temp_groups that have not been copied elsewhere + while ((group = (GF_AC4SubStreamGroupV1*)gf_list_pop_back(temp_groups))) { + if (group->substreams) { + for (int s = 0; s < gf_list_count(group->substreams); s++) { + GF_AC4SubStream* subs = gf_list_get(group->substreams, s); + gf_free(subs); + } + gf_list_del(group->substreams); + } + gf_free(group); + } gf_list_del(temp_groups); // If the substreams are channel-based, calculate channel_count with speaker_group_index_mask of the first/default presentation. If the substreams are non-channel-based, set channel_count to max(channel_count) @@ -16132,11 +16160,30 @@ Bool gf_ac4_parser_bs(GF_BitStream *bs, GF_AC4Config *hdr, Bool full_parse) /* fill some AC4 DSI info */ stream->ac4_dsi_version = 1; + if (stream->fs_index >= GF_ARRAY_LENGTH(AC4_SAMPLING_FREQ_TABLE)) { + GF_LOG(GF_LOG_ERROR, GF_LOG_CODING, ("[AC4] stream fs_index %d >= length AC4_SAMPLING_FREQ_TABLE\n", stream->fs_index)); + gf_bs_seek(bs, pos); + return GF_FALSE; + } hdr->sample_rate = AC4_SAMPLING_FREQ_TABLE[stream->fs_index]; if (stream->fs_index == 0) { + + if (stream->frame_rate_index >= MIN(GF_ARRAY_LENGTH(AC4_SAMPLE_DELTA_TABLE_441), GF_ARRAY_LENGTH(AC4_MEDIA_TIMESCALE_441))) { + GF_LOG(GF_LOG_ERROR, GF_LOG_CODING, ("[AC4] stream frame_rate_index %d >= length AC4_SAMPLE_DELTA_TABLE_441 or AC4_MEDIA_TIMESCALE_441\n", stream->frame_rate_index)); + gf_bs_seek(bs, pos); + return GF_FALSE; + } hdr->sample_duration = AC4_SAMPLE_DELTA_TABLE_441[stream->frame_rate_index]; hdr->media_time_scale = AC4_MEDIA_TIMESCALE_441[stream->frame_rate_index]; + } else { + + if (stream->frame_rate_index >= MIN(GF_ARRAY_LENGTH(AC4_SAMPLE_DELTA_TABLE_48), GF_ARRAY_LENGTH(AC4_MEDIA_TIMESCALE_48))) { + GF_LOG(GF_LOG_ERROR, GF_LOG_CODING, ("[AC4] stream frame_rate_index %d >= length AC4_SAMPLE_DELTA_TABLE_48 or AC4_MEDIA_TIMESCALE_48\n", stream->frame_rate_index)); + gf_bs_seek(bs, pos); + return GF_FALSE; + } + hdr->sample_duration = AC4_SAMPLE_DELTA_TABLE_48[stream->frame_rate_index]; hdr->media_time_scale = AC4_MEDIA_TIMESCALE_48[stream->frame_rate_index]; }
src/odf/descriptors.c+67 −31 modified@@ -1895,10 +1895,19 @@ GF_Err gf_odf_ac4_cfg_alternative_info(GF_AC4AlternativeInfo *info, GF_BitStream u32 i; GF_AC4_SSS(bs, info->name_len, 16, size, desc_mode); + + if (info->name_len >= GF_ARRAY_LENGTH(info->presentation_name)) + return GF_ISOM_INVALID_MEDIA; + for (i = 0; i < info->name_len; i++) { GF_AC4_SSS(bs, info->presentation_name[i], 8, size, desc_mode); } + GF_AC4_SSS(bs, info->n_targets, 5, size, desc_mode); + + if (info->n_targets >= MIN(GF_ARRAY_LENGTH(info->target_md_compat), GF_ARRAY_LENGTH(info->target_device_category))) + return GF_ISOM_INVALID_MEDIA; + for (i = 0; i < info->n_targets; i++) { GF_AC4_SSS(bs, info->target_md_compat[i], 3, size, desc_mode); GF_AC4_SSS(bs, info->target_device_category[i], 8, size, desc_mode); @@ -1957,6 +1966,9 @@ GF_Err gf_odf_ac4_cfg_substream_group_dsi(GF_AC4SubStreamGroupV1 *g, GF_BitStrea u32 i; GF_AC4SubStream *s; + if (!g) + return GF_BAD_PARAM; + GF_AC4_SSS(bs, g->b_substreams_present, 1, size, desc_mode); GF_AC4_SSS(bs, g->b_hsf_ext, 1, size, desc_mode); GF_AC4_SSS(bs, g->b_channel_coded, 1, size, desc_mode); @@ -2045,7 +2057,8 @@ GF_Err gf_odf_ac4_cfg_presentation_v1_dsi(GF_AC4PresentationV1 *p, GF_BitStream } else { // write or get_size g = (GF_AC4SubStreamGroupV1*)gf_list_get(p->substream_groups, 0); } - gf_odf_ac4_cfg_substream_group_dsi(g, bs, size, desc_mode); + if (g) + gf_odf_ac4_cfg_substream_group_dsi(g, bs, size, desc_mode); } else { GF_AC4_SSS(bs, p->b_multi_pid, 1, size, desc_mode); @@ -2088,7 +2101,7 @@ GF_Err gf_odf_ac4_cfg_presentation_v1_dsi(GF_AC4PresentationV1 *p, GF_BitStream } if (p->b_add_emdf_substreams) { GF_AC4_SSS(bs, p->n_add_emdf_substreams, 7, size, desc_mode); - for (i = 0; i < p->n_add_emdf_substreams; i++) { + for (i = 0; i < p->n_add_emdf_substreams && i < GF_ARRAY_LENGTH(p->substream_emdf_version) && i < GF_ARRAY_LENGTH(p->substream_key_id); i++) { GF_AC4_SSS(bs, p->substream_emdf_version[i], 5, size, desc_mode); GF_AC4_SSS(bs, p->substream_key_id[i], 10, size, desc_mode); } @@ -2136,6 +2149,9 @@ GF_Err gf_odf_ac4_cfg_dsi_v1(GF_AC4StreamInfo *dsi, GF_BitStream *bs, u64 *size, u8 *t_data = NULL; GF_BitStream *t_bs; + if (!dsi) + return GF_BAD_PARAM; + GF_AC4_SSS(bs, dsi->ac4_dsi_version, 3, size, desc_mode); GF_AC4_SSS(bs, dsi->bitstream_version, 7, size, desc_mode); GF_AC4_SSS(bs, dsi->fs_index, 1, size, desc_mode); @@ -2145,6 +2161,7 @@ GF_Err gf_odf_ac4_cfg_dsi_v1(GF_AC4StreamInfo *dsi, GF_BitStream *bs, u64 *size, // check whether legacy presentations are added in the presentations for (i = 0; i < dsi->n_presentations; i++) { p = gf_list_get(dsi->presentations, i); + if (!p) continue; if (p->presentation_version == 1) { legacy_pres_num += 1; } else if (p->presentation_version == 2) { @@ -2219,12 +2236,13 @@ GF_Err gf_odf_ac4_cfg_dsi_v1(GF_AC4StreamInfo *dsi, GF_BitStream *bs, u64 *size, presentation_bytes = (u32) (gf_bs_get_position(bs) - pos); skip_bytes = pres_bytes - presentation_bytes; - for (j = 0; j < skip_bytes; j++) { + for (j = 0; j < skip_bytes && gf_bs_available(bs); j++) { gf_bs_read_int(bs, 8); } } else if (desc_mode == GF_AC4_DESCMODE_WRITE) { p = gf_list_get(dsi->presentations, i); + if (!p) continue; t_bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); if (p->presentation_version == 0) { @@ -2343,7 +2361,7 @@ void gf_odf_ac4_cfg_deep_copy(GF_AC4Config *dst, GF_AC4Config *src) memcpy(dst, src, sizeof(GF_AC4Config)); - if (!src->stream.presentations || gf_list_count(presentations_src) == 0) { + if (!src->stream.presentations) { return; } @@ -2369,7 +2387,7 @@ void gf_odf_ac4_presentation_deep_copy(GF_AC4PresentationV1 *pres_dst, GF_AC4Pre memcpy(pres_dst, pres_src, sizeof(GF_AC4PresentationV1)); - if (!pres_src->substream_groups || gf_list_count(pres_src->substream_groups) == 0) { + if (!pres_src->substream_groups) { return; } @@ -2381,7 +2399,7 @@ void gf_odf_ac4_presentation_deep_copy(GF_AC4PresentationV1 *pres_dst, GF_AC4Pre memcpy(group_dst, group_src, sizeof(GF_AC4SubStreamGroupV1)); gf_list_add(pres_dst->substream_groups, group_dst); - if (!group_src->substreams || gf_list_count(group_src->substreams) == 0) { + if (!group_src->substreams) { continue; } @@ -2399,44 +2417,62 @@ void gf_odf_ac4_presentation_deep_copy(GF_AC4PresentationV1 *pres_dst, GF_AC4Pre GF_EXPORT void gf_odf_ac4_cfg_clean_list(GF_AC4Config *cfg) { - u32 i, j, s; + u32 i, s; GF_AC4PresentationV1 *pres; GF_AC4SubStreamGroupV1 *group; GF_AC4SubStream *subs; - if (!cfg || !cfg->stream.presentations) { + if (!cfg) return; - } - for (i = 0; i < gf_list_count(cfg->stream.presentations); i++) { - pres = gf_list_get(cfg->stream.presentations, i); - if (!pres || !pres->substream_groups) { - continue; - } + if (cfg->stream.presentations) { - for (j = 0; pres && j < gf_list_count(pres->substream_groups); j++) { - group = gf_list_get(pres->substream_groups, j); - if (!group || !group->substreams) { - continue; - } + while ( (pres = gf_list_pop_back(cfg->stream.presentations)) ) { + + if (pres->substream_groups) { + + while ( (group = gf_list_pop_back(pres->substream_groups)) ) { + + if (group->substreams) { + + for (s = 0; s < gf_list_count(group->substreams); s++) { + subs = gf_list_get(group->substreams, s); + if (!subs) { + continue; + } + + gf_free(subs); + } + gf_list_del(group->substreams); + + } + gf_free(group); + + // remove potential duplicates of group + s32 idx = 1; + while (idx>=0) { + idx = gf_list_find(pres->substream_groups, group); + if (idx>=0) gf_list_rem(pres->substream_groups, idx); + } + } + gf_list_del(pres->substream_groups); + + // remove potential duplicates of substream_groups + for (i=0; i<gf_list_count(cfg->stream.presentations); i++) { + GF_AC4PresentationV1* pres2 = gf_list_get(cfg->stream.presentations, i); + if (pres2 && pres2->substream_groups == pres->substream_groups) { + pres2->substream_groups = NULL; + } - for (s = 0; group && s < gf_list_count(group->substreams); s++) { - subs = gf_list_get(group->substreams, s); - if (!subs) { - continue; } - gf_free(subs); } - gf_list_del(group->substreams); - gf_free(group); + gf_free(pres); } - gf_list_del(pres->substream_groups); - gf_free(pres); - } - gf_list_del(cfg->stream.presentations); - cfg->stream.presentations = NULL; + gf_list_del(cfg->stream.presentations); + cfg->stream.presentations = NULL; + } } GF_EXPORT
Vulnerability mechanics
Synthesis attempt was rejected by the grounding validator. Re-run pending.
References
4News mentions
0No linked articles in our index yet.