CVE-2018-20763: Out-of-bounds Write (CWE-787)
value: In GPAC 0.7.1 and earlier, gf_text_get_utf8_line in media_tools/text_import.c in libgpac_static.a allows an out-of-bounds write because of missing szLineConv bounds checking.
CWE description: The product writes data past the end, or before the beginning, of the intended buffer.
CVSS v3 base score: 7.8
Published: 2019-02-06T23:29Z
Repository: https://github.com/gpac/gpac
Language: C
Files changed: applications/mp4client/main.c, src/media_tools/text_import.c
Commit date: 2019-01-11 15:02:51 +0100
Commit message: add some boundary checks on gf_text_get_utf8_line (#1188)

Diff: diff --git a/applications/mp4client/main.c b/applications/mp4client/main.c
index 46404ff985..df01947f3c 100644
--- a/applications/mp4client/main.c
+++ b/applications/mp4client/main.c
@@ -1713,11 +1713,11 @@ int mp4client_main(int argc, char **argv)
 				GF_DownloadSession *sess = gf_dm_sess_new(term->downloader, the_url, GF_NETIO_SESSION_NOT_THREADED, NULL, NULL, &e);
 				if (sess) {
 					e = gf_dm_sess_process(sess);
 					if (!e) {
 						strncpy(the_url, gf_dm_sess_get_cache_name(sess), sizeof(the_url) - 1);
-						the_url[sizeof(the_cfg) - 1] = 0;
+						the_url[sizeof(the_url) - 1] = 0;
 					}
 					gf_dm_sess_del(sess);
 				}
 			}
 
diff --git a/src/media_tools/text_import.c b/src/media_tools/text_import.c
index 18f10f33d1..af92000787 100644
--- a/src/media_tools/text_import.c
+++ b/src/media_tools/text_import.c
@@ -203,53 +203,80 @@ char *gf_text_get_utf8_line(char *szLine, u32 lineSize, FILE *txt_in, s32 unicod
 	sOK = fgets(szLine, lineSize, txt_in);
 	if (!sOK) return NULL;
 	if (unicode_type<=1) {
 		j=0;
 		len = (u32) strlen(szLine);
-		for (i=0; i<len; i++) {
+		for (i=0; i<len && j < sizeof(szLineConv) - 1; i++, j++) {
+
 			if (!unicode_type && (szLine[i] & 0x80)) {
 				/*non UTF8 (likely some win-CP)*/
 				if ((szLine[i+1] & 0xc0) != 0x80) {
-					szLineConv[j] = 0xc0 | ( (szLine[i] >> 6) & 0x3 );
-					j++;
-					szLine[i] &= 0xbf;
+					if (j + 1 < sizeof(szLineConv) - 1) {
+						szLineConv[j] = 0xc0 | ((szLine[i] >> 6) & 0x3);
+						j++;
+						szLine[i] &= 0xbf;
+					}
+					else
+						break;
 				}
 				/*UTF8 2 bytes char*/
 				else if ( (szLine[i] & 0xe0) == 0xc0) {
-					szLineConv[j] = szLine[i];
-					i++;
-					j++;
+
+					// don't cut multibyte in the middle in there is no more room in dest
+					if (j + 1 < sizeof(szLineConv) - 1 && i + 1 < len) {
+						szLineConv[j] = szLine[i];
+						i++;
+						j++;
+					}
+					else {
+						break;
+					}
 				}
 				/*UTF8 3 bytes char*/
 				else if ( (szLine[i] & 0xf0) == 0xe0) {
-					szLineConv[j] = szLine[i];
-					i++;
-					j++;
-					szLineConv[j] = szLine[i];
-					i++;
-					j++;
+					if (j + 2 < sizeof(szLineConv) - 1 && i + 2 < len) {
+						szLineConv[j] = szLine[i];
+						i++;
+						j++;
+						szLineConv[j] = szLine[i];
+						i++;
+						j++;
+					}
+					else {
+						break;
+					}
 				}
 				/*UTF8 4 bytes char*/
 				else if ( (szLine[i] & 0xf8) == 0xf0) {
-					szLineConv[j] = szLine[i];
-					i++;
-					j++;
-					szLineConv[j] = szLine[i];
-					i++;
-					j++;
-					szLineConv[j] = szLine[i];
-					i++;
-					j++;
+					if (j + 3 < sizeof(szLineConv) - 1 && i + 3 < len) {
+						szLineConv[j] = szLine[i];
+						i++;
+						j++;
+						szLineConv[j] = szLine[i];
+						i++;
+						j++;
+						szLineConv[j] = szLine[i];
+						i++;
+						j++;
+					}
+					else {
+						break;
+					}
 				} else {
 					i+=1;
 					continue;
 				}
 			}
-			szLineConv[j] = szLine[i];
-			j++;
+			if (j < sizeof(szLineConv)-1 && i<len)
+				szLineConv[j] = szLine[i];
+
 		}
-		szLineConv[j] = 0;
+		if (j >= sizeof(szLineConv))
+			szLineConv[sizeof(szLineConv) - 1] = 0;
+		else
+			szLineConv[j] = 0;
+
 		strcpy(szLine, szLineConv);
 		return sOK;
 	}
 
 #ifdef GPAC_BIG_ENDIAN

Vulnerable code: 						the_url[sizeof(the_cfg) - 1] = 0;
		for (i=0; i<len; i++) {
					szLineConv[j] = 0xc0 | ( (szLine[i] >> 6) & 0x3 );
					j++;
					szLine[i] &= 0xbf;
					szLineConv[j] = szLine[i];
					i++;
					j++;
					szLineConv[j] = szLine[i];
					i++;
					j++;
					szLineConv[j] = szLine[i];
					i++;
					j++;
					szLineConv[j] = szLine[i];
					i++;
					j++;
					szLineConv[j] = szLine[i];
					i++;
					j++;
					szLineConv[j] = szLine[i];
					i++;
					j++;
			szLineConv[j] = szLine[i];
			j++;
		szLineConv[j] = 0;
Fixed code: 						the_url[sizeof(the_url) - 1] = 0;
		for (i=0; i<len && j < sizeof(szLineConv) - 1; i++, j++) {

					if (j + 1 < sizeof(szLineConv) - 1) {
						szLineConv[j] = 0xc0 | ((szLine[i] >> 6) & 0x3);
						j++;
						szLine[i] &= 0xbf;
					}
					else
						break;

					// don't cut multibyte in the middle in there is no more room in dest
					if (j + 1 < sizeof(szLineConv) - 1 && i + 1 < len) {
						szLineConv[j] = szLine[i];
						i++;
						j++;
					}
					else {
						break;
					}
					if (j + 2 < sizeof(szLineConv) - 1 && i + 2 < len) {
						szLineConv[j] = szLine[i];
						i++;
						j++;
						szLineConv[j] = szLine[i];
						i++;
						j++;
					}
					else {
						break;
					}
					if (j + 3 < sizeof(szLineConv) - 1 && i + 3 < len) {
						szLineConv[j] = szLine[i];
						i++;
						j++;
						szLineConv[j] = szLine[i];
						i++;
						j++;
						szLineConv[j] = szLine[i];
						i++;
						j++;
					}
					else {
						break;
					}
			if (j < sizeof(szLineConv)-1 && i<len)
				szLineConv[j] = szLine[i];

		if (j >= sizeof(szLineConv))
			szLineConv[sizeof(szLineConv) - 1] = 0;
		else
			szLineConv[j] = 0;