Headline
CVE-2019-13283: read___heap-buffer-overflow in FoFiType1::parse calls strncpy
In Xpdf 4.01.01, a heap-based buffer over-read could be triggered in strncpy from FoFiType1::parse in fofi/FoFiType1.cc because it does not ensure the source string has a valid length before making a fixed-length copy. It can, for example, be triggered by sending a crafted PDF document to the pdftotext tool. It allows an attacker to use a crafted pdf file to cause Denial of Service or an information leak, or possibly have unspecified other impact.
Hi,
I’m Mike Zhang of Pangu Lab, I found a heap buffer overflow bug in xpdf code.
4.01.01 xpdf under Ubuntu 16.04.3 LTS
strncpy in FoFiType1::parse fofi/FoFiType1.cc:207 has not ensure the source string valid length before use a fixed copy length, causes an read___heap-buffer-overflow problem.
log from Ubuntu:
Code: Select all
==12947==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x621000009d00 at pc 0x7f29e1f08806 bp 0x7ffed0886130 sp 0x7ffed08858d8
READ of size 82 at 0x621000009d00 thread T0
#0 0x7f29e1f08805 in strncpy (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x94805)
#1 0xa03d0b in strncpy /usr/include/x86_64-linux-gnu/bits/string3.h:126
#2 0xa03d0b in FoFiType1::parse() /home/panguandroid/Documents/git/xpdf/xpdf-src/fofi/FoFiType1.cc:207
#3 0xa062da in FoFiType1::getName() /home/panguandroid/Documents/git/xpdf/xpdf-src/fofi/FoFiType1.cc:71
#4 0x64b990 in Gfx8BitFont::Gfx8BitFont(XRef*, char*, Ref, GString*, GfxFontType, Ref, Dict*) /home/panguandroid/Documents/git/xpdf/xpdf-src/xpdf/GfxFont.cc:1051
#5 0x658eb2 in GfxFont::makeFont(XRef*, char*, Ref, Dict*) /home/panguandroid/Documents/git/xpdf/xpdf-src/xpdf/GfxFont.cc:191
#6 0x65ed1c in GfxFontDict::GfxFontDict(XRef*, Ref*, Dict*) /home/panguandroid/Documents/git/xpdf/xpdf-src/xpdf/GfxFont.cc:2087
#7 0x5c950c in GfxResources::GfxResources(XRef*, Dict*, GfxResources*) /home/panguandroid/Documents/git/xpdf/xpdf-src/xpdf/Gfx.cc:292
#8 0x5cb765 in Gfx::Gfx(PDFDoc*, OutputDev*, int, Dict*, double, double, PDFRectangle*, PDFRectangle*, int, int (*)(void*), void*) /home/panguandroid/Documents/git/xpdf/xpdf-src/xpdf/Gfx.cc:509
#9 0x83ca1c in Page::displaySlice(OutputDev*, double, double, int, int, int, int, int, int, int, int, int (*)(void*), void*) /home/panguandroid/Documents/git/xpdf/xpdf-src/xpdf/Page.cc:369
#10 0x83ca1c in Page::display(OutputDev*, double, double, int, int, int, int, int (*)(void*), void*) /home/panguandroid/Documents/git/xpdf/xpdf-src/xpdf/Page.cc:321
#11 0x85ce9d in PDFDoc::displayPage(OutputDev*, int, double, double, int, int, int, int, int (*)(void*), void*) /home/panguandroid/Documents/git/xpdf/xpdf-src/xpdf/PDFDoc.cc:423
#12 0x85ce9d in PDFDoc::displayPages(OutputDev*, int, int, double, double, int, int, int, int, int (*)(void*), void*) /home/panguandroid/Documents/git/xpdf/xpdf-src/xpdf/PDFDoc.cc:436
#13 0x43e2d2 in main /home/panguandroid/Documents/git/xpdf/xpdf-src/xpdf/pdftotext.cc:253
#14 0x7f29e121d82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
#15 0x440068 in _start (/home/panguandroid/Documents/git/xpdf/afl-install/bin/pdftotext+0x440068)
0x621000009d00 is located 0 bytes to the right of 4096-byte region [0x621000008d00,0x621000009d00)
allocated by thread T0 here:
#0 0x7f29e1f52b50 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xdeb50)
#1 0x9a4c9f in grealloc /home/panguandroid/Documents/git/xpdf/xpdf-src/goo/gmem.cc:193
#2 0x642386 in GfxFont::readEmbFontFile(XRef*, int*) /home/panguandroid/Documents/git/xpdf/xpdf-src/xpdf/GfxFont.cc:849
#3 0x648b12 in Gfx8BitFont::Gfx8BitFont(XRef*, char*, Ref, GString*, GfxFontType, Ref, Dict*) /home/panguandroid/Documents/git/xpdf/xpdf-src/xpdf/GfxFont.cc:1049
#4 0x658eb2 in GfxFont::makeFont(XRef*, char*, Ref, Dict*) /home/panguandroid/Documents/git/xpdf/xpdf-src/xpdf/GfxFont.cc:191
#5 0x65ed1c in GfxFontDict::GfxFontDict(XRef*, Ref*, Dict*) /home/panguandroid/Documents/git/xpdf/xpdf-src/xpdf/GfxFont.cc:2087
#6 0x5c950c in GfxResources::GfxResources(XRef*, Dict*, GfxResources*) /home/panguandroid/Documents/git/xpdf/xpdf-src/xpdf/Gfx.cc:292
#7 0x5cb765 in Gfx::Gfx(PDFDoc*, OutputDev*, int, Dict*, double, double, PDFRectangle*, PDFRectangle*, int, int (*)(void*), void*) /home/panguandroid/Documents/git/xpdf/xpdf-src/xpdf/Gfx.cc:509
#8 0x83ca1c in Page::displaySlice(OutputDev*, double, double, int, int, int, int, int, int, int, int, int (*)(void*), void*) /home/panguandroid/Documents/git/xpdf/xpdf-src/xpdf/Page.cc:369
#9 0x83ca1c in Page::display(OutputDev*, double, double, int, int, int, int, int (*)(void*), void*) /home/panguandroid/Documents/git/xpdf/xpdf-src/xpdf/Page.cc:321
#10 0x85ce9d in PDFDoc::displayPage(OutputDev*, int, double, double, int, int, int, int, int (*)(void*), void*) /home/panguandroid/Documents/git/xpdf/xpdf-src/xpdf/PDFDoc.cc:423
#11 0x85ce9d in PDFDoc::displayPages(OutputDev*, int, int, double, double, int, int, int, int, int (*)(void*), void*) /home/panguandroid/Documents/git/xpdf/xpdf-src/xpdf/PDFDoc.cc:436
#12 0x43e2d2 in main /home/panguandroid/Documents/git/xpdf/xpdf-src/xpdf/pdftotext.cc:253
#13 0x7f29e121d82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
SUMMARY: AddressSanitizer: heap-buffer-overflow (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x94805) in strncpy
Shadow bytes around the buggy address:
0x0c427fff9350: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c427fff9360: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c427fff9370: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c427fff9380: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c427fff9390: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c427fff93a0:[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c427fff93b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c427fff93c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c427fff93d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c427fff93e0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c427fff93f0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
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
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
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
Left alloca redzone: ca
Right alloca redzone: cb
==12947==ABORTING
Code: Select all
void FoFiType1::parse() {
char *line, *line1, *p, *p2;
char buf[256];
char c;
int n, code, base, i, j;
GBool gotMatrix, startsWithDup, endsWithDup;
gotMatrix = gFalse;
for (i = 1, line = (char *)file;
i <= 100 && line && (!name || !encoding || !gotMatrix);
++i) {
// get font name
if (!name && !strncmp(line, "/FontName", 9)) {
strncpy(buf, line, 255); // L207: read___heap-buffer-overflow
//...
line = getNextLine(line);
“line” variable is reference member “file” memory,
When set breakpoints on all the “file” member assignment code, the following line used:
Code: Select all
FoFiBase::FoFiBase(char *fileA, int lenA, GBool freeFileDataA) {
fileData = file = (Guchar *)fileA; // L26
len = lenA;
freeFileData = freeFileDataA;
}
The constructor called from
Code: Select all
Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
GfxFontType typeA, Ref embFontIDA, Dict *fontDict):
GfxFont(tagA, idA, nameA, typeA, embFontIDA)
{
//...
char *buf;
int len;
//...
buf = NULL;
if (type == fontType1 && embFontID.num >= 0) {
if ((buf = readEmbFontFile(xref, &len))) { // set buf and len
if ((ffT1 = FoFiType1::make(buf, len))) { // L1050
This code call into “FoFiBase::FoFiBase” method, “buf” is “fileA” and “len” is "lenA".
Code: Select all
char *GfxFont::readEmbFontFile(XRef *xref, int *len) {
char *buf;
Object obj1, obj2;
Stream *str;
int size, n;
//...
do {
//...
buf = (char *)grealloc(buf, size + 4096); // L849: expand buf memory 4096 bytes everytime
n = str->getBlock(buf + size, 4096);
size += n;
} while (n == 4096); // read into buf until a non 4096 continue block with EOF byte in it
*len = size;
//...
return buf;
}
So, according to the above analysis, “len” is the “buf” memory length.
And with the dynamic debug analysis help, we found “line+255” is out of “file” memory block.
Related news
Xpdf prior to 4.04 lacked an integer overflow check in JPXStream.cc.