// 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; }