Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce Transaction Subsystem Fuzzing and Common Fuzzer Interface #2182

Merged
merged 10 commits into from
Aug 23, 2019
6 changes: 4 additions & 2 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -64,16 +64,18 @@ format: always
endif # USE_CLANG_FORMAT

if USE_AFL_FUZZ
FUZZER_MODE ?= overlay

fuzz-testcases: stellar-core
mkdir -p fuzz-testcases
for i in `seq 1 10`; do \
./stellar-core gen-fuzz fuzz-testcases/fuzz$$i.xdr; \
./stellar-core gen-fuzz fuzz-testcases/fuzz$$i.xdr --mode=${FUZZER_MODE}; \
done

fuzz: fuzz-testcases stellar-core
mkdir -p fuzz-findings
afl-fuzz -m 8000 -t 250 -i fuzz-testcases -o fuzz-findings \
./stellar-core fuzz @@
./stellar-core fuzz @@ --mode=${FUZZER_MODE}

fuzz-clean: always
rm -Rf fuzz-testcases fuzz-findings
Expand Down
15 changes: 15 additions & 0 deletions src/ledger/LedgerTxn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1288,6 +1288,21 @@ LedgerTxnRoot::Impl::~Impl()
}
}

#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
void
LedgerTxnRoot::Impl::resetForFuzzer()
{
mBestOffersCache.clear();
mEntryCache.clear();
}

void
LedgerTxnRoot::resetForFuzzer()
{
mImpl->resetForFuzzer();
}
#endif // FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION

void
LedgerTxnRoot::addChild(AbstractLedgerTxn& child)
{
Expand Down
4 changes: 4 additions & 0 deletions src/ledger/LedgerTxn.h
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,10 @@ class LedgerTxnRoot : public AbstractLedgerTxnParent
void dropOffers();
void dropTrustLines();

#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
void resetForFuzzer();
#endif // FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION

std::unordered_map<LedgerKey, LedgerEntry> getAllOffers() override;

std::shared_ptr<LedgerEntry const>
Expand Down
4 changes: 4 additions & 0 deletions src/ledger/LedgerTxnImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,10 @@ class LedgerTxnRoot::Impl
void dropOffers();
void dropTrustLines();

#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
void resetForFuzzer();
#endif // FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION

// getAllOffers has the basic exception safety guarantee. If it throws an
// exception, then
// - the prepared statement cache may be, but is not guaranteed to be,
Expand Down
58 changes: 51 additions & 7 deletions src/main/CommandLine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "main/StellarCoreVersion.h"
#include "main/dumpxdr.h"
#include "scp/QuorumSetUtils.h"
#include "test/Fuzzer.h"
#include "util/Logging.h"
#include "util/optional.h"

Expand Down Expand Up @@ -163,6 +164,38 @@ fileNameParser(std::string& string)
return requiredArgParser(string, "FILE-NAME");
}

ParserWithValidation
fuzzerModeParser(std::string& fuzzerModeArg, FuzzerMode& fuzzerMode)
{
auto validateFuzzerMode = [&] {
if (iequals(fuzzerModeArg, "overlay"))
{
fuzzerMode = FuzzerMode::OVERLAY;
return "";
}

if (iequals(fuzzerModeArg, "tx"))
{
fuzzerMode = FuzzerMode::TRANSACTION;
return "";
}

return "Unrecognized fuzz mode. Please select a valid mode.";
};

return {clara::Opt{fuzzerModeArg, "FUZZER-MODE"}["--mode"](
"set the fuzzer mode. Expected modes: overlay, "
"tx. Defaults to overlay."),
validateFuzzerMode};
}

clara::Opt
processIDParser(uint& num)
{
return clara::Opt{num, "PROCESS-ID"}["--process_id"](
"for spawning multiple instances in fuzzing parallelization");
}

clara::Opt
outputFileParser(std::string& string)
{
Expand Down Expand Up @@ -866,12 +899,17 @@ runFuzz(CommandLineArgs const& args)
el::Level logLevel{el::Level::Info};
std::vector<std::string> metrics;
std::string fileName;
uint processID = 0;
FuzzerMode fuzzerMode{FuzzerMode::OVERLAY};
std::string fuzzerModeArg = "overlay";

return runWithHelp(args,
{logLevelParser(logLevel), metricsParser(metrics),
fileNameParser(fileName)},
fileNameParser(fileName), processIDParser(processID),
fuzzerModeParser(fuzzerModeArg, fuzzerMode)},
[&] {
fuzz(fileName, logLevel, metrics);
fuzz(fileName, logLevel, metrics, processID,
fuzzerMode);
return 0;
});
}
Expand All @@ -880,11 +918,17 @@ int
runGenFuzz(CommandLineArgs const& args)
{
std::string fileName;
FuzzerMode fuzzerMode{FuzzerMode::OVERLAY};
std::string fuzzerModeArg = "overlay";
uint processID = 0;

return runWithHelp(args, {fileNameParser(fileName)}, [&] {
genfuzz(fileName);
return 0;
});
return runWithHelp(
args,
{fileNameParser(fileName), fuzzerModeParser(fuzzerModeArg, fuzzerMode)},
[&] {
FuzzUtils::createFuzzer(processID, fuzzerMode)->genFuzz(fileName);
return 0;
});
}
#endif

Expand Down Expand Up @@ -955,7 +999,7 @@ handleCommandLine(int argc, char* const* argv)
auto commandName = fmt::format("{0} {1}", exeName, command->name());
auto args = CommandLineArgs{exeName, commandName, command->description(),
adjustedCommandLine.second};
if (command->name() == "run")
if (command->name() == "run" || command->name() == "fuzz")
{
// run outside of catch block so that we properly capture crashes
return command->run(args);
Expand Down
32 changes: 32 additions & 0 deletions src/test/Fuzzer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#pragma once

// Copyright 2019 Stellar Development Foundation and contributors. Licensed
// under the Apache License, Version 2.0. See the COPYING file at the root
// of this distribution or at http://www.apache.org/licenses/LICENSE-2.0

#include <string>

namespace stellar
{

class XDRInputFileStream;

// Fuzzer is an encapsulation over some state that receives an
// XDRInputFileStream and deterministically injects it, applying it to its
// state.
class Fuzzer
{
public:
// inject receives an XDRInputFileStream attached to a fuzzed input file and
// attempts to apply it to the state according to whatever apply may mean,
// i.e. apply a transaction in the case of a TransactionFuzzer or send a
// message in case of an OverlayFuzzer
virtual void inject(XDRInputFileStream&) = 0;
virtual void initialize() = 0;
// genFuzz randomly generates an XDR input for the given fuzzer. For the
// TransactionFuzzer, this is a xdr::xvector of Operations, for the
// OverlayFuzzer this is a StellarMessage
virtual void genFuzz(std::string const& filename) = 0;
virtual int xdrSizeLimit() = 0;
};
}
Loading