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