fuzzers: fuzzers for keystore, rlp, trie, whisper (cred to @guidovranken)

This commit is contained in:
Martin Holst Swende 2019-05-19 21:04:17 +02:00
parent 23c8c74131
commit ce425cde6c
No known key found for this signature in database
GPG key ID: 683B438C05A5DDF0
9 changed files with 425 additions and 0 deletions

37
fuzzbuzz.yaml Normal file
View file

@ -0,0 +1,37 @@
# bmt keystore rlp trie whisperv6
base: ubuntu:16.04
targets:
- name: rlp
language: go
version: "1.11"
corpus: ./fuzzers/rlp/corpus
harness:
function: Fuzz
package: github.com/ethereum/go-ethereum/fuzzers/rlp
checkout: github.com/ethereum/go-ethereum/
- name: keystore
language: go
version: "1.11"
corpus: ./fuzzers/keystore/corpus
harness:
function: Fuzz
package: github.com/ethereum/go-ethereum/fuzzers/keystore
checkout: github.com/ethereum/go-ethereum/
- name: trie
language: go
version: "1.11"
corpus: ./fuzzers/trie/corpus
harness:
function: Fuzz
package: github.com/ethereum/go-ethereum/fuzzers/trie
checkout: github.com/ethereum/go-ethereum/
- name: whisperv6
language: go
version: "1.11"
corpus: ./fuzzers/whisperv6/corpus
harness:
function: Fuzz
package: github.com/ethereum/go-ethereum/fuzzers/whisperv6
checkout: github.com/ethereum/go-ethereum/

View file

@ -0,0 +1 @@
ns©,²Ô

View file

@ -0,0 +1,22 @@
package keystore
import (
"os"
"github.com/ethereum/go-ethereum/accounts/keystore"
)
func Fuzz(input []byte) int {
ks := keystore.NewKeyStore("/tmp/ks", keystore.LightScryptN, keystore.LightScryptP)
a, err := ks.NewAccount(string(input))
if err != nil {
panic(err)
}
if err := ks.Unlock(a, string(input)); err != nil {
panic(err)
}
os.Remove(a.URL.Path)
return 0
}

1
fuzzers/rlp/corpus/r.bin Normal file
View file

@ -0,0 +1 @@
Ë€€€À€ÀÃÀÀÀÀ

114
fuzzers/rlp/rlp_fuzzer.go Normal file
View file

@ -0,0 +1,114 @@
package rlp
import (
"bytes"
"fmt"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/rlp"
)
func decodeEncode(input []byte, val interface{}, i int) {
if err := rlp.DecodeBytes(input, val); err == nil {
output, err := rlp.EncodeToBytes(val)
if err != nil {
panic(err)
}
if !bytes.Equal(input, output) {
panic(fmt.Sprintf("case %d: encode-decode is not equal, \ninput : %x\noutput: %x", i, input, output))
}
}
}
func Fuzz(input []byte) int {
var i int
{
if len(input) > 0 {
rlp.Split(input)
}
}
{
if len(input) > 0 {
if elems, _, err := rlp.SplitList(input); err == nil {
rlp.CountValues(elems)
}
}
}
{
rlp.NewStream(bytes.NewReader(input), 0).Decode(new(interface{}))
}
{
decodeEncode(input, new(interface{}), i)
i++
}
{
var v struct {
Int uint
String string
Bytes []byte
}
decodeEncode(input, &v, i)
i++
}
{
type Types struct {
Bool bool
Raw rlp.RawValue
Slice []*Types
Iface []interface{}
}
var v Types
decodeEncode(input, &v, i)
i++
}
{
type AllTypes struct {
Int uint
String string
Bytes []byte
Bool bool
Raw rlp.RawValue
Slice []*AllTypes
Array [3]*AllTypes
Iface []interface{}
}
var v AllTypes
decodeEncode(input, &v, i)
i++
}
{
decodeEncode(input, [10]byte{}, i)
i++
}
{
var v struct {
Byte [10]byte
Rool [10]bool
}
decodeEncode(input, &v, i)
i++
}
{
var h types.Header
decodeEncode(input, &h, i)
i++
var b types.Block
decodeEncode(input, &b, i)
i++
var t types.Transaction
decodeEncode(input, &t, i)
i++
var txs types.Transactions
decodeEncode(input, &txs, i)
i++
var rs types.Receipts
decodeEncode(input, &rs, i)
i++
}
return 0
}

1
fuzzers/trie/corpus/data Normal file
View file

@ -0,0 +1 @@
asdlfkjasf23oiejfasdfadkfqlkjfasdlkfjalwk4jfalsdkfjawlefkjsadlfkjasldkfjwalefkjasdlfkjM

173
fuzzers/trie/trie-fuzzer.go Normal file
View file

