Commit ad8081daf597b8f46696d5ddae82770ab419ad82

Authored by Jay Berkenbilt
1 parent 9a095c5c

Fix fuzz issue 15442 (overflow checking in BufferInputSource)

fuzz/qpdf_extra/15442.fuzz 0 → 100644
  1 +trailer<</Length 9223372036854775807>>stream
0 2 \ No newline at end of file
... ...
include/qpdf/BufferInputSource.hh
... ... @@ -54,7 +54,7 @@ class BufferInputSource: public InputSource
54 54 virtual void unreadCh(char ch);
55 55  
56 56 private:
57   - qpdf_offset_t const bufSizeAsOffset() const;
  57 + static void range_check(qpdf_offset_t cur, qpdf_offset_t delta);
58 58  
59 59 class Members
60 60 {
... ... @@ -72,6 +72,7 @@ class BufferInputSource: public InputSource
72 72 std::string description;
73 73 Buffer* buf;
74 74 qpdf_offset_t cur_offset;
  75 + qpdf_offset_t max_offset;
75 76 };
76 77  
77 78 PointerHolder<Members> m;
... ...
libqpdf/BufferInputSource.cc
... ... @@ -3,6 +3,8 @@
3 3 #include <string.h>
4 4 #include <stdexcept>
5 5 #include <algorithm>
  6 +#include <limits>
  7 +#include <sstream>
6 8  
7 9 BufferInputSource::Members::Members(bool own_memory,
8 10 std::string const& description,
... ... @@ -10,7 +12,8 @@ BufferInputSource::Members::Members(bool own_memory,
10 12 own_memory(own_memory),
11 13 description(description),
12 14 buf(buf),
13   - cur_offset(0)
  15 + cur_offset(0),
  16 + max_offset(buf ? QIntC::to_offset(buf->getSize()) : 0)
14 17 {
15 18 }
16 19  
... ... @@ -29,6 +32,7 @@ BufferInputSource::BufferInputSource(std::string const&amp; description,
29 32 m(new Members(true, description, 0))
30 33 {
31 34 this->m->buf = new Buffer(contents.length());
  35 + this->m->max_offset = QIntC::to_offset(this->m->buf->getSize());
32 36 unsigned char* bp = this->m->buf->getBuffer();
33 37 memcpy(bp, contents.c_str(), contents.length());
34 38 }
... ... @@ -41,12 +45,6 @@ BufferInputSource::~BufferInputSource()
41 45 }
42 46 }
43 47  
44   -qpdf_offset_t const
45   -BufferInputSource::bufSizeAsOffset() const
46   -{
47   - return QIntC::to_offset(this->m->buf->getSize());
48   -}
49   -
50 48 qpdf_offset_t
51 49 BufferInputSource::findAndSkipNextEOL()
52 50 {
... ... @@ -54,7 +52,7 @@ BufferInputSource::findAndSkipNextEOL()
54 52 {
55 53 throw std::logic_error("INTERNAL ERROR: BufferInputSource offset < 0");
56 54 }
57   - qpdf_offset_t end_pos = bufSizeAsOffset();
  55 + qpdf_offset_t end_pos = this->m->max_offset;
58 56 if (this->m->cur_offset >= end_pos)
59 57 {
60 58 this->last_offset = end_pos;
... ... @@ -103,6 +101,20 @@ BufferInputSource::tell()
103 101 }
104 102  
105 103 void
  104 +BufferInputSource::range_check(qpdf_offset_t cur, qpdf_offset_t delta)
  105 +{
  106 + if ((delta > 0) &&
  107 + ((std::numeric_limits<qpdf_offset_t>::max() - cur) < delta))
  108 + {
  109 + std::ostringstream msg;
  110 + msg << "seeking forward from " << cur
  111 + << " by " << delta
  112 + << " would cause an overflow of the offset type";
  113 + throw std::range_error(msg.str());
  114 + }
  115 +}
  116 +
  117 +void
106 118 BufferInputSource::seek(qpdf_offset_t offset, int whence)
107 119 {
108 120 switch (whence)
... ... @@ -112,10 +124,12 @@ BufferInputSource::seek(qpdf_offset_t offset, int whence)
112 124 break;
113 125  
114 126 case SEEK_END:
115   - this->m->cur_offset = bufSizeAsOffset() + offset;
  127 + range_check(this->m->max_offset, offset);
  128 + this->m->cur_offset = this->m->max_offset + offset;
116 129 break;
117 130  
118 131 case SEEK_CUR:
  132 + range_check(this->m->cur_offset, offset);
119 133 this->m->cur_offset += offset;
120 134 break;
121 135  
... ... @@ -145,7 +159,7 @@ BufferInputSource::read(char* buffer, size_t length)
145 159 {
146 160 throw std::logic_error("INTERNAL ERROR: BufferInputSource offset < 0");
147 161 }
148   - qpdf_offset_t end_pos = bufSizeAsOffset();
  162 + qpdf_offset_t end_pos = this->m->max_offset;
149 163 if (this->m->cur_offset >= end_pos)
150 164 {
151 165 this->last_offset = end_pos;
... ...