Heap buffer overflow in XRef::getEntry due to integer overflow
Hey guys,
I recently found the following heap overflow in the pdftocairo:
/home/build/utils/pdftocairo -png issue7769.pdf_mutateds15AWHBEDIM0FJJSDG2HJSPL3612DRE
=================================================================
==42259==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x62e000000394 at pc 0x7fb786812fcc bp 0x7fff4da3fa20 sp 0x7fff4da3fa10
READ of size 4 at 0x62e000000394 thread T0
#0 0x7fb786812fcb in XRef::getEntry(int, bool) /home/poppler/poppler/XRef.cc:1553
#1 0x7fb7866b777e in Parser::makeStream(Object&&, unsigned char*, CryptAlgorithm, int, int, int, int, bool) /home/poppler/poppler/Parser.cc:204
#2 0x7fb7866bb47d in Parser::getObj(bool, unsigned char*, CryptAlgorithm, int, int, int, int, bool) /home/poppler/poppler/Parser.cc:134
#3 0x7fb78660dd74 in Hints::readTables(BaseStream*, Linearization*, XRef*, SecurityHandler*) /home/poppler/poppler/Hints.cc:211
#4 0x7fb7866c1956 in PDFDoc::checkLinearization() /home/poppler/poppler/PDFDoc.cc:702
#5 0x7fb7866ccce7 in PDFDoc::getPage(int) /home/poppler/poppler/PDFDoc.cc:2110
#6 0x40ff85 in PDFDoc::getPageMediaWidth(int) /home/poppler/poppler/PDFDoc.h:168
#7 0x40ff85 in main /home/poppler/utils/pdftocairo.cc:1215
#8 0x7fb7854ab82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
#9 0x413bb8 in _start (/home/build/utils/pdftocairo+0x413bb8)
0x62e000000394 is located 108 bytes to the left of 40960-byte region [0x62e000000400,0x62e00000a400)
allocated by thread T0 here:
#0 0x7fb7874fa602 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x98602)
#1 0x7fb7868038a6 in grealloc(void*, unsigned long, bool) /home/poppler/goo/gmem.h:73
#2 0x7fb7868038a6 in greallocn(void*, int, int, bool) /home/poppler/goo/gmem.h:160
#3 0x7fb7868038a6 in greallocn_checkoverflow(void*, int, int) /home/poppler/goo/gmem.h:164
#4 0x7fb7868038a6 in XRef::reserve(int) /home/poppler/poppler/XRef.cc:400
SUMMARY: AddressSanitizer: heap-buffer-overflow /home/poppler/poppler/XRef.cc:1553 XRef::getEntry(int, bool)
Shadow bytes around the buggy address:
0x0c5c7fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c5c7fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c5c7fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c5c7fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c5c7fff8060: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0c5c7fff8070: fa fa[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c5c7fff8080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c5c7fff8090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c5c7fff80a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c5c7fff80b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c5c7fff80c0: 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
==42259==ABORTING
Looks like, if variable i
is negative it causes entries[i].type == xrefEntryNone
be executed. You can find a reproducer in the attachment.