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 #ifndef SRC_LIBFUZZER_LIBFUZZER_MACRO_H_ 16 #define SRC_LIBFUZZER_LIBFUZZER_MACRO_H_ 17 18 #include <stddef.h> 19 20 #include <cstdint> 21 #include <functional> 22 #include <type_traits> 23 24 #include "port/protobuf.h" 25 26 // Defines custom mutator, crossover and test functions using default 27 // serialization format. Default is text. 28 #define DEFINE_PROTO_FUZZER(arg) DEFINE_TEXT_PROTO_FUZZER(arg) 29 // Defines custom mutator, crossover and test functions using text 30 // serialization. This format is more convenient to read. 31 #define DEFINE_TEXT_PROTO_FUZZER(arg) DEFINE_PROTO_FUZZER_IMPL(false, arg) 32 // Defines custom mutator, crossover and test functions using binary 33 // serialization. This makes mutations faster. However often test function is 34 // significantly slower than mutator, so fuzzing rate may stay unchanged. 35 #define DEFINE_BINARY_PROTO_FUZZER(arg) DEFINE_PROTO_FUZZER_IMPL(true, arg) 36 37 // Registers the callback as a potential mutation performed on the parent 38 // message of a field. This must be called inside an initialization code block. 39 // libFuzzer suggests putting one-time-initialization in a function used to 40 // initialize a static variable inside the fuzzer target. For example: 41 // 42 // static bool Modify( 43 // SomeMessage* message /* Fix or additionally modify the message */, 44 // unsigned int seed /* If random generator is needed use this seed */) { 45 // ... 46 // } 47 // 48 // DEFINE_PROTO_FUZZER(const SomeMessage& msg) { 49 // static PostProcessorRegistration reg(&Modify); 50 // } 51 52 // Implementation of macros above. 53 #define DEFINE_CUSTOM_PROTO_MUTATOR_IMPL(use_binary, Proto) \ 54 extern "C" size_t LLVMFuzzerCustomMutator( \ 55 uint8_t* data, size_t size, size_t max_size, unsigned int seed) { \ 56 using protobuf_mutator::libfuzzer::CustomProtoMutator; \ 57 Proto input; \ 58 return CustomProtoMutator(use_binary, data, size, max_size, seed, &input); \ 59 } 60 61 #define DEFINE_CUSTOM_PROTO_CROSSOVER_IMPL(use_binary, Proto) \ 62 extern "C" size_t LLVMFuzzerCustomCrossOver( \ 63 const uint8_t* data1, size_t size1, const uint8_t* data2, size_t size2, \ 64 uint8_t* out, size_t max_out_size, unsigned int seed) { \ 65 using protobuf_mutator::libfuzzer::CustomProtoCrossOver; \ 66 Proto input1; \ 67 Proto input2; \ 68 return CustomProtoCrossOver(use_binary, data1, size1, data2, size2, out, \ 69 max_out_size, seed, &input1, &input2); \ 70 } 71 72 #define DEFINE_TEST_ONE_PROTO_INPUT_IMPL(use_binary, Proto) \ 73 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { \ 74 using protobuf_mutator::libfuzzer::LoadProtoInput; \ 75 Proto input; \ 76 if (LoadProtoInput(use_binary, data, size, &input)) \ 77 TestOneProtoInput(input); \ 78 return 0; \ 79 } 80 81 #define DEFINE_POST_PROCESS_PROTO_MUTATION_IMPL(Proto) \ 82 using PostProcessorRegistration = \ 83 protobuf_mutator::libfuzzer::PostProcessorRegistration<Proto>; 84 85 #define DEFINE_PROTO_FUZZER_IMPL(use_binary, arg) \ 86 static void TestOneProtoInput(arg); \ 87 using FuzzerProtoType = std::remove_const<std::remove_reference< \ 88 std::function<decltype(TestOneProtoInput)>::argument_type>::type>::type; \ 89 DEFINE_CUSTOM_PROTO_MUTATOR_IMPL(use_binary, FuzzerProtoType) \ 90 DEFINE_CUSTOM_PROTO_CROSSOVER_IMPL(use_binary, FuzzerProtoType) \ 91 DEFINE_TEST_ONE_PROTO_INPUT_IMPL(use_binary, FuzzerProtoType) \ 92 DEFINE_POST_PROCESS_PROTO_MUTATION_IMPL(FuzzerProtoType) \ 93 static void TestOneProtoInput(arg) 94 95 namespace protobuf_mutator { 96 namespace libfuzzer { 97 98 size_t CustomProtoMutator(bool binary, uint8_t* data, size_t size, 99 size_t max_size, unsigned int seed, 100 protobuf::Message* input); 101 size_t CustomProtoCrossOver(bool binary, const uint8_t* data1, size_t size1, 102 const uint8_t* data2, size_t size2, uint8_t* out, 103 size_t max_out_size, unsigned int seed, 104 protobuf::Message* input1, 105 protobuf::Message* input2); 106 bool LoadProtoInput(bool binary, const uint8_t* data, size_t size, 107 protobuf::Message* input); 108 109 void RegisterPostProcessor( 110 const protobuf::Descriptor* desc, 111 std::function<void(protobuf::Message* message, unsigned int seed)> 112 callback); 113 114 template <class Proto> 115 struct PostProcessorRegistration { PostProcessorRegistrationPostProcessorRegistration116 PostProcessorRegistration( 117 const std::function<void(Proto* message, unsigned int seed)>& callback) { 118 RegisterPostProcessor( 119 Proto::descriptor(), 120 [callback](protobuf::Message* message, unsigned int seed) { 121 callback(static_cast<Proto*>(message), seed); 122 }); 123 } 124 }; 125 126 } // namespace libfuzzer 127 } // namespace protobuf_mutator 128 129 #endif // SRC_LIBFUZZER_LIBFUZZER_MACRO_H_ 130