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 = \ 88 protobuf_mutator::libfuzzer::macro_internal::GetFirstParam< \ 89 decltype(&TestOneProtoInput)>::type; \ 90 DEFINE_CUSTOM_PROTO_MUTATOR_IMPL(use_binary, FuzzerProtoType) \ 91 DEFINE_CUSTOM_PROTO_CROSSOVER_IMPL(use_binary, FuzzerProtoType) \ 92 DEFINE_TEST_ONE_PROTO_INPUT_IMPL(use_binary, FuzzerProtoType) \ 93 DEFINE_POST_PROCESS_PROTO_MUTATION_IMPL(FuzzerProtoType) \ 94 static void TestOneProtoInput(arg) 95 96 namespace protobuf_mutator { 97 namespace libfuzzer { 98 99 size_t CustomProtoMutator(bool binary, uint8_t* data, size_t size, 100 size_t max_size, unsigned int seed, 101 protobuf::Message* input); 102 size_t CustomProtoCrossOver(bool binary, const uint8_t* data1, size_t size1, 103 const uint8_t* data2, size_t size2, uint8_t* out, 104 size_t max_out_size, unsigned int seed, 105 protobuf::Message* input1, 106 protobuf::Message* input2); 107 bool LoadProtoInput(bool binary, const uint8_t* data, size_t size, 108 protobuf::Message* input); 109 110 void RegisterPostProcessor( 111 const protobuf::Descriptor* desc, 112 std::function<void(protobuf::Message* message, unsigned int seed)> 113 callback); 114 115 template <class Proto> 116 struct PostProcessorRegistration { PostProcessorRegistrationPostProcessorRegistration117 PostProcessorRegistration( 118 const std::function<void(Proto* message, unsigned int seed)>& callback) { 119 RegisterPostProcessor( 120 Proto::descriptor(), 121 [callback](protobuf::Message* message, unsigned int seed) { 122 callback(static_cast<Proto*>(message), seed); 123 }); 124 } 125 }; 126 127 namespace macro_internal { 128 129 template <typename T> 130 struct GetFirstParam; 131 132 template <class Arg> 133 struct GetFirstParam<void (*)(Arg)> { 134 using type = typename std::remove_const< 135 typename std::remove_reference<Arg>::type>::type; 136 }; 137 138 } // namespace macro_internal 139 140 } // namespace libfuzzer 141 } // namespace protobuf_mutator 142 143 #endif // SRC_LIBFUZZER_LIBFUZZER_MACRO_H_ 144