Commit message: fix some overflows due to strcpy

fixes #1184, #1186, #1187 among other things
CVE: CVE-2018-20761
CWE: CWE-119
Vulnerability description: GPAC version 0.7.1 and earlier has a Buffer Overflow vulnerability in the gf_sm_load_init function in scene_manager.c in libgpac_static.a.

Project: gpac
File: fileimport.c

GF_Err cat_multiple_files(GF_ISOFile *dest, char *fileName, u32 import_flags, Double force_fps, u32 frames_per_sample, char *tmp_dir, Bool force_cat, Bool align_timelines, Bool allow_add_in_command)
{
	CATEnum cat_enum;
	char *sep;

	cat_enum.dest = dest;
	cat_enum.import_flags = import_flags;
	cat_enum.force_fps = force_fps;
	cat_enum.frames_per_sample = frames_per_sample;
	cat_enum.tmp_dir = tmp_dir;
	cat_enum.force_cat = force_cat;
 	cat_enum.align_timelines = align_timelines;
 	cat_enum.allow_add_in_command = allow_add_in_command;
 
	if (strlen(fileName) >= sizeof(cat_enum.szPath)) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("File name %s is too long.\n", fileName));
		return GF_NOT_SUPPORTED;
	}
 	strcpy(cat_enum.szPath, fileName);
 	sep = strrchr(cat_enum.szPath, GF_PATH_SEPARATOR);
 	if (!sep) sep = strrchr(cat_enum.szPath, '/');
 	if (!sep) {
 		strcpy(cat_enum.szPath, ".");
		if (strlen(fileName) >= sizeof(cat_enum.szRad1)) {
			GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("File name %s is too long.\n", fileName));
			return GF_NOT_SUPPORTED;
		}
 		strcpy(cat_enum.szRad1, fileName);
 	} else {
		if (strlen(sep + 1) >= sizeof(cat_enum.szRad1)) {
			GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("File name %s is too long.\n", (sep + 1)));
			return GF_NOT_SUPPORTED;
		}
 		strcpy(cat_enum.szRad1, sep+1);
 		sep[0] = 0;
 	}
 	sep = strchr(cat_enum.szRad1, '*');
	if (strlen(sep + 1) >= sizeof(cat_enum.szRad2)) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("File name %s is too long.\n", (sep + 1)));
		return GF_NOT_SUPPORTED;
	}
 	strcpy(cat_enum.szRad2, sep+1);
 	sep[0] = 0;
 	sep = strchr(cat_enum.szRad2, '%');
 	if (!sep) sep = strchr(cat_enum.szRad2, '#');
 	if (!sep) sep = strchr(cat_enum.szRad2, ':');
 	strcpy(cat_enum.szOpt, "");
 	if (sep) {
		if (strlen(sep) >= sizeof(cat_enum.szOpt)) {
			GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Invalid option: %s.\n", sep));
			return GF_NOT_SUPPORTED;
		}
 		strcpy(cat_enum.szOpt, sep);
 		sep[0] = 0;
 	}
	return gf_enum_directory(cat_enum.szPath, 0, cat_enumerate, &cat_enum, NULL);
}

Project: gpac
File: main.c

