Skip to content
Open
33 changes: 16 additions & 17 deletions fuzzing/fuzzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -581,36 +581,35 @@ func chainSetupFromCompilations(fuzzer *Fuzzer, testChain *chain.TestChain) (*ex
func defaultCallSequenceGeneratorConfigFunc(fuzzer *Fuzzer, valueSet *valuegeneration.ValueSet, randomProvider *rand.Rand) (*CallSequenceGeneratorConfig, error) {
// Create the value generator and mutator for the worker.
mutationalGeneratorConfig := &valuegeneration.MutationalValueGeneratorConfig{
MinMutationRounds: 0,
MaxMutationRounds: 1,
GenerateRandomAddressBias: 0.05,
GenerateRandomIntegerBias: 0.5,
GenerateRandomStringBias: 0.05,
GenerateRandomBytesBias: 0.05,
MutateAddressProbability: 0.1,
MinMutationRounds: 0,
MaxMutationRounds: 1,
// Echidna: Generate a random ABI value 40% of the time
GenerateRandomAddressBias: 0.4,
GenerateRandomIntegerBias: 0.4,
GenerateRandomStringBias: 0.4,
GenerateRandomBytesBias: 0.4,
MutateAddressProbability: 0.0,
MutateArrayStructureProbability: 0.1,
MutateBoolProbability: 0.1,
MutateBoolProbability: 1.0,
MutateBytesProbability: 0.1,
MutateBytesGenerateNewBias: 0.45,
MutateFixedBytesProbability: 0.1,
MutateStringProbability: 0.1,
MutateStringGenerateNewBias: 0.7,
MutateIntegerProbability: 0.1,
MutateIntegerGenerateNewBias: 0.5,
RandomValueGeneratorConfig: &valuegeneration.RandomValueGeneratorConfig{
GenerateRandomArrayMinSize: 0,
GenerateRandomArrayMaxSize: 100,
GenerateRandomBytesMinSize: 0,
GenerateRandomBytesMaxSize: 100,
GenerateRandomStringMinSize: 0,
GenerateRandomStringMaxSize: 100,
GenerateRandomArrayMinSize: 1,
GenerateRandomArrayMaxSize: 32,
GenerateRandomBytesMinSize: 1,
GenerateRandomBytesMaxSize: 32,
GenerateRandomStringMinSize: 1,
GenerateRandomStringMaxSize: 32,
},
}
mutationalGenerator := valuegeneration.NewMutationalValueGenerator(mutationalGeneratorConfig, valueSet, randomProvider)

// Create a sequence generator config which uses the created value generator.
sequenceGenConfig := &CallSequenceGeneratorConfig{
NewSequenceProbability: 0.3,
MutateCallSequenceElementProbability: 0.1,
RandomUnmodifiedCorpusHeadWeight: 800,
RandomUnmodifiedCorpusTailWeight: 100,
RandomUnmodifiedSpliceAtRandomWeight: 200,
Expand Down
31 changes: 24 additions & 7 deletions fuzzing/fuzzer_worker_sequence_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ type CallSequenceGeneratorConfig struct {
// sequence rather than mutating one from the corpus.
NewSequenceProbability float32

// MutateCallSequenceElementProbability defines the probability that the CallSequenceGenerator should mutate a call
// sequence element.
MutateCallSequenceElementProbability float32

// RandomUnmodifiedCorpusHeadWeight defines the weight that the CallSequenceGenerator should use the call sequence
// generation strategy of taking the head of a corpus sequence (without mutations) and append newly generated calls
// to the end of it.
Expand Down Expand Up @@ -467,15 +471,28 @@ func prefetchModifyCallFuncMutate(sequenceGenerator *CallSequenceGenerator, elem
return nil
}

// Loop for each input value and mutate it
// If our bias directs us to it, do not mutate the element at all
randomGeneratorDecision := sequenceGenerator.worker.randomProvider.Float32()
if randomGeneratorDecision > sequenceGenerator.config.MutateCallSequenceElementProbability {
return nil
}

// If this element has no input values, exit early.
if len(element.Call.DataAbiValues.InputValues) == 0 {
return nil
}

// Choose which input value to mutate
idx := sequenceGenerator.worker.randomProvider.Intn(len(element.Call.DataAbiValues.InputValues))

// Mutate selected input value and replace the value
abiValuesMsgData := element.Call.DataAbiValues
for i := 0; i < len(abiValuesMsgData.InputValues); i++ {
mutatedInput, err := valuegeneration.MutateAbiValue(sequenceGenerator.config.ValueGenerator, sequenceGenerator.config.ValueMutator, &abiValuesMsgData.Method.Inputs[i].Type, abiValuesMsgData.InputValues[i])
if err != nil {
return fmt.Errorf("error when mutating call sequence input argument: %v", err)
}
abiValuesMsgData.InputValues[i] = mutatedInput
mutatedInput, err := valuegeneration.MutateAbiValue(sequenceGenerator.config.ValueGenerator, sequenceGenerator.config.ValueMutator, &abiValuesMsgData.Method.Inputs[idx].Type, abiValuesMsgData.InputValues[idx])
if err != nil {
return fmt.Errorf("error when mutating call sequence input argument: %v", err)
}
abiValuesMsgData.InputValues[idx] = mutatedInput

// Re-encode the message's calldata
element.Call.WithDataAbiValues(abiValuesMsgData)

Expand Down
43 changes: 17 additions & 26 deletions fuzzing/valuegeneration/abi_values.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ package valuegeneration
import (
"encoding/hex"
"fmt"
"github.com/crytic/medusa/logging"
"github.com/crytic/medusa/utils"
"math/big"
"reflect"
"strconv"
"strings"

"github.com/crytic/medusa/logging"
"github.com/crytic/medusa/utils"

"github.com/crytic/medusa/utils/reflectionutils"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
Expand Down Expand Up @@ -211,41 +212,31 @@ func MutateAbiValue(generator ValueGenerator, mutator ValueMutator, inputType *a
// Note: We create a copy, as existing arrays may not be assignable.
array := reflectionutils.CopyReflectedType(reflect.ValueOf(value))

// Mutate our array structure first
mutatedValues := mutator.MutateArray(reflectionutils.GetReflectedArrayValues(array), true)
// Mutate our array structure
mutatedValues := mutator.MutateArray(reflectionutils.GetReflectedArrayValues(array), true, inputType.Elem)

// TODO: Make sure that we do not need to create a new copy of the array with some unit tests.

// Create a new array of the appropriate size
array = reflect.New(reflect.ArrayOf(array.Len(), array.Type().Elem())).Elem()
/*array = reflect.New(reflect.ArrayOf(array.Len(), array.Type().Elem())).Elem()

// Next mutate each element in the array.
// Next set each element in the new array.
for i := 0; i < array.Len(); i++ {
// Obtain the element's reflected value to access its getter/setters
reflectedElement := array.Index(i)

// If any item is nil, we generate a new element in its place instead. Otherwise, we mutate the existing value.
if mutatedValues[i] == nil {
generatedElement := GenerateAbiValue(generator, inputType.Elem)
reflectedElement.Set(reflect.ValueOf(generatedElement))
} else {
mutatedElement, err := MutateAbiValue(generator, mutator, inputType.Elem, mutatedValues[i])
if err != nil {
return nil, fmt.Errorf("could not mutate array input as the value generator encountered an error: %v", err)
}
reflectedElement.Set(reflect.ValueOf(mutatedElement))
}
}
array.Index(i).Set(reflect.ValueOf(mutatedValues[i]))
}*/

return array.Interface(), nil
return mutatedValues, nil
case abi.SliceTy:
// Dynamic sized arrays are represented as slices.
// Note: We create a copy, as existing slices may not be assignable.
slice := reflectionutils.CopyReflectedType(reflect.ValueOf(value))

// Mutate our slice structure first
mutatedValues := mutator.MutateArray(reflectionutils.GetReflectedArrayValues(slice), false)
mutatedValues := mutator.MutateArray(reflectionutils.GetReflectedArrayValues(slice), false, inputType.Elem)

// TODO: Same TODO as for arrays above.
// Create a new slice of the appropriate size
slice = reflect.MakeSlice(reflect.SliceOf(slice.Type().Elem()), len(mutatedValues), len(mutatedValues))
/*slice = reflect.MakeSlice(reflect.SliceOf(slice.Type().Elem()), len(mutatedValues), len(mutatedValues))

// Next mutate each element in the slice.
for i := 0; i < slice.Len(); i++ {
Expand All @@ -263,8 +254,8 @@ func MutateAbiValue(generator ValueGenerator, mutator ValueMutator, inputType *a
}
reflectedElement.Set(reflect.ValueOf(mutatedElement))
}
}
return slice.Interface(), nil
}*/
return mutatedValues, nil
case abi.TupleTy:
// Structs are used to represent tuples.
// Note: We create a copy, as existing tuples may not be assignable.
Expand Down
37 changes: 17 additions & 20 deletions fuzzing/valuegeneration/abi_values_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -250,27 +250,24 @@ func TestABIGenerationAndMutation(t *testing.T) {
mutationalGeneratorConfig := &MutationalValueGeneratorConfig{
MinMutationRounds: 0,
MaxMutationRounds: 1,
GenerateRandomAddressBias: 0.5,
GenerateRandomIntegerBias: 0.5,
GenerateRandomStringBias: 0.5,
GenerateRandomBytesBias: 0.5,
MutateAddressProbability: 0.8,
MutateArrayStructureProbability: 0.8,
MutateBoolProbability: 0.8,
MutateBytesProbability: 0.8,
MutateBytesGenerateNewBias: 0.45,
MutateFixedBytesProbability: 0.8,
MutateStringProbability: 0.8,
MutateStringGenerateNewBias: 0.7,
MutateIntegerProbability: 0.8,
MutateIntegerGenerateNewBias: 0.5,
GenerateRandomAddressBias: 0.4,
GenerateRandomIntegerBias: 0.4,
GenerateRandomStringBias: 0.4,
GenerateRandomBytesBias: 0.4,
MutateAddressProbability: 0.1,
MutateArrayStructureProbability: 0.1,
MutateBoolProbability: 0.1,
MutateBytesProbability: 0.1,
MutateFixedBytesProbability: 0.1,
MutateStringProbability: 0.1,
MutateIntegerProbability: 0.1,
RandomValueGeneratorConfig: &RandomValueGeneratorConfig{
GenerateRandomArrayMinSize: 0,
GenerateRandomArrayMaxSize: 100,
GenerateRandomBytesMinSize: 0,
GenerateRandomBytesMaxSize: 100,
GenerateRandomStringMinSize: 0,
GenerateRandomStringMaxSize: 100,
GenerateRandomArrayMinSize: 1,
GenerateRandomArrayMaxSize: 32,
GenerateRandomBytesMinSize: 1,
GenerateRandomBytesMaxSize: 32,
GenerateRandomStringMinSize: 1,
GenerateRandomStringMaxSize: 32,
},
}
mutationalGenerator := NewMutationalValueGenerator(mutationalGeneratorConfig, NewValueSet(), rand.New(rand.NewSource(time.Now().UnixNano())))
Expand Down
Loading
Loading