256 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			256 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
// 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 <fuzzer/FuzzedDataProvider.h>
 | 
						|
 | 
						|
#include <cstdint>
 | 
						|
#include <cstdio>
 | 
						|
#include <cstdlib>
 | 
						|
#include <memory>
 | 
						|
#include <vector>
 | 
						|
 | 
						|
#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<std::vector<LzoAlgorithm>>& GetLzoAlgorithms() {
 | 
						|
  static auto* algorithms = new std::vector<std::vector<LzoAlgorithm>>{
 | 
						|
      {
 | 
						|
          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<uint8_t>& input_buffer) {
 | 
						|
  std::unique_ptr<uint8_t[]> working_buffer(
 | 
						|
      new uint8_t[algorithm.working_memory_size]);
 | 
						|
  std::unique_ptr<uint8_t[]> 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<uint8_t[]> 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<size_t>(0, algorithms.size() - 1);
 | 
						|
  const auto& algorithm_group = algorithms[first_level_index];
 | 
						|
  const auto second_level_index = data_provider.ConsumeIntegralInRange<size_t>(
 | 
						|
      0, algorithm_group.size() - 1);
 | 
						|
  const std::vector<uint8_t> input_buffer =
 | 
						|
      data_provider.ConsumeRemainingBytes<uint8_t>();
 | 
						|
  FuzzLzoAlgorithm(algorithm_group[second_level_index], input_buffer);
 | 
						|
  return 0;
 | 
						|
}
 |