| From e1cd2d7ab032e7fe80b4c13e07895194c8bac85e Mon Sep 17 00:00:00 2001 |
| From: Brian May <brian@linuxpenguins.xyz> |
| Date: Thu, 7 Dec 2017 07:46:47 +1100 |
| Subject: [PATCH 1/4] [PATCH] tiff2pdf: Fix CVE-2017-9935 |
| |
| Fix for http://bugzilla.maptools.org/show_bug.cgi?id=2704 |
| |
| This vulnerability - at least for the supplied test case - is because we |
| assume that a tiff will only have one transfer function that is the same |
| for all pages. This is not required by the TIFF standards. |
| |
| We than read the transfer function for every page. Depending on the |
| transfer function, we allocate either 2 or 4 bytes to the XREF buffer. |
| We allocate this memory after we read in the transfer function for the |
| page. |
| |
| For the first exploit - POC1, this file has 3 pages. For the first page |
| we allocate 2 extra extra XREF entries. Then for the next page 2 more |
| entries. Then for the last page the transfer function changes and we |
| allocate 4 more entries. |
| |
| When we read the file into memory, we assume we have 4 bytes extra for |
| each and every page (as per the last transfer function we read). Which |
| is not correct, we only have 2 bytes extra for the first 2 pages. As a |
| result, we end up writing past the end of the buffer. |
| |
| There are also some related issues that this also fixes. For example, |
| TIFFGetField can return uninitalized pointer values, and the logic to |
| detect a N=3 vs N=1 transfer function seemed rather strange. |
| |
| It is also strange that we declare the transfer functions to be of type |
| float, when the standard says they are unsigned 16 bit values. This is |
| fixed in another patch. |
| |
| This patch will check to ensure that the N value for every transfer |
| function is the same for every page. If this changes, we abort with an |
| error. In theory, we should perhaps check that the transfer function |
| itself is identical for every page, however we don't do that due to the |
| confusion of the type of the data in the transfer function. |
| |
| libtiff/tif_dir.c | 3 +++ |
| tools/tiff2pdf.c | 69 +++++++++++++++++++++++++++++++---------------- |
| 2 files changed, 49 insertions(+), 23 deletions(-) |
| |
| diff --git a/libtiff/tif_dir.c b/libtiff/tif_dir.c |
| index f00f808..c36a5f3 100644 |
| |
| |
| @@ -1067,6 +1067,9 @@ _TIFFVGetField(TIFF* tif, uint32 tag, va_list ap) |
| if (td->td_samplesperpixel - td->td_extrasamples > 1) { |
| *va_arg(ap, uint16**) = td->td_transferfunction[1]; |
| *va_arg(ap, uint16**) = td->td_transferfunction[2]; |
| + } else { |
| + *va_arg(ap, uint16**) = NULL; |
| + *va_arg(ap, uint16**) = NULL; |
| } |
| break; |
| case TIFFTAG_REFERENCEBLACKWHITE: |
| diff --git a/tools/tiff2pdf.c b/tools/tiff2pdf.c |
| index bdb9126..bd23c9e 100644 |
| |
| |
| @@ -239,7 +239,7 @@ typedef struct { |
| float tiff_whitechromaticities[2]; |
| float tiff_primarychromaticities[6]; |
| float tiff_referenceblackwhite[2]; |
| - float* tiff_transferfunction[3]; |
| + uint16* tiff_transferfunction[3]; |
| int pdf_image_interpolate; /* 0 (default) : do not interpolate, |
| 1 : interpolate */ |
| uint16 tiff_transferfunctioncount; |
| @@ -1049,6 +1049,8 @@ void t2p_read_tiff_init(T2P* t2p, TIFF* input){ |
| uint16 pagen=0; |
| uint16 paged=0; |
| uint16 xuint16=0; |
| + uint16 tiff_transferfunctioncount=0; |
| + uint16* tiff_transferfunction[3]; |
| |
| directorycount=TIFFNumberOfDirectories(input); |
| if(directorycount > TIFF_DIR_MAX) { |
| @@ -1157,26 +1159,48 @@ void t2p_read_tiff_init(T2P* t2p, TIFF* input){ |
| } |
| #endif |
| if (TIFFGetField(input, TIFFTAG_TRANSFERFUNCTION, |
| - &(t2p->tiff_transferfunction[0]), |
| - &(t2p->tiff_transferfunction[1]), |
| - &(t2p->tiff_transferfunction[2]))) { |
| - if((t2p->tiff_transferfunction[1] != (float*) NULL) && |
| - (t2p->tiff_transferfunction[2] != (float*) NULL) && |
| - (t2p->tiff_transferfunction[1] != |
| - t2p->tiff_transferfunction[0])) { |
| - t2p->tiff_transferfunctioncount = 3; |
| - t2p->tiff_pages[i].page_extra += 4; |
| - t2p->pdf_xrefcount += 4; |
| - } else { |
| - t2p->tiff_transferfunctioncount = 1; |
| - t2p->tiff_pages[i].page_extra += 2; |
| - t2p->pdf_xrefcount += 2; |
| - } |
| - if(t2p->pdf_minorversion < 2) |
| - t2p->pdf_minorversion = 2; |
| + &(tiff_transferfunction[0]), |
| + &(tiff_transferfunction[1]), |
| + &(tiff_transferfunction[2]))) { |
| + |
| + if((tiff_transferfunction[1] != (uint16*) NULL) && |
| + (tiff_transferfunction[2] != (uint16*) NULL) |
| + ) { |
| + tiff_transferfunctioncount=3; |
| + } else { |
| + tiff_transferfunctioncount=1; |
| + } |
| } else { |
| - t2p->tiff_transferfunctioncount=0; |
| + tiff_transferfunctioncount=0; |
| } |
| + |
| + if (i > 0){ |
| + if (tiff_transferfunctioncount != t2p->tiff_transferfunctioncount){ |
| + TIFFError( |
| + TIFF2PDF_MODULE, |
| + "Different transfer function on page %d", |
| + i); |
| + t2p->t2p_error = T2P_ERR_ERROR; |
| + return; |
| + } |
| + } |
| + |
| + t2p->tiff_transferfunctioncount = tiff_transferfunctioncount; |
| + t2p->tiff_transferfunction[0] = tiff_transferfunction[0]; |
| + t2p->tiff_transferfunction[1] = tiff_transferfunction[1]; |
| + t2p->tiff_transferfunction[2] = tiff_transferfunction[2]; |
| + if(tiff_transferfunctioncount == 3){ |
| + t2p->tiff_pages[i].page_extra += 4; |
| + t2p->pdf_xrefcount += 4; |
| + if(t2p->pdf_minorversion < 2) |
| + t2p->pdf_minorversion = 2; |
| + } else if (tiff_transferfunctioncount == 1){ |
| + t2p->tiff_pages[i].page_extra += 2; |
| + t2p->pdf_xrefcount += 2; |
| + if(t2p->pdf_minorversion < 2) |
| + t2p->pdf_minorversion = 2; |
| + } |
| + |
| if( TIFFGetField( |
| input, |
| TIFFTAG_ICCPROFILE, |
| @@ -1837,10 +1861,9 @@ void t2p_read_tiff_data(T2P* t2p, TIFF* input){ |
| &(t2p->tiff_transferfunction[0]), |
| &(t2p->tiff_transferfunction[1]), |
| &(t2p->tiff_transferfunction[2]))) { |
| - if((t2p->tiff_transferfunction[1] != (float*) NULL) && |
| - (t2p->tiff_transferfunction[2] != (float*) NULL) && |
| - (t2p->tiff_transferfunction[1] != |
| - t2p->tiff_transferfunction[0])) { |
| + if((t2p->tiff_transferfunction[1] != (uint16*) NULL) && |
| + (t2p->tiff_transferfunction[2] != (uint16*) NULL) |
| + ) { |
| t2p->tiff_transferfunctioncount=3; |
| } else { |
| t2p->tiff_transferfunctioncount=1; |
| -- |
| 2.17.0 |
| |