void set_cfg_option(char *opt_string)
{
	char *sep, *sep2, szSec[1024], szKey[1024], szVal[1024];
	sep = strchr(opt_string, ':');
	if (!sep) {
		fprintf(stderr, "Badly formatted option %s - expected Section:Name=Value\n", opt_string);
		return;
 	}
 	{
 		const size_t sepIdx = sep - opt_string;
		if (sepIdx >= sizeof(szSec)) {
			fprintf(stderr, "Badly formatted option %s - Section name is too long\n", opt_string);
			return;
		}

 		strncpy(szSec, opt_string, sepIdx);
 		szSec[sepIdx] = 0;
 	}
	sep ++;
	sep2 = strchr(sep, '=');
	if (!sep2) {
		fprintf(stderr, "Badly formatted option %s - expected Section:Name=Value\n", opt_string);
		return;
 	}
 	{
 		const size_t sepIdx = sep2 - sep;
		if (sepIdx >= sizeof(szKey)) {
			fprintf(stderr, "Badly formatted option %s - key name is too long\n", opt_string);
			return;
		}
 		strncpy(szKey, sep, sepIdx);
 		szKey[sepIdx] = 0;
		if (strlen(sep2 + 1) >= sizeof(szVal)) {
			fprintf(stderr, "Badly formatted option %s - value is too long\n", opt_string);
			return;
		}
 		strcpy(szVal, sep2+1);
 	}
 
	if (!stricmp(szKey, "*")) {
		if (stricmp(szVal, "null")) {
			fprintf(stderr, "Badly formatted option %s - expected Section:*=null\n", opt_string);
			return;
		}
		gf_cfg_del_section(cfg_file, szSec);
		return;
	}

	if (!stricmp(szVal, "null")) {
		szVal[0]=0;
	}
	gf_cfg_set_key(cfg_file, szSec, szKey, szVal[0] ? szVal : NULL);
}

Project: gpac
File: ffmpeg_demux.c

