aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHaibo Huang <hhb@google.com>2020-01-08 15:06:08 -0800
committerHaibo Huang <hhb@google.com>2020-01-08 15:06:08 -0800
commit7eae75fbc6bbf8803e915829a9c904f63968bf96 (patch)
tree8acbee52ff99335d6ea02a93ae661067b6bfeaef
parent59b168c66e67609fd2e5af390f4eba8e73ac6943 (diff)
parent69d93082200bb657f6db9c6b07b71bb94ea7bb47 (diff)
downloadlibprotobuf-mutator-7eae75fbc6bbf8803e915829a9c904f63968bf96.tar.gz
Upgrade libprotobuf-mutator to 69d93082200bb657f6db9c6b07b71bb94ea7bb47android-r-preview-1
Test: None Change-Id: I70e85bc40665b0bf6eaeb692cc0d47be506f65f7
-rw-r--r--METADATA8
-rw-r--r--README.md23
-rw-r--r--src/libfuzzer/libfuzzer_macro.cc5
-rw-r--r--src/libfuzzer/libfuzzer_macro.h9
-rw-r--r--src/mutator.cc47
-rw-r--r--src/mutator.h9
-rw-r--r--src/mutator_test.cc3
7 files changed, 82 insertions, 22 deletions
diff --git a/METADATA b/METADATA
index 975ee06..26788ce 100644
--- a/METADATA
+++ b/METADATA
@@ -5,11 +5,11 @@ third_party {
type: GIT
value: "https://github.com/google/libprotobuf-mutator"
}
- version: "62c5c91a2bfd675fa99cf61f6747fd227da8983a"
+ version: "69d93082200bb657f6db9c6b07b71bb94ea7bb47"
license_type: NOTICE
last_upgrade_date {
- year: 2019
- month: 9
- day: 28
+ year: 2020
+ month: 1
+ day: 8
}
}
diff --git a/README.md b/README.md
index 02683cd..842214e 100644
--- a/README.md
+++ b/README.md
@@ -88,6 +88,29 @@ DEFINE_PROTO_FUZZER(const MyMessageType& input) {
Please see [libfuzzer_example.cc](/examples/libfuzzer/libfuzzer_example.cc) as an example.
+### Mutation post-processing (experimental)
+Sometimes it's necessary to keep particular values in some fields without which the proto
+is going to be rejected by fuzzed code. E.g. code may expect consistency between some fields
+or it may use some fields as checksums. Such constraints are going to be significant bottleneck
+for fuzzer even if it's capable of inserting acceptable values with time.
+
+PostProcessorRegistration can be used to avoid such issue and guide your fuzzer towards interesing
+code. It registers callback which will be called for each message of particular type after each mutation.
+
+```
+DEFINE_PROTO_FUZZER(const MyMessageType& input) {
+ static PostProcessorRegistration reg = {
+ [](MyMessageType* message, unsigned int seed) {
+ TweakMyMessageType(message, seed);
+ }};
+
+ // Code which needs to be fuzzed.
+ ConsumeMyMessageType(input);
+}
+```
+
+Optional: Use seed if callback uses random numbers. It may help later with debugging.
+
## UTF-8 strings
"proto2" and "proto3" handle invalid UTF-8 strings differently. In both cases
string should be UTF-8, however only "proto3" enforces that. So if fuzzer is
diff --git a/src/libfuzzer/libfuzzer_macro.cc b/src/libfuzzer/libfuzzer_macro.cc
index 5f9023f..c37276d 100644
--- a/src/libfuzzer/libfuzzer_macro.cc
+++ b/src/libfuzzer/libfuzzer_macro.cc
@@ -184,10 +184,11 @@ bool LoadProtoInput(bool binary, const uint8_t* data, size_t size,
: ParseTextMessage(data, size, input);
}
-void RegisterPostProcessorImpl(
+void RegisterPostProcessor(
+ const protobuf::Descriptor* desc,
std::function<void(protobuf::Message* message, unsigned int seed)>
callback) {
- GetMutator()->RegisterPostProcessor(callback);
+ GetMutator()->RegisterPostProcessor(desc, callback);
}
} // namespace libfuzzer
diff --git a/src/libfuzzer/libfuzzer_macro.h b/src/libfuzzer/libfuzzer_macro.h
index a7d26ab..1a1fe0a 100644
--- a/src/libfuzzer/libfuzzer_macro.h
+++ b/src/libfuzzer/libfuzzer_macro.h
@@ -106,7 +106,8 @@ size_t CustomProtoCrossOver(bool binary, const uint8_t* data1, size_t size1,
bool LoadProtoInput(bool binary, const uint8_t* data, size_t size,
protobuf::Message* input);
-void RegisterPostProcessorImpl(
+void RegisterPostProcessor(
+ const protobuf::Descriptor* desc,
std::function<void(protobuf::Message* message, unsigned int seed)>
callback);
@@ -114,9 +115,9 @@ template <class Proto>
struct PostProcessorRegistration {
PostProcessorRegistration(
const std::function<void(Proto* message, unsigned int seed)>& callback) {
- protobuf_mutator::libfuzzer::RegisterPostProcessorImpl(
- [callback](protobuf_mutator::protobuf::Message* message,
- unsigned int seed) {
+ RegisterPostProcessor(
+ Proto::descriptor(),
+ [callback](protobuf::Message* message, unsigned int seed) {
callback(static_cast<Proto*>(message), seed);
});
}
diff --git a/src/mutator.cc b/src/mutator.cc
index e3c9b39..e4e0305 100644
--- a/src/mutator.cc
+++ b/src/mutator.cc
@@ -457,7 +457,43 @@ void Mutator::Mutate(Message* message, size_t size_increase_hint) {
InitializeAndTrim(message, kMaxInitializeDepth);
assert(!keep_initialized_ || message->IsInitialized());
- if (post_process_) post_process_(message, random_());
+ if (!post_processors_.empty()) {
+ ApplyPostProcessing(message);
+ }
+}
+
+void Mutator::RegisterPostProcessor(const protobuf::Descriptor* desc,
+ PostProcess callback) {
+ post_processors_.emplace(desc, callback);
+}
+
+void Mutator::ApplyPostProcessing(Message* message) {
+ const Descriptor* descriptor = message->GetDescriptor();
+
+ auto it = post_processors_.find(descriptor);
+ if (it != post_processors_.end()) {
+ it->second(message, random_());
+ }
+
+ // Now recursively apply custom mutators.
+ const Reflection* reflection = message->GetReflection();
+ for (int i = 0; i < descriptor->field_count(); i++) {
+ const FieldDescriptor* field = descriptor->field(i);
+ if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
+ continue;
+ }
+ if (field->is_repeated()) {
+ const int field_size = reflection->FieldSize(*message, field);
+ for (int j = 0; j < field_size; ++j) {
+ Message* nested_message =
+ reflection->MutableRepeatedMessage(message, field, j);
+ ApplyPostProcessing(nested_message);
+ }
+ } else if (reflection->HasField(*message, field)) {
+ Message* nested_message = reflection->MutableMessage(message, field);
+ ApplyPostProcessing(nested_message);
+ }
+ }
}
void Mutator::MutateImpl(Message* message, size_t size_increase_hint) {
@@ -500,7 +536,9 @@ void Mutator::CrossOver(const protobuf::Message& message1,
InitializeAndTrim(message2, kMaxInitializeDepth);
assert(!keep_initialized_ || message2->IsInitialized());
- if (post_process_) post_process_(message2, random_());
+ if (!post_processors_.empty()) {
+ ApplyPostProcessing(message2);
+ }
// Can't call mutate from crossover because of a bug in libFuzzer.
// if (MessageDifferencer::Equals(*message2_copy, *message2) ||
@@ -582,11 +620,6 @@ void Mutator::CrossOverImpl(const protobuf::Message& message1,
}
}
-void Mutator::RegisterPostProcessor(PostProcess post_process) {
- assert(!post_process_);
- post_process_ = post_process;
-}
-
void Mutator::InitializeAndTrim(Message* message, int max_depth) {
const Descriptor* descriptor = message->GetDescriptor();
const Reflection* reflection = message->GetReflection();
diff --git a/src/mutator.h b/src/mutator.h
index 73e1966..7af7b38 100644
--- a/src/mutator.h
+++ b/src/mutator.h
@@ -70,7 +70,8 @@ class Mutator {
// Register callback which will be called after every message mutation.
// In this callback fuzzer may adjust content of the message or mutate some
// fields in some fuzzer specific way.
- void RegisterPostProcessor(PostProcess post_process);
+ void RegisterPostProcessor(const protobuf::Descriptor* desc,
+ PostProcess callback);
protected:
// TODO(vitalybuka): Consider to replace with single mutate (uint8_t*, size).
@@ -85,6 +86,8 @@ class Mutator {
virtual std::string MutateString(const std::string& value,
size_t size_increase_hint);
+ std::unordered_map<const protobuf::Descriptor*, PostProcess> post_processors_;
+
RandomEngine* random() { return &random_; }
private:
@@ -96,12 +99,10 @@ class Mutator {
protobuf::Message* message2);
std::string MutateUtf8String(const std::string& value,
size_t size_increase_hint);
- bool ApplyCustomMutations(protobuf::Message* message,
- const protobuf::FieldDescriptor* field);
+ void ApplyPostProcessing(protobuf::Message* message);
bool keep_initialized_ = true;
size_t random_to_default_ratio_ = 100;
RandomEngine random_;
- PostProcess post_process_;
};
} // namespace protobuf_mutator
diff --git a/src/mutator_test.cc b/src/mutator_test.cc
index 0ae37aa..a86760a 100644
--- a/src/mutator_test.cc
+++ b/src/mutator_test.cc
@@ -593,7 +593,8 @@ TYPED_TEST(MutatorTypedTest, RegisterPostProcessor) {
TestMutator mutator(false);
mutator.RegisterPostProcessor(
- [kIndicatorString](protobuf::Message* message, uint32_t seed) {
+ TestFixture::Message::descriptor(),
+ [kIndicatorString](protobuf::Message* message, unsigned int seed) {
typename TestFixture::Message* test_message =
static_cast<typename TestFixture::Message*>(message);
if (seed % 2) test_message->set_optional_string(kIndicatorString);