Invalid Backgrounds causing SIGABRTs in `GfxShading::init`
Issue
Poppler SIGABRTs with the message Internal Error (0): Call to Object where the object was type 10, not the expected type 1, 14 or 2
(and also with objects of type 11 as well, depending on input file) for certain files.
I've tested the following versions, and the crash occurs on all of them:
- 21.04.0, built from source. What I'm fuzzing against.
- 20.09.0, from the ubuntu 20.10 package repositories.
- 0.62.0
Backtrace
[#0] 0x7ffff78a88cb → __GI_raise(sig=0x6)
[#1] 0x7ffff788d864 → __GI_abort()
[#2] 0x7ffff7dca019 → GfxShading::init(GfxResources*, Dict*, OutputDev*, GfxState*)()
[#3] 0x7ffff7dcaf6f → GfxAxialShading::parse(GfxResources*, Dict*, OutputDev*, GfxState*)()
[#4] 0x7ffff7dcfc39 → GfxShading::parse(GfxResources*, Object*, OutputDev*, GfxState*)()
[#5] 0x7ffff7dcfd35 → GfxShadingPattern::parse(GfxResources*, Object*, OutputDev*, GfxState*, int)()
[#6] 0x7ffff7dd00ee → GfxPattern::parse(GfxResources*, Object*, OutputDev*, GfxState*, int)()
[#7] 0x7ffff7d92450 → GfxResources::lookupPattern(char const*, OutputDev*, GfxState*)()
[#8] 0x7ffff7d936c6 → Gfx::opSetFillColorN(Object*, int)()
[#9] 0x7ffff7d9d9a7 → Gfx::go(bool)()
Testcases
- out.pdf - afl-tmin minimized file. Not strictly a valid PDF, but does trigger the bug with pdftotext, evince, etc.
- smallest.pdf - smallest instance of this bug to come from my fuzzer.
Triaging
(Line numbers are from 21.04.0's source release)
The SIGABRT is triggered by the macro OBJECT_3TYPES_CHECK
in Object.h
, which is only used by Object::getNum()
.
In GfxShading::init
, we see it gets called on line 3529:
obj1 = dict->lookup("Background");
if (obj1.isArray()) {
if (obj1.arrayGetLength() == colorSpace->getNComps()) {
hasBackground = true;
for (i = 0; i < colorSpace->getNComps(); ++i) {
Object obj2 = obj1.arrayGet(i);
> background.c[i] = dblToCol(obj2.getNum());
}
} else {
error(errSyntaxWarning, -1, "Bad Background in shading dictionary");
}
}
So it seems the code is missing a check to see if obj2
is number before we get to this point, causing the crash.
Patch
I'm not an expert on the codebase, so please do double check this.
Seems that every other instance where getNum()
is used in GfxState.cc
, it is preceded by a call to isNum()
. So a potential patch I wrote is:
diff --git a/GfxState.cc-old b/GfxState.cc
index 05ce3a8..b43818e 100644
--- a/GfxState.cc-old
+++ b/GfxState.cc
@@ -3526,7 +3526,12 @@ bool GfxShading::init(GfxResources *res, Dict *dict, OutputDev *out, GfxState *s
hasBackground = true;
for (i = 0; i < colorSpace->getNComps(); ++i) {
Object obj2 = obj1.arrayGet(i);
- background.c[i] = dblToCol(obj2.getNum());
+ if (obj2.isNum()) {
+ background.c[i] = dblToCol(obj2.getNum());
+ } else {
+ error(errSyntaxWarning, -1, "Bad Background in shading dictionary");
+ break;
+ }
}
} else {
error(errSyntaxWarning, -1, "Bad Background in shading dictionary");
Does resolve the issue as there are no longer any crashes when I apply the patch. However, not the cleanest fix, errors/warnings probably aren't up to the standard, etc.