From 3490090fbc7266dfcf7c80c6766d4d557b314292 Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Tue, 6 Feb 2024 15:12:41 -0500 Subject: [PATCH] Detect JSON object whose value is an indirect object --- .../7865f715436bd6c3cdb6b073fcb44b297cb98097 | 1 + fuzz/qtest/fuzz.test | 2 +- libqpdf/QPDF_json.cc | 4 ++ qpdf/qtest/qpdf-json.test | 1 + .../qpdf/qjson-object-value-indirect.json | 68 +++++++++++++++++++ .../qpdf/qjson-object-value-indirect.out | 2 + 6 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 fuzz/json_fuzzer_seed_corpus/7865f715436bd6c3cdb6b073fcb44b297cb98097 create mode 100644 qpdf/qtest/qpdf/qjson-object-value-indirect.json create mode 100644 qpdf/qtest/qpdf/qjson-object-value-indirect.out diff --git a/fuzz/json_fuzzer_seed_corpus/7865f715436bd6c3cdb6b073fcb44b297cb98097 b/fuzz/json_fuzzer_seed_corpus/7865f715436bd6c3cdb6b073fcb44b297cb98097 new file mode 100644 index 00000000..0500193d --- /dev/null +++ b/fuzz/json_fuzzer_seed_corpus/7865f715436bd6c3cdb6b073fcb44b297cb98097 @@ -0,0 +1 @@ +{"qpdf":[{},{"obj:1 0 R":{"value":"2 0 R" \ No newline at end of file diff --git a/fuzz/qtest/fuzz.test b/fuzz/qtest/fuzz.test index 4a20e5bf..28676339 100644 --- a/fuzz/qtest/fuzz.test +++ b/fuzz/qtest/fuzz.test @@ -16,7 +16,7 @@ my @fuzzers = ( ['dct' => 1], ['flate' => 1], ['hex' => 1], - ['json' => 38], + ['json' => 39], ['lzw' => 2], ['pngpredictor' => 1], ['runlength' => 6], diff --git a/libqpdf/QPDF_json.cc b/libqpdf/QPDF_json.cc index 502f2346..8326e6a5 100644 --- a/libqpdf/QPDF_json.cc +++ b/libqpdf/QPDF_json.cc @@ -441,6 +441,10 @@ QPDF::JSONReactor::containerEnd(JSON const& value) void QPDF::JSONReactor::replaceObject(QPDFObjectHandle&& replacement, JSON const& value) { + if (replacement.isIndirect()) { + error(replacement.getParsedOffset(), "the value of an object may not be an indirect object reference"); + return; + } auto& tos = stack.back(); auto og = tos.object.getObjGen(); this->pdf.replaceObject(og, replacement); diff --git a/qpdf/qtest/qpdf-json.test b/qpdf/qtest/qpdf-json.test index 2f7bcd86..9542bccf 100644 --- a/qpdf/qtest/qpdf-json.test +++ b/qpdf/qtest/qpdf-json.test @@ -28,6 +28,7 @@ my @badfiles = ( 'objects-not-dict', 'bad-object-key', 'object-not-dict', + 'object-value-indirect', 'stream-not-dict', 'stream-dict-not-dict', 'trailer-not-dict', diff --git a/qpdf/qtest/qpdf/qjson-object-value-indirect.json b/qpdf/qtest/qpdf/qjson-object-value-indirect.json new file mode 100644 index 00000000..107e99b5 --- /dev/null +++ b/qpdf/qtest/qpdf/qjson-object-value-indirect.json @@ -0,0 +1,68 @@ +{ + "qpdf": [ + { + "jsonversion": 2, + "pdfversion": "1.3", + "maxobjectid": 6 + }, + { + "obj:1 0 R": { + "value": "2 0 R" + }, + "obj:2 0 R": { + "value": { + "/Count": 1, + "/Kids": [ + "3 0 R" + ], + "/Type": "/Pages" + } + }, + "obj:3 0 R": { + "value": { + "/Contents": "4 0 R", + "/MediaBox": [ + 0, + 0, + 612, + 792 + ], + "/Parent": "2 0 R", + "/Resources": { + "/Font": { + "/F1": "6 0 R" + }, + "/ProcSet": "5 0 R" + }, + "/Type": "/Page" + } + }, + "obj:4 0 R": { + "stream": { + "data": "QlQKICAvRjEgMjQgVGYKICA3MiA3MjAgVGQKICAoUG90YXRvKSBUagpFVAo=", + "dict": {} + } + }, + "obj:5 0 R": { + "value": [ + "/PDF", + "/Text" + ] + }, + "obj:6 0 R": { + "value": { + "/BaseFont": "/Helvetica", + "/Encoding": "/WinAnsiEncoding", + "/Subtype": "/Type1", + "/Type": "/Font" + } + }, + "trailer": { + "value": { + "/Root": "1 0 R", + "/Size": 7 + } + } + } + ] +} diff --git a/qpdf/qtest/qpdf/qjson-object-value-indirect.out b/qpdf/qtest/qpdf/qjson-object-value-indirect.out new file mode 100644 index 00000000..cd702337 --- /dev/null +++ b/qpdf/qtest/qpdf/qjson-object-value-indirect.out @@ -0,0 +1,2 @@ +WARNING: qjson-object-value-indirect.json (obj:1 0 R): the value of an object may not be an indirect object reference +qpdf: qjson-object-value-indirect.json: errors found in JSON