Skip to content

Commit

Permalink
Pass mutation metadata from the domain mutation to LLVMFuzzerMutate.
Browse files Browse the repository at this point in the history
To avoid memory safety issues, a manager class is added to restrict the access of the metadata to be only available during the domain mutator's invocation to `LLVMFuzzerCustomMutator`

PiperOrigin-RevId: 704343455
  • Loading branch information
xinhaoyuan authored and copybara-github committed Dec 9, 2024
1 parent 194e390 commit 117570f
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 9 deletions.
5 changes: 4 additions & 1 deletion fuzztest/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -155,15 +155,18 @@ cc_library(
testonly = True,
srcs = ["llvm_fuzzer_wrapper.cc"],
deps = [
":coverage",
":domain_core",
":fuzztest",
":fuzztest_macros",
":io",
":logging",
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/base:no_destructor",
"@com_google_absl//absl/flags:flag",
"@com_google_absl//absl/log:check",
"@com_google_absl//absl/random",
"@com_google_absl//absl/random:bit_gen_ref",
"@com_google_absl//absl/synchronization",
],
alwayslink = True,
)
Expand Down
4 changes: 4 additions & 0 deletions fuzztest/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -128,12 +128,16 @@ fuzztest_cc_library(
fuzztest::fuzztest
fuzztest::io
fuzztest::llvm_fuzzer_main
fuzztest::logging
absl::core_headers
absl::flags
absl::log
absl::no_destructor
absl::random_random
absl::random_bit_gen_ref
absl::strings
absl::string_view
absl::synchronization
re2::re2
)

Expand Down
89 changes: 81 additions & 8 deletions fuzztest/llvm_fuzzer_wrapper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,26 @@
#include <cstdint>
#include <cstdlib>
#include <iostream>
#include <optional>
#include <string>
#include <utility>
#include <vector>

#include "absl/base/no_destructor.h"
#include "absl/base/thread_annotations.h"
#include "absl/flags/declare.h"
#include "absl/flags/flag.h"
#include "absl/log/check.h"
#include "absl/random/bit_gen_ref.h"
#include "absl/random/random.h"
#include "absl/synchronization/mutex.h"
#include "./fuzztest/fuzztest.h"
#include "./fuzztest/fuzztest_macros.h"
#include "./fuzztest/internal/domains/arbitrary_impl.h"
#include "./fuzztest/internal/domains/container_of_impl.h"
#include "./fuzztest/internal/domains/domain_base.h"
#include "./fuzztest/internal/io.h"
#include "./fuzztest/internal/coverage.h"
#include "./fuzztest/internal/logging.h"

ABSL_DECLARE_FLAG(std::string, llvm_fuzzer_wrapper_dict_file);
ABSL_DECLARE_FLAG(std::string, llvm_fuzzer_wrapper_corpus_dir);
Expand Down Expand Up @@ -125,6 +130,76 @@ class InplaceVector {
std::size_t size_;
};

namespace {

using ::fuzztest::domain_implementor::MutationMetadata;

// Manager that controls the access of mutation metadata for
// LLVMFuzzerMutate/LLVMFuzzerCustomMutator.
//
// The metadata is supposed to be active only when FuzzTest is calling
// LLVMFuzzerCustomMutator.
//
// If the metadata is active, `Acquire` would return a non-null metadata
// pointer, and the caller should call `Release` after the metadata usage.
// If the metadata is inactive, `Acquire` would abort - this would only happen
// when the fuzzer calls `LLVMFuzzerMutate` outside of
// `LLVMFuzzerCustomMutator`.
class LLVMFuzzerMutateMetadataManager {
public:
void Activate(MutationMetadata mutation_metadata) {
absl::MutexLock lock(&mu_);
FUZZTEST_INTERNAL_CHECK(
!mutation_metadata_.has_value(),
"MutationMetadata is already active before calling Activate()!");
FUZZTEST_INTERNAL_CHECK(
acquire_count_ == 0,
"MutationMetadata still has readers before being calling Activate()!");
mutation_metadata_ = std::move(mutation_metadata);
}

void Deactivate() {
absl::MutexLock lock(&mu_);
FUZZTEST_INTERNAL_CHECK(
mutation_metadata_.has_value(),
"MutationMetadata is not active before calling Deactivate()!");
FUZZTEST_INTERNAL_CHECK(
acquire_count_ == 0,
"MutationMetadata still has readers before calling Deactivate()!");
mutation_metadata_ = std::nullopt;
}

const MutationMetadata& Acquire() {
absl::MutexLock lock(&mu_);
FUZZTEST_INTERNAL_CHECK_PRECONDITION(
mutation_metadata_.has_value(),
"Cannot acquire unavailable mutation metadata, likely due to the "
"fuzzer calling LLVMFuzzerMutate() outside of "
"LLVMFuzzerCustomMutator() invocation, which is not allowed.");
++acquire_count_;
return *mutation_metadata_;
}

void Release() {
absl::MutexLock lock(&mu_);
FUZZTEST_INTERNAL_CHECK(
mutation_metadata_.has_value(),
"MutationMetadata is not active before calling Release()!");
FUZZTEST_INTERNAL_CHECK(
acquire_count_ > 0,
"MutationMetadata has no readers before calling Release()!");
--acquire_count_;
}

private:
absl::Mutex mu_;
size_t acquire_count_ ABSL_GUARDED_BY(mu_) = 0;
std::optional<MutationMetadata> mutation_metadata_ ABSL_GUARDED_BY(mu_);
};

absl::NoDestructor<LLVMFuzzerMutateMetadataManager> mutation_metadata_manager;
} // namespace

#ifdef FUZZTEST_USE_CENTIPEDE
extern "C" size_t CentipedeLLVMFuzzerMutateCallback(uint8_t* data, size_t size,
size_t max_size) {
Expand All @@ -137,12 +212,9 @@ extern "C" size_t LLVMFuzzerMutate(uint8_t* data, size_t size,
domain.WithMaxSize(max_size);
absl::BitGen bitgen;
InplaceVector<uint8_t> val(data, size);
fuzztest::domain_implementor::MutationMetadata metadata;
if (auto* coverage = fuzztest::internal::GetExecutionCoverage();
coverage != nullptr) {
metadata.cmp_tables = &coverage->GetTablesOfRecentCompares();
}
const auto& metadata = mutation_metadata_manager->Acquire();
domain.Mutate(val, bitgen, metadata, false);
mutation_metadata_manager->Release();
return val.size();
}

Expand All @@ -157,13 +229,14 @@ class ArbitraryByteVector
ArbitraryByteVector() { WithMaxSize(kByteArrayMaxLen); }

void Mutate(corpus_type& val, absl::BitGenRef prng,
const fuzztest::domain_implementor::MutationMetadata& metadata,
bool only_shrink) {
const MutationMetadata& metadata, bool only_shrink) {
if (LLVMFuzzerCustomMutator) {
const size_t size = val.size();
const size_t max_size = only_shrink ? size : kByteArrayMaxLen;
val.resize(max_size);
mutation_metadata_manager->Activate(metadata);
val.resize(LLVMFuzzerCustomMutator(val.data(), size, max_size, prng()));
mutation_metadata_manager->Deactivate();
} else {
Base::Mutate(val, prng, metadata, only_shrink);
}
Expand Down

0 comments on commit 117570f

Please sign in to comment.