CVE-2021-40566: Use After Free (CWE-416)
value: A Segmentation fault casued by heap use after free vulnerability exists in Gpac through 1.0.1 via the mpgviddmx_process function in reframe_mpgvid.c when using mp4box, which causes a denial of service.
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: 5.5
Published: 2022-01-12T22:15Z
Repository: https://github.com/gpac/gpac
Language: C
Files changed: src/filters/dec_xvid.c, src/filters/reframe_mpgvid.c
Commit date: 2021-08-30 15:46:16 +0200
Commit message: fixed #1887

Diff: diff --git a/src/filters/dec_xvid.c b/src/filters/dec_xvid.c
index dff56bf10da5..ab86d85b13de 100644
--- a/src/filters/dec_xvid.c
+++ b/src/filters/dec_xvid.c
@@ -179,11 +179,11 @@ static GF_Err xviddec_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool i
 	}
 
 	/*decode DSI*/
 	e = gf_m4v_get_config(p->value.data.ptr, p->value.data.size, &dsi);
 	if (e) return e;
-	if (!dsi.width || !dsi.height) return GF_NON_COMPLIANT_BITSTREAM;
+	if (!dsi.width || (dsi.width%2) || !dsi.height) return GF_NON_COMPLIANT_BITSTREAM;
 
 	memset(&par, 0, sizeof(par));
 	par.width = dsi.width;
 	par.height = dsi.height;
 	/*note that this may be irrelevant when used through systems (FPS is driven by systems CTS)*/
