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