static Bool FFD_CanHandleURL(GF_InputService *plug, const char *url)
{
	Bool has_audio, has_video;
	s32 i;
 	AVFormatContext *ctx;
 	AVOutputFormat *fmt_out;
 	Bool ret = GF_FALSE;
	char *ext, szName[1024], szExt[20];
 	const char *szExtList;
 	FFDemux *ffd;
 	if (!plug || !url)
		return GF_FALSE;
	/*disable RTP/RTSP from ffmpeg*/
	if (!strnicmp(url, "rtsp://", 7)) return GF_FALSE;
	if (!strnicmp(url, "rtspu://", 8)) return GF_FALSE;
	if (!strnicmp(url, "rtp://", 6)) return GF_FALSE;
	if (!strnicmp(url, "plato://", 8)) return GF_FALSE;
	if (!strnicmp(url, "udp://", 6)) return GF_FALSE;
	if (!strnicmp(url, "tcp://", 6)) return GF_FALSE;
	if (!strnicmp(url, "data:", 5)) return GF_FALSE;
 
 	ffd = (FFDemux*)plug->priv;
 
	if (strlen(url) >= sizeof(szName))
		return GF_FALSE;

 	strcpy(szName, url);
 	ext = strrchr(szName, '#');
 	if (ext) ext[0] = 0;
	ext = strrchr(szName, '?');
	if (ext) ext[0] = 0;

 	ext = strrchr(szName, '.');
 	if (ext && strlen(ext) > 19) ext = NULL;
 
	if (ext && strlen(ext) > 1 && strlen(ext) <= sizeof(szExt)) {
 		strcpy(szExt, &ext[1]);
 		strlwr(szExt);
 #ifndef FFMPEG_DEMUX_ENABLE_MPEG2TS
		if (strstr("ts m2t mts dmb trp", szExt) ) return GF_FALSE;
#endif

		/*note we forbid ffmpeg to handle files we support*/
		if (!strcmp(szExt, "mp4") || !strcmp(szExt, "mpg4") || !strcmp(szExt, "m4a") || !strcmp(szExt, "m21")
		        || !strcmp(szExt, "m4v") || !strcmp(szExt, "m4a")
		        || !strcmp(szExt, "m4s") || !strcmp(szExt, "3gs")
		        || !strcmp(szExt, "3gp") || !strcmp(szExt, "3gpp") || !strcmp(szExt, "3gp2") || !strcmp(szExt, "3g2")
		        || !strcmp(szExt, "mp3")
		        || !strcmp(szExt, "ac3")
		        || !strcmp(szExt, "amr")
		        || !strcmp(szExt, "bt") || !strcmp(szExt, "wrl") || !strcmp(szExt, "x3dv")
		        || !strcmp(szExt, "xmt") || !strcmp(szExt, "xmta") || !strcmp(szExt, "x3d")

		        || !strcmp(szExt, "jpg") || !strcmp(szExt, "jpeg") || !strcmp(szExt, "png")
		   ) return GF_FALSE;

		/*check any default stuff that should work with ffmpeg*/
		{
			u32 i;
			for (i = 0 ; FFD_MIME_TYPES[i]; i+=3) {
				if (gf_service_check_mime_register(plug, FFD_MIME_TYPES[i], FFD_MIME_TYPES[i+1], FFD_MIME_TYPES[i+2], ext))
					return GF_TRUE;
			}
		}
	}

	ffd_parse_options(ffd, url);

	ctx = NULL;
	if (open_file(&ctx, szName, NULL, ffd->options ? &ffd->options : NULL)<0) {
		AVInputFormat *av_in = NULL;
		/*some extensions not supported by ffmpeg*/
		if (ext && !strcmp(szExt, "cmp")) av_in = av_find_input_format("m4v");

		if (open_file(&ctx, szName, av_in, ffd->options ? &ffd->options : NULL)<0) {
			return GF_FALSE;
		}
	}

	if (!ctx) goto exit;
	if (av_find_stream_info(ctx) <0) goto exit;

	/*figure out if we can use codecs or not*/
	has_video = has_audio = GF_FALSE;
	for(i = 0; i < (s32)ctx->nb_streams; i++) {
		AVCodecContext *enc = ctx->streams[i]->codec;
		switch(enc->codec_type) {
		case AVMEDIA_TYPE_AUDIO:
			if (!has_audio) has_audio = GF_TRUE;
			break;
		case AVMEDIA_TYPE_VIDEO:
			if (!has_video) has_video= GF_TRUE;
			break;
		default:
			break;
		}
	}
	if (!has_audio && !has_video) goto exit;
	ret = GF_TRUE;
#if ((LIBAVFORMAT_VERSION_MAJOR == 52) && (LIBAVFORMAT_VERSION_MINOR <= 47)) || (LIBAVFORMAT_VERSION_MAJOR < 52)
	fmt_out = guess_stream_format(NULL, url, NULL);
#else
	fmt_out = av_guess_format(NULL, url, NULL);
#endif
	if (fmt_out) gf_service_register_mime(plug, fmt_out->mime_type, fmt_out->extensions, fmt_out->name);
	else {
		ext = strrchr(szName, '.');
		if (ext) {
			strcpy(szExt, &ext[1]);
			strlwr(szExt);

			szExtList = gf_modules_get_option((GF_BaseInterface *)plug, "MimeTypes", "application/x-ffmpeg");
			if (!szExtList) {
				gf_service_register_mime(plug, "application/x-ffmpeg", szExt, "Other Movies (FFMPEG)");
			} else if (!strstr(szExtList, szExt)) {
				u32 len;
				char *buf;
				len = (u32) (strlen(szExtList) + strlen(szExt) + 10);
				buf = (char*)gf_malloc(sizeof(char)*len);
				sprintf(buf, "\"%s ", szExt);
				strcat(buf, &szExtList[1]);
				gf_modules_set_option((GF_BaseInterface *)plug, "MimeTypes", "application/x-ffmpeg", buf);
				gf_free(buf);
			}
		}
	}

exit:
#if FF_API_CLOSE_INPUT_FILE
	if (ctx) av_close_input_file(ctx);
#else
	if (ctx) avformat_close_input(&ctx);
#endif
	return ret;
}

Project: gpac
File: scene_manager.c

