1 // Copyright 2017 Google Inc. All rights reserved.
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 "src/libfuzzer/libfuzzer_macro.h"
16
17 #include <algorithm>
18
19 #include "src/binary_format.h"
20 #include "src/libfuzzer/libfuzzer_mutator.h"
21 #include "src/text_format.h"
22
23 namespace protobuf_mutator {
24 namespace libfuzzer {
25
26 namespace {
27
28 class InputReader {
29 public:
InputReader(const uint8_t * data,size_t size)30 InputReader(const uint8_t* data, size_t size) : data_(data), size_(size) {}
31 virtual ~InputReader() = default;
32
33 virtual bool Read(protobuf::Message* message) const = 0;
34
data() const35 const uint8_t* data() const { return data_; }
size() const36 size_t size() const { return size_; }
37
38 private:
39 const uint8_t* data_;
40 size_t size_;
41 };
42
43 class OutputWriter {
44 public:
OutputWriter(uint8_t * data,size_t size)45 OutputWriter(uint8_t* data, size_t size) : data_(data), size_(size) {}
46 virtual ~OutputWriter() = default;
47
48 virtual size_t Write(const protobuf::Message& message) = 0;
49
data() const50 uint8_t* data() const { return data_; }
size() const51 size_t size() const { return size_; }
52
53 private:
54 uint8_t* data_;
55 size_t size_;
56 };
57
58 class TextInputReader : public InputReader {
59 public:
60 using InputReader::InputReader;
61
Read(protobuf::Message * message) const62 bool Read(protobuf::Message* message) const override {
63 return ParseTextMessage(data(), size(), message);
64 }
65 };
66
67 class TextOutputWriter : public OutputWriter {
68 public:
69 using OutputWriter::OutputWriter;
70
Write(const protobuf::Message & message)71 size_t Write(const protobuf::Message& message) override {
72 return SaveMessageAsText(message, data(), size());
73 }
74 };
75
76 class BinaryInputReader : public InputReader {
77 public:
78 using InputReader::InputReader;
79
Read(protobuf::Message * message) const80 bool Read(protobuf::Message* message) const override {
81 return ParseBinaryMessage(data(), size(), message);
82 }
83 };
84
85 class BinaryOutputWriter : public OutputWriter {
86 public:
87 using OutputWriter::OutputWriter;
88
Write(const protobuf::Message & message)89 size_t Write(const protobuf::Message& message) override {
90 return SaveMessageAsBinary(message, data(), size());
91 }
92 };
93
GetMutator()94 Mutator* GetMutator() {
95 static Mutator mutator;
96 return &mutator;
97 }
98
GetMaxSize(const InputReader & input,const OutputWriter & output,const protobuf::Message & message)99 size_t GetMaxSize(const InputReader& input, const OutputWriter& output,
100 const protobuf::Message& message) {
101 size_t max_size = message.ByteSizeLong() + output.size();
102 max_size -= std::min(max_size, input.size());
103 return max_size;
104 }
105
MutateMessage(unsigned int seed,const InputReader & input,OutputWriter * output,protobuf::Message * message)106 size_t MutateMessage(unsigned int seed, const InputReader& input,
107 OutputWriter* output, protobuf::Message* message) {
108 GetMutator()->Seed(seed);
109 input.Read(message);
110 size_t max_size = GetMaxSize(input, *output, *message);
111 GetMutator()->Mutate(message, max_size);
112 if (size_t new_size = output->Write(*message)) {
113 assert(new_size <= output->size());
114 return new_size;
115 }
116 return 0;
117 }
118
CrossOverMessages(unsigned int seed,const InputReader & input1,const InputReader & input2,OutputWriter * output,protobuf::Message * message1,protobuf::Message * message2)119 size_t CrossOverMessages(unsigned int seed, const InputReader& input1,
120 const InputReader& input2, OutputWriter* output,
121 protobuf::Message* message1,
122 protobuf::Message* message2) {
123 GetMutator()->Seed(seed);
124 input1.Read(message1);
125 input2.Read(message2);
126 size_t max_size = GetMaxSize(input1, *output, *message1);
127 GetMutator()->CrossOver(*message2, message1, max_size);
128 if (size_t new_size = output->Write(*message1)) {
129 assert(new_size <= output->size());
130 return new_size;
131 }
132 return 0;
133 }
134
MutateTextMessage(uint8_t * data,size_t size,size_t max_size,unsigned int seed,protobuf::Message * message)135 size_t MutateTextMessage(uint8_t* data, size_t size, size_t max_size,
136 unsigned int seed, protobuf::Message* message) {
137 TextInputReader input(data, size);
138 TextOutputWriter output(data, max_size);
139 return MutateMessage(seed, input, &output, message);
140 }
141
CrossOverTextMessages(const uint8_t * data1,size_t size1,const uint8_t * data2,size_t size2,uint8_t * out,size_t max_out_size,unsigned int seed,protobuf::Message * message1,protobuf::Message * message2)142 size_t CrossOverTextMessages(const uint8_t* data1, size_t size1,
143 const uint8_t* data2, size_t size2, uint8_t* out,
144 size_t max_out_size, unsigned int seed,
145 protobuf::Message* message1,
146 protobuf::Message* message2) {
147 TextInputReader input1(data1, size1);
148 TextInputReader input2(data2, size2);
149 TextOutputWriter output(out, max_out_size);
150 return CrossOverMessages(seed, input1, input2, &output, message1, message2);
151 }
152
MutateBinaryMessage(uint8_t * data,size_t size,size_t max_size,unsigned int seed,protobuf::Message * message)153 size_t MutateBinaryMessage(uint8_t* data, size_t size, size_t max_size,
154 unsigned int seed, protobuf::Message* message) {
155 BinaryInputReader input(data, size);
156 BinaryOutputWriter output(data, max_size);
157 return MutateMessage(seed, input, &output, message);
158 }
159
CrossOverBinaryMessages(const uint8_t * data1,size_t size1,const uint8_t * data2,size_t size2,uint8_t * out,size_t max_out_size,unsigned int seed,protobuf::Message * message1,protobuf::Message * message2)160 size_t CrossOverBinaryMessages(const uint8_t* data1, size_t size1,
161 const uint8_t* data2, size_t size2, uint8_t* out,
162 size_t max_out_size, unsigned int seed,
163 protobuf::Message* message1,
164 protobuf::Message* message2) {
165 BinaryInputReader input1(data1, size1);
166 BinaryInputReader input2(data2, size2);
167 BinaryOutputWriter output(out, max_out_size);
168 return CrossOverMessages(seed, input1, input2, &output, message1, message2);
169 }
170
171 } // namespace
172
CustomProtoMutator(bool binary,uint8_t * data,size_t size,size_t max_size,unsigned int seed,protobuf::Message * input)173 size_t CustomProtoMutator(bool binary, uint8_t* data, size_t size,
174 size_t max_size, unsigned int seed,
175 protobuf::Message* input) {
176 auto mutate = binary ? &MutateBinaryMessage : &MutateTextMessage;
177 return mutate(data, size, max_size, seed, input);
178 }
179
CustomProtoCrossOver(bool binary,const uint8_t * data1,size_t size1,const uint8_t * data2,size_t size2,uint8_t * out,size_t max_out_size,unsigned int seed,protobuf::Message * input1,protobuf::Message * input2)180 size_t CustomProtoCrossOver(bool binary, const uint8_t* data1, size_t size1,
181 const uint8_t* data2, size_t size2, uint8_t* out,
182 size_t max_out_size, unsigned int seed,
183 protobuf::Message* input1,
184 protobuf::Message* input2) {
185 auto cross = binary ? &CrossOverBinaryMessages : &CrossOverTextMessages;
186 return cross(data1, size1, data2, size2, out, max_out_size, seed, input1,
187 input2);
188 }
189
LoadProtoInput(bool binary,const uint8_t * data,size_t size,protobuf::Message * input)190 bool LoadProtoInput(bool binary, const uint8_t* data, size_t size,
191 protobuf::Message* input) {
192 return binary ? ParseBinaryMessage(data, size, input)
193 : ParseTextMessage(data, size, input);
194 }
195
RegisterPostProcessor(const protobuf::Descriptor * desc,std::function<void (protobuf::Message * message,unsigned int seed)> callback)196 void RegisterPostProcessor(
197 const protobuf::Descriptor* desc,
198 std::function<void(protobuf::Message* message, unsigned int seed)>
199 callback) {
200 GetMutator()->RegisterPostProcessor(desc, callback);
201 }
202
203 } // namespace libfuzzer
204 } // namespace protobuf_mutator
205