@ -0,0 +1,173 @@
package trie
import (
"bytes"
"encoding/binary"
"fmt"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethdb/memorydb"
"github.com/ethereum/go-ethereum/trie"
)
// randTest performs random trie operations.
// Instances of this test are created by Generate.
type randTest []randTestStep
type randTestStep struct {
op int
key []byte // for opUpdate, opDelete, opGet
value []byte // for opUpdate
err error // for debugging
}
type proofDb struct{}
func (proofDb) Put(key []byte, value []byte) error {
return nil
}
func (proofDb) Delete(key []byte) error {
return nil
}
const (
opUpdate = iota
opDelete
opGet
opCommit
opHash
opReset
opItercheckhash
opProve
opMax // boundary value, not an actual op
)
type dataSource struct {
input []byte
reader *bytes.Reader
}
func newDataSource(input []byte) *dataSource {
return &dataSource{
input, bytes.NewReader(input),
}
}
func (ds *dataSource) ReadByte() byte {
if b, err := ds.reader.ReadByte(); err != nil {
return 0
} else {
return b
}
}
func (ds *dataSource) Read(buf []byte) (int, error) {
return ds.reader.Read(buf)
}
func (ds *dataSource) Ended() bool {
return ds.reader.Len() == 0
}
func Generate(input []byte) randTest {
var allKeys [][]byte
r := newDataSource(input)
genKey := func() []byte {
if len(allKeys) < 2 || r.ReadByte() < 0x0f {
// new key
key := make([]byte, r.ReadByte()%50)
r.Read(key)
allKeys = append(allKeys, key)
return key
}
// use existing key
return allKeys[int(r.ReadByte())%len(allKeys)]
}
var steps randTest
for i := 0; !r.Ended(); i++ {
step := randTestStep{op: int(r.ReadByte()) % opMax}
switch step.op {
case opUpdate:
step.key = genKey()
step.value = make([]byte, 8)
binary.BigEndian.PutUint64(step.value, uint64(i))
case opGet, opDelete, opProve:
step.key = genKey()
}
steps = append(steps, step)
if len(steps) > 500 {
break
}
}
return steps
}
func Fuzz(input []byte) int {
program := Generate(input)
if len(program) == 0 {
return -1
}
if err := runRandTest(program); err != nil {
panic(err)
}
return 0
}
func runRandTest(rt randTest) error {
triedb := trie.NewDatabase(memorydb.New())
tr, _ := trie.New(common.Hash{}, triedb)
values := make(map[string]string) // tracks content of the trie
for i, step := range rt {
switch step.op {
case opUpdate:
tr.Update(step.key, step.value)
values[string(step.key)] = string(step.value)
case opDelete:
tr.Delete(step.key)
delete(values, string(step.key))
case opGet:
v := tr.Get(step.key)
want := values[string(step.key)]
if string(v) != want {
rt[i].err = fmt.Errorf("mismatch for key 0x%x, got 0x%x want 0x%x", step.key, v, want)
}
case opCommit:
_, rt[i].err = tr.Commit(nil)
case opHash:
tr.Hash()
case opReset:
hash, err := tr.Commit(nil)
if err != nil {
return err
}
newtr, err := trie.New(hash, triedb)
if err != nil {
return err
}
tr = newtr
case opItercheckhash:
checktr, _ := trie.New(common.Hash{}, triedb)
it := trie.NewIterator(tr.NodeIterator(nil))
for it.Next() {
checktr.Update(it.Key, it.Value)
}
if tr.Hash() != checktr.Hash() {
return fmt.Errorf("hash mismatch in opItercheckhash")
}
case opProve:
rt[i].err = tr.Prove(step.key, 0, proofDb{})
}
// Abort the test on error.
if rt[i].err != nil {
return rt[i].err
}
}
return nil
}

View file

@ -0,0 +1,76 @@
package whisperv6
import (
"bytes"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/whisper/whisperv6"
)
type MessageParams struct {
Topic whisperv6.TopicType
WorkTime uint32
TTL uint32
KeySym []byte
Payload []byte
}
//export fuzzer_entry
func Fuzz(input []byte) int {
var paramsDecoded MessageParams
err := rlp.DecodeBytes(input, &paramsDecoded)
if err != nil {
return 0
}
var params whisperv6.MessageParams
params.KeySym = make([]byte, 32)
if len(paramsDecoded.KeySym) <= 32 {
copy(params.KeySym, paramsDecoded.KeySym)
}
if input[0] == 255 {
params.PoW = 0.01
params.WorkTime = 1
} else {
params.PoW = 0
params.WorkTime = 0
}
params.TTL = paramsDecoded.TTL
params.Payload = paramsDecoded.Payload
text := make([]byte, 0, 512)
text = append(text, params.Payload...)
params.Topic = paramsDecoded.Topic
params.Src, err = crypto.GenerateKey()
if err != nil {
return 0
}
msg, err := whisperv6.NewSentMessage(&params)
if err != nil {
panic(err)
//return
}
env, err := msg.Wrap(&params)
if err != nil {
panic(err)
}
decrypted, err := env.OpenSymmetric(params.KeySym)
if err != nil {
panic(err)
}
if !decrypted.ValidateAndParse() {
panic("ValidateAndParse failed")
return 0
}
if !bytes.Equal(text, decrypted.Payload) {
panic("text != decrypted.Payload")
}
if len(decrypted.Signature) != 65 {
panic("Unexpected signature length")
}
if !whisperv6.IsPubKeyEqual(decrypted.Src, &params.Src.PublicKey) {
panic("Unexpected public key")
}
return 0
}