github.com/core-coin/go-core/v2@v2.1.9/tests/fuzzers/abi/abifuzzer.go (about) 1 // Copyright 2020 by the Authors 2 // This file is part of the go-core library. 3 // 4 // The go-core library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-core library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-core library. If not, see <http://www.gnu.org/licenses/>. 16 17 package abi 18 19 import ( 20 "bytes" 21 "fmt" 22 "math/rand" 23 "reflect" 24 "strings" 25 26 fuzz "github.com/google/gofuzz" 27 28 "github.com/core-coin/go-core/v2/accounts/abi" 29 "github.com/core-coin/go-core/v2/crypto" 30 ) 31 32 func unpackPack(abi abi.ABI, method string, inputType []interface{}, input []byte) bool { 33 outptr := reflect.New(reflect.TypeOf(inputType)) 34 if err := abi.UnpackIntoInterface(outptr.Interface(), method, input); err == nil { 35 output, err := abi.Pack(method, input) 36 if err != nil { 37 // We have some false positives as we can unpack these type successfully, but not pack them 38 if err.Error() == "abi: cannot use []uint8 as type [0]int8 as argument" || 39 err.Error() == "abi: cannot use uint8 as type int8 as argument" { 40 return false 41 } 42 panic(err) 43 } 44 if !bytes.Equal(input, output[4:]) { 45 panic(fmt.Sprintf("unpackPack is not equal, \ninput : %x\noutput: %x", input, output[4:])) 46 } 47 return true 48 } 49 return false 50 } 51 52 func packUnpack(abi abi.ABI, method string, input []interface{}) bool { 53 if packed, err := abi.Pack(method, input); err == nil { 54 outptr := reflect.New(reflect.TypeOf(input)) 55 err := abi.UnpackIntoInterface(outptr.Interface(), method, packed) 56 if err != nil { 57 panic(err) 58 } 59 out := outptr.Elem().Interface() 60 if !reflect.DeepEqual(input, out) { 61 panic(fmt.Sprintf("unpackPack is not equal, \ninput : %x\noutput: %x", input, out)) 62 } 63 return true 64 } 65 return false 66 } 67 68 type args struct { 69 name string 70 typ string 71 } 72 73 func createABI(name string, stateMutability, payable *string, inputs []args) (abi.ABI, error) { 74 sig := fmt.Sprintf(`[{ "type" : "function", "name" : "%v" `, name) 75 if stateMutability != nil { 76 sig += fmt.Sprintf(`, "stateMutability": "%v" `, *stateMutability) 77 } 78 if payable != nil { 79 sig += fmt.Sprintf(`, "payable": %v `, *payable) 80 } 81 if len(inputs) > 0 { 82 sig += `, "inputs" : [ {` 83 for i, inp := range inputs { 84 sig += fmt.Sprintf(`"name" : "%v", "type" : "%v" `, inp.name, inp.typ) 85 if i+1 < len(inputs) { 86 sig += "," 87 } 88 } 89 sig += "} ]" 90 sig += `, "outputs" : [ {` 91 for i, inp := range inputs { 92 sig += fmt.Sprintf(`"name" : "%v", "type" : "%v" `, inp.name, inp.typ) 93 if i+1 < len(inputs) { 94 sig += "," 95 } 96 } 97 sig += "} ]" 98 } 99 sig += `}]` 100 101 return abi.JSON(strings.NewReader(sig)) 102 } 103 104 func fillStruct(structs []interface{}, data []byte) { 105 if structs != nil && len(data) != 0 { 106 fuzz.NewFromGoFuzz(data).Fuzz(&structs) 107 } 108 } 109 110 func createStructs(args []args) []interface{} { 111 structs := make([]interface{}, len(args)) 112 for i, arg := range args { 113 t, err := abi.NewType(arg.typ, "", nil) 114 if err != nil { 115 panic(err) 116 } 117 structs[i] = reflect.New(t.GetType()).Elem() 118 } 119 return structs 120 } 121 122 func runFuzzer(input []byte) int { 123 good := false 124 125 names := []string{"_name", "name", "NAME", "name_", "__", "_name_", "n"} 126 stateMut := []string{"", "pure", "view", "payable"} 127 stateMutabilites := []*string{nil, &stateMut[0], &stateMut[1], &stateMut[2], &stateMut[3]} 128 pays := []string{"true", "false"} 129 payables := []*string{nil, &pays[0], &pays[1]} 130 varNames := []string{"a", "b", "c", "d", "e", "f", "g"} 131 varNames = append(varNames, names...) 132 varTypes := []string{"bool", "address", "bytes", "string", 133 "uint8", "int8", "uint8", "int8", "uint16", "int16", 134 "uint24", "int24", "uint32", "int32", "uint40", "int40", "uint48", "int48", "uint56", "int56", 135 "uint64", "int64", "uint72", "int72", "uint80", "int80", "uint88", "int88", "uint96", "int96", 136 "uint104", "int104", "uint112", "int112", "uint120", "int120", "uint128", "int128", "uint136", "int136", 137 "uint144", "int144", "uint152", "int152", "uint160", "int160", "uint168", "int168", "uint176", "int176", 138 "uint184", "int184", "uint192", "int192", "uint200", "int200", "uint208", "int208", "uint216", "int216", 139 "uint224", "int224", "uint232", "int232", "uint240", "int240", "uint248", "int248", "uint256", "int256", 140 "bytes1", "bytes2", "bytes3", "bytes4", "bytes5", "bytes6", "bytes7", "bytes8", "bytes9", "bytes10", "bytes11", 141 "bytes12", "bytes13", "bytes14", "bytes15", "bytes16", "bytes17", "bytes18", "bytes19", "bytes20", "bytes21", 142 "bytes22", "bytes23", "bytes24", "bytes25", "bytes26", "bytes27", "bytes28", "bytes29", "bytes30", "bytes31", 143 "bytes32", "bytes"} 144 rnd := rand.New(rand.NewSource(123456)) 145 if len(input) > 0 { 146 kec := crypto.SHA3(input) 147 rnd = rand.New(rand.NewSource(int64(kec[0]))) 148 } 149 name := names[rnd.Intn(len(names))] 150 stateM := stateMutabilites[rnd.Intn(len(stateMutabilites))] 151 payable := payables[rnd.Intn(len(payables))] 152 maxLen := 5 153 for k := 1; k < maxLen; k++ { 154 var arg []args 155 for i := k; i > 0; i-- { 156 argName := varNames[i] 157 argTyp := varTypes[rnd.Int31n(int32(len(varTypes)))] 158 if rnd.Int31n(10) == 0 { 159 argTyp += "[]" 160 } else if rnd.Int31n(10) == 0 { 161 arrayArgs := rnd.Int31n(30) + 1 162 argTyp += fmt.Sprintf("[%d]", arrayArgs) 163 } 164 arg = append(arg, args{ 165 name: argName, 166 typ: argTyp, 167 }) 168 } 169 abi, err := createABI(name, stateM, payable, arg) 170 if err != nil { 171 continue 172 } 173 structs := createStructs(arg) 174 b := unpackPack(abi, name, structs, input) 175 fillStruct(structs, input) 176 c := packUnpack(abi, name, structs) 177 good = good || b || c 178 } 179 if good { 180 return 1 181 } 182 return 0 183 } 184 185 func Fuzz(input []byte) int { 186 return runFuzzer(input) 187 }