aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2015-08-02 23:43:12 -0400
committerJack Lloyd <[email protected]>2015-08-02 23:43:12 -0400
commit392ce7db1eccf5e2eacb074195ea7f5016f70259 (patch)
tree49aa67753d35e5ae56feac3b67cc55b7274a53da /src/lib
parent8e19ecf11c2c50b5a2d6642477d729091409fec8 (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.cpp12
-rw-r--r--src/lib/filters/codec_filt/b64_filt.cpp5
-rw-r--r--src/lib/filters/data_src.cpp28
-rw-r--r--src/lib/filters/data_src.h4
-rw-r--r--src/lib/filters/pipe.h5
-rw-r--r--src/lib/filters/pipe_rw.cpp10
-rw-r--r--src/lib/filters/secqueue.h2
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
*/