// Copyright 2018 The Chromium OS Authors. All rights reserved.
|
// Use of this source code is governed by a BSD-style license that can be
|
// found in the LICENSE file.
|
|
#include <vector>
|
|
#include "base/logging.h"
|
#include "brillo/test_helpers.h"
|
|
#include "puffin/src/bit_reader.h"
|
#include "puffin/src/bit_writer.h"
|
#include "puffin/src/include/puffin/common.h"
|
#include "puffin/src/include/puffin/huffer.h"
|
#include "puffin/src/include/puffin/puffer.h"
|
#include "puffin/src/include/puffin/puffpatch.h"
|
#include "puffin/src/memory_stream.h"
|
#include "puffin/src/puff_reader.h"
|
#include "puffin/src/puff_writer.h"
|
|
using puffin::BitExtent;
|
using puffin::Buffer;
|
using puffin::BufferBitReader;
|
using puffin::BufferBitWriter;
|
using puffin::BufferPuffReader;
|
using puffin::BufferPuffWriter;
|
using puffin::ByteExtent;
|
using puffin::Huffer;
|
using puffin::MemoryStream;
|
using puffin::Puffer;
|
using puffin::UniqueStreamPtr;
|
using std::vector;
|
|
namespace puffin {
|
// From puffpatch.cc
|
bool DecodePatch(const uint8_t* patch,
|
size_t patch_length,
|
size_t* bsdiff_patch_offset,
|
size_t* bsdiff_patch_size,
|
vector<BitExtent>* src_deflates,
|
vector<BitExtent>* dst_deflates,
|
vector<ByteExtent>* src_puffs,
|
vector<ByteExtent>* dst_puffs,
|
uint64_t* src_puff_size,
|
uint64_t* dst_puff_size);
|
} // namespace puffin
|
|
namespace {
|
void FuzzPuff(const uint8_t* data, size_t size) {
|
BufferBitReader bit_reader(data, size);
|
Buffer puff_buffer(size * 2);
|
BufferPuffWriter puff_writer(puff_buffer.data(), puff_buffer.size());
|
vector<BitExtent> bit_extents;
|
Puffer puffer;
|
puffer.PuffDeflate(&bit_reader, &puff_writer, &bit_extents);
|
}
|
|
void FuzzHuff(const uint8_t* data, size_t size) {
|
BufferPuffReader puff_reader(data, size);
|
Buffer deflate_buffer(size);
|
BufferBitWriter bit_writer(deflate_buffer.data(), deflate_buffer.size());
|
Huffer huffer;
|
huffer.HuffDeflate(&puff_reader, &bit_writer);
|
}
|
|
template <typename T>
|
bool TestExtentsArrayForFuzzer(const vector<T>& extents) {
|
const size_t kMaxArraySize = 100;
|
if (extents.size() > kMaxArraySize) {
|
return false;
|
}
|
|
const size_t kMaxBufferSize = 1024; // 1Kb
|
for (const auto& ext : extents) {
|
if (ext.length > kMaxBufferSize) {
|
return false;
|
}
|
}
|
return true;
|
}
|
|
void FuzzPuffPatch(const uint8_t* data, size_t size) {
|
// First decode the header and make sure the deflate and puff buffer sizes do
|
// not excede some limits. This is to prevent the fuzzer complain with
|
// out-of-memory errors when the fuzz data is in such a way that causes a huge
|
// random size memory be allocated.
|
|
size_t bsdiff_patch_offset;
|
size_t bsdiff_patch_size = 0;
|
vector<BitExtent> src_deflates, dst_deflates;
|
vector<ByteExtent> src_puffs, dst_puffs;
|
uint64_t src_puff_size, dst_puff_size;
|
if (DecodePatch(data, size, &bsdiff_patch_offset, &bsdiff_patch_size,
|
&src_deflates, &dst_deflates, &src_puffs, &dst_puffs,
|
&src_puff_size, &dst_puff_size) &&
|
TestExtentsArrayForFuzzer(src_deflates) &&
|
TestExtentsArrayForFuzzer(dst_deflates) &&
|
TestExtentsArrayForFuzzer(src_puffs) &&
|
TestExtentsArrayForFuzzer(dst_puffs)) {
|
const size_t kBufferSize = 1000;
|
if ((!src_deflates.empty() &&
|
kBufferSize <
|
src_deflates.back().offset + src_deflates.back().length) ||
|
(!dst_deflates.empty() &&
|
kBufferSize <
|
dst_deflates.back().offset + dst_deflates.back().length)) {
|
return;
|
}
|
|
Buffer src_buffer(kBufferSize);
|
Buffer dst_buffer(kBufferSize);
|
auto src = MemoryStream::CreateForRead(src_buffer);
|
auto dst = MemoryStream::CreateForWrite(&dst_buffer);
|
puffin::PuffPatch(std::move(src), std::move(dst), data, size, kBufferSize);
|
}
|
}
|
|
struct Environment {
|
Environment() {
|
// To turn off the logging.
|
logging::SetMinLogLevel(logging::LOG_FATAL);
|
|
// To turn off logging for bsdiff library.
|
std::cerr.setstate(std::ios_base::failbit);
|
}
|
};
|
Environment* env = new Environment();
|
|
} // namespace
|
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
FuzzPuff(data, size);
|
FuzzHuff(data, size);
|
FuzzPuffPatch(data, size);
|
return 0;
|
}
|