Skip to content

Commit

Permalink
Merge pull request #5 from PAMunb/distance-coverage-orderer
Browse files Browse the repository at this point in the history
Distance coverage orderer
  • Loading branch information
faustocarva authored Apr 7, 2024
2 parents 6313f4f + ab74b30 commit 1aa40f3
Show file tree
Hide file tree
Showing 8 changed files with 214 additions and 24 deletions.
19 changes: 14 additions & 5 deletions cmd/dogefuzz/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ type Env interface {
BlackboxFuzzer() interfaces.Fuzzer
GreyboxFuzzer() interfaces.Fuzzer
DirectedGreyboxFuzzer() interfaces.Fuzzer
OtherDirectedGreyboxFuzzer() interfaces.Fuzzer
PowerSchedule() interfaces.PowerSchedule
}

Expand Down Expand Up @@ -128,11 +129,12 @@ type env struct {
transactionsCheckerJob interfaces.CronJob
transactionsTimeoutCheckerJob interfaces.CronJob

fuzzerLeader interfaces.FuzzerLeader
blackboxFuzzer interfaces.Fuzzer
greyboxFuzzer interfaces.Fuzzer
directedGreyboxFuzzer interfaces.Fuzzer
powerSchedule interfaces.PowerSchedule
fuzzerLeader interfaces.FuzzerLeader
blackboxFuzzer interfaces.Fuzzer
greyboxFuzzer interfaces.Fuzzer
directedGreyboxFuzzer interfaces.Fuzzer
otherDirectedGreyboxFuzzer interfaces.Fuzzer
powerSchedule interfaces.PowerSchedule
}

