Commit 5d0210a5142db059a4b7f9f69ddfe6ea06de096f
1 parent
bf615b8c
Refactor `QPDFAcroFormDocumentHelper::traverseField`: add validation for `/Paren…
…t` consistency to handle invalid entries, and improve loop detection logic.
Showing
5 changed files
with
16 additions
and
4 deletions
fuzz/CMakeLists.txt
fuzz/qpdf_extra/6322553212960768.fuzz
0 → 100644
No preview for this file type
fuzz/qtest/fuzz.test
| ... | ... | @@ -11,7 +11,7 @@ my $td = new TestDriver('fuzz'); |
| 11 | 11 | |
| 12 | 12 | my $qpdf_corpus = $ENV{'QPDF_FUZZ_CORPUS'} || die "must set QPDF_FUZZ_CORPUS"; |
| 13 | 13 | |
| 14 | -my $n_qpdf_files = 103; # increment when adding new files | |
| 14 | +my $n_qpdf_files = 104; # increment when adding new files | |
| 15 | 15 | |
| 16 | 16 | my @fuzzers = ( |
| 17 | 17 | ['ascii85' => 1], | ... | ... |
include/qpdf/QPDFAcroFormDocumentHelper.hh
| ... | ... | @@ -226,7 +226,7 @@ class QPDFAcroFormDocumentHelper: public QPDFDocumentHelper |
| 226 | 226 | |
| 227 | 227 | private: |
| 228 | 228 | void analyze(); |
| 229 | - void traverseField(QPDFObjectHandle const& field, QPDFObjectHandle const& parent, int depth); | |
| 229 | + void traverseField(QPDFObjectHandle field, QPDFObjectHandle const& parent, int depth); | |
| 230 | 230 | QPDFObjectHandle getOrCreateAcroForm(); |
| 231 | 231 | void adjustInheritedFields( |
| 232 | 232 | QPDFObjectHandle obj, | ... | ... |
libqpdf/QPDFAcroFormDocumentHelper.cc
| ... | ... | @@ -315,7 +315,7 @@ QPDFAcroFormDocumentHelper::analyze() |
| 315 | 315 | |
| 316 | 316 | void |
| 317 | 317 | QPDFAcroFormDocumentHelper::traverseField( |
| 318 | - QPDFObjectHandle const& field, QPDFObjectHandle const& parent, int depth) | |
| 318 | + QPDFObjectHandle field, QPDFObjectHandle const& parent, int depth) | |
| 319 | 319 | { |
| 320 | 320 | if (depth > 100) { |
| 321 | 321 | // Arbitrarily cut off recursion at a fixed depth to avoid specially crafted files that |
| ... | ... | @@ -360,7 +360,18 @@ QPDFAcroFormDocumentHelper::traverseField( |
| 360 | 360 | m->annotation_to_field[og] = QPDFFormFieldObjectHelper(our_field); |
| 361 | 361 | } |
| 362 | 362 | |
| 363 | - if (is_field && (field.hasKey("/T"))) { | |
| 363 | + if (is_field && depth != 0 && field["/Parent"] != parent) { | |
| 364 | + for (auto const& kid: Array(field["/Parent"]["/Kids"])) { | |
| 365 | + if (kid == parent) { | |
| 366 | + field.warn("loop detected while traversing /AcroForm"); | |
| 367 | + return; | |
| 368 | + } | |
| 369 | + } | |
| 370 | + field.warn("encountered invalid /Parent entry while traversing /AcroForm; correcting"); | |
| 371 | + field.replaceKey("/Parent", parent); | |
| 372 | + } | |
| 373 | + | |
| 374 | + if (is_field && field.hasKey("/T")) { | |
| 364 | 375 | QPDFFormFieldObjectHelper foh(field); |
| 365 | 376 | std::string name = foh.getFullyQualifiedName(); |
| 366 | 377 | auto old = m->field_to.find(og); | ... | ... |