blob: 73edee43d2fe136427d9db662cfe21b6b7a19098 [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_SYS_FUZZING_FRAMEWORK_TARGET_PROCESS_H_
#define SRC_SYS_FUZZING_FRAMEWORK_TARGET_PROCESS_H_
#include <fuchsia/fuzzer/cpp/fidl.h>
#include <lib/zx/time.h>
#include <stddef.h>
#include <stdint.h>
#include <atomic>
#include <mutex>
#include <vector>
#include "src/lib/fxl/macros.h"
#include "src/lib/fxl/synchronization/thread_annotations.h"
#include "src/sys/fuzzing/common/sancov.h"
#include "src/sys/fuzzing/common/signal-coordinator.h"
#include "src/sys/fuzzing/framework/target/module.h"
#include "src/sys/fuzzing/framework/target/process.h"
namespace fuzzing {
using ::fuchsia::fuzzer::Feedback;
using ::fuchsia::fuzzer::Options;
using ::fuchsia::fuzzer::ProcessProxySyncPtr;
// This class represents a target process being fuzzed. It is a singleton in each process, and its
// methods are typically invoked through various callbacks.
class Process {
public:
virtual ~Process();
// Adds defaults to unspecified options.
static void AddDefaults(Options* options);
// Adds the counters and PCs associated with modules for this process. Invoked via the
// |__sanitizer_cov_*_init| functions.
void AddModules() FXL_LOCKS_EXCLUDED(mutex_);
// |malloc| and |free| hooks, called from a static context via the
// |__sanitizer_install_malloc_and_free_hooks| function.
void OnMalloc(const volatile void* ptr, size_t size);
void OnFree(const volatile void* ptr);
// Exit hooks, called from a static context via the |__sanitizer_set_death_callback| function an
// |std::atexit|.
void OnDeath();
void OnExit();
protected:
Process();
// Accessors for unit testing.
const Options& options() const { return options_; }
size_t malloc_limit() const { return malloc_limit_; }
zx::time next_purge() const { return next_purge_; }
// Installs the hook functions above in the process' overall global, static context. The methods
// used, e.g. |__sanitizer_set_death_callback|, do not have corresponding methods to unset the
// hooks, so there is no corresponding "UninstallHooks". As a result, this method can only be
// called once per process; subsequent calls will return immediately.
static void InstallHooks();
// Connects to the engine. This should happen before main, typically as part of the singleton's
// constructor. This method can only be called once per object; subsequent calls will return
// immediately.
void Connect(ProcessProxySyncPtr&& proxy) FXL_LOCKS_EXCLUDED(mutex_);
private:
// SignalCoordinator callback.
bool OnSignal(zx_signals_t observed);
// Sends complete pending modules to the engine.
void AddModulesLocked() FXL_REQUIRE(mutex_);
// Update module counters.
void Update();
// Performs a leak check.
//
// Full leak detection is expensive, so the framework imitates libFuzzer's
// approach to leak detection and uses a heuristic to try and limit the number of false positives:
// For each input, it tracks the number of mallocs and frees, and reports whether these numbers
// match when the run finishes. Upon mismatch, the framework will try the same input again using a
// |kStartLeakCheck| signal. This is to distinguish between leaks and memory being accumulated in
// some global state without being leaked. For this second pass, LSan is *disabled* to avoid
// reporting the same leak twice. If the input still causes more mallocs than frees, the full leak
// check is performed. If it is a true leak, LSan will report details of the leak from the first
// run.
//
// Returns true if more mallocs were observed than frees. Returns false if the number of mallocs
// and frees were the same. Exits and does NOT return if a full leak check was performed and a
// leak was detected.
//
// See also libFuzzer's |Fuzzer::TryDetectingAMemoryLeak|.
bool DetectLeak();
// First call returns true if a sanitizer is present; all other calls return false.
static bool AcquireCrashState();
ProcessProxySyncPtr proxy_;
SignalCoordinator coordinator_;
// Options provided by the engine.
Options options_;
bool connected_ = false;
bool can_detect_leaks_ = false; // Is LSan available and is options.deteck_leaks == true?
size_t malloc_limit_ = 0;
// Module feedback.
std::mutex mutex_;
std::vector<Module> modules_ FXL_GUARDED_BY(mutex_);
// Memory tracking.
bool detecting_leaks_ = false; // Was the current iteration started with |kStartLeakCheck|?
std::atomic<uint64_t> num_mallocs_ = 0;
std::atomic<uint64_t> num_frees_ = 0;
zx::time next_purge_;
FXL_DISALLOW_COPY_ASSIGN_AND_MOVE(Process);
};
} // namespace fuzzing
#endif // SRC_SYS_FUZZING_FRAMEWORK_TARGET_PROCESS_H_