diff options
author | Jack Lloyd <[email protected]> | 2015-08-02 23:43:12 -0400 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2015-08-02 23:43:12 -0400 |
commit | 392ce7db1eccf5e2eacb074195ea7f5016f70259 (patch) | |
tree | 49aa67753d35e5ae56feac3b67cc55b7274a53da /src/lib | |
parent | 8e19ecf11c2c50b5a2d6642477d729091409fec8 (diff) |
Fix two crashes in the BER decoder found with afl.
One a read at 0 of an empty vector, the other causing allocation of an
arbitrary amount of memory.
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/asn1/ber_dec.cpp | 12 | ||||
-rw-r--r-- | src/lib/filters/codec_filt/b64_filt.cpp | 5 | ||||
-rw-r--r-- | src/lib/filters/data_src.cpp | 28 | ||||
-rw-r--r-- | src/lib/filters/data_src.h | 4 | ||||
-rw-r--r-- | src/lib/filters/pipe.h | 5 | ||||
-rw-r--r-- | src/lib/filters/pipe_rw.cpp | 10 | ||||
-rw-r--r-- | src/lib/filters/secqueue.h | 2 |
7 files changed, 60 insertions, 6 deletions
diff --git a/src/lib/asn1/ber_dec.cpp b/src/lib/asn1/ber_dec.cpp index 06543d9e7..4267d79dc 100644 --- a/src/lib/asn1/ber_dec.cpp +++ b/src/lib/asn1/ber_dec.cpp @@ -1,6 +1,7 @@ + /* * BER Decoder -* (C) 1999-2008 Jack Lloyd +* (C) 1999-2008,2015 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ @@ -218,7 +219,10 @@ BER_Object BER_Decoder::get_next_object() if(next.type_tag == NO_OBJECT) return next; - size_t length = decode_length(source); + const size_t length = decode_length(source); + if(!source->check_available(length)) + throw BER_Decoding_Error("Value truncated"); + next.value.resize(length); if(source->read(next.value.data(), length) != length) throw BER_Decoding_Error("Value truncated"); @@ -526,6 +530,8 @@ BER_Decoder& BER_Decoder::decode(secure_vector<byte>& buffer, buffer = obj.value; else { + if(obj.value.empty()) + throw BER_Decoding_Error("Invalid BIT STRING"); if(obj.value[0] >= 8) throw BER_Decoding_Error("Bad number of unused bits in BIT STRING"); @@ -549,6 +555,8 @@ BER_Decoder& BER_Decoder::decode(std::vector<byte>& buffer, buffer = unlock(obj.value); else { + if(obj.value.empty()) + throw BER_Decoding_Error("Invalid BIT STRING"); if(obj.value[0] >= 8) throw BER_Decoding_Error("Bad number of unused bits in BIT STRING"); diff --git a/src/lib/filters/codec_filt/b64_filt.cpp b/src/lib/filters/codec_filt/b64_filt.cpp index d9e4a5f8a..df3cad6a4 100644 --- a/src/lib/filters/codec_filt/b64_filt.cpp +++ b/src/lib/filters/codec_filt/b64_filt.cpp @@ -126,6 +126,11 @@ void Base64_Decoder::write(const byte input[], size_t length) while(length) { size_t to_copy = std::min<size_t>(length, in.size() - position); + if(to_copy == 0) + { + in.resize(in.size()*2); + out.resize(out.size()*2); + } copy_mem(&in[position], input, to_copy); position += to_copy; diff --git a/src/lib/filters/data_src.cpp b/src/lib/filters/data_src.cpp index 7551b0037..4e0725943 100644 --- a/src/lib/filters/data_src.cpp +++ b/src/lib/filters/data_src.cpp @@ -34,10 +34,18 @@ size_t DataSource::peek_byte(byte& out) const */ size_t DataSource::discard_next(size_t n) { + byte buf[64] = { 0 }; size_t discarded = 0; - byte dummy; - for(size_t j = 0; j != n; ++j) - discarded += read_byte(dummy); + + while(n) + { + const size_t got = this->read(buf, std::min(n, sizeof(buf))); + discarded += got; + + if(got == 0) + break; + } + return discarded; } @@ -52,6 +60,11 @@ size_t DataSource_Memory::read(byte out[], size_t length) return got; } +bool DataSource_Memory::check_available(size_t n) + { + return (n <= (source.size() - offset)); + } + /* * Peek into a memory buffer */ @@ -99,6 +112,15 @@ size_t DataSource_Stream::read(byte out[], size_t length) return got; } +bool DataSource_Stream::check_available(size_t n) + { + const std::streampos orig_pos = source.tellg(); + source.seekg(0, std::ios::end); + const size_t avail = source.tellg() - orig_pos; + source.seekg(orig_pos); + return (avail >= n); + } + /* * Peek into a stream */ diff --git a/src/lib/filters/data_src.h b/src/lib/filters/data_src.h index 8f6593879..2b6998448 100644 --- a/src/lib/filters/data_src.h +++ b/src/lib/filters/data_src.h @@ -32,6 +32,8 @@ class BOTAN_DLL DataSource */ virtual size_t read(byte out[], size_t length) = 0; + virtual bool check_available(size_t n) = 0; + /** * Read from the source but do not modify the internal * offset. Consecutive calls to peek() will return portions of @@ -99,6 +101,7 @@ class BOTAN_DLL DataSource_Memory : public DataSource public: size_t read(byte[], size_t) override; size_t peek(byte[], size_t, size_t) const override; + bool check_available(size_t n) override; bool end_of_data() const override; /** @@ -143,6 +146,7 @@ class BOTAN_DLL DataSource_Stream : public DataSource public: size_t read(byte[], size_t) override; size_t peek(byte[], size_t, size_t) const override; + bool check_available(size_t n) override; bool end_of_data() const override; std::string id() const override; diff --git a/src/lib/filters/pipe.h b/src/lib/filters/pipe.h index fac8a1ba3..3f8d4d04c 100644 --- a/src/lib/filters/pipe.h +++ b/src/lib/filters/pipe.h @@ -224,7 +224,10 @@ class BOTAN_DLL Pipe : public DataSource /** * @return the number of bytes read from the specified message. */ - size_t get_bytes_read(message_id msg = DEFAULT_MESSAGE) const; + size_t get_bytes_read(message_id msg) const; + + bool check_available(size_t n) override; + bool check_available_msg(size_t n, message_id msg); /** * @return currently set default message diff --git a/src/lib/filters/pipe_rw.cpp b/src/lib/filters/pipe_rw.cpp index 077bd93bb..796f9100e 100644 --- a/src/lib/filters/pipe_rw.cpp +++ b/src/lib/filters/pipe_rw.cpp @@ -168,4 +168,14 @@ size_t Pipe::get_bytes_read(message_id msg) const return outputs->get_bytes_read(msg); } +bool Pipe::check_available(size_t n) + { + return (n <= remaining(DEFAULT_MESSAGE)); + } + +bool Pipe::check_available_msg(size_t n, message_id msg) + { + return (n <= remaining(msg)); + } + } diff --git a/src/lib/filters/secqueue.h b/src/lib/filters/secqueue.h index a0164dcf2..b548f367f 100644 --- a/src/lib/filters/secqueue.h +++ b/src/lib/filters/secqueue.h @@ -32,6 +32,8 @@ class BOTAN_DLL SecureQueue : public Fanout_Filter, public DataSource bool empty() const; + bool check_available(size_t n) { return n <= size(); } + /** * @return number of bytes available in the queue */ |