1 // Copyright 2019 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <fuzzer/FuzzedDataProvider.h>
16
17 #include <cstdint>
18 #include <cstdio>
19 #include <cstdlib>
20 #include <memory>
21 #include <vector>
22
23 #include "lzo1.h"
24 #include "lzo1a.h"
25 #include "lzo1b.h"
26 #include "lzo1c.h"
27 #include "lzo1f.h"
28 #include "lzo1x.h"
29 #include "lzo1y.h"
30 #include "lzo1z.h"
31 #include "lzo2a.h"
32 #include "lzoconf.h"
33
34 namespace {
35
36 struct LzoAlgorithm {
37 enum class Category { LZO1, LZO2 };
38 enum class Type {
39 LZO1,
40 LZO1A,
41 LZO1B,
42 LZO1C,
43 LZO1F,
44 LZO1X,
45 LZO1Y,
46 LZO1Z,
47 LZO2A
48 };
49
LzoAlgorithm__anonc6b672860111::LzoAlgorithm50 constexpr LzoAlgorithm(Category category, Type type, int compression_level,
51 int memory_level, lzo_compress_t compress_fn,
52 lzo_decompress_t decompress_fn,
53 size_t working_memory_size)
54 : category(category),
55 type(type),
56 compression_level(compression_level),
57 memory_level(memory_level),
58 compress_fn(compress_fn),
59 decompress_fn(decompress_fn),
60 working_memory_size(working_memory_size) {}
61
GetMaxCompressedSize__anonc6b672860111::LzoAlgorithm62 size_t GetMaxCompressedSize(size_t size) const {
63 // Formula taken from the LZO FAQ.
64 switch (category) {
65 case Category::LZO1:
66 return size + (size / 16) + 64 + 3;
67 case Category::LZO2:
68 return size + (size / 8) + 128 + 3;
69 }
70 }
71
72 Category category;
73 Type type;
74 int compression_level;
75 int memory_level;
76
77 lzo_compress_t compress_fn;
78 lzo_decompress_t decompress_fn;
79 size_t working_memory_size;
80 };
81
GetLzoAlgorithms()82 static const std::vector<std::vector<LzoAlgorithm>>& GetLzoAlgorithms() {
83 static auto* algorithms = new std::vector<std::vector<LzoAlgorithm>>{
84 {
85 LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1,
86 0, 0, lzo1_compress, lzo1_decompress, LZO1_MEM_COMPRESS),
87 LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1,
88 99, 0, lzo1_99_compress, lzo1_decompress,
89 LZO1_99_MEM_COMPRESS),
90 },
91 {
92 LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1A,
93 0, 0, lzo1a_compress, lzo1a_decompress,
94 LZO1A_MEM_COMPRESS),
95 LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1A,
96 99, 0, lzo1a_99_compress, lzo1a_decompress,
97 LZO1A_99_MEM_COMPRESS),
98 },
99 {
100 LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1B,
101 1, 0, lzo1b_1_compress, lzo1b_decompress,
102 LZO1B_MEM_COMPRESS),
103 LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1B,
104 2, 0, lzo1b_2_compress, lzo1b_decompress,
105 LZO1B_MEM_COMPRESS),
106 LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1B,
107 3, 0, lzo1b_3_compress, lzo1b_decompress,
108 LZO1B_MEM_COMPRESS),
109 LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1B,
110 4, 0, lzo1b_4_compress, lzo1b_decompress,
111 LZO1B_MEM_COMPRESS),
112 LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1B,
113 5, 0, lzo1b_5_compress, lzo1b_decompress,
114 LZO1B_MEM_COMPRESS),
115 LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1B,
116 6, 0, lzo1b_6_compress, lzo1b_decompress,
117 LZO1B_MEM_COMPRESS),
118 LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1B,
119 7, 0, lzo1b_7_compress, lzo1b_decompress,
120 LZO1B_MEM_COMPRESS),
121 LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1B,
122 8, 0, lzo1b_8_compress, lzo1b_decompress,
123 LZO1B_MEM_COMPRESS),
124 LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1B,
125 9, 0, lzo1b_9_compress, lzo1b_decompress,
126 LZO1B_MEM_COMPRESS),
127 LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1B,
128 99, 0, lzo1b_99_compress, lzo1b_decompress,
129 LZO1B_99_MEM_COMPRESS),
130 LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1B,
131 999, 0, lzo1b_999_compress, lzo1b_decompress,
132 LZO1B_999_MEM_COMPRESS),
133 },
134 {
135 LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1C,
136 1, 0, lzo1c_1_compress, lzo1c_decompress,
137 LZO1C_MEM_COMPRESS),
138 LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1C,
139 5, 0, lzo1c_5_compress, lzo1c_decompress,
140 LZO1C_MEM_COMPRESS),
141 LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1C,
142 9, 0, lzo1c_9_compress, lzo1c_decompress,
143 LZO1C_MEM_COMPRESS),
144 LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1C,
145 99, 0, lzo1c_99_compress, lzo1c_decompress,
146 LZO1C_99_MEM_COMPRESS),
147 LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1C,
148 999, 0, lzo1c_999_compress, lzo1c_decompress,
149 LZO1C_999_MEM_COMPRESS),
150 },
151 {
152 LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1F,
153 1, 0, lzo1f_1_compress, lzo1f_decompress,
154 LZO1F_MEM_COMPRESS),
155 LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1F,
156 999, 0, lzo1f_999_compress, lzo1f_decompress,
157 LZO1F_999_MEM_COMPRESS),
158 },
159 {
160 LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1X,
161 1, 0, lzo1x_1_compress, lzo1x_decompress,
162 LZO1X_1_MEM_COMPRESS),
163 LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1X,
164 1, 11, lzo1x_1_11_compress, lzo1x_decompress,
165 LZO1X_1_11_MEM_COMPRESS),
166 LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1X,
167 1, 12, lzo1x_1_12_compress, lzo1x_decompress,
168 LZO1X_1_12_MEM_COMPRESS),
169 LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1X,
170 1, 15, lzo1x_1_15_compress, lzo1x_decompress,
171 LZO1X_1_15_MEM_COMPRESS),
172 LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1X,
173 999, 0, lzo1x_999_compress, lzo1x_decompress,
174 LZO1X_999_MEM_COMPRESS),
175 },
176 {
177 LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1Y,
178 1, 0, lzo1y_1_compress, lzo1y_decompress,
179 LZO1Y_MEM_COMPRESS),
180 LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1Y,
181 999, 0, lzo1y_999_compress, lzo1y_decompress,
182 LZO1Y_999_MEM_COMPRESS),
183 },
184 {
185 LzoAlgorithm(LzoAlgorithm::Category::LZO1, LzoAlgorithm::Type::LZO1Z,
186 999, 0, lzo1z_999_compress, lzo1z_decompress,
187 LZO1Z_999_MEM_COMPRESS),
188 },
189 {
190 LzoAlgorithm(LzoAlgorithm::Category::LZO2, LzoAlgorithm::Type::LZO2A,
191 999, 0, lzo2a_999_compress, lzo2a_decompress,
192 LZO2A_999_MEM_COMPRESS),
193 },
194 };
195 return *algorithms;
196 }
197
FuzzLzoAlgorithm(const LzoAlgorithm & algorithm,const std::vector<uint8_t> & input_buffer)198 void FuzzLzoAlgorithm(const LzoAlgorithm& algorithm,
199 const std::vector<uint8_t>& input_buffer) {
200 std::unique_ptr<uint8_t[]> working_buffer(
201 new uint8_t[algorithm.working_memory_size]);
202 std::unique_ptr<uint8_t[]> compressed_buffer(
203 new uint8_t[algorithm.GetMaxCompressedSize(input_buffer.size())]);
204
205 lzo_uint compressed_size;
206 if (algorithm.compress_fn(input_buffer.data(), input_buffer.size(),
207 compressed_buffer.get(), &compressed_size,
208 working_buffer.get()) != LZO_E_OK) {
209 abort();
210 }
211
212 std::unique_ptr<uint8_t[]> decompressed_buffer(
213 new uint8_t[input_buffer.size()]);
214 lzo_uint decompressed_size;
215 if (algorithm.decompress_fn(compressed_buffer.get(), compressed_size,
216 decompressed_buffer.get(), &decompressed_size,
217 nullptr) != LZO_E_OK) {
218 abort();
219 }
220
221 if (decompressed_size != input_buffer.size()) {
222 fprintf(stderr, "Decompressed size %zu does not match original size %zu.\n",
223 decompressed_size, input_buffer.size());
224 abort();
225 } else if (memcmp(input_buffer.data(), decompressed_buffer.get(),
226 input_buffer.size()) != 0) {
227 fprintf(stderr,
228 "Decompressed buffer does not match original buffer of size %zu.\n",
229 input_buffer.size());
230 abort();
231 }
232 }
233
234 } // namespace
235
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)236 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
237 static bool initialized __attribute__((unused)) = []() {
238 if (lzo_init() != LZO_E_OK) {
239 abort();
240 }
241 return true;
242 }();
243
244 FuzzedDataProvider data_provider(data, size);
245 const auto& algorithms = GetLzoAlgorithms();
246 const auto first_level_index =
247 data_provider.ConsumeIntegralInRange<size_t>(0, algorithms.size() - 1);
248 const auto& algorithm_group = algorithms[first_level_index];
249 const auto second_level_index = data_provider.ConsumeIntegralInRange<size_t>(
250 0, algorithm_group.size() - 1);
251 const std::vector<uint8_t> input_buffer =
252 data_provider.ConsumeRemainingBytes<uint8_t>();
253 FuzzLzoAlgorithm(algorithm_group[second_level_index], input_buffer);
254 return 0;
255 }
256