Merge pull request #9028 from Enmk/Gorilla_and_DoubleDelta_buffer_overflow_fix

Fixed buffer overflow on decoding small sequences with Gorilla and DoubleDelta
This commit is contained in:
alesapin 2020-02-07 11:40:08 +03:00 committed by GitHub
commit f4467aaa65
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 36 additions and 25 deletions

View File

@ -241,30 +241,35 @@ void decompressDataForType(const char * source, UInt32 source_size, char * dest)
const char * source_end = source + source_size; const char * source_end = source + source_size;
if (source + sizeof(UInt32) > source_end)
return;
const UInt32 items_count = unalignedLoad<UInt32>(source); const UInt32 items_count = unalignedLoad<UInt32>(source);
source += sizeof(items_count); source += sizeof(items_count);
ValueType prev_value{}; ValueType prev_value{};
UnsignedDeltaType prev_delta{}; UnsignedDeltaType prev_delta{};
if (source < source_end) // decoding first item
{ if (source + sizeof(ValueType) > source_end || items_count < 1)
return;
prev_value = unalignedLoad<ValueType>(source); prev_value = unalignedLoad<ValueType>(source);
unalignedStore<ValueType>(dest, prev_value); unalignedStore<ValueType>(dest, prev_value);
source += sizeof(prev_value); source += sizeof(prev_value);
dest += sizeof(prev_value); dest += sizeof(prev_value);
}
if (source < source_end) // decoding second item
{ if (source + sizeof(UnsignedDeltaType) > source_end || items_count < 2)
return;
prev_delta = unalignedLoad<UnsignedDeltaType>(source); prev_delta = unalignedLoad<UnsignedDeltaType>(source);
prev_value = prev_value + static_cast<ValueType>(prev_delta); prev_value = prev_value + static_cast<ValueType>(prev_delta);
unalignedStore<ValueType>(dest, prev_value); unalignedStore<ValueType>(dest, prev_value);
source += sizeof(prev_delta); source += sizeof(prev_delta);
dest += sizeof(prev_value); dest += sizeof(prev_value);
}
BitReader reader(source, source_size - sizeof(prev_value) - sizeof(prev_delta) - sizeof(items_count)); BitReader reader(source, source_size - sizeof(prev_value) - sizeof(prev_delta) - sizeof(items_count));

View File

@ -159,19 +159,23 @@ void decompressDataForType(const char * source, UInt32 source_size, char * dest)
const char * source_end = source + source_size; const char * source_end = source + source_size;
if (source + sizeof(UInt32) > source_end)
return;
const UInt32 items_count = unalignedLoad<UInt32>(source); const UInt32 items_count = unalignedLoad<UInt32>(source);
source += sizeof(items_count); source += sizeof(items_count);
T prev_value{}; T prev_value{};
if (source < source_end) // decoding first item
{ if (source + sizeof(T) > source_end || items_count < 1)
return;
prev_value = unalignedLoad<T>(source); prev_value = unalignedLoad<T>(source);
unalignedStore<T>(dest, prev_value); unalignedStore<T>(dest, prev_value);
source += sizeof(prev_value); source += sizeof(prev_value);
dest += sizeof(prev_value); dest += sizeof(prev_value);
}
BitReader reader(source, source_size - sizeof(items_count) - sizeof(prev_value)); BitReader reader(source, source_size - sizeof(items_count) - sizeof(prev_value));

View File

@ -158,8 +158,8 @@ public:
explicit BinaryDataAsSequenceOfValuesIterator(const Container & container_) explicit BinaryDataAsSequenceOfValuesIterator(const Container & container_)
: container(container_), : container(container_),
data(&container[0]), data(container.data()),
data_end(reinterpret_cast<const char *>(data) + container.size()), data_end(container.data() + container.size()),
current_value(T{}) current_value(T{})
{ {
static_assert(sizeof(container[0]) == 1 && std::is_pod<std::decay_t<decltype(container[0])>>::value, "Only works on containers of byte-size PODs."); static_assert(sizeof(container[0]) == 1 && std::is_pod<std::decay_t<decltype(container[0])>>::value, "Only works on containers of byte-size PODs.");
@ -789,12 +789,14 @@ auto FFand0Generator = []()
}; };
// Makes many sequences with generator, first sequence length is 1, second is 2... up to `sequences_count`. // Makes many sequences with generator, first sequence length is 0, second is 1..., third is 2 up to `sequences_count`.
template <typename T, typename Generator> template <typename T, typename Generator>
std::vector<CodecTestSequence> generatePyramidOfSequences(const size_t sequences_count, Generator && generator, const char* generator_name) std::vector<CodecTestSequence> generatePyramidOfSequences(const size_t sequences_count, Generator && generator, const char* generator_name)
{ {
std::vector<CodecTestSequence> sequences; std::vector<CodecTestSequence> sequences;
sequences.reserve(sequences_count); sequences.reserve(sequences_count);
sequences.push_back(makeSeq<T>()); // sequence of size 0
for (size_t i = 1; i < sequences_count; ++i) for (size_t i = 1; i < sequences_count; ++i)
{ {
std::string name = generator_name + std::string(" from 0 to ") + std::to_string(i); std::string name = generator_name + std::string(" from 0 to ") + std::to_string(i);