// 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 #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* src_deflates, vector* dst_deflates, vector* src_puffs, vector* 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 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 bool TestExtentsArrayForFuzzer(const vector& 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 src_deflates, dst_deflates; vector 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; }