CVE-2024-6064: Use After Free (CWE-416)
value: A vulnerability was found in GPAC 2.5-DEV-rev228-g11067ea92-master. It has been declared as problematic. This vulnerability affects the function xmt_node_end of the file src/scene_manager/loader_xmt.c of the component MP4Box. The manipulation leads to use after free. Local access is required to approach this attack. The exploit has been disclosed to the public and may be used. The name of the patch is f4b3e4d2f91bc1749e7a924a8ab171af03a355a8/c1b9c794bad8f262c56f3cf690567980d96662f5. It is recommended to apply a patch to fix this issue. The identifier of this vulnerability is VDB-268792.
CWE description: The product reuses or references memory after it has been freed. At some point afterward, the memory may be allocated again and saved in another pointer, while the original pointer references a location somewhere within the new allocation. Any operations using the original pointer are no longer valid because the memory "belongs" to the code that operates on the new pointer.
Published: 2024-06-17T21:15Z
Repository: https://github.com/gpac/gpac
Language: C
Files changed: src/scene_manager/loader_xmt.c
Commit date: 2024-06-13 11:00:50 +0200
Commit message: xmt links double free (#2874)

Diff: diff --git a/src/scene_manager/loader_xmt.c b/src/scene_manager/loader_xmt.c
index e88ab414a8a..11fb2f77d97 100644
--- a/src/scene_manager/loader_xmt.c
+++ b/src/scene_manager/loader_xmt.c
@@ -603,10 +603,54 @@ static void xmt_resolve_od_links(GF_XMTParser *parser)
 		gf_list_rem(parser->od_links, 0);
 	}
 }
 
 
+static void xmt_remove_link_for_descriptor(GF_XMTParser* parser, GF_Descriptor* desc) {
+
+	u32 i=0;
+	XMT_ODLink *l, *to_del=NULL;
+	while ((l = (XMT_ODLink*)gf_list_enum(parser->od_links, &i)) ) {
+		if (l->od && l->od == (GF_ObjectDescriptor*)desc) {
+			l->od = NULL;
+			to_del = l;
+			break;
+		}
+	}
+	if (to_del) {
+
+		i=0;
+		GF_Descriptor* subdesc;
+		while ((subdesc = gf_list_enum(((GF_ObjectDescriptor*)desc)->ESDescriptors, &i))) {
+			if (subdesc) xmt_remove_link_for_descriptor(parser, subdesc);
+		}
+
+		gf_list_del_item(parser->od_links, to_del);
+		if (to_del->desc_name) gf_free(to_del->desc_name);
+		gf_list_del(to_del->mf_urls);
+		gf_free(to_del);
+	}
+
+	XMT_ESDLink *esdl, *esdl_del=NULL;
+	i=0;
+	while ((esdl = (XMT_ESDLink *)gf_list_enum(parser->esd_links, &i))) {
+		if (esdl->esd && esdl->esd == (GF_ESD*)desc) {
+			esdl->esd = NULL;
+			esdl_del = esdl;
+			break;
+		}
+	}
+
+	if (esdl_del) {
+		gf_list_del_item(parser->esd_links, esdl_del);
+		if (esdl_del->desc_name) gf_free(esdl_del->desc_name);
+		gf_free(esdl_del);
+	}
+
+}
+
+
 static u32 xmt_get_next_node_id(GF_XMTParser *parser)
 {
 	u32 ID;
 	GF_SceneGraph *sc = parser->load->scene_graph;
 	if (parser->parsing_proto) sc = gf_sg_proto_get_graph(parser->parsing_proto);
@@ -1994,10 +2038,11 @@ GF_Descriptor *xmt_parse_descriptor(GF_XMTParser *parser, char *name, const GF_X
 	}
 	if (parent) {
 		e = gf_odf_desc_add_desc(parent, desc);
 		if (e) {
 			xmt_report(parser, GF_OK, "Invalid child descriptor");
+			xmt_remove_link_for_descriptor(parser, desc);
 			gf_odf_desc_del(desc);
 			return NULL;
 		}
 		/*finally check for scene manager streams (scene description, OD, ...)*/
 		if (parent->tag == GF_ODF_ESD_TAG) {
@@ -2670,18 +2715,14 @@ static void xmt_node_end(void *sax_cbck, const char *name, const char *name_spac
 			if ((parser->doc_type==1) && (parser->state==XMT_STATE_HEAD) && parser->load->ctx && !parser->load->ctx->root_od) {
 				parser->load->ctx->root_od = (GF_ObjectDescriptor *)desc;
 			}
 			else if (!parser->od_command) {
 				xmt_report(parser, GF_OK, "Warning: descriptor %s defined outside scene scope - skipping", name);
+
+				xmt_remove_link_for_descriptor(parser, desc);
 				gf_odf_desc_del(desc);
-				XMT_ODLink *prev_l = gf_list_last(parser->od_links);
-				if ((GF_Descriptor *) prev_l->od == desc) {
-					gf_list_pop_back(parser->od_links);
-					if (prev_l->desc_name) gf_free(prev_l->desc_name);
-					gf_list_del(prev_l->mf_urls);
-					gf_free(prev_l);
-				}
+
 			} else {
 				switch (parser->od_command->tag) {
 				case GF_ODF_ESD_UPDATE_TAG:
 					gf_list_add( ((GF_ESDUpdate *)parser->od_command)->ESDescriptors, desc);
 					break;

Vulnerable code: 				XMT_ODLink *prev_l = gf_list_last(parser->od_links);
				if ((GF_Descriptor *) prev_l->od == desc) {
					gf_list_pop_back(parser->od_links);
					if (prev_l->desc_name) gf_free(prev_l->desc_name);
					gf_list_del(prev_l->mf_urls);
					gf_free(prev_l);
				}
Fixed code: static void xmt_remove_link_for_descriptor(GF_XMTParser* parser, GF_Descriptor* desc) {

	u32 i=0;
	XMT_ODLink *l, *to_del=NULL;
	while ((l = (XMT_ODLink*)gf_list_enum(parser->od_links, &i)) ) {
		if (l->od && l->od == (GF_ObjectDescriptor*)desc) {
			l->od = NULL;
			to_del = l;
			break;
		}
	}
	if (to_del) {

		i=0;
		GF_Descriptor* subdesc;
		while ((subdesc = gf_list_enum(((GF_ObjectDescriptor*)desc)->ESDescriptors, &i))) {
			if (subdesc) xmt_remove_link_for_descriptor(parser, subdesc);
		}

		gf_list_del_item(parser->od_links, to_del);
		if (to_del->desc_name) gf_free(to_del->desc_name);
		gf_list_del(to_del->mf_urls);
		gf_free(to_del);
	}

	XMT_ESDLink *esdl, *esdl_del=NULL;
	i=0;
	while ((esdl = (XMT_ESDLink *)gf_list_enum(parser->esd_links, &i))) {
		if (esdl->esd && esdl->esd == (GF_ESD*)desc) {
			esdl->esd = NULL;
			esdl_del = esdl;
			break;
		}
	}

	if (esdl_del) {
		gf_list_del_item(parser->esd_links, esdl_del);
		if (esdl_del->desc_name) gf_free(esdl_del->desc_name);
		gf_free(esdl_del);
	}

}


			xmt_remove_link_for_descriptor(parser, desc);

				xmt_remove_link_for_descriptor(parser, desc);