Hi,
I've found a heap overflow bug in podofo library during my fuzzing with
libFuzzer.
My wrapper just simply called
PdfMemDocument doc( filename );
It crashed when parsing a crafted pdf file.
the crash log is as follows:
==17463==ERROR: AddressSanitizer: heap-buffer-overflow on address
0x620000000f38 at pc 0x000000630b12 bp 0x7ffe31de2df0 sp 0x7ffe31de2de8
READ of size 8 at 0x620000000f38 thread T0
#0 0x630b11 (/home/name/podofo-0.9.5/build/src/podofofuzzer+0x630b11)
#1 0x62e26e (/home/name/podofo-0.9.5/build/src/podofofuzzer+0x62e26e)
#2 0x62ce48 (/home/name/podofo-0.9.5/build/src/podofofuzzer+0x62ce48)
#3 0x5cdc64 (/home/name/podofo-0.9.5/build/src/podofofuzzer+0x5cdc64)
#4 0x5cd681 (/home/name/podofo-0.9.5/build/src/podofofuzzer+0x5cd681)
#5 0x5a7852 (/home/name/podofo-0.9.5/build/src/podofofuzzer+0x5a7852)
#6 0x899263 (/home/name/podofo-0.9.5/build/src/podofofuzzer+0x899263)
#7 0x899490 (/home/name/podofo-0.9.5/build/src/podofofuzzer+0x899490)
#8 0x890021 (/home/name/podofo-0.9.5/build/src/podofofuzzer+0x890021)
#9 0x891f8c (/home/name/podofo-0.9.5/build/src/podofofuzzer+0x891f8c)
#10 0x88fd90 (/home/name/podofo-0.9.5/build/src/podofofuzzer+0x88fd90)
#11 0x7f47d126482f (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
#12 0x4cc8e8 (/home/name/podofo-0.9.5/build/src/podofofuzzer+0x4cc8e8)
0x620000000f38 is located 24 bytes to the right of 3744-byte region
[0x620000000080,0x620000000f20)
allocated by thread T0 here:
#0 0x5a456b (/home/name/podofo-0.9.5/build/src/podofofuzzer+0x5a456b)
#1 0x648905 (/home/name/podofo-0.9.5/build/src/podofofuzzer+0x648905)
#2 0x648872 (/home/name/podofo-0.9.5/build/src/podofofuzzer+0x648872)
#3 0x647eaa (/home/name/podofo-0.9.5/build/src/podofofuzzer+0x647eaa)
#4 0x646e83 (/home/name/podofo-0.9.5/build/src/podofofuzzer+0x646e83)
#5 0x6463c5 (/home/name/podofo-0.9.5/build/src/podofofuzzer+0x6463c5)
when debugging with gdb, the backtrace is as follows.
(gdb) bt
#0 0x00000000005924b0 in __sanitizer::Die() ()
#1 0x000000000057b735 in __asan::ScopedInErrorReport::~ScopedInErrorReport()
()
#2 0x000000000057b0ab in __asan::ReportGenericError(unsigned long,
unsigned long, unsigned long, unsigned long, bool, unsigned long, unsigned
int, bool) ()
#3 0x000000000057be1b in __asan_report_load8 ()
#4 0x0000000000630b12 in PoDoFo::PdfParser::ReadObjects
(this=0x617000000080) at /home/name/podofo-0.9.5/src/base/PdfParser.cpp:955
#5 0x000000000062e26f in PoDoFo::PdfParser::ParseFile
(this=0x617000000080, rDevice=..., bLoadOnDemand=true)
at /home/name/podofo-0.9.5/src/base/PdfParser.cpp:221
#6 0x000000000062ce49 in PoDoFo::PdfParser::ParseFile
(this=0x617000000080, pszFilename=0x8c9ec0 <.str> "tempinput.pdf",
bLoadOnDemand=true) at /home/name/podofo-0.9.5/src/
base/PdfParser.cpp:164
#7 0x00000000005cdc65 in PoDoFo::PdfMemDocument::Load
(this=0x7fffffffbfa0, pszFilename=0x8c9ec0 <.str> "tempinput.pdf",
bForUpdate=false) at /home/name/podofo-0.9.5/src/
doc/PdfMemDocument.cpp:256
#8 0x00000000005cd682 in PoDoFo::PdfMemDocument::PdfMemDocument
(this=0x7fffffffbfa0, pszFilename=0x8c9ec0 <.str> "tempinput.pdf",
bForUpdate=false) at /home/name/podofo-0.9.5/src/
doc/PdfMemDocument.cpp:102
The related code snippet is in /podofo-0.9.5/src/base/PdfParser.cpp:955 ,
in function PoDoFo::PdfParser::ReadObjects().
void PdfParser::ReadObjects()
{
//......
if( pEncrypt->IsReference() )
{
i = pEncrypt->GetReference().ObjectNumber(); // GET i
pObject = new PdfParserObject( m_vecObjects, m_device,
m_buffer, m_offsets[i].lOffset );
if( !pObject )
PODOFO_RAISE_ERROR( ePdfError_OutOfMemory );
pObject->SetLoadOnDemand( false ); // Never load this on
demand, as we will use it immediately
try {
pObject->ParseFile( NULL ); // The encryption dictionary is
not encrypted :)
// Never add the encryption dictionary to m_vecObjects
// we create a new one, if we need it for writing
// m_vecObjects->push_back( pObject );
m_offsets[i].bParsed = false;
m_pEncrypt = PdfEncrypt::CreatePdfEncrypt( pObject );
delete pObject;
} catch( PdfError & e ) {
std::ostringstream oss;
oss << "Error while loading object " <<
pObject->Reference().ObjectNumber() << " "
<< pObject->Reference().GenerationNumber() << std::endl;
delete pObject;
e.AddToCallstack( __FILE__, __LINE__, oss.str().c_str() );
throw e;
}
}
//......
}
when pEncrypt->IsReference() returns true. The program will get into the
above branch, getting objectNumber from pEncrypt pointer, and using the i
as the index of m_offsets without checking its boundary.
if i is larger than m_offsets.size(),there would be a heap based overflow
issue. both oob read and oob write.
When I added some debug logging code into the source code, I monitored that
in my case, i get 157, bug size is just 156:
@debug i=157
@debug m_offsets.size()=156
to fix the problem, we just have to check the value between i and
m_offsets.size().
Best Regards,
Xiang Xiaobo of VARAS@IIE
------------------------------------------------------------------------------
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