CVE-2018-18557 (published 2018-10-22T16:29Z)

LibTIFF 3.9.3, 3.9.4, 3.9.5, 3.9.6, 3.9.7, 4.0.0alpha4, 4.0.0alpha5, 4.0.0alpha6, 4.0.0beta7, 4.0.0, 4.0.1, 4.0.2, 4.0.3, 4.0.4, 4.0.4beta, 4.0.5, 4.0.6, 4.0.7, 4.0.8 and 4.0.9 (with JBIG enabled) decodes arbitrarily-sized JBIG into a buffer, ignoring the buffer size, which leads to a tif_jbig.c JBIGDecode out-of-bounds write.

Severity: MEDIUM
CVSS v2 base score: 6.8 (AV:N/AC:M/Au:N/C:P/I:P/A:P)
CVSS v3 base score: 8.8, HIGH (CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-787
cwe_name: Out-of-bounds Write
description: The product writes data past the end, or before the beginning, of the intended buffer.
extended_description: 
            
            
             
			 
         
         

Fix information:
repo_url: https://gitlab.com/libtiff/libtiff
commit_details: repo_url: https://gitlab.com/libtiff/libtiff
author: Even Rouault
author_date: 2018-10-14 16:38:29+02:00
msg: JBIG: fix potential out-of-bounds write in JBIGDecode()

JBIGDecode doesn't check if the user provided buffer is large enough
to store the JBIG decoded image, which can potentially cause out-of-bounds
write in the buffer.
This issue was reported and analyzed by Thomas Dullien.

Also fixes a (harmless) potential use of uninitialized memory when
tif->tif_rawsize > tif->tif_rawcc

And in case libtiff is compiled with CHUNKY_STRIP_READ_SUPPORT, make sure
that whole strip data is provided to JBIGDecode()
repository: repo_url: https://gitlab.com/libtiff/libtiff
repo_name: visit repo url
description: visit repo url
repo_language: visit repo url
owner: libtiff
file_changes: filename: tif_jbig.c
change_type: ModificationType.MODIFY
diff: @@ -51,17 +51,18 @@ static int JBIGDecode(TIFF* tif, uint8* buffer, tmsize_t size, uint16 s)
 	struct jbg_dec_state decoder;
 	int decodeStatus = 0;
 	unsigned char* pImage = NULL;
-	(void) size, (void) s;
+	unsigned long decodedSize;
+	(void) s;
 
 	if (isFillOrder(tif, tif->tif_dir.td_fillorder))
 	{
-		TIFFReverseBits(tif->tif_rawdata, tif->tif_rawdatasize);
+		TIFFReverseBits(tif->tif_rawcp, tif->tif_rawcc);
 	}
 
 	jbg_dec_init(&decoder);
 
 #if defined(HAVE_JBG_NEWLEN)
-	jbg_newlen(tif->tif_rawdata, (size_t)tif->tif_rawdatasize);
+	jbg_newlen(tif->tif_rawcp, (size_t)tif->tif_rawcc);
 	/*
 	 * I do not check the return status of jbg_newlen because even if this
 	 * function fails it does not necessarily mean that decoding the image
@@ -74,8 +75,8 @@ static int JBIGDecode(TIFF* tif, uint8* buffer, tmsize_t size, uint16 s)
 	 */
 #endif /* HAVE_JBG_NEWLEN */
 
-	decodeStatus = jbg_dec_in(&decoder, (unsigned char*)tif->tif_rawdata,
-				  (size_t)tif->tif_rawdatasize, NULL);
+	decodeStatus = jbg_dec_in(&decoder, (unsigned char*)tif->tif_rawcp,
+				  (size_t)tif->tif_rawcc, NULL);
 	if (JBG_EOK != decodeStatus)
 	{
 		/*
@@ -96,9 +97,28 @@ static int JBIGDecode(TIFF* tif, uint8* buffer, tmsize_t size, uint16 s)
 		return 0;
 	}
 
+	decodedSize = jbg_dec_getsize(&decoder);
+	if( (tmsize_t)decodedSize < size )
+	{
+	    TIFFWarningExt(tif->tif_clientdata, "JBIG",
+	                   "Only decoded %lu bytes, whereas %lu requested",
+	                   decodedSize, (unsigned long)size);
+	}
+	else if( (tmsize_t)decodedSize > size )
+	{
+	    TIFFErrorExt(tif->tif_clientdata, "JBIG",
+	                 "Decoded %lu bytes, whereas %lu were requested",
+	                 decodedSize, (unsigned long)size);
+	    jbg_dec_free(&decoder);
+	    return 0;
+	}
 	pImage = jbg_dec_getimage(&decoder, 0);
-	_TIFFmemcpy(buffer, pImage, jbg_dec_getsize(&decoder));
+	_TIFFmemcpy(buffer, pImage, decodedSize);
 	jbg_dec_free(&decoder);
+
+        tif->tif_rawcp += tif->tif_rawcc;
+        tif->tif_rawcc = 0;
+
 	return 1;
 }
 

programming_language: C
filename: tif_read.c
change_type: ModificationType.MODIFY
diff: @@ -346,7 +346,8 @@ TIFFSeek(TIFF* tif, uint32 row, uint16 sample )
             return 0;
         whole_strip = tif->tif_dir.td_stripbytecount[strip] < 10
                 || isMapped(tif);
-        if( td->td_compression == COMPRESSION_LERC )
+        if( td->td_compression == COMPRESSION_LERC ||
+            td->td_compression == COMPRESSION_JBIG )
         {
             /* Ideally plugins should have a way to declare they don't support
              * chunk strip */

programming_language: C