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.
This commit is contained in:
Jay Berkenbilt 2018-08-13 19:26:20 -04:00
parent 5d9d80beba
commit 164cbdde46
7 changed files with 109 additions and 61 deletions

View File

@ -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();
# ----------

View File

@ -0,0 +1 @@
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>癬¦¦¦¦踰譯<EFBFBD>軟霪跛<EFBFBD><EFBFBD><EFBFBD>笨¦¦¦¦<EFBFBD><EFBFBD>踰¦髜¦鋻鶴¦¦髜<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>鴪匿絃<EFBFBD>¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦鋻¦¦¦鋻¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦頗¦¦¦¦¦鋻¦¦鋻¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦頗¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦頗¦¦¦¦¦¦<EFBFBD>┸絃<EFBFBD><EFBFBD><EFBFBD>篤¦¦¦¦¦¦¦¦¦¦¦¦¦鋻¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦鋻¦¦¦¦¦¦¦<EFBFBD><EFBFBD>ζ韶縄趁<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>縄趁<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>縄趁<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>縄趁<EFBFBD><EFBFBD><EFBFBD><EFBFBD>朗跛<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>縄趁<EFBFBD>¦頗踰踰<EFBFBD><EFBFBD>汝鯑晋奨①凸¦鑈銘摸摸閒¦閒¦閒¦閒¦鑈¦鑈¦鍗<EFBFBD>┸絃<EFBFBD><EFBFBD><EFBFBD>篤晋鹸奨<EFBFBD>燾福蜑<EFBFBD><EFBFBD><EFBFBD>

Binary file not shown.

View File

@ -0,0 +1 @@
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>癬¦¦¦¦¦¦踰譯<EFBFBD>軟鞦<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>笨¦¦髜¦¦¦¦¦ⅱ鯑晋奨①日¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦<EFBFBD><EFBFBD>ζ韶笨¦¦¦¦¦¦¦鶴鶴鶴<EFBFBD>笨¦¦¦¦踰踰<EFBFBD><EFBFBD>笨¦¦¦<EFBFBD><EFBFBD>¦¦¦¦¦<EFBFBD><EFBFBD>笨¦¦韶笨笨¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ⅱ鱆¦¦¦¦蹊踰<EFBFBD><EFBFBD>鴪¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¬踰譯<EFBFBD>軟鞦¦¦笨¦¦¦笨¦¦踰踰<EFBFBD><EFBFBD>乍¦¦¦¦¦<EFBFBD><EFBFBD><EFBFBD>踰¦鶴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>乍¦¦糶¦¦綟鴪¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦鉸奨<EFBFBD><EFBFBD>¦¦¦¦¦踰¦¦讓貽¦¦¦¦踰¦¦譬貽¦¦¦¦踰¦¦譬貽¦¦¦¦¦踰¦¦譬貽¦¦¦¦¦踰¦¦譬貽¦¦¦¦¦踰¦¦譬貽¦¦¦¦¦踰¦¦譬貽¦¦¦ⅷ¦踰¦¦譬貽¦¦¦¦¦踰¦¦譬貽絃⑤<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>語諟鶴<EFBFBD>鴪晋鹸奨<EFBFBD>逸鍗蜑<EFBFBD><EFBFBD><EFBFBD>

View File

@ -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

View File

@ -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

View File

@ -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 ") +