Skip to content

Commit

Permalink
show coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
duytai committed Aug 10, 2019
1 parent c9b9197 commit 0765700
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 54 deletions.
54 changes: 33 additions & 21 deletions libfuzzer/Fuzzer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,16 @@ Fuzzer::Fuzzer(FuzzParam fuzzParam): fuzzParam(fuzzParam){
}

/* Detect new exception */
void Fuzzer::updateExceptions(unordered_set<uint64_t> exps) {
void Fuzzer::updateExceptions(unordered_set<string> exps) {
for (auto it: exps) uniqExceptions.insert(it);
}

/* Detect new bits by comparing tracebits to virginbits */
void Fuzzer::updateTracebits(unordered_set<uint64_t> _tracebits) {
void Fuzzer::updateTracebits(unordered_set<string> _tracebits) {
for (auto it: _tracebits) tracebits.insert(it);
}

void Fuzzer::updatePredicates(unordered_map<uint64_t, u256> _pred) {
void Fuzzer::updatePredicates(unordered_map<string, u256> _pred) {
for (auto it : _pred) {
predicates.insert(it.first);
};
Expand All @@ -50,7 +50,7 @@ ContractInfo Fuzzer::mainContract() {
return *it;
}

void Fuzzer::showStats(const Mutation &mutation) {
void Fuzzer::showStats(const Mutation &mutation, const tuple<unordered_set<uint64_t>, unordered_set<uint64_t>> &validJumpis) {
int numLines = 24, i = 0;
if (!fuzzStat.clearScreen) {
for (i = 0; i < numLines; i++) cout << endl;
Expand All @@ -69,6 +69,8 @@ void Fuzzer::showStats(const Mutation &mutation) {
auto cycleProgress = padStr(to_string(fuzzStat.idx + 1) + " (" + to_string(cyclePercentage) + "%)", 20);
auto cycleDone = padStr(to_string(fuzzStat.queueCycle), 15);
auto numBranches = padStr(to_string(tracebits.size()), 15);
auto totalBranches = (get<0>(validJumpis).size() + get<1>(validJumpis).size()) * 2;
auto coverage = padStr(to_string((uint64_t)((float)(tracebits.size()) / totalBranches) * 100) + "%", 15);
auto flip1 = to_string(fuzzStat.stageFinds[STAGE_FLIP1]) + "/" + to_string(mutation.stageCycles[STAGE_FLIP1]);
auto flip2 = to_string(fuzzStat.stageFinds[STAGE_FLIP2]) + "/" + to_string(mutation.stageCycles[STAGE_FLIP2]);
auto flip4 = to_string(fuzzStat.stageFinds[STAGE_FLIP4]) + "/" + to_string(mutation.stageCycles[STAGE_FLIP4]);
Expand All @@ -91,7 +93,7 @@ void Fuzzer::showStats(const Mutation &mutation) {
auto hav1 = to_string(fuzzStat.stageFinds[STAGE_HAVOC]) + "/" + to_string(mutation.stageCycles[STAGE_HAVOC]);
auto havoc = padStr(hav1, 30);
auto pending = padStr(to_string(leaders.size() - fuzzStat.idx - 1), 5);
auto fav = count_if(leaders.begin(), leaders.end(), [](const pair<uint64_t, Leader> &p) {
auto fav = count_if(leaders.begin(), leaders.end(), [](const pair<string, Leader> &p) {
return !p.second.item.fuzzedCount;
});
auto pendingFav = padStr(to_string(fav), 5);
Expand All @@ -107,7 +109,7 @@ void Fuzzer::showStats(const Mutation &mutation) {
printf(bLTR bV5 cGRN " stage progress " cRST bV5 bV10 bV2 bV bTTR bV2 cGRN " overall results " cRST bV2 bV5 bV2 bV2 bV bRTR "\n");
printf(bH " now trying : %s" bH " cycles done : %s" bH "\n", nowTrying.c_str(), cycleDone.c_str());
printf(bH " stage execs : %s" bH " branches : %s" bH "\n", stageExec.c_str(), numBranches.c_str());
printf(bH " total execs : %s" bH " %s" bH "\n", allExecs.c_str(), padStr("", 15).c_str());
printf(bH " total execs : %s" bH " coverage : %s" bH "\n", allExecs.c_str(), coverage.c_str());
printf(bH " exec speed : %s" bH " %s" bH "\n", execSpeed.c_str(), padStr("", 15).c_str());
printf(bH " cycle prog : %s" bH " %s" bH "\n", cycleProgress.c_str(), padStr("", 15).c_str());
printf(bLTR bV5 cGRN " fuzzing yields " cRST bV5 bV5 bV5 bV2 bV bBTR bV10 bV bTTR bV cGRN " path geometry " cRST bV2 bV2 bRTR "\n");
Expand Down Expand Up @@ -151,7 +153,7 @@ FuzzItem Fuzzer::saveIfInterest(TargetExecutive& te, bytes data, uint64_t depth,
for (auto tracebit: item.res.tracebits) {
if (!tracebits.count(tracebit)) {
// Remove leader
auto fi = [=](const pair<uint64_t, Leader>& p) { return p.first == tracebit;};
auto fi = [=](const pair<string, Leader>& p) { return p.first == tracebit;};
auto it = find_if(leaders.begin(), leaders.end(), fi);
if (it!= leaders.end()) leaders.erase(it);
// Insert leader
Expand All @@ -160,20 +162,20 @@ FuzzItem Fuzzer::saveIfInterest(TargetExecutive& te, bytes data, uint64_t depth,
leaders.insert(make_pair(tracebit, leader));
if (depth + 1 > fuzzStat.maxdepth) fuzzStat.maxdepth = depth + 1;
fuzzStat.lastNewPath = timer.elapsed();
Logger::debug("Cover new branch " + to_string(tracebit));
Logger::debug("Cover new branch " + tracebit);
Logger::debug(Logger::testFormat(item.data));
}
}
for (auto predicateIt: item.res.predicates) {
auto fi = [=](const pair<uint64_t, Leader>& p) { return p.first == predicateIt.first;};
auto fi = [=](const pair<string, Leader>& p) { return p.first == predicateIt.first;};
auto leaderIt = find_if(leaders.begin(), leaders.end(), fi);
if (
leaderIt != leaders.end() // Found Leader
&& leaderIt->second.comparisonValue > 0 // Not a covered branch
&& leaderIt->second.comparisonValue > predicateIt.second // ComparisonValue is better
) {
// Debug now
Logger::debug("Found better test case for uncovered branch " + to_string(predicateIt.first));
Logger::debug("Found better test case for uncovered branch " + predicateIt.first);
Logger::debug("prev: " + leaderIt->second.comparisonValue.str());
Logger::debug("now : " + predicateIt.second.str());
// Stop debug
Expand Down Expand Up @@ -202,6 +204,16 @@ FuzzItem Fuzzer::saveIfInterest(TargetExecutive& te, bytes data, uint64_t depth,
return item;
}

/* Stop fuzzing */
void Fuzzer::stop() {
Logger::debug("==== TEST CASES ====");
for (auto it : leaders) {
Logger::debug("BR " + it.first);
Logger::debug(Logger::testFormat(it.second.item.data));
}
exit(1);
}

/* Start fuzzing */
void Fuzzer::start() {
TargetContainer container;
Expand Down Expand Up @@ -232,38 +244,38 @@ void Fuzzer::start() {
// No branch
if (!originHitCount) {
cout << "No branch" << endl;
exit(0);
stop();
}
// There are uncovered branches or not
auto fi = [&](const pair<uint64_t, Leader> &p) { return p.second.comparisonValue != 0;};
auto fi = [&](const pair<string, Leader> &p) { return p.second.comparisonValue != 0;};
auto numUncoveredBranches = count_if(leaders.begin(), leaders.end(), fi);
if (!numUncoveredBranches) {
auto curItem = (*leaders.begin()).second.item;
Mutation mutation(curItem, make_tuple(codeDict, addressDict));
vulnerabilities = container.analyze();
switch (fuzzParam.reporter) {
case TERMINAL: {
showStats(mutation);
showStats(mutation, validJumpis);
break;
}
case JSON: {
writeStats(mutation);
break;
}
case BOTH: {
showStats(mutation);
showStats(mutation, validJumpis);
writeStats(mutation);
break;
}
}
exit(1);
stop();
}
// Jump to fuzz loop
while (true) {
Logger::debug("== LEADERS ==");
for (auto leaderIt : leaders) {
if (leaderIt.second.comparisonValue != 0) {
Logger::debug("Branch \t\t\t : " + to_string(leaderIt.first));
Logger::debug("Branch \t\t\t : " + leaderIt.first);
Logger::debug("Score \t\t\t : " + leaderIt.second.comparisonValue.str());
Logger::debug("Fuzzed \t\t\t : " + to_string(leaderIt.second.item.fuzzedCount));
Logger::debug("Depth \t\t\t : " + to_string(leaderIt.second.item.depth));
Expand All @@ -286,15 +298,15 @@ void Fuzzer::start() {
}
switch (fuzzParam.reporter) {
case TERMINAL: {
showStats(mutation);
showStats(mutation, validJumpis);
break;
}
case JSON: {
writeStats(mutation);
break;
}
case BOTH: {
showStats(mutation);
showStats(mutation, validJumpis);
writeStats(mutation);
break;
}
Expand All @@ -306,20 +318,20 @@ void Fuzzer::start() {
vulnerabilities = container.analyze();
switch(fuzzParam.reporter) {
case TERMINAL: {
showStats(mutation);
showStats(mutation, validJumpis);
break;
}
case JSON: {
writeStats(mutation);
break;
}
case BOTH: {
showStats(mutation);
showStats(mutation, validJumpis);
writeStats(mutation);
break;
}
}
exit(0);
stop();
}
return item;
};
Expand Down
17 changes: 9 additions & 8 deletions libfuzzer/Fuzzer.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ namespace fuzzer {
};
class Fuzzer {
vector<bool> vulnerabilities;
unordered_set<uint64_t> tracebits;
unordered_set<uint64_t> predicates;
unordered_map<uint64_t, Leader> leaders;
unordered_set<uint64_t> uniqExceptions;
unordered_set<string> tracebits;
unordered_set<string> predicates;
unordered_map<string, Leader> leaders;
unordered_set<string> uniqExceptions;
Timer timer;
FuzzParam fuzzParam;
FuzzStat fuzzStat;
Expand All @@ -59,10 +59,11 @@ namespace fuzzer {
public:
Fuzzer(FuzzParam fuzzParam);
FuzzItem saveIfInterest(TargetExecutive& te, bytes data, uint64_t depth, const tuple<unordered_set<uint64_t>, unordered_set<uint64_t>> &validJumpis);
void showStats(const Mutation &mutation);
void updateTracebits(unordered_set<uint64_t> tracebits);
void updatePredicates(unordered_map<uint64_t, u256> predicates);
void updateExceptions(unordered_set<uint64_t> uniqExceptions);
void showStats(const Mutation &mutation, const tuple<unordered_set<uint64_t>, unordered_set<uint64_t>> &validJumpis);
void updateTracebits(unordered_set<string> tracebits);
void updatePredicates(unordered_map<string, u256> predicates);
void updateExceptions(unordered_set<string> uniqExceptions);
void start();
void stop();
};
}
8 changes: 4 additions & 4 deletions libfuzzer/TargetContainerResult.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
namespace fuzzer {

TargetContainerResult::TargetContainerResult(
unordered_set<uint64_t> tracebits,
unordered_map<uint64_t, u256> predicates,
unordered_set<uint64_t> uniqExceptions,
double cksum
unordered_set<string> tracebits,
unordered_map<string, u256> predicates,
unordered_set<string> uniqExceptions,
string cksum
) {
this->tracebits = tracebits;
this->cksum = cksum;
Expand Down
16 changes: 8 additions & 8 deletions libfuzzer/TargetContainerResult.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,19 @@ namespace fuzzer {
struct TargetContainerResult {
TargetContainerResult() {}
TargetContainerResult(
unordered_set<uint64_t> tracebits,
unordered_map<uint64_t, u256> predicates,
unordered_set<uint64_t> uniqExceptions,
double cksum
unordered_set<string> tracebits,
unordered_map<string, u256> predicates,
unordered_set<string> uniqExceptions,
string cksum
);

/* Contains execution paths */
unordered_set<uint64_t> tracebits;
unordered_set<string> tracebits;
/* Save predicates */
unordered_map<uint64_t, u256> predicates;
unordered_map<string, u256> predicates;
/* Exception path */
unordered_set<uint64_t> uniqExceptions;
unordered_set<string> uniqExceptions;
/* Contains checksum of tracebits */
double cksum;
string cksum;
};
}
25 changes: 13 additions & 12 deletions libfuzzer/TargetExecutive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ namespace fuzzer {
u256 lastCompValue = 0;
u64 jumpDest1 = 0;
u64 jumpDest2 = 0;
unordered_set<uint64_t> uniqExceptions;
unordered_set<uint64_t> tracebits;
unordered_map<uint64_t, u256> predicates;
unordered_set<string> uniqExceptions;
unordered_set<string> tracebits;
unordered_map<string, u256> predicates;
vector<bytes> outputs;
size_t savepoint = program->savepoint();
OnOpFunc onOp = [&](u64, u64 pc, Instruction inst, bigint, bigint, bigint, VMFace const* _vm, ExtVMFace const* ext) {
Expand Down Expand Up @@ -107,11 +107,12 @@ namespace fuzzer {
recordable = recordParam.isDeployment && get<0>(validJumpis).count(recordParam.lastpc);
recordable = recordable || !recordParam.isDeployment && get<1>(validJumpis).count(recordParam.lastpc);
if (prevInst == Instruction::JUMPCI && recordable) {
tracebits.insert(pc ^ recordParam.prevLocation);
auto branchId = to_string(recordParam.lastpc) + ":" + to_string(pc);
tracebits.insert(branchId);
/* Calculate branch distance */
u64 jumpDest = pc == jumpDest1 ? jumpDest2 : jumpDest1;
predicates[jumpDest ^ recordParam.prevLocation] = lastCompValue;
recordParam.prevLocation = pc >> 1;
branchId = to_string(recordParam.lastpc) + ":" + to_string(jumpDest);
predicates[branchId] = lastCompValue;
}
prevInst = inst;
recordParam.lastpc = pc;
Expand All @@ -124,7 +125,6 @@ namespace fuzzer {
program->updateEnv(ca.decodeAccounts(), ca.decodeBlock());
oracleFactory->initialize();
/* Record all JUMPI in constructor */
recordParam.prevLocation = 0;
recordParam.isDeployment = true;
auto sender = ca.getSender();
OpcodePayload payload;
Expand All @@ -136,7 +136,8 @@ namespace fuzzer {
oracleFactory->save(OpcodeContext(0, payload));
auto res = program->invoke(addr, CONTRACT_CONSTRUCTOR, ca.encodeConstructor(), ca.isPayable(""), onOp);
if (res.excepted != TransactionException::None) {
uniqExceptions.insert(recordParam.lastpc ^ recordParam.prevLocation);
auto exceptionId = to_string(recordParam.lastpc);
uniqExceptions.insert(exceptionId) ;
/* Save Call Log */
OpcodePayload payload;
payload.inst = Instruction::INVALID;
Expand All @@ -148,7 +149,6 @@ namespace fuzzer {
auto func = funcs[funcIdx];
auto fd = ca.fds[funcIdx];
/* Ignore JUMPI until program reaches inside function */
recordParam.prevLocation = (uint64_t) u256("0x" + toHex(bytes(func.begin(), func.begin() + 4)));
recordParam.isDeployment = false;
OpcodePayload payload;
payload.data = func;
Expand All @@ -160,7 +160,8 @@ namespace fuzzer {
res = program->invoke(addr, CONTRACT_FUNCTION, func, ca.isPayable(fd.name), onOp);
outputs.push_back(res.output);
if (res.excepted != TransactionException::None) {
uniqExceptions.insert(recordParam.lastpc ^ recordParam.prevLocation);
auto exceptionId = to_string(recordParam.lastpc);
uniqExceptions.insert(exceptionId);
/* Save Call Log */
OpcodePayload payload;
payload.inst = Instruction::INVALID;
Expand All @@ -170,8 +171,8 @@ namespace fuzzer {
}
/* Reset data before running new contract */
program->rollback(savepoint);
double cksum = 0;
for (auto t : tracebits) cksum = cksum + (double)(t + cksum)/3;
string cksum = "";
for (auto t : tracebits) cksum = cksum + t;
return TargetContainerResult(tracebits, predicates, uniqExceptions, cksum);
}
}
1 change: 0 additions & 1 deletion libfuzzer/TargetExecutive.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ using namespace std;

namespace fuzzer {
struct RecordParam {
u64 prevLocation = 0;
u64 lastpc = 0;
bool isDeployment = false;
};
Expand Down

0 comments on commit 0765700

Please sign in to comment.