diff --git a/projects/lzo/Dockerfile b/projects/lzo/Dockerfile index d6971e6ff..e309f621c 100644 --- a/projects/lzo/Dockerfile +++ b/projects/lzo/Dockerfile @@ -19,5 +19,5 @@ MAINTAINER info@oberhumer.com RUN apt-get update && apt-get install -y make autoconf automake libtool wget RUN wget -O lzo.tar.gz \ http://www.oberhumer.com/opensource/lzo/download/lzo-2.10.tar.gz -COPY *.c *.options build.sh $SRC/ +COPY *.c *.cc *.options build.sh $SRC/ COPY lzo_decompress_target_seeds $SRC/lzo_decompress_target_seeds diff --git a/projects/lzo/all_lzo_compress.cc b/projects/lzo/all_lzo_compress.cc new file mode 100644 index 000000000..13c3d113d --- /dev/null +++ b/projects/lzo/all_lzo_compress.cc @@ -0,0 +1,255 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include +#include +#include +#include +#include + +#include "lzo1.h" +#include "lzo1a.h" +#include "lzo1b.h" +#include "lzo1c.h" +#include "lzo1f.h" +#include "lzo1x.h" +#include "lzo1y.h" +#include "lzo1z.h" +#include "lzo2a.h" +#include "lzoconf.h" + +namespace { + +struct LzoAlgorithm { + enum class Category { LZO1, LZO2 }; + enum class Type { + LZO1, + LZO1A, + LZO1B, + LZO1C, + LZO1F, + LZO1X, + LZO1Y, + LZO1Z, + LZO2A + }; + + constexpr LzoAlgorithm(Category category, Type type, int compression_level, + int memory_level, lzo_compress_t compress_fn, + lzo_decompress_t decompress_fn, + size_t working_memory_size) + : category(category), + type(type), + compression_level(compression_level), + memory_level(memory_level), + compress_fn(compress_fn), + decompress_fn(decompress_fn), + working_memory_size(working_memory_size) {} + + size_t GetMaxCompressedSize(size_t size) const { + // Formula taken from the LZO FAQ. + switch (category) { + case Category::LZO1: + return size + (size / 16) + 64 + 3; + case Category::LZO2: + return size + (size / 8) + 128 + 3; + } + } + + Category category; + Type type; + int compression_level; + int memory_level; + + lzo_compress_t compress_fn; + lzo_decompress_t decompress_fn; + size_t working_memory_size; +}; + +static const std::vector>& GetLzoAlgorithms() { + static auto* algorithms = new std::vector>{ + { + LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1, + 0, 0, lzo1_compress, lzo1_decompress, LZO1_MEM_COMPRESS), + LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1, + 99, 0, lzo1_99_compress, lzo1_decompress, + LZO1_99_MEM_COMPRESS), + }, + { + LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1A, + 0, 0, lzo1a_compress, lzo1a_decompress, + LZO1A_MEM_COMPRESS), + LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1A, + 99, 0, lzo1a_99_compress, lzo1a_decompress, + LZO1A_99_MEM_COMPRESS), + }, + { + LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1B, + 1, 0, lzo1b_1_compress, lzo1b_decompress, + LZO1B_MEM_COMPRESS), + LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1B, + 2, 0, lzo1b_2_compress, lzo1b_decompress, + LZO1B_MEM_COMPRESS), + LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1B, + 3, 0, lzo1b_3_compress, lzo1b_decompress, + LZO1B_MEM_COMPRESS), + LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1B, + 4, 0, lzo1b_4_compress, lzo1b_decompress, + LZO1B_MEM_COMPRESS), + LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1B, + 5, 0, lzo1b_5_compress, lzo1b_decompress, + LZO1B_MEM_COMPRESS), + LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1B, + 6, 0, lzo1b_6_compress, lzo1b_decompress, + LZO1B_MEM_COMPRESS), + LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1B, + 7, 0, lzo1b_7_compress, lzo1b_decompress, + LZO1B_MEM_COMPRESS), + LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1B, + 8, 0, lzo1b_8_compress, lzo1b_decompress, + LZO1B_MEM_COMPRESS), + LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1B, + 9, 0, lzo1b_9_compress, lzo1b_decompress, + LZO1B_MEM_COMPRESS), + LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1B, + 99, 0, lzo1b_99_compress, lzo1b_decompress, + LZO1B_99_MEM_COMPRESS), + LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1B, + 999, 0, lzo1b_999_compress, lzo1b_decompress, + LZO1B_999_MEM_COMPRESS), + }, + { + LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1C, + 1, 0, lzo1c_1_compress, lzo1c_decompress, + LZO1C_MEM_COMPRESS), + LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1C, + 5, 0, lzo1c_5_compress, lzo1c_decompress, + LZO1C_MEM_COMPRESS), + LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1C, + 9, 0, lzo1c_9_compress, lzo1c_decompress, + LZO1C_MEM_COMPRESS), + LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1C, + 99, 0, lzo1c_99_compress, lzo1c_decompress, + LZO1C_99_MEM_COMPRESS), + LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1C, + 999, 0, lzo1c_999_compress, lzo1c_decompress, + LZO1C_999_MEM_COMPRESS), + }, + { + LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1F, + 1, 0, lzo1f_1_compress, lzo1f_decompress, + LZO1F_MEM_COMPRESS), + LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1F, + 999, 0, lzo1f_999_compress, lzo1f_decompress, + LZO1F_999_MEM_COMPRESS), + }, + { + LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1X, + 1, 0, lzo1x_1_compress, lzo1x_decompress, + LZO1X_1_MEM_COMPRESS), + LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1X, + 1, 11, lzo1x_1_11_compress, lzo1x_decompress, + LZO1X_1_11_MEM_COMPRESS), + LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1X, + 1, 12, lzo1x_1_12_compress, lzo1x_decompress, + LZO1X_1_12_MEM_COMPRESS), + LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1X, + 1, 15, lzo1x_1_15_compress, lzo1x_decompress, + LZO1X_1_15_MEM_COMPRESS), + LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1X, + 999, 0, lzo1x_999_compress, lzo1x_decompress, + LZO1X_999_MEM_COMPRESS), + }, + { + LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1Y, + 1, 0, lzo1y_1_compress, lzo1y_decompress, + LZO1Y_MEM_COMPRESS), + LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1Y, + 999, 0, lzo1y_999_compress, lzo1y_decompress, + LZO1Y_999_MEM_COMPRESS), + }, + { + LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1Z, + 999, 0, lzo1z_999_compress, lzo1z_decompress, + LZO1Z_999_MEM_COMPRESS), + }, + { + LzoAlgorithm(LzoAlgorithm::Category::LZO2, LzoAlgorithm::Type::LZO2A, + 999, 0, lzo2a_999_compress, lzo2a_decompress, + LZO2A_999_MEM_COMPRESS), + }, + }; + return *algorithms; +} + +void FuzzLzoAlgorithm(const LzoAlgorithm& algorithm, + const std::vector& input_buffer) { + std::unique_ptr working_buffer( + new uint8_t[algorithm.working_memory_size]); + std::unique_ptr compressed_buffer( + new uint8_t[algorithm.GetMaxCompressedSize(input_buffer.size())]); + + lzo_uint compressed_size; + if (algorithm.compress_fn(input_buffer.data(), input_buffer.size(), + compressed_buffer.get(), &compressed_size, + working_buffer.get()) != LZO_E_OK) { + abort(); + } + + std::unique_ptr decompressed_buffer( + new uint8_t[input_buffer.size()]); + lzo_uint decompressed_size; + if (algorithm.decompress_fn(compressed_buffer.get(), compressed_size, + decompressed_buffer.get(), &decompressed_size, + nullptr) != LZO_E_OK) { + abort(); + } + + if (decompressed_size != input_buffer.size()) { + fprintf(stderr, "Decompressed size %zu does not match original size %zu.\n", + decompressed_size, input_buffer.size()); + abort(); + } else if (memcmp(input_buffer.data(), decompressed_buffer.get(), + input_buffer.size()) != 0) { + fprintf(stderr, + "Decompressed buffer does not match original buffer of size %zu.\n", + input_buffer.size()); + abort(); + } +} + +} // namespace + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + static bool initialized __attribute__((unused)) = []() { + if (lzo_init() != LZO_E_OK) { + abort(); + } + return true; + }(); + + FuzzedDataProvider data_provider(data, size); + const auto& algorithms = GetLzoAlgorithms(); + const auto first_level_index = + data_provider.ConsumeIntegralInRange(0, algorithms.size() - 1); + const auto& algorithm_group = algorithms[first_level_index]; + const auto second_level_index = data_provider.ConsumeIntegralInRange( + 0, algorithm_group.size() - 1); + const std::vector input_buffer = + data_provider.ConsumeRemainingBytes(); + FuzzLzoAlgorithm(algorithm_group[second_level_index], input_buffer); + return 0; +} diff --git a/projects/lzo/build.sh b/projects/lzo/build.sh index bfe78b95e..58012a506 100755 --- a/projects/lzo/build.sh +++ b/projects/lzo/build.sh @@ -30,6 +30,10 @@ do -o $OUT/${name} $LIB_FUZZING_ENGINE src/.libs/liblzo2.a done +$CXX $CXXFLAGS -std=c++11 -I include -I minilzo -I include/lzo \ + $SRC/all_lzo_compress.cc \ + -o $OUT/all_lzo_compress $LIB_FUZZING_ENGINE src/.libs/liblzo2.a + # copy fuzzer options cp $SRC/*.options $OUT/ zip -j $OUT/lzo_decompress_target_seed_corpus.zip $SRC/lzo_decompress_target_seeds/*