1*07fb1d06SElliott Hughes // Copyright 2018 The ChromiumOS Authors
2*07fb1d06SElliott Hughes // Use of this source code is governed by a BSD-style license that can be
3*07fb1d06SElliott Hughes // found in the LICENSE file.
4*07fb1d06SElliott Hughes
5*07fb1d06SElliott Hughes #include <vector>
6*07fb1d06SElliott Hughes
7*07fb1d06SElliott Hughes #include "base/logging.h"
8*07fb1d06SElliott Hughes #include "brillo/test_helpers.h"
9*07fb1d06SElliott Hughes
10*07fb1d06SElliott Hughes #include "puffin/memory_stream.h"
11*07fb1d06SElliott Hughes #include "puffin/src/include/puffin/common.h"
12*07fb1d06SElliott Hughes #include "puffin/src/include/puffin/puffpatch.h"
13*07fb1d06SElliott Hughes
14*07fb1d06SElliott Hughes using puffin::BitExtent;
15*07fb1d06SElliott Hughes using puffin::Buffer;
16*07fb1d06SElliott Hughes using puffin::ByteExtent;
17*07fb1d06SElliott Hughes using puffin::MemoryStream;
18*07fb1d06SElliott Hughes using std::vector;
19*07fb1d06SElliott Hughes
20*07fb1d06SElliott Hughes namespace puffin {
21*07fb1d06SElliott Hughes // From puffpatch.cc
22*07fb1d06SElliott Hughes bool DecodePatch(const uint8_t* patch,
23*07fb1d06SElliott Hughes size_t patch_length,
24*07fb1d06SElliott Hughes size_t* bsdiff_patch_offset,
25*07fb1d06SElliott Hughes size_t* bsdiff_patch_size,
26*07fb1d06SElliott Hughes vector<BitExtent>* src_deflates,
27*07fb1d06SElliott Hughes vector<BitExtent>* dst_deflates,
28*07fb1d06SElliott Hughes vector<ByteExtent>* src_puffs,
29*07fb1d06SElliott Hughes vector<ByteExtent>* dst_puffs,
30*07fb1d06SElliott Hughes uint64_t* src_puff_size,
31*07fb1d06SElliott Hughes uint64_t* dst_puff_size);
32*07fb1d06SElliott Hughes } // namespace puffin
33*07fb1d06SElliott Hughes
34*07fb1d06SElliott Hughes namespace {
35*07fb1d06SElliott Hughes template <typename T>
TestExtentsArrayForFuzzer(const vector<T> & extents)36*07fb1d06SElliott Hughes bool TestExtentsArrayForFuzzer(const vector<T>& extents) {
37*07fb1d06SElliott Hughes const size_t kMaxArraySize = 100;
38*07fb1d06SElliott Hughes if (extents.size() > kMaxArraySize) {
39*07fb1d06SElliott Hughes return false;
40*07fb1d06SElliott Hughes }
41*07fb1d06SElliott Hughes
42*07fb1d06SElliott Hughes const size_t kMaxBufferSize = 1024; // 1Kb
43*07fb1d06SElliott Hughes for (const auto& ext : extents) {
44*07fb1d06SElliott Hughes if (ext.length > kMaxBufferSize) {
45*07fb1d06SElliott Hughes return false;
46*07fb1d06SElliott Hughes }
47*07fb1d06SElliott Hughes }
48*07fb1d06SElliott Hughes return true;
49*07fb1d06SElliott Hughes }
50*07fb1d06SElliott Hughes
FuzzPuffPatch(const uint8_t * data,size_t size)51*07fb1d06SElliott Hughes void FuzzPuffPatch(const uint8_t* data, size_t size) {
52*07fb1d06SElliott Hughes // First decode the header and make sure the deflate and puff buffer sizes do
53*07fb1d06SElliott Hughes // not excede some limits. This is to prevent the fuzzer complain with
54*07fb1d06SElliott Hughes // out-of-memory errors when the fuzz data is in such a way that causes a huge
55*07fb1d06SElliott Hughes // random size memory be allocated.
56*07fb1d06SElliott Hughes
57*07fb1d06SElliott Hughes size_t bsdiff_patch_offset;
58*07fb1d06SElliott Hughes size_t bsdiff_patch_size = 0;
59*07fb1d06SElliott Hughes vector<BitExtent> src_deflates, dst_deflates;
60*07fb1d06SElliott Hughes vector<ByteExtent> src_puffs, dst_puffs;
61*07fb1d06SElliott Hughes uint64_t src_puff_size, dst_puff_size;
62*07fb1d06SElliott Hughes if (DecodePatch(data, size, &bsdiff_patch_offset, &bsdiff_patch_size,
63*07fb1d06SElliott Hughes &src_deflates, &dst_deflates, &src_puffs, &dst_puffs,
64*07fb1d06SElliott Hughes &src_puff_size, &dst_puff_size) &&
65*07fb1d06SElliott Hughes TestExtentsArrayForFuzzer(src_deflates) &&
66*07fb1d06SElliott Hughes TestExtentsArrayForFuzzer(dst_deflates) &&
67*07fb1d06SElliott Hughes TestExtentsArrayForFuzzer(src_puffs) &&
68*07fb1d06SElliott Hughes TestExtentsArrayForFuzzer(dst_puffs)) {
69*07fb1d06SElliott Hughes const size_t kBufferSize = 1000;
70*07fb1d06SElliott Hughes if ((!src_deflates.empty() &&
71*07fb1d06SElliott Hughes kBufferSize <
72*07fb1d06SElliott Hughes src_deflates.back().offset + src_deflates.back().length) ||
73*07fb1d06SElliott Hughes (!dst_deflates.empty() &&
74*07fb1d06SElliott Hughes kBufferSize <
75*07fb1d06SElliott Hughes dst_deflates.back().offset + dst_deflates.back().length)) {
76*07fb1d06SElliott Hughes return;
77*07fb1d06SElliott Hughes }
78*07fb1d06SElliott Hughes
79*07fb1d06SElliott Hughes Buffer src_buffer(kBufferSize);
80*07fb1d06SElliott Hughes Buffer dst_buffer(kBufferSize);
81*07fb1d06SElliott Hughes auto src = MemoryStream::CreateForRead(src_buffer);
82*07fb1d06SElliott Hughes auto dst = MemoryStream::CreateForWrite(&dst_buffer);
83*07fb1d06SElliott Hughes puffin::PuffPatch(std::move(src), std::move(dst), data, size, kBufferSize);
84*07fb1d06SElliott Hughes }
85*07fb1d06SElliott Hughes }
86*07fb1d06SElliott Hughes
87*07fb1d06SElliott Hughes class Environment {
88*07fb1d06SElliott Hughes public:
Environment()89*07fb1d06SElliott Hughes Environment() {
90*07fb1d06SElliott Hughes // To turn off the logging.
91*07fb1d06SElliott Hughes logging::SetMinLogLevel(logging::LOGGING_FATAL);
92*07fb1d06SElliott Hughes
93*07fb1d06SElliott Hughes // To turn off logging for bsdiff library.
94*07fb1d06SElliott Hughes std::cerr.setstate(std::ios_base::failbit);
95*07fb1d06SElliott Hughes }
96*07fb1d06SElliott Hughes };
97*07fb1d06SElliott Hughes
98*07fb1d06SElliott Hughes } // namespace
99*07fb1d06SElliott Hughes
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)100*07fb1d06SElliott Hughes extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
101*07fb1d06SElliott Hughes static Environment env;
102*07fb1d06SElliott Hughes
103*07fb1d06SElliott Hughes FuzzPuffPatch(data, size);
104*07fb1d06SElliott Hughes return 0;
105*07fb1d06SElliott Hughes }
106