CVE-2021-32139: NULL Pointer Dereference (CWE-476)
value: The gf_isom_vp_config_get function in GPAC 1.0.1 allows attackers to cause a denial of service (NULL pointer dereference) via a crafted file in the MP4Box command.
CWE description: The product dereferences a pointer that it expects to be valid but is NULL.
CVSS v3 base score: 5.5
Published: 2021-09-13T20:15Z
Repository: https://github.com/gpac/gpac
Language: C
Files changed: src/isomedia/box_code_3gpp.c, src/isomedia/box_funcs.c, src/isomedia/tx3g.c
Commit date: 2021-04-30 10:13:24 +0200
Commit message: fixed #1768

Diff: diff --git a/src/isomedia/box_code_3gpp.c b/src/isomedia/box_code_3gpp.c
index 87885d0c0e7..61bef36a1b9 100644
--- a/src/isomedia/box_code_3gpp.c
+++ b/src/isomedia/box_code_3gpp.c
@@ -345,14 +345,20 @@ GF_Err text_box_read(GF_Box *s, GF_BitStream *bs)
 {
 	GF_Err e;
 	u16 pSize;
 	GF_TextSampleEntryBox *ptr = (GF_TextSampleEntryBox*)s;
 
-	ISOM_DECREASE_SIZE(ptr, 51);
-
+	ISOM_DECREASE_SIZE(ptr, 8);
 	e = gf_isom_base_sample_entry_read((GF_SampleEntryBox *)ptr, bs);
 	if (e) return e;
+	//some weird text entries are not QT text nor 3gpp, cf issue #1030
+	if (!ptr->size) {
+		ptr->textJustification = 1;
+		return GF_OK;
+	}
+	ISOM_DECREASE_SIZE(ptr, 43);
+
 
 	ptr->displayFlags = gf_bs_read_u32(bs);			/*Display flags*/
 	ptr->textJustification = gf_bs_read_u32(bs);	/*Text justification*/
 	gf_bs_read_data(bs, ptr->background_color, 6);	/*Background color*/
 	gpp_read_box(bs, &ptr->default_box);			/*Default text box*/
@@ -470,10 +476,11 @@ GF_Err text_box_write(GF_Box *s, GF_BitStream *bs)
 
 	e = gf_isom_box_write_header(s, bs);
 	if (e) return e;
 	gf_bs_write_data(bs, ptr->reserved, 6);
 	gf_bs_write_u16(bs, ptr->dataReferenceIndex);
+
 	gf_bs_write_u32(bs, ptr->displayFlags);			/*Display flags*/
 	gf_bs_write_u32(bs, ptr->textJustification);	/*Text justification*/
 	gf_bs_write_data(bs, ptr->background_color, 6);	/*Background color*/
 	gpp_write_box(bs, &ptr->default_box);			/*Default text box*/
 	gf_bs_write_data(bs, ptr->reserved1, 8);		/*Reserved*/
@@ -501,12 +508,13 @@ GF_Err tx3g_box_size(GF_Box *s)
 
 GF_Err text_box_size(GF_Box *s)
 {
 	GF_TextSampleEntryBox *ptr = (GF_TextSampleEntryBox*)s;
 
+	s->size += 8;
 	/*base + this + string length*/
-	s->size += 51 + 1;
+	s->size += 43 + 1;
 	if (ptr->textName)
 		s->size += strlen(ptr->textName);
 	return GF_OK;
 }
 
diff --git a/src/isomedia/box_funcs.c b/src/isomedia/box_funcs.c
index 1caa03ad371..12fd12d0d39 100644
--- a/src/isomedia/box_funcs.c
+++ b/src/isomedia/box_funcs.c
@@ -248,12 +248,10 @@ GF_Err gf_isom_box_parse_ex(GF_Box **outBox, GF_BitStream *bs, u32 parent_type,
 	if (restore_type)
 		newBox->type = restore_type;
 
 	payload_start = gf_bs_get_position(bs);
 
-retry_unknown_box:
-
 	end = gf_bs_available(bs);
 	if (size - hdr_size > end ) {
 		newBox->size = size - hdr_size - end;
 		*outBox = newBox;
 		return GF_ISOM_INCOMPLETE_FILE;
@@ -303,18 +301,10 @@ retry_unknown_box:
 
 	if (e && (e != GF_ISOM_INCOMPLETE_FILE)) {
 		gf_isom_box_del(newBox);
 		*outBox = NULL;
 
-		if (parent_type==GF_ISOM_BOX_TYPE_STSD) {
-			newBox = gf_isom_box_new(GF_ISOM_BOX_TYPE_UNKNOWN);
-			if (!newBox) return GF_OUT_OF_MEM;
-			((GF_UnknownBox *)newBox)->original_4cc = type;
-			newBox->size = size;
-			gf_bs_seek(bs, payload_start);
-			goto retry_unknown_box;
-		}
 		if (!skip_logs) {
 			GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Read Box \"%s\" (start "LLU") failed (%s) - skipping\n", gf_4cc_to_str(type), start, gf_error_to_string(e)));
 		}
 		//we don't try to reparse known boxes that have been failing (too dangerous)
 		return e;
diff --git a/src/isomedia/tx3g.c b/src/isomedia/tx3g.c
index 799667ca74f..ff80fff1f50 100644
--- a/src/isomedia/tx3g.c
+++ b/src/isomedia/tx3g.c
@@ -26,18 +26,33 @@
 #include <gpac/internal/isomedia_dev.h>
 #include <gpac/constants.h>
 
 #ifndef GPAC_DISABLE_ISOM
 
+static u32 rgb_48_to_32(char *val)
+{
+	u32 res = 0x0;
+	u32 i;
+
+	for (i=0; i<3; i++) {
+		u32 v = val[2*i];
+		v<<=8;
+		v|=val[2*i + 1];
+		v/=0xFF;
+
+		res <<= 8;
+		res |= v;
+	}
+	return res;
+}
 
 GF_Err gf_isom_get_text_description(GF_ISOFile *movie, u32 trackNumber, u32 descriptionIndex, GF_TextSampleDescriptor **out_desc)
 {
 	GF_TrackBox *trak;
 	u32 i;
-	Bool is_qt_text = GF_FALSE;
-	GF_Tx3gSampleEntryBox *txt;
-
+	GF_Tx3gSampleEntryBox *txt = NULL;
+	GF_TextSampleEntryBox *qt_txt = NULL;
 	if (!descriptionIndex || !out_desc) return GF_BAD_PARAM;
 
 	trak = gf_isom_get_track_from_file(movie, trackNumber);
 	if (!trak || !trak->Media) return GF_BAD_PARAM;
 
@@ -53,32 +68,40 @@ GF_Err gf_isom_get_text_description(GF_ISOFile *movie, u32 trackNumber, u32 desc
 	if (!txt) return GF_BAD_PARAM;
 	switch (txt->type) {
 	case GF_ISOM_BOX_TYPE_TX3G:
 		break;
 	case GF_ISOM_BOX_TYPE_TEXT:
-		is_qt_text = GF_TRUE;
+		qt_txt = (GF_TextSampleEntryBox *)txt;
+		txt = NULL;
 		break;
 	default:
 		return GF_BAD_PARAM;
 	}
 
 	(*out_desc) = (GF_TextSampleDescriptor *) gf_odf_desc_new(GF_ODF_TX3G_TAG);
 	if (! (*out_desc) ) return GF_OUT_OF_MEM;
-	(*out_desc)->back_color = txt->back_color;
-	(*out_desc)->default_pos = txt->default_box;
-	(*out_desc)->default_style = txt->default_style;
-	(*out_desc)->displayFlags = txt->displayFlags;
-	(*out_desc)->vert_justif = txt->vertical_justification;
-	(*out_desc)->horiz_justif = txt->horizontal_justification;
-	if (is_qt_text) {
-		GF_TextSampleEntryBox *qt_txt = (GF_TextSampleEntryBox *) txt;
+
+	if (qt_txt) {
+		(*out_desc)->back_color = rgb_48_to_32(qt_txt->background_color);
+		(*out_desc)->default_pos = qt_txt->default_box;
+		(*out_desc)->default_style.style_flags = qt_txt->fontFace;
+		(*out_desc)->default_style.text_color = rgb_48_to_32(qt_txt->foreground_color);
+		(*out_desc)->displayFlags = qt_txt->displayFlags;
+		(*out_desc)->vert_justif = -1;
+		(*out_desc)->horiz_justif = qt_txt->textJustification;
 		if (qt_txt->textName) {
 			(*out_desc)->font_count = 1;
 			(*out_desc)->fonts = (GF_FontRecord *) gf_malloc(sizeof(GF_FontRecord));
 			(*out_desc)->fonts[0].fontName = gf_strdup(qt_txt->textName);
 		}
 	} else {
+		(*out_desc)->back_color = txt->back_color;
+		(*out_desc)->default_pos = txt->default_box;
+		(*out_desc)->default_style = txt->default_style;
+		(*out_desc)->displayFlags = txt->displayFlags;
+		(*out_desc)->vert_justif = txt->vertical_justification;
+		(*out_desc)->horiz_justif = txt->horizontal_justification;
 		(*out_desc)->font_count = txt->font_table->entry_count;
 		(*out_desc)->fonts = (GF_FontRecord *) gf_malloc(sizeof(GF_FontRecord) * txt->font_table->entry_count);
 		for (i=0; i<txt->font_table->entry_count; i++) {
 			(*out_desc)->fonts[i].fontID = txt->font_table->fonts[i].fontID;
 			if (txt->font_table->fonts[i].fontName)
@@ -693,74 +716,83 @@ GF_TextSample *gf_isom_parse_text_sample_from_data(u8 *data, u32 dataLength)
 
 /*out-of-band sample desc (128 and 255 reserved in RFC)*/
 #define SAMPLE_INDEX_OFFSET		129
 
 
-static void gf_isom_write_tx3g(GF_Tx3gSampleEntryBox *a, GF_BitStream *bs, u32 sidx, u32 sidx_offset)
+static void gf_isom_write_tx3g(GF_Tx3gSampleEntryBox *_a, GF_BitStream *bs, u32 sidx, u32 sidx_offset)
 {
 	u32 size, j, fount_count;
-	Bool is_qt_text = (a->type==GF_ISOM_BOX_TYPE_TEXT) ? GF_TRUE : GF_FALSE;
 	const char *qt_fontname = NULL;
 	void gpp_write_rgba(GF_BitStream *bs, u32 col);
 	void gpp_write_box(GF_BitStream *bs, GF_BoxRecord *rec);
 	void gpp_write_style(GF_BitStream *bs, GF_StyleRecord *rec);
 
+	GF_TextSampleEntryBox *qt = (_a->type==GF_ISOM_BOX_TYPE_TEXT) ? (GF_TextSampleEntryBox *)_a : NULL;
+	GF_Tx3gSampleEntryBox *ttxt = (_a->type!=GF_ISOM_BOX_TYPE_TEXT) ? (GF_Tx3gSampleEntryBox *)_a : NULL;
 
 	if (sidx_offset) gf_bs_write_u8(bs, sidx + sidx_offset);
 
 	/*SINCE WINCE HAS A READONLY VERSION OF MP4 WE MUST DO IT BY HAND*/
 	size = 8 + 18 + 8 + 12;
 	size += 8 + 2;
 	fount_count = 0;
-	if (is_qt_text) {
-		GF_TextSampleEntryBox *qt = (GF_TextSampleEntryBox *)a;
-		if (qt->textName) {
-			qt_fontname = qt->textName;
-			fount_count = 1;
-		}
-	} else {
-		if (a->font_table) {
-			fount_count = a->font_table->entry_count;
-			for (j=0; j<fount_count; j++) {
-				size += 3;
-				if (a->font_table->fonts[j].fontName) size += (u32) strlen(a->font_table->fonts[j].fontName);
-			}
+	if (qt && qt->textName) {
+		qt_fontname = qt->textName;
+		fount_count = 1;
+	} else if (ttxt && ttxt->font_table) {
+		fount_count = ttxt->font_table->entry_count;
+		for (j=0; j<fount_count; j++) {
+			size += 3;
+			if (ttxt->font_table->fonts[j].fontName)
+				size += (u32) strlen(ttxt->font_table->fonts[j].fontName);
 		}
 	}
 	/*write TextSampleEntry box*/
 	gf_bs_write_u32(bs, size);
-	gf_bs_write_u32(bs, a->type);
-	gf_bs_write_data(bs, a->reserved, 6);
-	gf_bs_write_u16(bs, a->dataReferenceIndex);
-	gf_bs_write_u32(bs, a->displayFlags);
-	gf_bs_write_u8(bs, a->horizontal_justification);
-	gf_bs_write_u8(bs, a->vertical_justification);
-	gpp_write_rgba(bs, a->back_color);
-	gpp_write_box(bs, &a->default_box);
-	gpp_write_style(bs, &a->default_style);
+	gf_bs_write_u32(bs, GF_ISOM_BOX_TYPE_TX3G);
+	gf_bs_write_data(bs, _a->reserved, 6);
+	gf_bs_write_u16(bs, _a->dataReferenceIndex);
+	gf_bs_write_u32(bs, _a->displayFlags);
+	if (qt) {
+		GF_StyleRecord sr;
+		memset(&sr, 0, sizeof(GF_StyleRecord));
+		gf_bs_write_u8(bs, qt->textJustification);
+		gf_bs_write_u8(bs, (u8) -1);
+		gpp_write_rgba(bs, rgb_48_to_32(qt->background_color) );
+		gpp_write_box(bs, &qt->default_box);
+		sr.text_color = rgb_48_to_32(qt->foreground_color);
+		sr.style_flags = qt->fontFace;
+		gpp_write_style(bs, &sr);
+	} else {
+		gf_bs_write_u8(bs, ttxt->horizontal_justification);
+		gf_bs_write_u8(bs, ttxt->vertical_justification);
+		gpp_write_rgba(bs, ttxt->back_color);
+		gpp_write_box(bs, &ttxt->default_box);
+		gpp_write_style(bs, &ttxt->default_style);
+	}
 	/*write font table box*/
 	size -= (8 + 18 + 8 + 12);
 	gf_bs_write_u32(bs, size);
 	gf_bs_write_u32(bs, GF_ISOM_BOX_TYPE_FTAB);
 
 	gf_bs_write_u16(bs, fount_count);
 	for (j=0; j<fount_count; j++) {
-		if (is_qt_text) {
+		if (qt) {
 			gf_bs_write_u16(bs, 0);
 			if (qt_fontname) {
 				u32 len = (u32) strlen(qt_fontname);
 				gf_bs_write_u8(bs, len);
 				gf_bs_write_data(bs, qt_fontname, len);
 			} else {
 				gf_bs_write_u8(bs, 0);
 			}
 		} else {
-			gf_bs_write_u16(bs, a->font_table->fonts[j].fontID);
-			if (a->font_table->fonts[j].fontName) {
-				u32 len = (u32) strlen(a->font_table->fonts[j].fontName);
+			gf_bs_write_u16(bs, ttxt->font_table->fonts[j].fontID);
+			if (ttxt->font_table->fonts[j].fontName) {
+				u32 len = (u32) strlen(ttxt->font_table->fonts[j].fontName);
 				gf_bs_write_u8(bs, len);
-				gf_bs_write_data(bs, a->font_table->fonts[j].fontName, len);
+				gf_bs_write_data(bs, ttxt->font_table->fonts[j].fontName, len);
 			} else {
 				gf_bs_write_u8(bs, 0);
 			}
 		}
 	}

Vulnerable code: 	ISOM_DECREASE_SIZE(ptr, 51);

	s->size += 51 + 1;
retry_unknown_box:

		if (parent_type==GF_ISOM_BOX_TYPE_STSD) {
			newBox = gf_isom_box_new(GF_ISOM_BOX_TYPE_UNKNOWN);
			if (!newBox) return GF_OUT_OF_MEM;
			((GF_UnknownBox *)newBox)->original_4cc = type;
			newBox->size = size;
			gf_bs_seek(bs, payload_start);
			goto retry_unknown_box;
		}
	Bool is_qt_text = GF_FALSE;
	GF_Tx3gSampleEntryBox *txt;

		is_qt_text = GF_TRUE;
	(*out_desc)->back_color = txt->back_color;
	(*out_desc)->default_pos = txt->default_box;
	(*out_desc)->default_style = txt->default_style;
	(*out_desc)->displayFlags = txt->displayFlags;
	(*out_desc)->vert_justif = txt->vertical_justification;
	(*out_desc)->horiz_justif = txt->horizontal_justification;
	if (is_qt_text) {
		GF_TextSampleEntryBox *qt_txt = (GF_TextSampleEntryBox *) txt;
static void gf_isom_write_tx3g(GF_Tx3gSampleEntryBox *a, GF_BitStream *bs, u32 sidx, u32 sidx_offset)
	Bool is_qt_text = (a->type==GF_ISOM_BOX_TYPE_TEXT) ? GF_TRUE : GF_FALSE;
	if (is_qt_text) {
		GF_TextSampleEntryBox *qt = (GF_TextSampleEntryBox *)a;
		if (qt->textName) {
			qt_fontname = qt->textName;
			fount_count = 1;
		}
	} else {
		if (a->font_table) {
			fount_count = a->font_table->entry_count;
			for (j=0; j<fount_count; j++) {
				size += 3;
				if (a->font_table->fonts[j].fontName) size += (u32) strlen(a->font_table->fonts[j].fontName);
			}
	gf_bs_write_u32(bs, a->type);
	gf_bs_write_data(bs, a->reserved, 6);
	gf_bs_write_u16(bs, a->dataReferenceIndex);
	gf_bs_write_u32(bs, a->displayFlags);
	gf_bs_write_u8(bs, a->horizontal_justification);
	gf_bs_write_u8(bs, a->vertical_justification);
	gpp_write_rgba(bs, a->back_color);
	gpp_write_box(bs, &a->default_box);
	gpp_write_style(bs, &a->default_style);
		if (is_qt_text) {
			gf_bs_write_u16(bs, a->font_table->fonts[j].fontID);
			if (a->font_table->fonts[j].fontName) {
				u32 len = (u32) strlen(a->font_table->fonts[j].fontName);
				gf_bs_write_data(bs, a->font_table->fonts[j].fontName, len);
Fixed code: 	ISOM_DECREASE_SIZE(ptr, 8);
	//some weird text entries are not QT text nor 3gpp, cf issue #1030
	if (!ptr->size) {
		ptr->textJustification = 1;
		return GF_OK;
	}
	ISOM_DECREASE_SIZE(ptr, 43);


	s->size += 8;
	s->size += 43 + 1;
static u32 rgb_48_to_32(char *val)
{
	u32 res = 0x0;
	u32 i;

	for (i=0; i<3; i++) {
		u32 v = val[2*i];
		v<<=8;
		v|=val[2*i + 1];
		v/=0xFF;

		res <<= 8;
		res |= v;
	}
	return res;
}
	GF_Tx3gSampleEntryBox *txt = NULL;
	GF_TextSampleEntryBox *qt_txt = NULL;
		qt_txt = (GF_TextSampleEntryBox *)txt;
		txt = NULL;

	if (qt_txt) {
		(*out_desc)->back_color = rgb_48_to_32(qt_txt->background_color);
		(*out_desc)->default_pos = qt_txt->default_box;
		(*out_desc)->default_style.style_flags = qt_txt->fontFace;
		(*out_desc)->default_style.text_color = rgb_48_to_32(qt_txt->foreground_color);
		(*out_desc)->displayFlags = qt_txt->displayFlags;
		(*out_desc)->vert_justif = -1;
		(*out_desc)->horiz_justif = qt_txt->textJustification;
		(*out_desc)->back_color = txt->back_color;
		(*out_desc)->default_pos = txt->default_box;
		(*out_desc)->default_style = txt->default_style;
		(*out_desc)->displayFlags = txt->displayFlags;
		(*out_desc)->vert_justif = txt->vertical_justification;
		(*out_desc)->horiz_justif = txt->horizontal_justification;
static void gf_isom_write_tx3g(GF_Tx3gSampleEntryBox *_a, GF_BitStream *bs, u32 sidx, u32 sidx_offset)
	GF_TextSampleEntryBox *qt = (_a->type==GF_ISOM_BOX_TYPE_TEXT) ? (GF_TextSampleEntryBox *)_a : NULL;
	GF_Tx3gSampleEntryBox *ttxt = (_a->type!=GF_ISOM_BOX_TYPE_TEXT) ? (GF_Tx3gSampleEntryBox *)_a : NULL;
	if (qt && qt->textName) {
		qt_fontname = qt->textName;
		fount_count = 1;
	} else if (ttxt && ttxt->font_table) {
		fount_count = ttxt->font_table->entry_count;
		for (j=0; j<fount_count; j++) {
			size += 3;
			if (ttxt->font_table->fonts[j].fontName)
				size += (u32) strlen(ttxt->font_table->fonts[j].fontName);
	gf_bs_write_u32(bs, GF_ISOM_BOX_TYPE_TX3G);
	gf_bs_write_data(bs, _a->reserved, 6);
	gf_bs_write_u16(bs, _a->dataReferenceIndex);
	gf_bs_write_u32(bs, _a->displayFlags);
	if (qt) {
		GF_StyleRecord sr;
		memset(&sr, 0, sizeof(GF_StyleRecord));
		gf_bs_write_u8(bs, qt->textJustification);
		gf_bs_write_u8(bs, (u8) -1);
		gpp_write_rgba(bs, rgb_48_to_32(qt->background_color) );
		gpp_write_box(bs, &qt->default_box);
		sr.text_color = rgb_48_to_32(qt->foreground_color);
		sr.style_flags = qt->fontFace;
		gpp_write_style(bs, &sr);
	} else {
		gf_bs_write_u8(bs, ttxt->horizontal_justification);
		gf_bs_write_u8(bs, ttxt->vertical_justification);
		gpp_write_rgba(bs, ttxt->back_color);
		gpp_write_box(bs, &ttxt->default_box);
		gpp_write_style(bs, &ttxt->default_style);
	}
		if (qt) {
			gf_bs_write_u16(bs, ttxt->font_table->fonts[j].fontID);
			if (ttxt->font_table->fonts[j].fontName) {
				u32 len = (u32) strlen(ttxt->font_table->fonts[j].fontName);
				gf_bs_write_data(bs, ttxt->font_table->fonts[j].fontName, len);