Commit f60dbb5f2866b297db475f597833e44bf2c5a281

Authored by m-holger
Committed by GitHub
2 parents 4d2a0fe2 d68f45e0

Merge pull request #1476 from m-holger/fuzz

Enhance error handling for unexpected tokens during sanity checks
libqpdf/QPDFParser.cc
@@ -324,6 +324,12 @@ QPDFParser::parseRemainder(bool content_stream) @@ -324,6 +324,12 @@ QPDFParser::parseRemainder(bool content_stream)
324 add(std::move(object)); 324 add(std::move(object));
325 } else { 325 } else {
326 QTC::TC("qpdf", "QPDFParser bad array close in parseRemainder"); 326 QTC::TC("qpdf", "QPDFParser bad array close in parseRemainder");
  327 + if (sanity_checks) {
  328 + // During sanity checks, assume nesting of containers is corrupt and object is
  329 + // unusable.
  330 + warn("unexpected array close token; giving up on reading object");
  331 + return {QPDFObject::create<QPDF_Null>()};
  332 + }
327 warn("treating unexpected array close token as null"); 333 warn("treating unexpected array close token as null");
328 if (tooManyBadTokens()) { 334 if (tooManyBadTokens()) {
329 return {QPDFObject::create<QPDF_Null>()}; 335 return {QPDFObject::create<QPDF_Null>()};
@@ -374,6 +380,12 @@ QPDFParser::parseRemainder(bool content_stream) @@ -374,6 +380,12 @@ QPDFParser::parseRemainder(bool content_stream)
374 add(std::move(object)); 380 add(std::move(object));
375 } else { 381 } else {
376 QTC::TC("qpdf", "QPDFParser bad dictionary close in parseRemainder"); 382 QTC::TC("qpdf", "QPDFParser bad dictionary close in parseRemainder");
  383 + if (sanity_checks) {
  384 + // During sanity checks, assume nesting of containers is corrupt and object is
  385 + // unusable.
  386 + warn("unexpected dictionary close token; giving up on reading object");
  387 + return {QPDFObject::create<QPDF_Null>()};
  388 + }
377 warn("unexpected dictionary close token"); 389 warn("unexpected dictionary close token");
378 if (tooManyBadTokens()) { 390 if (tooManyBadTokens()) {
379 return {QPDFObject::create<QPDF_Null>()}; 391 return {QPDFObject::create<QPDF_Null>()};
@@ -436,6 +448,15 @@ QPDFParser::parseRemainder(bool content_stream) @@ -436,6 +448,15 @@ QPDFParser::parseRemainder(bool content_stream)
436 if (content_stream) { 448 if (content_stream) {
437 addScalar<QPDF_Operator>(tokenizer.getValue()); 449 addScalar<QPDF_Operator>(tokenizer.getValue());
438 } else { 450 } else {
  451 + if (sanity_checks &&
  452 + (tokenizer.getValue() == "endobj" || tokenizer.getValue() == "endstream")) {
  453 + // During sanity checks, assume an unexpected endobj or endstream indicates that
  454 + // we are parsing past the end of the object.
  455 + warn(
  456 + "unexpected 'endobj' or 'endstream' while reading object; giving up on "
  457 + "reading object");
  458 + return {QPDFObject::create<QPDF_Null>()};
  459 + }
439 QTC::TC("qpdf", "QPDFParser treat word as string in parseRemainder"); 460 QTC::TC("qpdf", "QPDFParser treat word as string in parseRemainder");
440 warn("unknown token while reading object; treating as string"); 461 warn("unknown token while reading object; treating as string");
441 if (tooManyBadTokens()) { 462 if (tooManyBadTokens()) {
qpdf/qtest/qpdf/bad16-recover.out
@@ -6,11 +6,7 @@ WARNING: bad16.pdf (trailer, offset 779): unexpected EOF @@ -6,11 +6,7 @@ WARNING: bad16.pdf (trailer, offset 779): unexpected EOF
6 WARNING: bad16.pdf: file is damaged 6 WARNING: bad16.pdf: file is damaged
7 WARNING: bad16.pdf (offset 712): expected trailer dictionary 7 WARNING: bad16.pdf (offset 712): expected trailer dictionary
8 WARNING: bad16.pdf: Attempting to reconstruct cross-reference table 8 WARNING: bad16.pdf: Attempting to reconstruct cross-reference table
9 -WARNING: bad16.pdf (trailer, offset 753): unexpected dictionary close token  
10 -WARNING: bad16.pdf (trailer, offset 756): unexpected dictionary close token  
11 -WARNING: bad16.pdf (trailer, offset 759): unknown token while reading object; treating as string  
12 -WARNING: bad16.pdf (trailer, offset 779): parse error while reading object  
13 -WARNING: bad16.pdf (trailer, offset 779): unexpected EOF 9 +WARNING: bad16.pdf (trailer, offset 753): unexpected dictionary close token; giving up on reading object
14 WARNING: bad16.pdf: unable to find trailer dictionary while recovering damaged file 10 WARNING: bad16.pdf: unable to find trailer dictionary while recovering damaged file
15 /QTest is implicit 11 /QTest is implicit
16 /QTest is direct and has type null (2) 12 /QTest is direct and has type null (2)
qpdf/qtest/qpdf/issue-335a.out
@@ -144,28 +144,10 @@ WARNING: issue-335a.pdf (trailer, offset 21452): invalid character (-) in hexstr @@ -144,28 +144,10 @@ WARNING: issue-335a.pdf (trailer, offset 21452): invalid character (-) in hexstr
144 WARNING: issue-335a.pdf (trailer, offset 21436): stream keyword found in trailer 144 WARNING: issue-335a.pdf (trailer, offset 21436): stream keyword found in trailer
145 WARNING: issue-335a.pdf (trailer, offset 21407): recovered trailer has no /Root entry 145 WARNING: issue-335a.pdf (trailer, offset 21407): recovered trailer has no /Root entry
146 WARNING: issue-335a.pdf (trailer, offset 21287): unknown token while reading object; treating as string 146 WARNING: issue-335a.pdf (trailer, offset 21287): unknown token while reading object; treating as string
147 -WARNING: issue-335a.pdf (trailer, offset 21389): unexpected dictionary close token  
148 -WARNING: issue-335a.pdf (trailer, offset 21392): unknown token while reading object; treating as string  
149 -WARNING: issue-335a.pdf (trailer, offset 21400): unknown token while reading object; treating as string  
150 -WARNING: issue-335a.pdf (trailer, offset 21430): unknown token while reading object; treating as string  
151 -WARNING: issue-335a.pdf (trailer, offset 21438): unknown token while reading object; treating as string  
152 -WARNING: issue-335a.pdf (trailer, offset 21441): unknown token while reading object; treating as string  
153 -WARNING: issue-335a.pdf (trailer, offset 21444): unknown token while reading object; treating as string  
154 -WARNING: issue-335a.pdf (trailer, offset 21452): invalid character (-) in hexstring  
155 -WARNING: issue-335a.pdf (trailer, offset 21819): unknown token while reading object; treating as string  
156 -WARNING: issue-335a.pdf (trailer, offset 21819): too many errors; giving up on reading object 147 +WARNING: issue-335a.pdf (trailer, offset 21389): unexpected dictionary close token; giving up on reading object
157 WARNING: issue-335a.pdf (trailer, offset 21277): unknown token while reading object; treating as string 148 WARNING: issue-335a.pdf (trailer, offset 21277): unknown token while reading object; treating as string
158 WARNING: issue-335a.pdf (trailer, offset 21287): unknown token while reading object; treating as string 149 WARNING: issue-335a.pdf (trailer, offset 21287): unknown token while reading object; treating as string
159 -WARNING: issue-335a.pdf (trailer, offset 21389): unexpected dictionary close token  
160 -WARNING: issue-335a.pdf (trailer, offset 21392): unknown token while reading object; treating as string  
161 -WARNING: issue-335a.pdf (trailer, offset 21400): unknown token while reading object; treating as string  
162 -WARNING: issue-335a.pdf (trailer, offset 21430): unknown token while reading object; treating as string  
163 -WARNING: issue-335a.pdf (trailer, offset 21438): unknown token while reading object; treating as string  
164 -WARNING: issue-335a.pdf (trailer, offset 21441): unknown token while reading object; treating as string  
165 -WARNING: issue-335a.pdf (trailer, offset 21444): unknown token while reading object; treating as string  
166 -WARNING: issue-335a.pdf (trailer, offset 21452): invalid character (-) in hexstring  
167 -WARNING: issue-335a.pdf (trailer, offset 21819): unknown token while reading object; treating as string  
168 -WARNING: issue-335a.pdf (trailer, offset 21819): too many errors; giving up on reading object 150 +WARNING: issue-335a.pdf (trailer, offset 21389): unexpected dictionary close token; giving up on reading object
169 WARNING: issue-335a.pdf (trailer, offset 21228): treating unexpected brace token as null 151 WARNING: issue-335a.pdf (trailer, offset 21228): treating unexpected brace token as null
170 WARNING: issue-335a.pdf (trailer, offset 21229): unexpected ) 152 WARNING: issue-335a.pdf (trailer, offset 21229): unexpected )
171 WARNING: issue-335a.pdf (trailer, offset 21230): unknown token while reading object; treating as string 153 WARNING: issue-335a.pdf (trailer, offset 21230): unknown token while reading object; treating as string
@@ -1003,4 +985,20 @@ WARNING: issue-335a.pdf (trailer, offset 499): unexpected ) @@ -1003,4 +985,20 @@ WARNING: issue-335a.pdf (trailer, offset 499): unexpected )
1003 WARNING: issue-335a.pdf (trailer, offset 563): unexpected ) 985 WARNING: issue-335a.pdf (trailer, offset 563): unexpected )
1004 WARNING: issue-335a.pdf (trailer, offset 596): unexpected ) 986 WARNING: issue-335a.pdf (trailer, offset 596): unexpected )
1005 WARNING: issue-335a.pdf (trailer, offset 596): too many errors; giving up on reading object 987 WARNING: issue-335a.pdf (trailer, offset 596): too many errors; giving up on reading object
  988 +WARNING: issue-335a.pdf (trailer, offset 461): invalid character (<) in hexstring
  989 +WARNING: issue-335a.pdf (trailer, offset 447): unknown token while reading object; treating as string
  990 +WARNING: issue-335a.pdf (trailer, offset 450): unknown token while reading object; treating as string
  991 +WARNING: issue-335a.pdf (trailer, offset 461): invalid character (<) in hexstring
  992 +WARNING: issue-335a.pdf (trailer, offset 464): invalid character (¨) in hexstring
  993 +WARNING: issue-335a.pdf (trailer, offset 499): unexpected )
  994 +WARNING: issue-335a.pdf (trailer, offset 563): unexpected )
  995 +WARNING: issue-335a.pdf (trailer, offset 563): too many errors; giving up on reading object
  996 +WARNING: issue-335a.pdf (trailer, offset 431): treating unexpected brace token as null
  997 +WARNING: issue-335a.pdf (trailer, offset 432): unexpected )
  998 +WARNING: issue-335a.pdf (trailer, offset 433): unexpected )
  999 +WARNING: issue-335a.pdf (trailer, offset 563): unexpected )
  1000 +WARNING: issue-335a.pdf (trailer, offset 596): unexpected )
  1001 +WARNING: issue-335a.pdf (trailer, offset 597): name with stray # will not work with PDF >= 1.2
  1002 +WARNING: issue-335a.pdf (trailer, offset 600): unexpected )
  1003 +WARNING: issue-335a.pdf (trailer, offset 600): too many errors; giving up on reading object
