CVE-2018-7752: Improper Restriction of Operations within the Bounds of a Memory Buffer (CWE-119)
value: GPAC through 0.7.1 has a Buffer Overflow in the gf_media_avc_read_sps function in media_tools/av_parsers.c, a different vulnerability than CVE-2018-1000100.
CWE description: The product performs operations on a memory buffer, but it reads from or writes to a memory location outside the buffer's intended boundary. This may result in read or write operations on unexpected memory locations that could be linked to other variables, data structures, or internal program data.
CVSS v3 base score: 7.8
Published: 2018-03-07T23:29Z
Repository: https://github.com/gpac/gpac
Language: C
Files changed: include/gpac/tools.h, src/isomedia/avc_ext.c, src/media_tools/av_parsers.c
Commit date: 2018-03-06 11:40:47 +0100
Commit message: fix some exploitable overflows (#994, #997)

Diff: diff --git a/include/gpac/tools.h b/include/gpac/tools.h
index dbc3cebf33..15483d7d6b 100644
--- a/include/gpac/tools.h
+++ b/include/gpac/tools.h
@@ -1065,10 +1065,11 @@ extern void gf_fm_request_set_callback(void *cbk_obj, fm_callback_func cbk_func)
 void gf_fm_request_call(u32 type, u32 param, int *value);
 #endif //GPAC_ANDROID
 
 /* \endcond */
 
+#define ARRAY_LENGTH(a) (sizeof(a) / sizeof((a)[0]))
 
 #ifdef __cplusplus
 }
 #endif
 
diff --git a/src/isomedia/avc_ext.c b/src/isomedia/avc_ext.c
index c1096f8724..c59f2ce979 100644
--- a/src/isomedia/avc_ext.c
+++ b/src/isomedia/avc_ext.c
@@ -2411,10 +2411,12 @@ GF_Err gf_isom_oinf_read_entry(void *entry, GF_BitStream *bs)
 		GF_SAFEALLOC(op, LHEVC_OperatingPoint);
 		if (!op) return GF_OUT_OF_MEM;
 		op->output_layer_set_idx = gf_bs_read_u16(bs);
 		op->max_temporal_id = gf_bs_read_u8(bs);
 		op->layer_count = gf_bs_read_u8(bs);
+		if (op->layer_count > ARRAY_LENGTH(op->layers_info))
+			return GF_NON_COMPLIANT_BITSTREAM;
 		for (j = 0; j < op->layer_count; j++) {
 			op->layers_info[j].ptl_idx = gf_bs_read_u8(bs);
 			op->layers_info[j].layer_id = gf_bs_read_int(bs, 6);
 			op->layers_info[j].is_outputlayer = gf_bs_read_int(bs, 1) ? GF_TRUE : GF_FALSE;
 			op->layers_info[j].is_alternate_outputlayer = gf_bs_read_int(bs, 1) ? GF_TRUE : GF_FALSE;
diff --git a/src/media_tools/av_parsers.c b/src/media_tools/av_parsers.c
index b9b5acdbba..27a6807d98 100644
--- a/src/media_tools/av_parsers.c
+++ b/src/media_tools/av_parsers.c
@@ -2383,10 +2383,14 @@ s32 gf_media_avc_read_sps(const char *sps_data, u32 sps_size, AVCState *avc, u32
 	} else if(sps->poc_type == 1) {
 		sps->delta_pic_order_always_zero_flag = gf_bs_read_int(bs, 1);
 		sps->offset_for_non_ref_pic = bs_get_se(bs);
 		sps->offset_for_top_to_bottom_field = bs_get_se(bs);
 		sps->poc_cycle_length = bs_get_ue(bs);
+		if (sps->poc_cycle_length > ARRAY_LENGTH(sps->offset_for_ref_frame)) {
+			GF_LOG(GF_LOG_ERROR, GF_LOG_CODING, ("[avc-h264] offset_for_ref_frame overflow from poc_cycle_length\n"));
+			goto exit;
+		}
 		for(i=0; i<sps->poc_cycle_length; i++) sps->offset_for_ref_frame[i] = bs_get_se(bs);
 	}
 	if (sps->poc_type > 2) {
 		sps_id = -1;
 		goto exit;

Fixed code: #define ARRAY_LENGTH(a) (sizeof(a) / sizeof((a)[0]))
		if (op->layer_count > ARRAY_LENGTH(op->layers_info))
			return GF_NON_COMPLIANT_BITSTREAM;
		if (sps->poc_cycle_length > ARRAY_LENGTH(sps->offset_for_ref_frame)) {
			GF_LOG(GF_LOG_ERROR, GF_LOG_CODING, ("[avc-h264] offset_for_ref_frame overflow from poc_cycle_length\n"));
			goto exit;
		}