diff options
author | Jay Berkenbilt <ejb@ql.org> | 2018-08-14 01:26:20 +0200 |
---|---|---|
committer | Jay Berkenbilt <ejb@ql.org> | 2018-08-14 01:26:20 +0200 |
commit | 164cbdde46d7ec6924782a60f346a6a465a79a26 (patch) | |
tree | 719c10db22a05ad0b7c30053eb66298ce2c6cebf | |
parent | 5d9d80beba1caa5828093dd1932fd806df1e644b (diff) | |
download | qpdf-164cbdde46d7ec6924782a60f346a6a465a79a26.tar.zst |
Protect against virus warnings (fixes #216)
Some files in the test suite trigger antivirus warnings. These are
not infected files with malicious intent. They are test files to
ensure that qpdf does not crash when it encounters the files. This
change enables those files to be obfuscated in the source repository
so that checking out qpdf from version control or extracting the
source code doesn't trigger antivirus warnings.
-rw-r--r-- | qpdf/qtest/qpdf.test | 30 | ||||
-rw-r--r-- | qpdf/qtest/qpdf/issue-118.obfuscated | 1 | ||||
-rw-r--r-- | qpdf/qtest/qpdf/issue-118.pdf | bin | 806 -> 0 bytes | |||
-rw-r--r-- | qpdf/qtest/qpdf/issue-51.obfuscated | 1 | ||||
-rw-r--r-- | qpdf/qtest/qpdf/issue-51.out | 1 | ||||
-rw-r--r-- | qpdf/qtest/qpdf/issue-51.pdf | 22 | ||||
-rw-r--r-- | qpdf/test_driver.cc | 115 |
7 files changed, 109 insertions, 61 deletions
diff --git a/qpdf/qtest/qpdf.test b/qpdf/qtest/qpdf.test index a091456c..1468a438 100644 --- a/qpdf/qtest/qpdf.test +++ b/qpdf/qtest/qpdf.test @@ -291,11 +291,31 @@ $n_tests += scalar(@bug_tests); foreach my $d (@bug_tests) { my ($n, $description, $exit_status) = @$d; - $td->runtest($description, - {$td->COMMAND => "qpdf issue-$n.pdf a.pdf"}, - {$td->FILE => "issue-$n.out", - $td->EXIT_STATUS => $exit_status}, - $td->NORMALIZE_NEWLINES); + if (-f "issue-$n.obfuscated") + { + # Some of the PDF files in the test suite trigger anti-virus + # warnings (MAL/PDFEx-H) and are quarantined or deleted by + # some antivirus software. These files are not actually + # infected files with malicious intent. They are present in + # the test suite to ensure that qpdf does not crash when + # process those files. Base64-encode them and pass them to + # stdin to prevent anti-virus programs from messing up the + # extracted sources. Search for "obfuscated" in test_driver.cc + # for instructions on how to obfuscate input files. + $td->runtest($description, + {$td->COMMAND => "test_driver 45 issue-$n"}, + {$td->FILE => "issue-$n.out", + $td->EXIT_STATUS => $exit_status}, + $td->NORMALIZE_NEWLINES); + } + else + { + $td->runtest($description, + {$td->COMMAND => "qpdf issue-$n.pdf a.pdf"}, + {$td->FILE => "issue-$n.out", + $td->EXIT_STATUS => $exit_status}, + $td->NORMALIZE_NEWLINES); + } } show_ntests(); # ---------- diff --git a/qpdf/qtest/qpdf/issue-118.obfuscated b/qpdf/qtest/qpdf/issue-118.obfuscated new file mode 100644 index 00000000..54ea8fe5 --- /dev/null +++ b/qpdf/qtest/qpdf/issue-118.obfuscated @@ -0,0 +1 @@ +éáýüüüüüüüüüýìü죮ŠÆððÆìì㵌©ìãüüüüüüüüüãìüüüüãüüü¿üìüüüüüã©¢«ž€ìøýôÆòòÆ¿žŸ©¡Æüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüü¿üüüüüüü¿üüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüü¿üüüüüüüüüüüü¿üüüüü¿üüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüü¿üüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüü¿üüüüüüüüüüüüü©¢š¿žŸ©¡Æ©¢š£®ŠÆÆüüüüüüüüüüüüüüüüüüüüüüüüüüü¿üüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüü¿üüüüüüüüüüüüüüôìü죮ŠÆððÆìì㵌©ì㩪Æìì㥶©ìõÆììã
¢š©ŽìüìõÆììãìýìþìýÆììã©¢«ž€ìÿúÆìì㣣žìþìüìÆììãüü¿üìüìüìÆòòÆ¿žŸ©¡ÆÌüüüÍÌÃÌÎÌÎüÎüüüÎüüüÎüüüÎüüüÍüüüÍüüüÆ©¢š¿žŸ©¡Æ©¢š£®ŠÆÆ¿žŸžŽŸ©ªÆúýûÆéé
\ No newline at end of file diff --git a/qpdf/qtest/qpdf/issue-118.pdf b/qpdf/qtest/qpdf/issue-118.pdf Binary files differdeleted file mode 100644 index 5dc05f6d..00000000 --- a/qpdf/qtest/qpdf/issue-118.pdf +++ /dev/null diff --git a/qpdf/qtest/qpdf/issue-51.obfuscated b/qpdf/qtest/qpdf/issue-51.obfuscated new file mode 100644 index 00000000..0d81d9ed --- /dev/null +++ b/qpdf/qtest/qpdf/issue-51.obfuscated @@ -0,0 +1 @@ +éáýüüüüüüüüüüüüüþìü죮ŠÆððã©¢«ž€ìþìüìãüüüüüüãüüüüüüüüüüüòòÆ¿žŸ©¡Æüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüýìü죮ŠÆððãüüüüüüüüüüüüüüüüìüìüìãüüüüüüüüüìüìüìãüüüüüüüüüüüüüüüüüüüãüüüüüððãüãüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüòòãüüüüüüüüìþìüìòòüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüûìü죮ŠÆððãüüüüãüüüüüüüãüüüüüìüìüìÆãüüüüüüüüüüýìüììüüüü좹 좹 ìüÆãüüüüäüüüüüåÆòòüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüŽŸ©ªÆüìõÆüüüüüüüüüüìüüüüüìªìÆüüüüüüüþüüìüüüüüì¢ìÆüüüüüüüüüõìüüüüüì¢ìÆüüüüüüüüüüìüüüüüì¢ìÆüüüüüüüüüüìüüüüüì¢ìÆüüüüüüüüüüìüüüüüì¢ìÆüüüüüüüüüüìüüüüüì¢ìÆüüüüüüüøüüìüüüüüì¢ìÆüüüüüüüüüüìüüüüüì¢ìÆžŸ¥ ©Ÿðð㥶©ìü㣣žìûìüìòò¿žŸžŽŸ©ªÆûøüÆéé
\ No newline at end of file diff --git a/qpdf/qtest/qpdf/issue-51.out b/qpdf/qtest/qpdf/issue-51.out index 692c0984..e361b7d0 100644 --- a/qpdf/qtest/qpdf/issue-51.out +++ b/qpdf/qtest/qpdf/issue-51.out @@ -8,4 +8,3 @@ WARNING: issue-51.pdf (object 2 0, offset 71): attempting to recover stream leng WARNING: issue-51.pdf (object 2 0, offset 71): unable to recover stream data; treating stream as empty WARNING: issue-51.pdf (object 2 0, offset 977): expected endobj WARNING: issue-51.pdf (object 2 0, offset 977): EOF after endobj -qpdf: operation succeeded with warnings; resulting file may have some problems diff --git a/qpdf/qtest/qpdf/issue-51.pdf b/qpdf/qtest/qpdf/issue-51.pdf deleted file mode 100644 index 2dafce1a..00000000 --- a/qpdf/qtest/qpdf/issue-51.pdf +++ /dev/null @@ -1,22 +0,0 @@ -%PDF-100000000000002 0 obj -<</Length 2 0 R/000000/00000000000>> -stream -000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 0 obj -<</0000000000000000 0 0 R/000000000 0 0 R/00000000[00000000000]/00000<</0/00000000000000000000000000000000>>/00000000 2 0 R>>000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007 0 obj -<</0000/0000000/00000 0 0 R -/0000000000[1 0 R 0000 null null 0] -/0000(00000) ->>0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000xref -0 9 -0000000000 00000 f -0000000200 00000 n -0000000009 00000 n -0000000000 00000 n -0000000000 00000 n -0000000000 00000 n -0000000000 00000 n -0000000400 00000 n -0000000000 00000 n -trailer<</Size 0/Root 7 0 R>>startxref -740 -%%EOF
\ No newline at end of file diff --git a/qpdf/test_driver.cc b/qpdf/test_driver.cc index 14a317ba..69d13d54 100644 --- a/qpdf/test_driver.cc +++ b/qpdf/test_driver.cc @@ -161,6 +161,44 @@ static void print_rect(std::ostream& out, << r.urx << ", " << r.ury << "]"; } +static void read_file_into_memory( + char const* filename, + PointerHolder<char>& file_buf, size_t& size) +{ + FILE* f = QUtil::safe_fopen(filename, "rb"); + fseek(f, 0, SEEK_END); + size = QUtil::tell(f); + fseek(f, 0, SEEK_SET); + file_buf = PointerHolder<char>(true, new char[size]); + char* buf_p = file_buf.getPointer(); + size_t bytes_read = 0; + size_t len = 0; + while ((len = fread(buf_p + bytes_read, 1, size - bytes_read, f)) > 0) + { + bytes_read += len; + } + if (bytes_read != size) + { + if (ferror(f)) + { + throw std::runtime_error( + std::string("failure reading file ") + filename + + " into memory: read " + + QUtil::int_to_string(bytes_read) + "; wanted " + + QUtil::int_to_string(size)); + } + else + { + throw std::logic_error( + std::string("premature eof reading file ") + filename + + " into memory: read " + + QUtil::int_to_string(bytes_read) + "; wanted " + + QUtil::int_to_string(size)); + } + } + fclose(f); +} + void runtest(int n, char const* filename1, char const* arg2) { // Most tests here are crafted to work on specific files. Look at @@ -200,6 +238,34 @@ void runtest(int n, char const* filename1, char const* arg2) // arg2 is password pdf.processFile(filename1, arg2); } + else if (n == 45) + { + // Decode obfuscated files. To obfuscated, run the input file + // through this perl script, and save the result to + // filename.obfuscated. This pretends that the input was + // called filename.pdf and that that file contained the + // deobfuscated version. + + // undef $/; + // my @str = split('', <STDIN>); + // for (my $i = 0; $i < scalar(@str); ++$i) + // { + // $str[$i] = chr(ord($str[$i]) ^ 0xcc); + // } + // print(join('', @str)); + + std::string filename(std::string(filename1) + ".obfuscated"); + PointerHolder<char> file_buf; + size_t size = 0; + read_file_into_memory(filename.c_str(), file_buf, size); + char* p = file_buf.getPointer(); + for (size_t i = 0; i < size; ++i) + { + p[i] ^= 0xcc; + } + pdf.processMemoryFile((std::string(filename1) + ".pdf").c_str(), + p, size); + } else if (n % 2 == 0) { if (n % 4 == 0) @@ -217,39 +283,9 @@ void runtest(int n, char const* filename1, char const* arg2) else { QTC::TC("qpdf", "exercise processMemoryFile"); - FILE* f = QUtil::safe_fopen(filename1, "rb"); - fseek(f, 0, SEEK_END); - size_t size = QUtil::tell(f); - fseek(f, 0, SEEK_SET); - file_buf = PointerHolder<char>(true, new char[size]); - char* buf_p = file_buf.getPointer(); - size_t bytes_read = 0; - size_t len = 0; - while ((len = fread(buf_p + bytes_read, 1, size - bytes_read, f)) > 0) - { - bytes_read += len; - } - if (bytes_read != size) - { - if (ferror(f)) - { - throw std::runtime_error( - std::string("failure reading file ") + filename1 + - " into memory: read " + - QUtil::int_to_string(bytes_read) + "; wanted " + - QUtil::int_to_string(size)); - } - else - { - throw std::logic_error( - std::string("premature eof reading file ") + filename1 + - " into memory: read " + - QUtil::int_to_string(bytes_read) + "; wanted " + - QUtil::int_to_string(size)); - } - } - fclose(f); - pdf.processMemoryFile(filename1, buf_p, size); + size_t size = 0; + read_file_into_memory(filename1, file_buf, size); + pdf.processMemoryFile(filename1, file_buf.getPointer(), size); } if ((n == 0) || (n == 1)) @@ -1612,6 +1648,19 @@ void runtest(int n, char const* filename1, char const* arg2) w.setSuppressOriginalObjectIDs(true); w.write(); } + else if (n == 45) + { + // Decode obfuscated files. This is here to help test with + // files that trigger anti-virus warnings. See comments in + // qpdf.test for details. + QPDFWriter w(pdf, "a.pdf"); + w.setStaticID(true); + w.write(); + if (! pdf.getWarnings().empty()) + { + exit(3); + } + } else { throw std::runtime_error(std::string("invalid test ") + |