CVE-2022-2453: Use After Free (CWE-416)
value: Use After Free in GitHub repository gpac/gpac prior to 2.1-DEV.
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.
CVSS v3 base score: 7.8
Published: 2022-07-19T14:15Z
Repository: https://github.com/gpac/gpac
Language: C
Files changed: src/bifs/field_decode.c
Commit date: 2022-07-12 17:57:03 +0200
Commit message: fixed #2212

Diff: diff --git a/src/bifs/field_decode.c b/src/bifs/field_decode.c
index 5537da7d3d87..65d045b02ae8 100644
--- a/src/bifs/field_decode.c
+++ b/src/bifs/field_decode.c
@@ -425,68 +425,75 @@ GF_Err BD_DecMFFieldVec(GF_BifsDecoder * codec, GF_BitStream *bs, GF_Node *node,
 			e = gf_sg_vrml_mf_get_item(field->far_ptr, field->fieldType, & sffield.far_ptr, i);
 			if (e) return e;
 			e = gf_bifs_dec_sf_field(codec, bs, node, &sffield, GF_FALSE);
 			if (e) return e;
 		}
-	} else {
-		last = NULL;
-		for (i=0; i<nbFields; i++) {
-			GF_Node *new_node = gf_bifs_dec_node(codec, bs, field->NDTtype);
-			if (new_node) {
-				e = gf_node_register(new_node, is_mem_com ? NULL : node);
-				if (e) return e;
-
-				if (node) {
-					/*special case for QP, register as the current QP*/
-					if (gf_node_get_tag(new_node) == TAG_MPEG4_QuantizationParameter) {
-						qp_local = ((M_QuantizationParameter *)new_node)->isLocal;
-						/*we have a QP in the same scope, remove previous
-						NB: we assume this is the right behavior, the spec doesn't say
-						whether QP is cumulative or not*/
-						if (qp_on) gf_bifs_dec_qp_remove(codec, GF_FALSE);
+		return GF_OK;
+	}
 
-						e = gf_bifs_dec_qp_set(codec, new_node);
-						if (e) return e;
-						qp_on = 1;
-						if (qp_local) qp_local = 2;
-						if (codec->force_keep_qp) {
-							e = gf_node_list_add_child_last(field->far_ptr, new_node, &last);
-							if (e) return e;
-						} else {
-							gf_node_register(new_node, NULL);
-							gf_node_unregister(new_node, node);
-						}
-					} else {
+	e = GF_OK;
+	last = NULL;
+	for (i=0; i<nbFields; i++) {
+		GF_Node *new_node = gf_bifs_dec_node(codec, bs, field->NDTtype);
+		if (new_node) {
+			e = gf_node_register(new_node, is_mem_com ? NULL : node);
+			if (e) goto exit;
+
+			if (node) {
+				/*special case for QP, register as the current QP*/
+				if (gf_node_get_tag(new_node) == TAG_MPEG4_QuantizationParameter) {
+					qp_local = ((M_QuantizationParameter *)new_node)->isLocal;
+					/*we have a QP in the same scope, remove previous
+					NB: we assume this is the right behavior, the spec doesn't say
+					whether QP is cumulative or not*/
+					if (qp_on) gf_bifs_dec_qp_remove(codec, GF_FALSE);
+
+					e = gf_bifs_dec_qp_set(codec, new_node);
+					if (e) goto exit;
+					qp_on = 1;
+					if (qp_local) qp_local = 2;
+					if (codec->force_keep_qp) {
 						e = gf_node_list_add_child_last(field->far_ptr, new_node, &last);
-						if (e) return e;
+						if (e) goto exit;
+					} else {
+						gf_node_register(new_node, NULL);
+						gf_node_unregister(new_node, node);
 					}
+				} else {
+					e = gf_node_list_add_child_last(field->far_ptr, new_node, &last);
+					if (e) goto exit;
 				}
-				/*proto coding*/
-				else if (codec->pCurrentProto) {
-					/*TO DO: what happens if this is a QP node on the interface ?*/
-					e = gf_node_list_add_child_last( (GF_ChildNodeItem **)field->far_ptr, new_node, &last);
-					if (e) return e;
-				}
-			} else {
-				return codec->LastError ? codec->LastError : GF_NON_COMPLIANT_BITSTREAM;
 			}
+			/*proto coding*/
+			else if (codec->pCurrentProto) {
+				/*TO DO: what happens if this is a QP node on the interface ?*/
+				e = gf_node_list_add_child_last( (GF_ChildNodeItem **)field->far_ptr, new_node, &last);
+				if (e)goto exit;
+			}
+		} else {
+			e = codec->LastError ? codec->LastError : GF_NON_COMPLIANT_BITSTREAM;
+			goto exit;
 		}
-		/*according to the spec, the QP applies to the current node itself, not just children.
-		If IsLocal is TRUE remove the node*/
-		if (qp_on && qp_local) {
-			if (qp_local == 2) {
+	}
+
+exit:
+
+	/*according to the spec, the QP applies to the current node itself, not just children.
+	If IsLocal is TRUE remove the node*/
+	if (qp_on && qp_local) {
+		if (qp_local == 2) {
 //				qp_local = 1;
-			} else {
-				//ask to get rid of QP and reactivate if we had a QP when entering the node
-				gf_bifs_dec_qp_remove(codec, initial_qp);
+		} else {
+			//ask to get rid of QP and reactivate if we had a QP when entering the node
+			gf_bifs_dec_qp_remove(codec, initial_qp);
 //				qp_local = 0;
-			}
 		}
 	}
+
 	/*finally delete the QP if any (local or not) as we get out of this node*/
 	if (qp_on) gf_bifs_dec_qp_remove(codec, GF_TRUE);
-	return GF_OK;
+	return e;
 }
 
 
 void gf_bifs_check_field_change(GF_Node *node, GF_FieldInfo *field)
 {

Vulnerable code: 	} else {
		last = NULL;
		for (i=0; i<nbFields; i++) {
			GF_Node *new_node = gf_bifs_dec_node(codec, bs, field->NDTtype);
			if (new_node) {
				e = gf_node_register(new_node, is_mem_com ? NULL : node);
				if (e) return e;

				if (node) {
					/*special case for QP, register as the current QP*/
					if (gf_node_get_tag(new_node) == TAG_MPEG4_QuantizationParameter) {
						qp_local = ((M_QuantizationParameter *)new_node)->isLocal;
						/*we have a QP in the same scope, remove previous
						NB: we assume this is the right behavior, the spec doesn't say
						whether QP is cumulative or not*/
						if (qp_on) gf_bifs_dec_qp_remove(codec, GF_FALSE);
						e = gf_bifs_dec_qp_set(codec, new_node);
						if (e) return e;
						qp_on = 1;
						if (qp_local) qp_local = 2;
						if (codec->force_keep_qp) {
							e = gf_node_list_add_child_last(field->far_ptr, new_node, &last);
							if (e) return e;
						} else {
							gf_node_register(new_node, NULL);
							gf_node_unregister(new_node, node);
						}
					} else {
						if (e) return e;
				/*proto coding*/
				else if (codec->pCurrentProto) {
					/*TO DO: what happens if this is a QP node on the interface ?*/
					e = gf_node_list_add_child_last( (GF_ChildNodeItem **)field->far_ptr, new_node, &last);
					if (e) return e;
				}
			} else {
				return codec->LastError ? codec->LastError : GF_NON_COMPLIANT_BITSTREAM;
		/*according to the spec, the QP applies to the current node itself, not just children.
		If IsLocal is TRUE remove the node*/
		if (qp_on && qp_local) {
			if (qp_local == 2) {
			} else {
				//ask to get rid of QP and reactivate if we had a QP when entering the node
				gf_bifs_dec_qp_remove(codec, initial_qp);
			}
	return GF_OK;
Fixed code: 		return GF_OK;
	}
	e = GF_OK;
	last = NULL;
	for (i=0; i<nbFields; i++) {
		GF_Node *new_node = gf_bifs_dec_node(codec, bs, field->NDTtype);
		if (new_node) {
			e = gf_node_register(new_node, is_mem_com ? NULL : node);
			if (e) goto exit;

			if (node) {
				/*special case for QP, register as the current QP*/
				if (gf_node_get_tag(new_node) == TAG_MPEG4_QuantizationParameter) {
					qp_local = ((M_QuantizationParameter *)new_node)->isLocal;
					/*we have a QP in the same scope, remove previous
					NB: we assume this is the right behavior, the spec doesn't say
					whether QP is cumulative or not*/
					if (qp_on) gf_bifs_dec_qp_remove(codec, GF_FALSE);

					e = gf_bifs_dec_qp_set(codec, new_node);
					if (e) goto exit;
					qp_on = 1;
					if (qp_local) qp_local = 2;
					if (codec->force_keep_qp) {
						if (e) goto exit;
					} else {
						gf_node_register(new_node, NULL);
						gf_node_unregister(new_node, node);
				} else {
					e = gf_node_list_add_child_last(field->far_ptr, new_node, &last);
					if (e) goto exit;
			/*proto coding*/
			else if (codec->pCurrentProto) {
				/*TO DO: what happens if this is a QP node on the interface ?*/
				e = gf_node_list_add_child_last( (GF_ChildNodeItem **)field->far_ptr, new_node, &last);
				if (e)goto exit;
			}
		} else {
			e = codec->LastError ? codec->LastError : GF_NON_COMPLIANT_BITSTREAM;
			goto exit;
	}

exit:

	/*according to the spec, the QP applies to the current node itself, not just children.
	If IsLocal is TRUE remove the node*/
	if (qp_on && qp_local) {
		if (qp_local == 2) {
		} else {
			//ask to get rid of QP and reactivate if we had a QP when entering the node
			gf_bifs_dec_qp_remove(codec, initial_qp);

	return e;