Hi: another CVE appeared, CVE-2017-8787 (see also https://bugs.debian.org/861738)
According to a private email from the OP this is already fixed/unreproducible in trunk, so it would only need $somebody to find the fixing commit. Forwarding here as a FYI. ----- Forwarded message from Xiaobo Xiang <xiangxb2...@gmail.com> ----- Date: Wed, 3 May 2017 18:55:49 +0800 From: Xiaobo Xiang <xiangxb2...@gmail.com> To: sub...@bugs.debian.org Subject: Bug#861738: [bug report][libpodofo]heap based overflow in ReadXRefStreamEntry Message-ID: <cahhvycq9zsft5x68gwdbf13_w17iq5g4luvor3gz4p33113...@mail.gmail.com> Package: libpodofo Version: 0.9.5 [summary] I've found a heap based buffer overflow in libpodofo using libFuzzer. PdfXRefStreamParserObject::ReadXRefStreamEntry(src/base/PdfXRefStreamParserObject.cpp:224) [details] in function PdfXRefStreamParserObject::ReadXRefTable(), the program get nW[] array from file data, and does no check on it. void PdfXRefStreamParserObject::ReadXRefTable() { pdf_int64 lSize = this->GetDictionary().GetKeyAsLong( PdfName::KeySize, 0 ); PdfVariant vWArray = *(this->GetDictionary().GetKey( "W" )); // The pdf reference states that W is always an array with 3 entries // all of them have to be integers if( !vWArray.IsArray() || vWArray.GetArray().size() != 3 ) { PODOFO_RAISE_ERROR( ePdfError_NoXRef ); } pdf_int64 nW[W_ARRAY_SIZE] = { 0, 0, 0 }; for( int i=0;i<W_ARRAY_SIZE;i++ ) { if( !vWArray.GetArray()[i].IsNumber() ) { PODOFO_RAISE_ERROR( ePdfError_NoXRef ); } nW[i] = static_cast<pdf_int64>(vWArray.GetArray()[i].GetNumber()); // get from file data, without check. } std::vector<pdf_int64> vecIndeces; GetIndeces( vecIndeces, static_cast<pdf_int64>(lSize) ); ParseStream( nW, vecIndeces ); // pass the array to ParseStream } the nW array will be passed to ParseStream Function, they are used to calculate entryLen using add. const size_t entryLen = static_cast<size_t>(nW[0] + nW[1] + nW[2]); Followed are two while loop, in the second loop, program calls ReadXRefStreamEntry: void PdfXRefStreamParserObject::ParseStream( const pdf_int64 nW[W_ARRAY_SIZE], const std::vector<pdf_int64> & rvecIndeces ) { char* pBuffer; pdf_long lBufferLen; const size_t entryLen = static_cast<size_t>(nW[0] + nW[1] + nW[2]); // may be 0xffffffff std::vector<pdf_int64>::const_iterator it = rvecIndeces.begin(); char* const pStart = pBuffer; while( it != rvecIndeces.end() ) { //....... while( nCount > 0 ) { if( (pBuffer - pStart) >= lBufferLen ) { PODOFO_RAISE_ERROR_INFO( ePdfError_NoXRef, "Invalid count in XRef stream" ); } //printf("nCount=%i ", static_cast<int>(nCount)); //printf("pBuffer=%li ", (long)(pBuffer - pStart)); //printf("pEnd=%li ", lBufferLen); if ( nFirstObj >= 0 && nFirstObj < static_cast<pdf_int64>(m_pOffsets->size()) && ! (*m_pOffsets)[static_cast<int>(nFirstObj)].bParsed) { ReadXRefStreamEntry( pBuffer, lBufferLen, nW, static_cast<int>(nFirstObj) ); // calling ReadXRefStreamEntry } nFirstObj++ ; pBuffer += entryLen; // heap out of bound read --nCount; } //...... } podofo_free( pStart ); } in ReadXRefStreamEntry function,there are two loops, in the second loop, program fetches data from pBuffer pointer and assigns it to nData[i], this could result in out of bound read in the heap. Because pBuffer was modified in ParseStream by "pBuffer += entryLen;" . in my case, the nW[]=[1 -4 2] , entryLen=1-4+2=0xffffffff I've recorded the value before the assignment sentence. the value of pBuffer pointer is as follows: pBuffer=0x621000019100 pBuffer=0x621000019101 pBuffer=0x621000019102 pBuffer=0x6210000190ff after calling pBuffer+=entryLen for several times, the pBuffer will get under overflow, when it returned to ReadXRefStreamEntry again, heap overflow. [crash log] Below is my crash log: ./podofopdfinfo ./heap-overflow-ReadXRefStreamEntry ================================================================= ==23234==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6210000190ff at pc 0x0000005bd7a4 bp 0x7fff686b0350 sp 0x7fff686b0340 READ of size 1 at 0x6210000190ff thread T0 #0 0x5bd7a3 in PoDoFo::PdfXRefStreamParserObject::ReadXRefStreamEntry(char*, long, long const*, int) podofo-0.9.5/src/base/PdfXRefStreamParserObject.cpp:224 #1 0x5bcf41 in PoDoFo::PdfXRefStreamParserObject::ParseStream(long const*, std::vector<long, std::allocator<long> > const&) podofo-0.9.5/src/base/PdfXRefStreamParserObject.cpp:156 #2 0x5bc9b0 in PoDoFo::PdfXRefStreamParserObject::ReadXRefTable() podofo-0.9.5/src/base/PdfXRefStreamParserObject.cpp:118 #3 0x598894 in PoDoFo::PdfParser::ReadXRefStreamContents(long, bool) podofo-0.9.5/src/base/PdfParser.cpp:858 #4 0x597720 in PoDoFo::PdfParser::ReadXRefContents(long, bool) podofo-0.9.5/src/base/PdfParser.cpp:682 #5 0x594106 in PoDoFo::PdfParser::ReadDocumentStructure() podofo-0.9.5/src/base/PdfParser.cpp:337 #6 0x593734 in PoDoFo::PdfParser::ParseFile(PoDoFo::PdfRefCountedInputDevice const&, bool) podofo-0.9.5/src/base/PdfParser.cpp:220 #7 0x59331e in PoDoFo::PdfParser::ParseFile(char const*, bool) podofo-0.9.5/src/base/PdfParser.cpp:164 #8 0x540f4f in PoDoFo::PdfMemDocument::Load(char const*, bool) podofo-0.9.5/src/doc/PdfMemDocument.cpp:256 #9 0x53fde9 in PoDoFo::PdfMemDocument::PdfMemDocument(char const*, bool) podofo-0.9.5/src/doc/PdfMemDocument.cpp:102 #10 0x4b8021 in PdfInfo::PdfInfo(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) podofo-0.9.5/tools/podofopdfinfo/pdfinfo.cpp:25 #11 0x4bee20 in main podofo-0.9.5/tools/podofopdfinfo/podofopdfinfo.cpp:110 #12 0x7fe5111a882f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f) #13 0x4b7ee8 in _start (podofopdfinfo+0x4b7ee8) 0x6210000190ff is located 1 bytes to the left of 4096-byte region [0x621000019100,0x62100001a100) allocated by thread T0 here: #0 0x7fe512a0779a in __interceptor_calloc (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x9879a) #1 0x591652 in PoDoFo::podofo_calloc(unsigned long, unsigned long) podofo-0.9.5/src/base/PdfMemoryManagement.cpp:136 #2 0x591aa6 in PoDoFo::PdfMemoryOutputStream::PdfMemoryOutputStream(long) podofo-0.9.5/src/base/PdfOutputStream.cpp:77 #3 0x4db667 in PoDoFo::PdfStream::GetFilteredCopy(char**, long*) const podofo-0.9.5/src/base/PdfStream.cpp:91 #4 0x5bccb1 in PoDoFo::PdfXRefStreamParserObject::ParseStream(long const*, std::vector<long, std::allocator<long> > const&) podofo-0.9.5/src/base/PdfXRefStreamParserObject.cpp:127 #5 0x5bc9b0 in PoDoFo::PdfXRefStreamParserObject::ReadXRefTable() podofo-0.9.5/src/base/PdfXRefStreamParserObject.cpp:118 #6 0x598894 in PoDoFo::PdfParser::ReadXRefStreamContents(long, bool) podofo-0.9.5/src/base/PdfParser.cpp:858 #7 0x597720 in PoDoFo::PdfParser::ReadXRefContents(long, bool) podofo-0.9.5/src/base/PdfParser.cpp:682 #8 0x594106 in PoDoFo::PdfParser::ReadDocumentStructure() podofo-0.9.5/src/base/PdfParser.cpp:337 #9 0x593734 in PoDoFo::PdfParser::ParseFile(PoDoFo::PdfRefCountedInputDevice const&, bool) podofo-0.9.5/src/base/PdfParser.cpp:220 #10 0x59331e in PoDoFo::PdfParser::ParseFile(char const*, bool) podofo-0.9.5/src/base/PdfParser.cpp:164 #11 0x540f4f in PoDoFo::PdfMemDocument::Load(char const*, bool) podofo-0.9.5/src/doc/PdfMemDocument.cpp:256 #12 0x53fde9 in PoDoFo::PdfMemDocument::PdfMemDocument(char const*, bool) podofo-0.9.5/src/doc/PdfMemDocument.cpp:102 #13 0x4b8021 in PdfInfo::PdfInfo(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) podofo-0.9.5/tools/podofopdfinfo/pdfinfo.cpp:25 #14 0x4bee20 in main podofo-0.9.5/tools/podofopdfinfo/podofopdfinfo.cpp:110 #15 0x7fe5111a882f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f) SUMMARY: AddressSanitizer: heap-buffer-overflow podofo-0.9.5/src/base/PdfXRefStreamParserObject.cpp:224 PoDoFo::PdfXRefStreamParserObject::ReadXRefStreamEntry(char*, long, long const*, int) Shadow bytes around the buggy address: 0x0c427fffb1c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c427fffb1d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c427fffb1e0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c427fffb1f0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c427fffb200: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa =>0x0c427fffb210: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa[fa] 0x0c427fffb220: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c427fffb230: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c427fffb240: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c427fffb250: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c427fffb260: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Heap right redzone: fb Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack partial redzone: f4 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe ==23234==ABORTING [how to reproduce] compile the podofo project with address sanitizer, and run the following command ./podofopdfinfo ./heap-overflow-ReadXRefStreamEntry [how to fix] I think checking the value of the nW array to ensure they are positive will work. Please feel free to ask me if you have further question about this report. Best Regards, Xiang Xiaobo of VARAS@IIE ----- End forwarded message ----- -- regards, Mattia Rizzolo GPG Key: 66AE 2B4A FCCF 3F52 DA18 4D18 4B04 3FCD B944 4540 .''`. more about me: https://mapreri.org : :' : Launchpad user: https://launchpad.net/~mapreri `. `'` Debian QA page: https://qa.debian.org/developer.php?login=mattia `-
signature.asc
Description: PGP signature
------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________ Podofo-users mailing list Podofo-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/podofo-users