func NewEnv(cfg *config.Config) *env {
Expand Down Expand Up @@ -477,6 +479,13 @@ func (e *env) DirectedGreyboxFuzzer() interfaces.Fuzzer {
return e.directedGreyboxFuzzer
}

func (e *env) OtherDirectedGreyboxFuzzer() interfaces.Fuzzer {
if e.otherDirectedGreyboxFuzzer == nil {
e.otherDirectedGreyboxFuzzer = fuzz.NewOtherDirectedGreyboxFuzzer(e)
}
return e.otherDirectedGreyboxFuzzer
}

func (e *env) PowerSchedule() interfaces.PowerSchedule {
if e.powerSchedule == nil {
e.powerSchedule = fuzz.NewPowerSchedule(e)
Expand Down
3 changes: 3 additions & 0 deletions fuzz/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type env interface {
BlackboxFuzzer() interfaces.Fuzzer
GreyboxFuzzer() interfaces.Fuzzer
DirectedGreyboxFuzzer() interfaces.Fuzzer
OtherDirectedGreyboxFuzzer() interfaces.Fuzzer
PowerSchedule() interfaces.PowerSchedule

TransactionService() interfaces.TransactionService
Expand All @@ -33,6 +34,8 @@ func buildOrderer(strategy common.PowerScheduleStrategy, contract *dto.ContractD
return newCoverageBasedOrderer()
case common.DISTANCE_BASED_STRATEGY:
return newDistanceBasedOrderer(contract)
case common.DISTANCE_COVERAGE_BASED_STRATEGY:
return newDistanceCoverageBasedOrderer(contract)
default:
panic(fmt.Sprintf("invalid power schedule strategy: %s", strategy))
}
Expand Down
83 changes: 83 additions & 0 deletions fuzz/distance_coverage_orderer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package fuzz

import (
"math"
"sort"

"github.com/dogefuzz/dogefuzz/pkg/dto"
)

type distanceCoverageBasedOrderer struct {
contract *dto.ContractDTO
}

func newDistanceCoverageBasedOrderer(contract *dto.ContractDTO) *distanceCoverageBasedOrderer {
return &distanceCoverageBasedOrderer{contract}
}

func (o *distanceCoverageBasedOrderer) OrderTransactions(transactions []*dto.TransactionDTO) {
sort.SliceStable(transactions, func(i, j int) bool {
return o.computeScore(transactions[i]) > o.computeScore(transactions[j])
})
}

func (o *distanceCoverageBasedOrderer) computeScore(transaction *dto.TransactionDTO) float64 {
return math.Max(o.computeCriticalInstructionsHits(transaction), math.Max(o.computeCoverage(transaction), o.computeDistance(transaction)))
}

func (o *distanceCoverageBasedOrderer) computeCoverage(transaction *dto.TransactionDTO) float64 {
var totalInstructions = len(o.contract.CFG.Instructions)
var executedInstructions = len(transaction.ExecutedInstructions)

if totalInstructions != 0 {
return float64(executedInstructions) / float64(totalInstructions)
}

return 0
}

func (o *distanceCoverageBasedOrderer) computeDistance(transaction *dto.TransactionDTO) float64 {
var maxDistance map[string]uint32
var distanceSum int64 = 0
var distancePercentage float64 = 0
var minDistance uint64 = transaction.DeltaMinDistance

for _, distance := range o.contract.DistanceMap {
if maxDistance == nil {
maxDistance = make(map[string]uint32)
for pc := range distance {
maxDistance[pc] = 0
}
}

for instr := range maxDistance {
if val, ok := distance[instr]; ok {
if val != math.MaxUint32 && val > maxDistance[instr] {
maxDistance[instr] = val
}
}
}
}

for _, distance := range maxDistance {
distanceSum += int64(distance)
}

if minDistance >= uint64(math.MaxUint32) {
minDistance -= math.MaxUint32
}

if distanceSum != 0 {
distancePercentage = float64(minDistance) / float64(distanceSum)
}

return distancePercentage
}

func (o *distanceCoverageBasedOrderer) computeCriticalInstructionsHits(transaction *dto.TransactionDTO) float64 {
if o.contract.TargetInstructionsFreq != 0 {
return float64(transaction.CriticalInstructionsHits) / float64(o.contract.TargetInstructionsFreq)
}

return 0
}
16 changes: 10 additions & 6 deletions fuzz/leader.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,18 @@ import (
)

type fuzzerLeader struct {
blackboxFuzzer interfaces.Fuzzer
greyboxFuzzer interfaces.Fuzzer
directedGreyboxFuzzer interfaces.Fuzzer
blackboxFuzzer interfaces.Fuzzer
greyboxFuzzer interfaces.Fuzzer
directedGreyboxFuzzer interfaces.Fuzzer
otherDirectedGreyboxFuzzer interfaces.Fuzzer
}

func NewFuzzerLeader(e env) *fuzzerLeader {
return &fuzzerLeader{
blackboxFuzzer: e.BlackboxFuzzer(),
greyboxFuzzer: e.GreyboxFuzzer(),
directedGreyboxFuzzer: e.DirectedGreyboxFuzzer(),
blackboxFuzzer: e.BlackboxFuzzer(),
greyboxFuzzer: e.GreyboxFuzzer(),
directedGreyboxFuzzer: e.DirectedGreyboxFuzzer(),
otherDirectedGreyboxFuzzer: e.OtherDirectedGreyboxFuzzer(),
}
}

Expand All @@ -27,6 +29,8 @@ func (l *fuzzerLeader) GetFuzzerStrategy(typ common.FuzzingType) (interfaces.Fuz
return l.greyboxFuzzer, nil
case common.DIRECTED_GREYBOX_FUZZING:
return l.directedGreyboxFuzzer, nil
case common.OTHER_DIRECTED_GREYBOX_FUZZING:
return l.otherDirectedGreyboxFuzzer, nil
default:
return nil, ErrFuzzerTypeNotFound
}
Expand Down
66 changes: 66 additions & 0 deletions fuzz/other_directed_greybox.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package fuzz

import (
"strings"

"github.com/dogefuzz/dogefuzz/pkg/common"
"github.com/dogefuzz/dogefuzz/pkg/interfaces"
"github.com/ethereum/go-ethereum/accounts/abi"
)

// This is temporally, it is like 'directed_greybox' but with another strategy to order seeds
type otherDirectedGreyboxFuzzer struct {
powerSchedule interfaces.PowerSchedule

solidityService interfaces.SolidityService
functionService interfaces.FunctionService
contractService interfaces.ContractService
}

func NewOtherDirectedGreyboxFuzzer(e env) *otherDirectedGreyboxFuzzer {
return &otherDirectedGreyboxFuzzer{
powerSchedule: e.PowerSchedule(),
solidityService: e.SolidityService(),
functionService: e.FunctionService(),
contractService: e.ContractService(),
}
}

func (f *otherDirectedGreyboxFuzzer) GenerateInput(functionId string) ([]interface{}, error) {
function, err := f.functionService.Get(functionId)
if err != nil {
return nil, err
}

contract, err := f.contractService.Get(function.ContractId)
if err != nil {
return nil, err
}

abiDefinition, err := abi.JSON(strings.NewReader(contract.AbiDefinition))
if err != nil {
return nil, err
}
method := abiDefinition.Methods[function.Name]

seedsList, err := f.powerSchedule.RequestSeeds(functionId, common.DISTANCE_COVERAGE_BASED_STRATEGY)
if err != nil {
return nil, err
}

chosenSeeds := common.RandomChoice(seedsList)

inputs := make([]interface{}, len(method.Inputs))
for inputsIdx, inputDefinition := range method.Inputs {
handler, err := f.solidityService.GetTypeHandlerWithContext(inputDefinition.Type)
if err != nil {
return nil, err
}
handler.SetValue(chosenSeeds[inputsIdx])
mutationFunction := common.RandomChoice(handler.GetMutators())
mutationFunction()
inputs[inputsIdx] = handler.GetValue()
}

return inputs, nil
}
1 change: 1 addition & 0 deletions listener/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,6 @@ type Env interface {
BlackboxFuzzer() interfaces.Fuzzer
GreyboxFuzzer() interfaces.Fuzzer
DirectedGreyboxFuzzer() interfaces.Fuzzer
OtherDirectedGreyboxFuzzer() interfaces.Fuzzer
PowerSchedule() interfaces.PowerSchedule
}
12 changes: 7 additions & 5 deletions pkg/common/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@ var (
type FuzzingType string

const (
BLACKBOX_FUZZING FuzzingType = "blackbox"
GREYBOX_FUZZING FuzzingType = "greybox"
DIRECTED_GREYBOX_FUZZING FuzzingType = "directed_greybox"
BLACKBOX_FUZZING FuzzingType = "blackbox"
GREYBOX_FUZZING FuzzingType = "greybox"
DIRECTED_GREYBOX_FUZZING FuzzingType = "directed_greybox"
OTHER_DIRECTED_GREYBOX_FUZZING FuzzingType = "other_directed_greybox"
)

type ContractStatus string
Expand Down Expand Up @@ -77,8 +78,9 @@ type DistanceMap map[string]map[string]uint32 // blockPC => instruction => dista
type PowerScheduleStrategy string

const (
DISTANCE_BASED_STRATEGY PowerScheduleStrategy = "distance_based"
COVERAGE_BASED_STRATEGY PowerScheduleStrategy = "coverage_based"
DISTANCE_BASED_STRATEGY PowerScheduleStrategy = "distance_based"
COVERAGE_BASED_STRATEGY PowerScheduleStrategy = "coverage_based"
DISTANCE_COVERAGE_BASED_STRATEGY PowerScheduleStrategy = "distance_coverage_based"
)

type TaskReport struct {
Expand Down
38 changes: 30 additions & 8 deletions pkg/solc/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"regexp"
"strconv"
"strings"
"time"

"github.com/Masterminds/semver/v3"
"github.com/dogefuzz/dogefuzz/pkg/common"
Expand All @@ -25,23 +26,40 @@ var ErrContractNotFound = errors.New("the contract was not found in compiled cod

type solidityCompiler struct {
storageFolder string
versions []string
}

func NewSolidityCompiler(storageFolder string) *solidityCompiler {
return &solidityCompiler{storageFolder: storageFolder}
versions, err := getDescendingOrderedVersionsFromSolidyBinariesEndpoint()
if err != nil {
versions = []string{}
}
return &solidityCompiler{storageFolder: storageFolder, versions: versions}
}

func (c *solidityCompiler) CompileSource(contractName string, contractSource string) (*common.Contract, error) {
if len(contractSource) == 0 {
return nil, ErrEmptySourceFile
}

solcVersion, err := getIdealSolcVersionBasedOnSource(contractSource)
if err != nil {
return nil, err
var solcVersion *semver.Version
maxRetries := 5
var err error
for retries := 1; retries <= maxRetries; retries++ {
if retries == maxRetries {
return nil, err
}

solcVersion, err = c.getIdealSolcVersionBasedOnSource(contractSource)
if err != nil {
time.Sleep(100 * time.Millisecond)
continue
}
break
}

var solcBinaryLocation string

if location, ok := c.getSolcBinaryLocationIfExists(solcVersion); ok {
solcBinaryLocation = location
} else {
Expand Down Expand Up @@ -154,10 +172,14 @@ func run(cmd *exec.Cmd, source string, maxVersion *semver.Version) (map[string]*
return compiler.ParseCombinedJSON(stdout.Bytes(), source, maxVersion.String(), maxVersion.String(), strings.Join(buildArgs(maxVersion), " "))
}

func getIdealSolcVersionBasedOnSource(source string) (*semver.Version, error) {
versions, err := getDescendingOrderedVersionsFromSolidyBinariesEndpoint()
if err != nil {
return nil, err
func (c *solidityCompiler) getIdealSolcVersionBasedOnSource(source string) (*semver.Version, error) {
var versions = c.versions
if len(versions) == 0 {
var err error
versions, err = getDescendingOrderedVersionsFromSolidyBinariesEndpoint()
if err != nil {
return nil, err
}
}

versionConstraint, err := extractVersionConstraintFromSource(source)
Expand Down

0 comments on commit 1aa40f3

Please sign in to comment.