diff --git a/src/filters/reframe_mpgvid.c b/src/filters/reframe_mpgvid.c
index 308546f28ce1..328db2855101 100644
--- a/src/filters/reframe_mpgvid.c
+++ b/src/filters/reframe_mpgvid.c
@@ -803,16 +803,21 @@ GF_Err mpgviddmx_process(GF_Filter *filter)
 				gf_bs_reassign_buffer(ctx->bs, start, remain);
 				e = gf_m4v_parse_config(ctx->vparser, &ctx->dsi);
 				//not enough data, accumulate until we can parse the full header
 				if (e==GF_EOS) {
 					if (vosh_start<0) vosh_start = 0;
-					if (ctx->hdr_store_alloc < ctx->hdr_store_size + pck_size - vosh_start) {
-						ctx->hdr_store_alloc = (u32) (ctx->hdr_store_size + pck_size - vosh_start);
-						ctx->hdr_store = gf_realloc(ctx->hdr_store, sizeof(char)*ctx->hdr_store_alloc);
+					if (data == ctx->hdr_store) {
+						memmove(ctx->hdr_store, start, remain);
+						ctx->hdr_store_size = remain;
+					} else {
+						if (ctx->hdr_store_alloc < ctx->hdr_store_size + pck_size - vosh_start) {
+							ctx->hdr_store_alloc = (u32) (ctx->hdr_store_size + pck_size - vosh_start);
+							ctx->hdr_store = gf_realloc(ctx->hdr_store, sizeof(char)*ctx->hdr_store_alloc);
+						}
+						memcpy(ctx->hdr_store + ctx->hdr_store_size, data + vosh_start, (size_t) (pck_size - vosh_start) );
+						ctx->hdr_store_size += pck_size - (u32) vosh_start;
 					}
-					memcpy(ctx->hdr_store + ctx->hdr_store_size, data + vosh_start, (size_t) (pck_size - vosh_start) );
-					ctx->hdr_store_size += pck_size - (u32) vosh_start;
 					gf_filter_pid_drop_packet(ctx->ipid);
 					return GF_OK;
 				} else if (e != GF_OK) {
 					GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[MPGVid] Failed to parse VOS header: %s\n", gf_error_to_string(e) ));
 				} else {
@@ -842,16 +847,21 @@ GF_Err mpgviddmx_process(GF_Filter *filter)
 				e = gf_m4v_parse_config(ctx->vparser, &ctx->dsi);
 				ctx->dsi.VideoPL = PL;
 				//not enough data, accumulate until we can parse the full header
 				if (e==GF_EOS) {
 					if (vosh_start<0) vosh_start = 0;
-					if (ctx->hdr_store_alloc < ctx->hdr_store_size + pck_size - vosh_start) {
-						ctx->hdr_store_alloc = (u32) (ctx->hdr_store_size + pck_size - (u32) vosh_start);
-						ctx->hdr_store = gf_realloc(ctx->hdr_store, sizeof(char)*ctx->hdr_store_alloc);
+					if (data == ctx->hdr_store) {
+						memmove(ctx->hdr_store, start, remain);
+						ctx->hdr_store_size = remain;
+					} else {
+						if (ctx->hdr_store_alloc < ctx->hdr_store_size + pck_size - vosh_start) {
+							ctx->hdr_store_alloc = (u32) (ctx->hdr_store_size + pck_size - (u32) vosh_start);
+							ctx->hdr_store = gf_realloc(ctx->hdr_store, sizeof(char)*ctx->hdr_store_alloc);
+						}
+						memcpy(ctx->hdr_store + ctx->hdr_store_size, data + vosh_start, (size_t) (pck_size - vosh_start) );
+						ctx->hdr_store_size += pck_size - (u32) vosh_start;
 					}
-					memcpy(ctx->hdr_store + ctx->hdr_store_size, data + vosh_start, (size_t) (pck_size - vosh_start) );
-					ctx->hdr_store_size += pck_size - (u32) vosh_start;
 					gf_filter_pid_drop_packet(ctx->ipid);
 					return GF_OK;
 				} else if (e != GF_OK) {
 					GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[MPGVid] Failed to parse VOS header: %s\n", gf_error_to_string(e) ));
 				} else {

Vulnerable code: 	if (!dsi.width || !dsi.height) return GF_NON_COMPLIANT_BITSTREAM;
					if (ctx->hdr_store_alloc < ctx->hdr_store_size + pck_size - vosh_start) {
						ctx->hdr_store_alloc = (u32) (ctx->hdr_store_size + pck_size - vosh_start);
						ctx->hdr_store = gf_realloc(ctx->hdr_store, sizeof(char)*ctx->hdr_store_alloc);
					memcpy(ctx->hdr_store + ctx->hdr_store_size, data + vosh_start, (size_t) (pck_size - vosh_start) );
					ctx->hdr_store_size += pck_size - (u32) vosh_start;
					if (ctx->hdr_store_alloc < ctx->hdr_store_size + pck_size - vosh_start) {
						ctx->hdr_store_alloc = (u32) (ctx->hdr_store_size + pck_size - (u32) vosh_start);
						ctx->hdr_store = gf_realloc(ctx->hdr_store, sizeof(char)*ctx->hdr_store_alloc);
					memcpy(ctx->hdr_store + ctx->hdr_store_size, data + vosh_start, (size_t) (pck_size - vosh_start) );
					ctx->hdr_store_size += pck_size - (u32) vosh_start;
Fixed code: 	if (!dsi.width || (dsi.width%2) || !dsi.height) return GF_NON_COMPLIANT_BITSTREAM;
					if (data == ctx->hdr_store) {
						memmove(ctx->hdr_store, start, remain);
						ctx->hdr_store_size = remain;
					} else {
						if (ctx->hdr_store_alloc < ctx->hdr_store_size + pck_size - vosh_start) {
							ctx->hdr_store_alloc = (u32) (ctx->hdr_store_size + pck_size - vosh_start);
							ctx->hdr_store = gf_realloc(ctx->hdr_store, sizeof(char)*ctx->hdr_store_alloc);
						}
						memcpy(ctx->hdr_store + ctx->hdr_store_size, data + vosh_start, (size_t) (pck_size - vosh_start) );
						ctx->hdr_store_size += pck_size - (u32) vosh_start;
					if (data == ctx->hdr_store) {
						memmove(ctx->hdr_store, start, remain);
						ctx->hdr_store_size = remain;
					} else {
						if (ctx->hdr_store_alloc < ctx->hdr_store_size + pck_size - vosh_start) {
							ctx->hdr_store_alloc = (u32) (ctx->hdr_store_size + pck_size - (u32) vosh_start);
							ctx->hdr_store = gf_realloc(ctx->hdr_store, sizeof(char)*ctx->hdr_store_alloc);
						}
						memcpy(ctx->hdr_store + ctx->hdr_store_size, data + vosh_start, (size_t) (pck_size - vosh_start) );
						ctx->hdr_store_size += pck_size - (u32) vosh_start;