GF_Err gf_sm_load_init(GF_SceneLoader *load)
{
	GF_Err e = GF_NOT_SUPPORTED;
	char *ext, szExt[50];
	/*we need at least a scene graph*/
	if (!load || (!load->ctx && !load->scene_graph)
#ifndef GPAC_DISABLE_ISOM
	        || (!load->fileName && !load->isom && !(load->flags & GF_SM_LOAD_FOR_PLAYBACK) )
#endif
	   ) return GF_BAD_PARAM;

	if (!load->type) {
#ifndef GPAC_DISABLE_ISOM
		if (load->isom) {
			load->type = GF_SM_LOAD_MP4;
		} else
#endif
		{
			ext = (char *)strrchr(load->fileName, '.');
			if (!ext) return GF_NOT_SUPPORTED;
			if (!stricmp(ext, ".gz")) {
				char *anext;
				ext[0] = 0;
				anext = (char *)strrchr(load->fileName, '.');
 				ext[0] = '.';
 				ext = anext;
 			}
			if (strlen(ext) < 2 || strlen(ext) > sizeof(szExt)) {
				GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[Scene Manager] invalid extension in file name %s\n", load->fileName));
				return GF_NOT_SUPPORTED;
			}
 			strcpy(szExt, &ext[1]);
 			strlwr(szExt);
 			if (strstr(szExt, "bt")) load->type = GF_SM_LOAD_BT;
			else if (strstr(szExt, "wrl")) load->type = GF_SM_LOAD_VRML;
			else if (strstr(szExt, "x3dv")) load->type = GF_SM_LOAD_X3DV;
#ifndef GPAC_DISABLE_LOADER_XMT
			else if (strstr(szExt, "xmt") || strstr(szExt, "xmta")) load->type = GF_SM_LOAD_XMTA;
			else if (strstr(szExt, "x3d")) load->type = GF_SM_LOAD_X3D;
#endif
			else if (strstr(szExt, "swf")) load->type = GF_SM_LOAD_SWF;
			else if (strstr(szExt, "mov")) load->type = GF_SM_LOAD_QT;
			else if (strstr(szExt, "svg")) load->type = GF_SM_LOAD_SVG;
			else if (strstr(szExt, "xsr")) load->type = GF_SM_LOAD_XSR;
			else if (strstr(szExt, "xbl")) load->type = GF_SM_LOAD_XBL;
			else if (strstr(szExt, "xml")) {
				char *rtype = gf_xml_get_root_type(load->fileName, &e);
				if (rtype) {
					if (!strcmp(rtype, "SAFSession")) load->type = GF_SM_LOAD_XSR;
					else if (!strcmp(rtype, "XMT-A")) load->type = GF_SM_LOAD_XMTA;
					else if (!strcmp(rtype, "X3D")) load->type = GF_SM_LOAD_X3D;
					else if (!strcmp(rtype, "bindings")) load->type = GF_SM_LOAD_XBL;

					gf_free(rtype);
				}
			}
		}
	}
	if (!load->type) return e;

	if (!load->scene_graph) load->scene_graph = load->ctx->scene_graph;

	switch (load->type) {
#ifndef GPAC_DISABLE_LOADER_BT
	case GF_SM_LOAD_BT:
	case GF_SM_LOAD_VRML:
	case GF_SM_LOAD_X3DV:
		return gf_sm_load_init_bt(load);
#endif

#ifndef GPAC_DISABLE_LOADER_XMT
	case GF_SM_LOAD_XMTA:
	case GF_SM_LOAD_X3D:
		return gf_sm_load_init_xmt(load);
#endif

#ifndef GPAC_DISABLE_SVG
	case GF_SM_LOAD_SVG:
	case GF_SM_LOAD_XSR:
	case GF_SM_LOAD_DIMS:
		return gf_sm_load_init_svg(load);

	case GF_SM_LOAD_XBL:
		e = gf_sm_load_init_xbl(load);

		load->process = gf_sm_load_run_xbl;
		load->done = gf_sm_load_done_xbl;
		return e;
#endif

#ifndef GPAC_DISABLE_SWF_IMPORT
	case GF_SM_LOAD_SWF:
		return gf_sm_load_init_swf(load);
#endif

#ifndef GPAC_DISABLE_LOADER_ISOM
	case GF_SM_LOAD_MP4:
		return gf_sm_load_init_isom(load);
#endif

#ifndef GPAC_DISABLE_QTVR
	case GF_SM_LOAD_QT:
		return gf_sm_load_init_qt(load);
#endif
	default:
		return GF_NOT_SUPPORTED;
	}
	return GF_NOT_SUPPORTED;
}