1006 qpdf: issue-335a.pdf: too many errors while reconstructing cross-reference table 1004 qpdf: issue-335a.pdf: too many errors while reconstructing cross-reference table
qpdf/qtest/qpdf/issue-99.out
@@ -11,28 +11,14 @@ WARNING: issue-99.pdf (object 1 0, offset 855): too many errors; giving up on re @@ -11,28 +11,14 @@ WARNING: issue-99.pdf (object 1 0, offset 855): too many errors; giving up on re
11 WARNING: issue-99.pdf (object 1 0, offset 858): expected endobj 11 WARNING: issue-99.pdf (object 1 0, offset 858): expected endobj
12 WARNING: issue-99.pdf (object 2 0, offset 64): expected endobj 12 WARNING: issue-99.pdf (object 2 0, offset 64): expected endobj
13 WARNING: issue-99.pdf (object 5 0, offset 2452): unknown token while reading object; treating as string 13 WARNING: issue-99.pdf (object 5 0, offset 2452): unknown token while reading object; treating as string
14 -WARNING: issue-99.pdf (object 6 0, offset 2506): treating unexpected array close token as null  
15 -WARNING: issue-99.pdf (object 6 0, offset 2507): unknown token while reading object; treating as string  
16 -WARNING: issue-99.pdf (object 6 0, offset 2551): unknown token while reading object; treating as string  
17 -WARNING: issue-99.pdf (object 6 0, offset 2475): dictionary has duplicated key /Type; last occurrence overrides earlier ones  
18 -WARNING: issue-99.pdf (object 6 0, offset 2475): dictionary has duplicated key /Parent; last occurrence overrides earlier ones  
19 -WARNING: issue-99.pdf (object 6 0, offset 2475): dictionary has duplicated key /Group; last occurrence overrides earlier ones  
20 -WARNING: issue-99.pdf (object 6 0, offset 2475): expected dictionary key but found non-name object; inserting key /QPDFFake1  
21 -WARNING: issue-99.pdf (object 6 0, offset 2475): expected dictionary key but found non-name object; inserting key /QPDFFake2  
22 -WARNING: issue-99.pdf (object 6 0, offset 2475): expected dictionary key but found non-name object; inserting key /QPDFFake3 14 +WARNING: issue-99.pdf (object 6 0, offset 2506): unexpected array close token; giving up on reading object
  15 +WARNING: issue-99.pdf (object 6 0, offset 2507): expected endobj
