Hi, I found a segmentation bug which can be reproduced in version 0.9.6 and the latest commit r1974.
The output of sanitizer is as followings.
$ ~/vuln-fuzz/program/podofo-r1974/sanitizer-build/install/bin/podofoimpose ./3-segmentation output native
Source : ./3-segmentation
Target : output
Plan : native
PdfTranslator::PdfTranslator
1
2
<</ID[<D6CF927DCF82444068EB69A914F807><713CE394E60921469FE4DDD670CE068F>]/Root 1 0 R/Size 18>>
ASAN:DEADLYSIGNAL
=================================================================
==81204==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000013 (pc 0x0000005ee07a bp 0x7ffe6d83d580 sp 0x7ffe6d83d540 T0)
==81204==The signal is caused by a READ memory access.
==81204==Hint: address points to the zero page.
#0 0x5ee079 in PoDoFo::PdfVariant::DelayedLoad() const /home/lt/vuln-fuzz/program/podofo-r1974/podofo/base/../../src/base/PdfVariant.h:555:9
#1 0x5edfc8 in PoDoFo::PdfVariant::GetDataType() const /home/lt/vuln-fuzz/program/podofo-r1974/podofo/base/../../src/base/PdfVariant.h:585:5
#2 0x5e7754 in PoDoFo::PdfVariant::IsDictionary() const /home/lt/vuln-fuzz/program/podofo-r1974/podofo/base/../../src/base/PdfVariant.h:197:47
#3 0x5e0955 in PoDoFo::Impose::PdfTranslator::migrateResource(PoDoFo::PdfObject*) /home/lt/vuln-fuzz/program/podofo-r1974/tools/podofoimpose/pdftranslator.cpp:181:14
#4 0x5e11f6 in PoDoFo::Impose::PdfTranslator::migrateResource(PoDoFo::PdfObject*) /home/lt/vuln-fuzz/program/podofo-r1974/tools/podofoimpose/pdftranslator.cpp:215:21
#5 0x5e0bea in PoDoFo::Impose::PdfTranslator::migrateResource(PoDoFo::PdfObject*) /home/lt/vuln-fuzz/program/podofo-r1974/tools/podofoimpose/pdftranslator.cpp:189:51
#6 0x5e0bea in PoDoFo::Impose::PdfTranslator::migrateResource(PoDoFo::PdfObject*) /home/lt/vuln-fuzz/program/podofo-r1974/tools/podofoimpose/pdftranslator.cpp:189:51
#7 0x5e18aa in PoDoFo::Impose::PdfTranslator::getInheritedResources(PoDoFo::PdfPage*) /home/lt/vuln-fuzz/program/podofo-r1974/tools/podofoimpose/pdftranslator.cpp:243:12
#8 0x5e3053 in PoDoFo::Impose::PdfTranslator::setTarget(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) /home/lt/vuln-fuzz/program/podofo-r1974/tools/podofoimpose/pdftranslator.cpp:325:22
#9 0x5de075 in main /home/lt/vuln-fuzz/program/podofo-r1974/tools/podofoimpose/podofoimpose.cpp:108:15
#10 0x7f004c04d82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
#11 0x4e7558 in _start (/home/lt/vuln-fuzz/program/podofo-r1974/sanitizer-build/install/bin/podofoimpose+0x4e7558)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /home/lt/vuln-fuzz/program/podofo-r1974/podofo/base/../../src/base/PdfVariant.h:555:9 in PoDoFo::PdfVariant::DelayedLoad() const
==81204==ABORTING
I tried to debug using gdb to find out what causes this error. The gdb result is as followings.
When calling migrateResource at pdftranslator.cpp:214(PdfObject * o ( migrateResource ( sourceDoc->GetObjects().GetObject ( obj->GetReference() ) ) );), the parameter obj of migrateResource is zero. When migrateResource enters function PdfVariant::DelayedLoad() which is at pdfVariant.h:555, it will using obj to get a value which is located at [obj+13]=[13]. But the address 13 is not capable to read. So the program crashed for segmentation error.
─
gef➤
0x00000000005ee07a 555 if( !m_bDelayedLoadDone)
Python Exception <class 'gdb.error'> There is no member named _M_dataplus.:
[ Legend: Modified register | Code | Heap | Stack | String ]
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ────
$rax : 0x13
$rbx : 0x00007fffffffbe20 → 0x00007fffffffbf40 → 0x000060d0000000d0 → 0x00000000cc6e96b9 → 0x0000000000000000
$rcx : 0x2
$rdx : 0x0000617000000000 → 0x00000000cc6e96b9 → 0x0000000000000000
$rsp : 0x00007fffffffb9c0 → 0x0000000045e0360e
$rbp : 0x00007fffffffba00 → 0x00007fffffffba30 → 0x00007fffffffba50 → 0x00007fffffffc0f0 → 0x00007fffffffc790 → 0x00007fffffffce30 → 0x00007fffffffd4d0 → 0x00007fffffffd6b0
$rsi : 0x00000ffffffff750 → 0x0000000000000000
$rdi : 0x0
$rip : 0x00000000005ee07a → <PoDoFo::PdfVariant::DelayedLoad()+0> test BYTE PTR [rax], 0x1
$r8 : 0xf2000000f2f2f2f2
$r9 : 0xf2f2f200f2f2f2
$r10 : 0xf2f2f200f1f1f1f1
$r11 : 0x000010007fff774c → 0xf2f2f200f1f1f1f1
$r12 : 0x00007fffffffbaa0 → 0x0000607000004578 → 0x0000000000000000
$r13 : 0x00007fffffffbaf0 → 0x00000000006252a0 → <PoDoFo::PdfDictionary::Clear()+0> push rbp
$r14 : 0x00000000008c0ebd → "17 32 8 3 ret 64 48 6 resmap 144 8 5 itres 176 8 7[...]"
$r15 : 0x00007fffffffba80 → 0x0000000000000000
$eflags: [carry PARITY adjust ZERO sign trap INTERRUPT direction overflow resume virtualx86 identification]
$cs: 0x0033 $ss: 0x002b $ds: 0x0000 $es: 0x0000 $fs: 0x0000 $gs: 0x0000
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ────
0x00007fffffffb9c0│+0x0000: 0x0000000045e0360e ← $rsp
0x00007fffffffb9c8│+0x0008: 0x00000000008c0fdf → "1 32 4 7 ref.tmp"
0x00007fffffffb9d0│+0x0010: 0x00000000005eef10 → <PoDoFo::PdfDataType::AssertMutable()+0> push rbp
0x00007fffffffb9d8│+0x0018: 0x00007fffffffbab0 → 0x00007fffffffbad0 → 0x00007fffffffbc40 → 0x00007fffffffbc90 → 0x00007fffffffbcc0 → 0x00007fffffffbd80 → 0x00007fffffffbdc0
0x00007fffffffb9e0│+0x0020: 0x00007fffffffba60 → 0x0000000041b58ab3
0x00007fffffffb9e8│+0x0028: 0x0000000000000013
0x00007fffffffb9f0│+0x0030: 0x0000000000000000
0x00007fffffffb9f8│+0x0038: 0x0000000000000000
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:64 ────
0x5ee06d <PoDoFo::PdfVariant::DelayedLoad()+0> mov rdi, QWORD PTR [rbp-0x18]
0x5ee071 <PoDoFo::PdfVariant::DelayedLoad()+0> call 0x5aa3c0 <__asan::__asan_report_load1(__sanitizer::uptr)>
0x5ee076 <PoDoFo::PdfVariant::DelayedLoad()+0> mov rax, QWORD PTR [rbp-0x18]
→ 0x5ee07a <PoDoFo::PdfVariant::DelayedLoad()+0> test BYTE PTR [rax], 0x1
0x5ee07d <PoDoFo::PdfVariant::DelayedLoad()+0> jne 0x5ee128 <PoDoFo::PdfVariant::DelayedLoad() const+264>
0x5ee083 <PoDoFo::PdfVariant::DelayedLoad()+0> mov rax, QWORD PTR [rbp-0x10]
0x5ee087 <PoDoFo::PdfVariant::DelayedLoad()+0> mov rcx, rax
0x5ee08a <PoDoFo::PdfVariant::DelayedLoad()+0> shr rcx, 0x3
0x5ee08e <PoDoFo::PdfVariant::DelayedLoad()+0> cmp BYTE PTR [rcx+0x7fff8000], 0x0
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── source:/home/lt/vuln-f[...].h+555 ────
550 // Whoops! Delayed loading triggered during delayed loading. Someone probably
551 // used a public method that calls DelayedLoad() from a delayed load.
552 if (m_bDelayedLoadInProgress)
553 PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Recursive DelayedLoad() detected" );
554 #endif
→ 555 if( !m_bDelayedLoadDone)
556 {
557 #if defined(PODOFO_EXTRA_CHECKS)
558 m_bDelayedLoadInProgress = true;
559 #endif
560 const_cast<PdfVariant*>(this)->DelayedLoadImpl();
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "podofoimpose", stopped, reason: SINGLE STEP
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0x5ee07a → PoDoFo::PdfVariant::DelayedLoad(this=0x0)
[#1] 0x5edfc9 → PoDoFo::PdfVariant::GetDataType(this=0x0)
[#2] 0x5e7755 → PoDoFo::PdfVariant::IsDictionary(this=0x0)
[#3] 0x5e0956 → PoDoFo::Impose::PdfTranslator::migrateResource(this=0x617000000080, obj=0x0)
[#4] 0x5e11f7 → PoDoFo::Impose::PdfTranslator::migrateResource(this=0x617000000080, obj=0x606000003bc0)
[#5] 0x5e0beb → PoDoFo::Impose::PdfTranslator::migrateResource(this=0x617000000080, obj=0x606000003b60)
[#6] 0x5e0beb → PoDoFo::Impose::PdfTranslator::migrateResource(this=0x617000000080, obj=0x606000003b00)
[#7] 0x5e18ab → PoDoFo::Impose::PdfTranslator::getInheritedResources(this=0x617000000080, page=0x60d0000001e0)
[#8] 0x5e3054 → PoDoFo::Impose::PdfTranslator::setTarget(this=0x617000000080, target=)
[#9] 0x5de076 → main(argc=0x4, argv=0x7fffffffe528)
Tickets: #1
Tickets: #2
Tickets: #3
Tickets: #4
Tickets: #5
Tickets: #6
Tickets: #7
Tickets: #8
Tickets: #9
I'll implement my fix shortly after I've committed the one for issue #42.
I misunderstood what it takes (it was actually easier), I've actually now tested my fix (attached here, please don't commit it) for this with GCC 4.8 and clang 3.8 on the Debian 8 derivate I still use. I'm going to test it with GCC 7.4 and clang 7.0 soon, I hope tomorrow. (Edit: It was GCC 7.4, not 7.3, because of a package upgrade)
Last edit: Matthew Brincke 2019-05-14
My fix for this is now committed (to svn r1986), leaving this "pending" for verification of its correctness by someone else, particularly Windows users are invited to test, as I don't use it, therefore I can't test on it.
Last edit: Matthew Brincke 2019-05-14
Let's close this, to avoid forever-pending issues.