23 WARNING: issue-99.pdf (object 10 0, offset 3708): expected dictionary key but found non-name object; inserting key /QPDFFake1 16 WARNING: issue-99.pdf (object 10 0, offset 3708): expected dictionary key but found non-name object; inserting key /QPDFFake1
24 WARNING: issue-99.pdf (object 11 0, offset 4485): unknown token while reading object; treating as string 17 WARNING: issue-99.pdf (object 11 0, offset 4485): unknown token while reading object; treating as string
25 -WARNING: issue-99.pdf (object 11 0, offset 4497): treating unexpected array close token as null  
26 -WARNING: issue-99.pdf (object 11 0, offset 4502): unexpected )  
27 -WARNING: issue-99.pdf (object 11 0, offset 4504): unexpected >  
28 -WARNING: issue-99.pdf (object 11 0, offset 4508): unknown token while reading object; treating as string  
29 -WARNING: issue-99.pdf (object 11 0, offset 4520): unknown token while reading object; treating as string  
30 -WARNING: issue-99.pdf (object 11 0, offset 4520): too many errors; giving up on reading object  
31 -WARNING: issue-99.pdf (object 11 0, offset 4524): expected endobj 18 +WARNING: issue-99.pdf (object 11 0, offset 4497): unexpected array close token; giving up on reading object
  19 +WARNING: issue-99.pdf (object 11 0, offset 4499): expected endobj
32 WARNING: issue-99.pdf: unable to find trailer dictionary while recovering damaged file 20 WARNING: issue-99.pdf: unable to find trailer dictionary while recovering damaged file
33 WARNING: object 1 0: Pages tree includes non-dictionary object; ignoring 21 WARNING: object 1 0: Pages tree includes non-dictionary object; ignoring
34 WARNING: object 1 0: operation for dictionary attempted on object of type null: returning false for a key containment request 22 WARNING: object 1 0: operation for dictionary attempted on object of type null: returning false for a key containment request
35 WARNING: object 1 0: operation for dictionary attempted on object of type null: ignoring key replacement request 23 WARNING: object 1 0: operation for dictionary attempted on object of type null: ignoring key replacement request
36 -WARNING: object 1 0: operation for dictionary attempted on object of type null: returning false for a key containment request  
37 -WARNING: object 1 0: operation for dictionary attempted on object of type null: ignoring key replacement request  
38 qpdf: issue-99.pdf: unable to find any pages while recovering damaged file 24 qpdf: issue-99.pdf: unable to find any pages while recovering damaged file