From cebb62997d3a467f0814332683772e9181dc261c Mon Sep 17 00:00:00 2001 From: Preston Van Loon Date: Mon, 14 Sep 2020 13:42:08 -0500 Subject: [PATCH] Add beacon state unmarshal fuzzer, afl support (#6625) * Add AFL third_party libraries * add beacon state fuzzing, add afl fuzz bundle * rm fuzzing engine * fix and lint * Check for array out of bounds when calculating proposer delta * failing test * fix * Checkpoint progress * Add requirement that inclusion distance is not zero, add regression test * No need for HTR since that is covered in process slots * Removing some fuzzit logic, old fuzz tests * Add ssz encoder test and fix * Fuzzing checkpoint, adding fuzzing to the p2p layer * ignore some libfuzzer files * Full testing of p2p processing of blocks, with some mocked stuff * use tmpdir and always process blocks * use checkptr * Update ethereumapis * go mod tidy * benchmarks for ferran's fast ssz hash tree root * Update fastssz * fmt * gaz * goimports * Fix * fix ethereumapis * fix again * kafka * fix gen file * fix compute signing root * gofmt * checkpoint progress * progress * checkpoint * updates * updates * merge fix * WIP * merge * fix build * fix merge related issues * cleanup * revert unrelated * lint * lint * lint * manual tags for fuzz * Commentary on upload script * some import fixes, but not all * fix //fuzz:fuzz_tests * rm unused test * update generated ssz * Set // +build libfuzzer * remove debug code * A bit of refactoring ot explain why there is a committee_disabled file Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com> --- .bazelrc | 8 +- .gitignore | 4 + beacon-chain/blockchain/BUILD.bazel | 5 +- beacon-chain/cache/BUILD.bazel | 11 +- beacon-chain/cache/committee.go | 21 +- beacon-chain/cache/committee_disabled.go | 50 + beacon-chain/cache/committees.go | 16 + beacon-chain/core/helpers/BUILD.bazel | 5 +- beacon-chain/core/helpers/committee.go | 3 +- beacon-chain/db/BUILD.bazel | 1 + .../forkchoice/protoarray/BUILD.bazel | 5 +- .../operations/attestations/BUILD.bazel | 5 +- beacon-chain/operations/slashings/BUILD.bazel | 5 +- .../operations/voluntaryexits/BUILD.bazel | 5 +- beacon-chain/p2p/encoder/BUILD.bazel | 1 + beacon-chain/p2p/testing/BUILD.bazel | 6 +- beacon-chain/p2p/testing/fuzz_p2p.go | 163 + beacon-chain/state/stategen/BUILD.bazel | 5 +- beacon-chain/sync/BUILD.bazel | 1 + beacon-chain/sync/fuzz_exports.go | 54 + fuzz/BUILD.bazel | 214 +- fuzz/README.md | 2 +- fuzz/attestation_fuzz.go | 33 - fuzz/attester_slashing_fuzz.go | 38 - fuzz/block_fuzz.go | 204 +- fuzz/block_header_fuzz.go | 30 - fuzz/deposit_corpus/.gitkeep | 0 fuzz/deposit_fuzz.go | 30 - fuzz/generated.ssz.go | 487 +- fuzz/inputs.go | 39 +- fuzz/proposer_slashing_fuzz.go | 40 - fuzz/ssz_encoder_attestations_fuzz.go | 27 + fuzz/state_fuzz.go | 40 + fuzz/voluntary_exit_corpus/.gitkeep | 0 fuzz/voluntary_exit_fuzz.go | 31 - proto/testing/BUILD.bazel | 1 + scripts/upload_fuzzers.sh | 15 + shared/params/spectest/config.go | 2 +- shared/params/testutils.go | 2 +- shared/testutil/spectest.go | 2 +- third_party/afl/BUILD.bazel | 80 + third_party/afl/afl-fuzz | Bin 0 -> 794688 bytes third_party/afl/afl-fuzz.c | 8099 +++++++++++++++++ third_party/afl/afl-showmap.c | 780 ++ third_party/afl/afl_driver.cpp | 277 + third_party/afl/alloc-inl.h | 570 ++ third_party/afl/config.h | 350 + third_party/afl/debug.h | 251 + third_party/afl/hash.h | 104 + third_party/afl/llvm_mode/afl-llvm-rt.o.c | 306 + third_party/afl/types.h | 86 + tools/BUILD.bazel | 6 - tools/fuzzit_wrapper.sh | 19 - tools/go/def.bzl | 2 +- tools/go/fuzz.bzl | 103 +- 55 files changed, 11761 insertions(+), 883 deletions(-) create mode 100644 beacon-chain/cache/committee_disabled.go create mode 100644 beacon-chain/cache/committees.go create mode 100644 beacon-chain/p2p/testing/fuzz_p2p.go create mode 100644 beacon-chain/sync/fuzz_exports.go delete mode 100644 fuzz/attestation_fuzz.go delete mode 100644 fuzz/attester_slashing_fuzz.go delete mode 100644 fuzz/block_header_fuzz.go delete mode 100644 fuzz/deposit_corpus/.gitkeep delete mode 100644 fuzz/deposit_fuzz.go delete mode 100644 fuzz/proposer_slashing_fuzz.go create mode 100644 fuzz/ssz_encoder_attestations_fuzz.go create mode 100644 fuzz/state_fuzz.go delete mode 100644 fuzz/voluntary_exit_corpus/.gitkeep delete mode 100644 fuzz/voluntary_exit_fuzz.go create mode 100755 scripts/upload_fuzzers.sh create mode 100644 third_party/afl/BUILD.bazel create mode 100755 third_party/afl/afl-fuzz create mode 100644 third_party/afl/afl-fuzz.c create mode 100644 third_party/afl/afl-showmap.c create mode 100644 third_party/afl/afl_driver.cpp create mode 100644 third_party/afl/alloc-inl.h create mode 100644 third_party/afl/config.h create mode 100644 third_party/afl/debug.h create mode 100644 third_party/afl/hash.h create mode 100644 third_party/afl/llvm_mode/afl-llvm-rt.o.c create mode 100644 third_party/afl/types.h delete mode 100755 tools/fuzzit_wrapper.sh diff --git a/.bazelrc b/.bazelrc index 6093689d8..6a6b3f7c5 100644 --- a/.bazelrc +++ b/.bazelrc @@ -69,18 +69,12 @@ build:fuzz --copt=-fno-omit-frame-pointer build:fuzz --define=FUZZING_ENGINE=libfuzzer build:fuzz --copt=-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION build:fuzz --linkopt -Wl,--no-as-needed -build:fuzz --define=gc_goopts=-d=libfuzzer +build:fuzz --define=gc_goopts=-d=libfuzzer,checkptr build:fuzz --run_under=//tools:fuzz_wrapper build:fuzz --compilation_mode=opt test:fuzz --local_test_jobs="HOST_CPUS*.5" -test:fuzzit --config=fuzz -test:fuzzit --test_env=FUZZIT_API_KEY -test:fuzzit --test_env=PRYSM_BUILD_IMAGE=gcr.io/prysmaticlabs/prysm-fuzzit:v0.11.0 -test:fuzzit --test_timeout=1200 -test:fuzzit --run_under=//tools:fuzzit_wrapper - # Build binary with cgo symbolizer for debugging / profiling. build:cgo_symbolizer --config=llvm build:cgo_symbolizer --copt=-g diff --git a/.gitignore b/.gitignore index 1ab57e816..f6e5694e1 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,7 @@ password.txt # Dist files dist + +# libfuzzer +oom-* +crash-* diff --git a/beacon-chain/blockchain/BUILD.bazel b/beacon-chain/blockchain/BUILD.bazel index 31ae9567e..59330c686 100644 --- a/beacon-chain/blockchain/BUILD.bazel +++ b/beacon-chain/blockchain/BUILD.bazel @@ -20,7 +20,10 @@ go_library( "service.go", ], importpath = "github.com/prysmaticlabs/prysm/beacon-chain/blockchain", - visibility = ["//beacon-chain:__subpackages__"], + visibility = [ + "//beacon-chain:__subpackages__", + "//fuzz:__pkg__", + ], deps = [ "//beacon-chain/cache:go_default_library", "//beacon-chain/cache/depositcache:go_default_library", diff --git a/beacon-chain/cache/BUILD.bazel b/beacon-chain/cache/BUILD.bazel index a4e212b16..06cfac6f2 100644 --- a/beacon-chain/cache/BUILD.bazel +++ b/beacon-chain/cache/BUILD.bazel @@ -6,14 +6,21 @@ go_library( srcs = [ "attestation_data.go", "checkpoint_state.go", - "committee.go", + "committees.go", "common.go", "doc.go", "hot_state_cache.go", "skip_slot_cache.go", "state_summary.go", "subnet_ids.go", - ], + ] + select({ + "//fuzz:fuzzing_enabled": [ + "committee_disabled.go", + ], + "//conditions:default": [ + "committee.go", + ], + }), importpath = "github.com/prysmaticlabs/prysm/beacon-chain/cache", visibility = [ "//beacon-chain:__subpackages__", diff --git a/beacon-chain/cache/committee.go b/beacon-chain/cache/committee.go index 0ebb0de65..388b6f3fe 100644 --- a/beacon-chain/cache/committee.go +++ b/beacon-chain/cache/committee.go @@ -1,3 +1,5 @@ +// -build libfuzzer + package cache import ( @@ -12,10 +14,6 @@ import ( ) var ( - // ErrNotCommittee will be returned when a cache object is not a pointer to - // a Committee struct. - ErrNotCommittee = errors.New("object is not a committee struct") - // maxCommitteesCacheSize defines the max number of shuffled committees on per randao basis can cache. // Due to reorgs and long finality, it's good to keep the old cache around for quickly switch over. maxCommitteesCacheSize = uint64(32) @@ -32,15 +30,6 @@ var ( }) ) -// Committees defines the shuffled committees seed. -type Committees struct { - CommitteeCount uint64 - Seed [32]byte - ShuffledIndices []uint64 - SortedIndices []uint64 - ProposerIndices []uint64 -} - // CommitteeCache is a struct with 1 queue for looking up shuffled indices list by seed. type CommitteeCache struct { CommitteeCache *cache.FIFO @@ -216,6 +205,12 @@ func (c *CommitteeCache) ProposerIndices(seed [32]byte) ([]uint64, error) { return item.ProposerIndices, nil } +// HasEntry returns true if the committee cache has a value. +func (c *CommitteeCache) HasEntry(seed string) bool { + _, ok, err := c.CommitteeCache.GetByKey(seed) + return err == nil && ok +} + func startEndIndices(c *Committees, index uint64) (uint64, uint64) { validatorCount := uint64(len(c.ShuffledIndices)) start := sliceutil.SplitOffset(validatorCount, c.CommitteeCount, index) diff --git a/beacon-chain/cache/committee_disabled.go b/beacon-chain/cache/committee_disabled.go new file mode 100644 index 000000000..835083d04 --- /dev/null +++ b/beacon-chain/cache/committee_disabled.go @@ -0,0 +1,50 @@ +// +build libfuzzer + +// This file is used in fuzzer builds to bypass global committee caches. +package cache + +// FakeCommitteeCache is a struct with 1 queue for looking up shuffled indices list by seed. +type FakeCommitteeCache struct { +} + +// NewCommitteesCache creates a new committee cache for storing/accessing shuffled indices of a committee. +func NewCommitteesCache() *FakeCommitteeCache { + return &FakeCommitteeCache{} +} + +// Committee fetches the shuffled indices by slot and committee index. Every list of indices +// represent one committee. Returns true if the list exists with slot and committee index. Otherwise returns false, nil. +func (c *FakeCommitteeCache) Committee(slot uint64, seed [32]byte, index uint64) ([]uint64, error) { + return nil, nil +} + +// AddCommitteeShuffledList adds Committee shuffled list object to the cache. T +// his method also trims the least recently list if the cache size has ready the max cache size limit. +func (c *FakeCommitteeCache) AddCommitteeShuffledList(committees *Committees) error { + return nil +} + +// AddProposerIndicesList updates the committee shuffled list with proposer indices. +func (c *FakeCommitteeCache) AddProposerIndicesList(seed [32]byte, indices []uint64) error { + return nil +} + +// ActiveIndices returns the active indices of a given seed stored in cache. +func (c *FakeCommitteeCache) ActiveIndices(seed [32]byte) ([]uint64, error) { + return nil, nil +} + +// ActiveIndicesCount returns the active indices count of a given seed stored in cache. +func (c *FakeCommitteeCache) ActiveIndicesCount(seed [32]byte) (int, error) { + return 0, nil +} + +// ProposerIndices returns the proposer indices of a given seed. +func (c *FakeCommitteeCache) ProposerIndices(seed [32]byte) ([]uint64, error) { + return nil, nil +} + +// HasEntry returns true if the committee cache has a value. +func (c *FakeCommitteeCache) HasEntry(string) bool { + return false +} diff --git a/beacon-chain/cache/committees.go b/beacon-chain/cache/committees.go new file mode 100644 index 000000000..7ab74fbf0 --- /dev/null +++ b/beacon-chain/cache/committees.go @@ -0,0 +1,16 @@ +package cache + +import "errors" + +// ErrNotCommittee will be returned when a cache object is not a pointer to +// a Committee struct. +var ErrNotCommittee = errors.New("object is not a committee struct") + +// Committees defines the shuffled committees seed. +type Committees struct { + CommitteeCount uint64 + Seed [32]byte + ShuffledIndices []uint64 + SortedIndices []uint64 + ProposerIndices []uint64 +} diff --git a/beacon-chain/core/helpers/BUILD.bazel b/beacon-chain/core/helpers/BUILD.bazel index 938767f3b..fda41a414 100644 --- a/beacon-chain/core/helpers/BUILD.bazel +++ b/beacon-chain/core/helpers/BUILD.bazel @@ -18,12 +18,13 @@ go_library( visibility = [ "//beacon-chain:__subpackages__", "//endtoend/evaluators:__pkg__", + "//fuzz:__pkg__", + "//shared/attestationutil:__pkg__", "//shared/benchutil/benchmark_files:__subpackages__", + "//shared/depositutil:__pkg__", "//shared/interop:__pkg__", "//shared/keystore:__pkg__", - "//shared/depositutil:__pkg__", "//shared/p2putils:__pkg__", - "//shared/attestationutil:__pkg__", "//shared/testutil:__pkg__", "//slasher:__subpackages__", "//tools:__subpackages__", diff --git a/beacon-chain/core/helpers/committee.go b/beacon-chain/core/helpers/committee.go index 51e842e41..6d1917778 100644 --- a/beacon-chain/core/helpers/committee.go +++ b/beacon-chain/core/helpers/committee.go @@ -312,7 +312,8 @@ func UpdateCommitteeCache(state *stateTrie.BeaconState, epoch uint64) error { if err != nil { return err } - if _, exists, err := committeeCache.CommitteeCache.GetByKey(string(seed[:])); err == nil && exists { + + if committeeCache.HasEntry(string(seed[:])) { return nil } diff --git a/beacon-chain/db/BUILD.bazel b/beacon-chain/db/BUILD.bazel index cdffcb76b..487def908 100644 --- a/beacon-chain/db/BUILD.bazel +++ b/beacon-chain/db/BUILD.bazel @@ -23,6 +23,7 @@ go_library( importpath = "github.com/prysmaticlabs/prysm/beacon-chain/db", visibility = [ "//beacon-chain:__subpackages__", + "//fuzz:__pkg__", "//tools:__subpackages__", ], deps = [ diff --git a/beacon-chain/forkchoice/protoarray/BUILD.bazel b/beacon-chain/forkchoice/protoarray/BUILD.bazel index e5e2c2b2b..9124c45ec 100644 --- a/beacon-chain/forkchoice/protoarray/BUILD.bazel +++ b/beacon-chain/forkchoice/protoarray/BUILD.bazel @@ -14,7 +14,10 @@ go_library( "types.go", ], importpath = "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray", - visibility = ["//beacon-chain:__subpackages__"], + visibility = [ + "//beacon-chain:__subpackages__", + "//fuzz:__pkg__", + ], deps = [ "//shared/params:go_default_library", "@com_github_pkg_errors//:go_default_library", diff --git a/beacon-chain/operations/attestations/BUILD.bazel b/beacon-chain/operations/attestations/BUILD.bazel index 3207fd924..0c9e0235f 100644 --- a/beacon-chain/operations/attestations/BUILD.bazel +++ b/beacon-chain/operations/attestations/BUILD.bazel @@ -12,7 +12,10 @@ go_library( "service.go", ], importpath = "github.com/prysmaticlabs/prysm/beacon-chain/operations/attestations", - visibility = ["//beacon-chain:__subpackages__"], + visibility = [ + "//beacon-chain:__subpackages__", + "//fuzz:__pkg__", + ], deps = [ "//beacon-chain/operations/attestations/kv:go_default_library", "//beacon-chain/state:go_default_library", diff --git a/beacon-chain/operations/slashings/BUILD.bazel b/beacon-chain/operations/slashings/BUILD.bazel index aa1e80f2f..27e7c77b4 100644 --- a/beacon-chain/operations/slashings/BUILD.bazel +++ b/beacon-chain/operations/slashings/BUILD.bazel @@ -11,7 +11,10 @@ go_library( "types.go", ], importpath = "github.com/prysmaticlabs/prysm/beacon-chain/operations/slashings", - visibility = ["//beacon-chain:__subpackages__"], + visibility = [ + "//beacon-chain:__subpackages__", + "//fuzz:__pkg__", + ], deps = [ "//beacon-chain/core/blocks:go_default_library", "//beacon-chain/core/helpers:go_default_library", diff --git a/beacon-chain/operations/voluntaryexits/BUILD.bazel b/beacon-chain/operations/voluntaryexits/BUILD.bazel index b9a15a283..cd4cb3bd1 100644 --- a/beacon-chain/operations/voluntaryexits/BUILD.bazel +++ b/beacon-chain/operations/voluntaryexits/BUILD.bazel @@ -8,7 +8,10 @@ go_library( "service.go", ], importpath = "github.com/prysmaticlabs/prysm/beacon-chain/operations/voluntaryexits", - visibility = ["//beacon-chain:__subpackages__"], + visibility = [ + "//beacon-chain:__subpackages__", + "//fuzz:__pkg__", + ], deps = [ "//beacon-chain/core/helpers:go_default_library", "//beacon-chain/state:go_default_library", diff --git a/beacon-chain/p2p/encoder/BUILD.bazel b/beacon-chain/p2p/encoder/BUILD.bazel index be11a8f1c..d3f39bf51 100644 --- a/beacon-chain/p2p/encoder/BUILD.bazel +++ b/beacon-chain/p2p/encoder/BUILD.bazel @@ -12,6 +12,7 @@ go_library( importpath = "github.com/prysmaticlabs/prysm/beacon-chain/p2p/encoder", visibility = [ "//beacon-chain:__subpackages__", + "//fuzz:__pkg__", ], deps = [ "//shared/params:go_default_library", diff --git a/beacon-chain/p2p/testing/BUILD.bazel b/beacon-chain/p2p/testing/BUILD.bazel index 6c85db959..e101ad33f 100644 --- a/beacon-chain/p2p/testing/BUILD.bazel +++ b/beacon-chain/p2p/testing/BUILD.bazel @@ -4,13 +4,17 @@ go_library( name = "go_default_library", testonly = True, srcs = [ + "fuzz_p2p.go", "mock_broadcaster.go", "mock_peermanager.go", "mock_peersprovider.go", "p2p.go", ], importpath = "github.com/prysmaticlabs/prysm/beacon-chain/p2p/testing", - visibility = ["//beacon-chain:__subpackages__"], + visibility = [ + "//beacon-chain:__subpackages__", + "//fuzz:__pkg__", + ], deps = [ "//beacon-chain/p2p/encoder:go_default_library", "//beacon-chain/p2p/peers:go_default_library", diff --git a/beacon-chain/p2p/testing/fuzz_p2p.go b/beacon-chain/p2p/testing/fuzz_p2p.go new file mode 100644 index 000000000..3ad0e21ca --- /dev/null +++ b/beacon-chain/p2p/testing/fuzz_p2p.go @@ -0,0 +1,163 @@ +package testing + +import ( + "context" + + "github.com/ethereum/go-ethereum/p2p/enr" + "github.com/gogo/protobuf/proto" + "github.com/libp2p/go-libp2p-core/control" + "github.com/libp2p/go-libp2p-core/host" + "github.com/libp2p/go-libp2p-core/network" + "github.com/libp2p/go-libp2p-core/peer" + pubsub "github.com/libp2p/go-libp2p-pubsub" + "github.com/multiformats/go-multiaddr" + ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" + + "github.com/prysmaticlabs/prysm/beacon-chain/p2p/encoder" + "github.com/prysmaticlabs/prysm/beacon-chain/p2p/peers" + pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" +) + +// FakeP2P stack +type FakeP2P struct { +} + +// NewFuzzTestP2P - Create a new fake p2p stack. +func NewFuzzTestP2P() *FakeP2P { + return &FakeP2P{} +} + +// Encoding -- fake. +func (p *FakeP2P) Encoding() encoder.NetworkEncoding { + return &encoder.SszNetworkEncoder{} +} + +// AddConnectionHandler -- fake. +func (p *FakeP2P) AddConnectionHandler(f func(ctx context.Context, id peer.ID) error) { + +} + +// AddDisconnectionHandler -- fake. +func (p *FakeP2P) AddDisconnectionHandler(f func(ctx context.Context, id peer.ID) error) { +} + +// AddPingMethod -- fake. +func (p *FakeP2P) AddPingMethod(reqFunc func(ctx context.Context, id peer.ID) error) { + +} + +// PeerID -- fake. +func (p *FakeP2P) PeerID() peer.ID { + return peer.ID("fake") +} + +// ENR returns the enr of the local peer. +func (p *FakeP2P) ENR() *enr.Record { + return new(enr.Record) +} + +// FindPeersWithSubnet mocks the p2p func. +func (p *FakeP2P) FindPeersWithSubnet(ctx context.Context, index uint64) (bool, error) { + return false, nil +} + +// RefreshENR mocks the p2p func. +func (p *FakeP2P) RefreshENR() { + return +} + +// LeaveTopic -- fake. +func (p *FakeP2P) LeaveTopic(topic string) error { + return nil + +} + +// Metadata -- fake. +func (p *FakeP2P) Metadata() *pb.MetaData { + return nil +} + +// Peers -- fake. +func (p *FakeP2P) Peers() *peers.Status { + return nil +} + +// PublishToTopic -- fake. +func (p *FakeP2P) PublishToTopic(ctx context.Context, topic string, data []byte, opts ...pubsub.PubOpt) error { + return nil +} + +// Send -- fake. +func (p *FakeP2P) Send(ctx context.Context, msg interface{}, topic string, pid peer.ID) (network.Stream, error) { + return nil, nil +} + +// PubSub -- fake. +func (p *FakeP2P) PubSub() *pubsub.PubSub { + return nil +} + +// MetadataSeq -- fake. +func (p *FakeP2P) MetadataSeq() uint64 { + return 0 +} + +// SetStreamHandler -- fake. +func (p *FakeP2P) SetStreamHandler(topic string, handler network.StreamHandler) { + +} + +// SubscribeToTopic -- fake. +func (p *FakeP2P) SubscribeToTopic(topic string, opts ...pubsub.SubOpt) (*pubsub.Subscription, error) { + return nil, nil +} + +// JoinTopic -- fake. +func (p *FakeP2P) JoinTopic(topic string, opts ...pubsub.TopicOpt) (*pubsub.Topic, error) { + return nil, nil +} + +// Host -- fake. +func (p *FakeP2P) Host() host.Host { + return nil +} + +// Disconnect -- fake. +func (p *FakeP2P) Disconnect(pid peer.ID) error { + return nil +} + +// Broadcast -- fake. +func (p *FakeP2P) Broadcast(ctx context.Context, msg proto.Message) error { + return nil +} + +// BroadcastAttestation -- fake. +func (p *FakeP2P) BroadcastAttestation(ctx context.Context, subnet uint64, att *ethpb.Attestation) error { + return nil +} + +// InterceptPeerDial -- fake. +func (p *FakeP2P) InterceptPeerDial(peer.ID) (allow bool) { + return true +} + +// InterceptAddrDial -- fake. +func (p *FakeP2P) InterceptAddrDial(peer.ID, multiaddr.Multiaddr) (allow bool) { + return true +} + +// InterceptAccept -- fake. +func (p *FakeP2P) InterceptAccept(n network.ConnMultiaddrs) (allow bool) { + return true +} + +// InterceptSecured -- fake. +func (p *FakeP2P) InterceptSecured(network.Direction, peer.ID, network.ConnMultiaddrs) (allow bool) { + return true +} + +// InterceptUpgraded -- fake. +func (p *FakeP2P) InterceptUpgraded(network.Conn) (allow bool, reason control.DisconnectReason) { + return true, 0 +} diff --git a/beacon-chain/state/stategen/BUILD.bazel b/beacon-chain/state/stategen/BUILD.bazel index 4b8899772..1686e9a8b 100644 --- a/beacon-chain/state/stategen/BUILD.bazel +++ b/beacon-chain/state/stategen/BUILD.bazel @@ -15,7 +15,10 @@ go_library( "setter.go", ], importpath = "github.com/prysmaticlabs/prysm/beacon-chain/state/stategen", - visibility = ["//beacon-chain:__subpackages__"], + visibility = [ + "//beacon-chain:__subpackages__", + "//fuzz:__pkg__", + ], deps = [ "//beacon-chain/cache:go_default_library", "//beacon-chain/core/helpers:go_default_library", diff --git a/beacon-chain/sync/BUILD.bazel b/beacon-chain/sync/BUILD.bazel index 28b30344b..e1365e47e 100644 --- a/beacon-chain/sync/BUILD.bazel +++ b/beacon-chain/sync/BUILD.bazel @@ -8,6 +8,7 @@ go_library( "decode_pubsub.go", "doc.go", "error.go", + "fuzz_exports.go", # keep "log.go", "metrics.go", "pending_attestations_queue.go", diff --git a/beacon-chain/sync/fuzz_exports.go b/beacon-chain/sync/fuzz_exports.go new file mode 100644 index 000000000..a9279ec25 --- /dev/null +++ b/beacon-chain/sync/fuzz_exports.go @@ -0,0 +1,54 @@ +// +build libfuzzer + +package sync + +import ( + "context" + + "github.com/gogo/protobuf/proto" + "github.com/libp2p/go-libp2p-core/peer" + pubsub "github.com/libp2p/go-libp2p-pubsub" + ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" +) + +// NewRegularSyncFuzz service without registering handlers. +func NewRegularSyncFuzz(cfg *Config) *Service { + rLimiter := newRateLimiter(cfg.P2P) + ctx, cancel := context.WithCancel(context.Background()) + r := &Service{ + ctx: ctx, + cancel: cancel, + db: cfg.DB, + p2p: cfg.P2P, + attPool: cfg.AttPool, + exitPool: cfg.ExitPool, + slashingPool: cfg.SlashingPool, + chain: cfg.Chain, + initialSync: cfg.InitialSync, + attestationNotifier: cfg.AttestationNotifier, + slotToPendingBlocks: make(map[uint64][]*ethpb.SignedBeaconBlock), + seenPendingBlocks: make(map[[32]byte]bool), + blkRootToPendingAtts: make(map[[32]byte][]*ethpb.SignedAggregateAttestationAndProof), + stateNotifier: cfg.StateNotifier, + blockNotifier: cfg.BlockNotifier, + stateSummaryCache: cfg.StateSummaryCache, + stateGen: cfg.StateGen, + rateLimiter: rLimiter, + } + + return r +} + +// FuzzValidateBeaconBlockPubSub exports private method validateBeaconBlockPubSub for fuzz testing. +func (s *Service) FuzzValidateBeaconBlockPubSub(ctx context.Context, pid peer.ID, msg *pubsub.Message) pubsub.ValidationResult { + return s.validateBeaconBlockPubSub(ctx, pid, msg) +} + +// FuzzBeaconBlockSubscriber exports private method beaconBlockSubscriber for fuzz testing. +func (s *Service) FuzzBeaconBlockSubscriber(ctx context.Context, msg proto.Message) error { + return s.beaconBlockSubscriber(ctx, msg) +} + +func (s *Service) InitCaches() error { + return s.initCaches() +} diff --git a/fuzz/BUILD.bazel b/fuzz/BUILD.bazel index 1e8f30632..c258f250a 100644 --- a/fuzz/BUILD.bazel +++ b/fuzz/BUILD.bazel @@ -2,9 +2,15 @@ load("@prysm//tools/go:def.bzl", "go_library") load("//tools/go:fuzz.bzl", "go_fuzz_test") load("@com_github_prysmaticlabs_ethereumapis//tools:ssz.bzl", "SSZ_DEPS", "ssz_gen_marshal") load("@io_bazel_rules_docker//container:container.bzl", "container_image", "container_push") +load("@io_bazel_rules_go//go:def.bzl", "go_test") # gazelle:ignore generated.ssz.go +config_setting( + name = "fuzzing_enabled", + values = {"define": "gotags=libfuzzer"}, +) + ssz_gen_marshal( name = "ssz_generated_files", srcs = ["inputs.go"], @@ -13,36 +19,10 @@ ssz_gen_marshal( "@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library", ], objs = [ - "InputBlockHeader", - "InputAttesterSlashingWrapper", - "InputAttestationWrapper", - "InputDepositWrapper", - "InputVoluntaryExitWrapper", - "InputProposerSlashingWrapper", + "InputBlockWithPrestate", ], ) -container_image( - name = "prysm_fuzzit", - base = "@fuzzit_base//image", - directory = "/beacon_states", - env = { - "BEACONSTATES_PATH": "/beacon_states", - }, - files = [ - "@sigp_beacon_fuzz_corpora//:current_mainnet_beaconstate", - ], -) - -container_push( - name = "push_image", - format = "Docker", - image = ":prysm_fuzzit", - registry = "gcr.io", - repository = "prysmaticlabs/prysm-fuzzit", - tag = "v0.11.0", -) - IMPORT_PATH = "github.com/prysmaticlabs/prysm/fuzz" COMMON_DEPS = [ @@ -64,49 +44,12 @@ test_suite( name = "fuzz_tests", tags = ["manual"], tests = [ - ":attestation_fuzz_test_with_libfuzzer", - ":attester_slashing_fuzz_test_with_libfuzzer", ":block_fuzz_test_with_libfuzzer", - ":block_header_fuzz_test_with_libfuzzer", - ":deposit_fuzz_test_with_libfuzzer", - ":proposer_slashing_fuzz_test_with_libfuzzer", ":rpc_status_fuzz_test_with_libfuzzer", - ":voluntary_exit_fuzz_test_with_libfuzzer", + ":state_fuzz_test_with_libfuzzer", ], ) -go_fuzz_test( - name = "attestation_fuzz_test", - srcs = [ - "attestation_fuzz.go", - ] + COMMON_SRCS, - corpus = "@sigp_beacon_fuzz_corpora//:current_mainnet_attestation", - corpus_path = "external/sigp_beacon_fuzz_corpora/0-11-0/mainnet/attestation", - func = "BeaconFuzzAttestation", - importpath = IMPORT_PATH, - deps = [ - "//beacon-chain/core/blocks:go_default_library", - "//fuzz/testing:go_default_library", - "//shared/params:go_default_library", - ] + COMMON_DEPS, -) - -go_fuzz_test( - name = "attester_slashing_fuzz_test", - srcs = [ - "attester_slashing_fuzz.go", - ] + COMMON_SRCS, - corpus = "@sigp_beacon_fuzz_corpora//:current_mainnet_attester_slashing", - corpus_path = "external/sigp_beacon_fuzz_corpora/0-11-0/mainnet/attester_slashing", - func = "BeaconFuzzAttesterSlashing", - importpath = IMPORT_PATH, - deps = [ - "//beacon-chain/core/blocks:go_default_library", - "//fuzz/testing:go_default_library", - "//shared/params:go_default_library", - ] + COMMON_DEPS, -) - go_fuzz_test( name = "block_fuzz_test", srcs = [ @@ -116,59 +59,31 @@ go_fuzz_test( corpus_path = "external/sigp_beacon_fuzz_corpora/0-11-0/mainnet/block_header", func = "BeaconFuzzBlock", importpath = IMPORT_PATH, + max_len = 30000000, deps = [ "//beacon-chain/core/blocks:go_default_library", "//beacon-chain/core/state:go_default_library", "//fuzz/testing:go_default_library", "//shared/params:go_default_library", - ] + COMMON_DEPS, -) - -go_fuzz_test( - name = "block_header_fuzz_test", - srcs = [ - "block_header_fuzz.go", - ] + COMMON_SRCS, - corpus = "@sigp_beacon_fuzz_corpora//:current_mainnet_block_header", - corpus_path = "external/sigp_beacon_fuzz_corpora/0-11-0/mainnet/block_header", - func = "BeaconFuzzBlockHeader", - importpath = IMPORT_PATH, - deps = [ - "//beacon-chain/core/blocks:go_default_library", - "//fuzz/testing:go_default_library", - "//shared/params:go_default_library", - ] + COMMON_DEPS, -) - -go_fuzz_test( - name = "deposit_fuzz_test", - srcs = [ - "deposit_fuzz.go", - ] + COMMON_SRCS, - corpus = "deposit_corpus", - corpus_path = "fuzz/deposit_corpus", - func = "BeaconFuzzDeposit", - importpath = IMPORT_PATH, - deps = [ - "//beacon-chain/core/blocks:go_default_library", - "//fuzz/testing:go_default_library", - "//shared/params:go_default_library", - ] + COMMON_DEPS, -) - -go_fuzz_test( - name = "proposer_slashing_fuzz_test", - srcs = [ - "proposer_slashing_fuzz.go", - ] + COMMON_SRCS, - corpus = "@sigp_beacon_fuzz_corpora//:current_mainnet_proposer_slashing", - corpus_path = "external/sigp_beacon_fuzz_corpora/0-11-0/mainnet/proposer_slashing", - func = "BeaconFuzzProposerSlashing", - importpath = IMPORT_PATH, - deps = [ - "//beacon-chain/core/blocks:go_default_library", - "//fuzz/testing:go_default_library", - "//shared/params:go_default_library", + "//proto/beacon/p2p/v1:go_default_library", + "//beacon-chain/operations/attestations:go_default_library", + "//beacon-chain/p2p/testing:go_default_library", + "//beacon-chain/sync:go_default_library", + "//beacon-chain/db:go_default_library", + "//beacon-chain/operations/voluntaryexits:go_default_library", + "//beacon-chain/blockchain:go_default_library", + "//beacon-chain/operations/slashings:go_default_library", + "//beacon-chain/forkchoice/protoarray:go_default_library", + "//shared/testutil:go_default_library", + "@com_github_libp2p_go_libp2p_core//peer:go_default_library", + "@com_github_libp2p_go_libp2p_pubsub//:go_default_library", + "@com_github_libp2p_go_libp2p_pubsub//pb:go_default_library", + "@com_github_sirupsen_logrus//:go_default_library", + "//beacon-chain/p2p:go_default_library", + "//beacon-chain/blockchain/testing:go_default_library", + "//beacon-chain/cache:go_default_library", + "//beacon-chain/state/stategen:go_default_library", + "//shared/rand:go_default_library", ] + COMMON_DEPS, ) @@ -200,17 +115,35 @@ go_fuzz_test( ) go_fuzz_test( - name = "voluntary_exit_fuzz_test", + name = "ssz_encoder_attestations_test", srcs = [ - "voluntary_exit_fuzz.go", + "ssz_encoder_attestations_fuzz.go", ] + COMMON_SRCS, - corpus = "voluntary_exit_corpus", - corpus_path = "fuzz/voluntary_exit_corpus", - func = "BeaconFuzzVoluntaryExit", + corpus = "@sigp_beacon_fuzz_corpora//:current_mainnet_block_header", + corpus_path = "external/sigp_beacon_fuzz_corpora/0-11-0/mainnet/block_header", + func = "SszEncoderAttestationFuzz", importpath = IMPORT_PATH, deps = [ - "//beacon-chain/core/blocks:go_default_library", - "//fuzz/testing:go_default_library", + "//beacon-chain/p2p/encoder:go_default_library", + "//shared/params:go_default_library", + "//proto/beacon/p2p/v1:go_default_library", + ] + COMMON_DEPS, +) + +go_fuzz_test( + name = "state_fuzz_test", + srcs = [ + "state_fuzz.go", + ] + COMMON_SRCS, + corpus = "@sigp_beacon_fuzz_corpora//:0_11_0_mainnet_beaconstate", + corpus_path = "external/sigp_beacon_fuzz_corpora/0-11-0/mainnet/beaconstate", + func = "BeaconStateFuzz", + importpath = IMPORT_PATH, + max_len = 30000000, + deps = [ + "//proto/beacon/p2p/v1:go_default_library", + "//beacon-chain/core/state:go_default_library", + "//beacon-chain/core/helpers:go_default_library", "//shared/params:go_default_library", ] + COMMON_DEPS, ) @@ -219,41 +152,64 @@ go_library( name = "go_default_library", testonly = 1, srcs = [ - "attestation_fuzz.go", - "attester_slashing_fuzz.go", - "block_fuzz.go", - "block_header_fuzz.go", "common.go", - "deposit_fuzz.go", "inputs.go", "rpc_status_fuzz.go", - "voluntary_exit_fuzz.go", + "ssz_encoder_attestations_fuzz.go", + "state_fuzz.go", ":ssz_generated_files", # keep ], importpath = "github.com/prysmaticlabs/prysm/fuzz", visibility = ["//visibility:public"], deps = [ + "//beacon-chain/blockchain:go_default_library", "//beacon-chain/blockchain/testing:go_default_library", "//beacon-chain/cache:go_default_library", "//beacon-chain/core/blocks:go_default_library", + "//beacon-chain/core/helpers:go_default_library", "//beacon-chain/core/state:go_default_library", + "//beacon-chain/db:go_default_library", + "//beacon-chain/forkchoice/protoarray:go_default_library", + "//beacon-chain/operations/attestations:go_default_library", + "//beacon-chain/operations/slashings:go_default_library", + "//beacon-chain/operations/voluntaryexits:go_default_library", "//beacon-chain/p2p:go_default_library", + "//beacon-chain/p2p/encoder:go_default_library", + "//beacon-chain/p2p/testing:go_default_library", "//beacon-chain/state:go_default_library", - "//beacon-chain/state/stateutil:go_default_library", + "//beacon-chain/state/stategen:go_default_library", "//beacon-chain/sync:go_default_library", "//beacon-chain/sync/initial-sync/testing:go_default_library", "//fuzz/testing:go_default_library", "//proto/beacon/p2p/v1:go_default_library", + "//shared/bytesutil:go_default_library", "//shared/featureconfig:go_default_library", "//shared/params:go_default_library", - "//shared/bytesutil:go_default_library", - "@com_github_libp2p_go_libp2p//:go_default_library", + "//shared/rand:go_default_library", + "//shared/testutil:go_default_library", "@com_github_libp2p_go_libp2p_core//host:go_default_library", "@com_github_libp2p_go_libp2p_core//network:go_default_library", "@com_github_libp2p_go_libp2p_core//peer:go_default_library", + "@com_github_libp2p_go_libp2p_pubsub//:go_default_library", + "@com_github_libp2p_go_libp2p_pubsub//pb:go_default_library", + "@com_github_libp2p_go_libp2p//:go_default_library", "@com_github_pkg_errors//:go_default_library", "@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library", "@com_github_prysmaticlabs_go_ssz//:go_default_library", "@com_github_sirupsen_logrus//:go_default_library", ] + SSZ_DEPS, # keep ) + +go_library( + name = "inputs", + srcs = [ + "inputs.go", + ":ssz_generated_files", # keep + ], + importpath = "github.com/prysmaticlabs/prysm/fuzz", + visibility = ["//visibility:public"], + deps = [ + "//proto/beacon/p2p/v1:go_default_library", + "@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library", + ] + SSZ_DEPS, # keep +) diff --git a/fuzz/README.md b/fuzz/README.md index de321aae5..3064242c7 100644 --- a/fuzz/README.md +++ b/fuzz/README.md @@ -23,7 +23,7 @@ deserialize to input objects. _Example: Block header input data_ ```go -type InputBlockHeader struct { +type InputBlockWithPrestate struct { StateID uint16 Block *ethpb.BeaconBlock } diff --git a/fuzz/attestation_fuzz.go b/fuzz/attestation_fuzz.go deleted file mode 100644 index 99605cb32..000000000 --- a/fuzz/attestation_fuzz.go +++ /dev/null @@ -1,33 +0,0 @@ -package fuzz - -import ( - "context" - - "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks" - stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state" - prylabs_testing "github.com/prysmaticlabs/prysm/fuzz/testing" - "github.com/prysmaticlabs/prysm/shared/params" -) - -// BeaconFuzzAttestation implements libfuzzer and beacon fuzz interface. -func BeaconFuzzAttestation(b []byte) ([]byte, bool) { - params.UseMainnetConfig() - input := &InputAttestationWrapper{} - if err := input.UnmarshalSSZ(b); err != nil { - return fail(err) - } - s, err := prylabs_testing.GetBeaconFuzzState(input.StateID) - if err != nil || s == nil { - return nil, false - } - st, err := stateTrie.InitializeFromProto(s) - if err != nil { - return fail(err) - } - post, err := blocks.ProcessAttestationNoVerifySignature(context.Background(), st, input.Attestation) - if err != nil { - return fail(err) - } - - return success(post) -} diff --git a/fuzz/attester_slashing_fuzz.go b/fuzz/attester_slashing_fuzz.go deleted file mode 100644 index be6d4bcfc..000000000 --- a/fuzz/attester_slashing_fuzz.go +++ /dev/null @@ -1,38 +0,0 @@ -package fuzz - -import ( - "context" - - ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" - "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks" - stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state" - prylabs_testing "github.com/prysmaticlabs/prysm/fuzz/testing" - "github.com/prysmaticlabs/prysm/shared/params" -) - -// BeaconFuzzAttesterSlashing implements libfuzzer and beacon fuzz interface. -func BeaconFuzzAttesterSlashing(b []byte) ([]byte, bool) { - params.UseMainnetConfig() - input := &InputAttesterSlashingWrapper{} - if err := input.UnmarshalSSZ(b); err != nil { - return fail(err) - } - s, err := prylabs_testing.GetBeaconFuzzState(input.StateID) - if err != nil || s == nil { - return nil, false - } - st, err := stateTrie.InitializeFromProto(s) - if err != nil { - return fail(err) - } - block := ðpb.SignedBeaconBlock{ - Block: ðpb.BeaconBlock{ - Body: ðpb.BeaconBlockBody{AttesterSlashings: []*ethpb.AttesterSlashing{input.AttesterSlashing}}, - }, - } - post, err := blocks.ProcessAttesterSlashings(context.Background(), st, block) - if err != nil { - return fail(err) - } - return success(post) -} diff --git a/fuzz/block_fuzz.go b/fuzz/block_fuzz.go index 8044e135f..9c4e848d5 100644 --- a/fuzz/block_fuzz.go +++ b/fuzz/block_fuzz.go @@ -1,33 +1,195 @@ +// +build libfuzzer + package fuzz import ( + "bytes" "context" + "encoding/hex" + "io/ioutil" + "os" + "path" - ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" + "github.com/libp2p/go-libp2p-core/peer" + pubsub "github.com/libp2p/go-libp2p-pubsub" + pubsub_pb "github.com/libp2p/go-libp2p-pubsub/pb" + "github.com/prysmaticlabs/go-ssz" + + "github.com/prysmaticlabs/prysm/beacon-chain/blockchain" + "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing" + "github.com/prysmaticlabs/prysm/beacon-chain/cache" "github.com/prysmaticlabs/prysm/beacon-chain/core/state" + "github.com/prysmaticlabs/prysm/beacon-chain/db" + "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray" + "github.com/prysmaticlabs/prysm/beacon-chain/operations/attestations" + "github.com/prysmaticlabs/prysm/beacon-chain/operations/slashings" + "github.com/prysmaticlabs/prysm/beacon-chain/operations/voluntaryexits" + "github.com/prysmaticlabs/prysm/beacon-chain/p2p" + p2pt "github.com/prysmaticlabs/prysm/beacon-chain/p2p/testing" stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state" - prylabs_testing "github.com/prysmaticlabs/prysm/fuzz/testing" + "github.com/prysmaticlabs/prysm/beacon-chain/state/stategen" + "github.com/prysmaticlabs/prysm/beacon-chain/sync" + "github.com/prysmaticlabs/prysm/shared/featureconfig" "github.com/prysmaticlabs/prysm/shared/params" + "github.com/prysmaticlabs/prysm/shared/rand" + "github.com/prysmaticlabs/prysm/shared/testutil" + "github.com/sirupsen/logrus" ) -// BeaconFuzzBlock using the corpora from sigp/beacon-fuzz. -func BeaconFuzzBlock(b []byte) ([]byte, bool) { - params.UseMainnetConfig() - input := &InputBlockHeader{} - if err := input.UnmarshalSSZ(b); err != nil { - return fail(err) +const topic = p2p.BlockSubnetTopicFormat + +var db1 db.Database +var ssc *cache.StateSummaryCache +var dbPath = path.Join(os.TempDir(), "fuzz_beacondb", randomHex(6)) + +func randomHex(n int) string { + bytes := make([]byte, n) + if _, err := rand.NewGenerator().Read(bytes); err != nil { + panic(err) + } + return hex.EncodeToString(bytes) +} + +func init() { + featureconfig.Init(&featureconfig.Flags{SkipBLSVerify: true}) + + logrus.SetLevel(logrus.PanicLevel) + logrus.SetOutput(ioutil.Discard) + + ssc = cache.NewStateSummaryCache() + + var err error + + db1, err = db.NewDB(dbPath, ssc) + if err != nil { + panic(err) + } +} + +func setupDB() { + if err := db1.ClearDB(); err != nil { + _ = err + } + + ctx := context.Background() + s := testutil.NewBeaconState() + b := testutil.NewBeaconBlock() + if err := db1.SaveBlock(ctx, b); err != nil { + panic(err) + } + br, err := ssz.HashTreeRoot(b) + if err != nil { + panic(err) + } + if err := db1.SaveState(ctx, s, br); err != nil { + panic(err) + } + if err := db1.SaveGenesisBlockRoot(ctx, br); err != nil { + panic(err) + } +} + +type fakeChecker struct{} + +func (fakeChecker) Syncing() bool { + return false +} +func (fakeChecker) Status() error { + return nil +} + +func (fakeChecker) Resync() error { + return nil +} + +// BeaconFuzzBlock runs full processing of beacon block against a given state. +func BeaconFuzzBlock(b []byte) { + params.UseMainnetConfig() + input := &InputBlockWithPrestate{} + if err := input.UnmarshalSSZ(b); err != nil { + return + } + st, err := stateTrie.InitializeFromProtoUnsafe(input.State) + if err != nil { + return + } + + setupDB() + + p2p := p2pt.NewFuzzTestP2P() + sgen := stategen.New(db1, ssc) + sn := &testing.MockStateNotifier{} + bn := &testing.MockBlockNotifier{} + an := &testing.MockOperationNotifier{} + ap := attestations.NewPool() + ep := voluntaryexits.NewPool() + sp := slashings.NewPool() + ops, err := attestations.NewService(context.Background(), &attestations.Config{Pool: ap}) + if err != nil { + panic(err) + } + + chain, err := blockchain.NewService(context.Background(), &blockchain.Config{ + ChainStartFetcher: nil, + BeaconDB: db1, + DepositCache: nil, + AttPool: ap, + ExitPool: ep, + SlashingPool: sp, + P2p: p2p, + StateNotifier: sn, + ForkChoiceStore: protoarray.New(0, 0, [32]byte{}), + OpsService: ops, + StateGen: sgen, + }) + if err != nil { + panic(err) + } + chain.Start() + + s := sync.NewRegularSyncFuzz(&sync.Config{ + DB: db1, + P2P: p2p, + Chain: chain, + InitialSync: fakeChecker{}, + StateNotifier: sn, + BlockNotifier: bn, + AttestationNotifier: an, + AttPool: ap, + ExitPool: ep, + SlashingPool: sp, + StateSummaryCache: ssc, + StateGen: sgen, + }) + + if err := s.InitCaches(); err != nil { + panic(err) + } + + buf := new(bytes.Buffer) + _, err = p2p.Encoding().EncodeGossip(buf, input.Block) + if err != nil { + panic(err) + } + + ctx := context.Background() + pid := peer.ID("fuzz") + msg := &pubsub.Message{ + Message: &pubsub_pb.Message{ + Data: buf.Bytes(), + TopicIDs: []string{topic}, + }, + } + + if res := s.FuzzValidateBeaconBlockPubSub(ctx, pid, msg); res != pubsub.ValidationAccept { + return + } + + if err := s.FuzzBeaconBlockSubscriber(ctx, msg); err != nil { + _ = err + } + + if _, err := state.ProcessBlock(ctx, st, input.Block); err != nil { + _ = err } - s, err := prylabs_testing.GetBeaconFuzzState(input.StateID) - if err != nil || s == nil { - return nil, false - } - st, err := stateTrie.InitializeFromProto(s) - if err != nil { - return fail(err) - } - post, err := state.ProcessBlock(context.Background(), st, ðpb.SignedBeaconBlock{Block: input.Block}) - if err != nil { - return fail(err) - } - return success(post) } diff --git a/fuzz/block_header_fuzz.go b/fuzz/block_header_fuzz.go deleted file mode 100644 index 278d27ae5..000000000 --- a/fuzz/block_header_fuzz.go +++ /dev/null @@ -1,30 +0,0 @@ -package fuzz - -import ( - "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks" - stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state" - prylabs_testing "github.com/prysmaticlabs/prysm/fuzz/testing" - "github.com/prysmaticlabs/prysm/shared/params" -) - -// BeaconFuzzBlockHeader using the corpora from sigp/beacon-fuzz. -func BeaconFuzzBlockHeader(b []byte) ([]byte, bool) { - params.UseMainnetConfig() - input := &InputBlockHeader{} - if err := input.UnmarshalSSZ(b); err != nil { - return fail(err) - } - s, err := prylabs_testing.GetBeaconFuzzState(input.StateID) - if err != nil || s == nil { - return nil, false - } - st, err := stateTrie.InitializeFromProto(s) - if err != nil { - return fail(err) - } - post, err := blocks.ProcessBlockHeaderNoVerify(st, input.Block) - if err != nil { - return fail(err) - } - return success(post) -} diff --git a/fuzz/deposit_corpus/.gitkeep b/fuzz/deposit_corpus/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/fuzz/deposit_fuzz.go b/fuzz/deposit_fuzz.go deleted file mode 100644 index 1a1959c68..000000000 --- a/fuzz/deposit_fuzz.go +++ /dev/null @@ -1,30 +0,0 @@ -package fuzz - -import ( - "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks" - stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state" - prylabs_testing "github.com/prysmaticlabs/prysm/fuzz/testing" - "github.com/prysmaticlabs/prysm/shared/params" -) - -// BeaconFuzzDeposit implements libfuzzer and beacon fuzz interface. -func BeaconFuzzDeposit(b []byte) ([]byte, bool) { - params.UseMainnetConfig() - input := &InputDepositWrapper{} - if err := input.UnmarshalSSZ(b); err != nil { - return fail(err) - } - s, err := prylabs_testing.GetBeaconFuzzState(input.StateID) - if err != nil || s == nil { - return nil, false - } - st, err := stateTrie.InitializeFromProto(s) - if err != nil { - return fail(err) - } - post, err := blocks.ProcessDeposit(st, input.Deposit, true) - if err != nil { - return fail(err) - } - return success(post) -} diff --git a/fuzz/generated.ssz.go b/fuzz/generated.ssz.go index 40d269550..619b0ebb0 100755 --- a/fuzz/generated.ssz.go +++ b/fuzz/generated.ssz.go @@ -4,28 +4,38 @@ package fuzz import ( ssz "github.com/ferranbt/fastssz" ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" + pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" ) -// MarshalSSZ ssz marshals the InputBlockHeader object -func (i *InputBlockHeader) MarshalSSZ() ([]byte, error) { +// MarshalSSZ ssz marshals the InputBlockWithPrestate object +func (i *InputBlockWithPrestate) MarshalSSZ() ([]byte, error) { return ssz.MarshalSSZ(i) } -// MarshalSSZTo ssz marshals the InputBlockHeader object to a target array -func (i *InputBlockHeader) MarshalSSZTo(buf []byte) (dst []byte, err error) { +// MarshalSSZTo ssz marshals the InputBlockWithPrestate object to a target array +func (i *InputBlockWithPrestate) MarshalSSZTo(buf []byte) (dst []byte, err error) { dst = buf - offset := int(12) + offset := int(8) - // Field (0) 'StateID' - dst = ssz.MarshalUint64(dst, i.StateID) + // Offset (0) 'State' + dst = ssz.WriteOffset(dst, offset) + if i.State == nil { + i.State = new(pb.BeaconState) + } + offset += i.State.SizeSSZ() // Offset (1) 'Block' dst = ssz.WriteOffset(dst, offset) if i.Block == nil { - i.Block = new(ethpb.BeaconBlock) + i.Block = new(ethpb.SignedBeaconBlock) } offset += i.Block.SizeSSZ() + // Field (0) 'State' + if dst, err = i.State.MarshalSSZTo(dst); err != nil { + return + } + // Field (1) 'Block' if dst, err = i.Block.MarshalSSZTo(dst); err != nil { return @@ -34,30 +44,43 @@ func (i *InputBlockHeader) MarshalSSZTo(buf []byte) (dst []byte, err error) { return } -// UnmarshalSSZ ssz unmarshals the InputBlockHeader object -func (i *InputBlockHeader) UnmarshalSSZ(buf []byte) error { +// UnmarshalSSZ ssz unmarshals the InputBlockWithPrestate object +func (i *InputBlockWithPrestate) UnmarshalSSZ(buf []byte) error { var err error size := uint64(len(buf)) - if size < 12 { + if size < 8 { return ssz.ErrSize } tail := buf - var o1 uint64 + var o0, o1 uint64 - // Field (0) 'StateID' - i.StateID = ssz.UnmarshallUint64(buf[0:8]) + // Offset (0) 'State' + if o0 = ssz.ReadOffset(buf[0:4]); o0 > size { + return ssz.ErrOffset + } // Offset (1) 'Block' - if o1 = ssz.ReadOffset(buf[8:12]); o1 > size { + if o1 = ssz.ReadOffset(buf[4:8]); o1 > size || o0 > o1 { return ssz.ErrOffset } + // Field (0) 'State' + { + buf = tail[o0:o1] + if i.State == nil { + i.State = new(pb.BeaconState) + } + if err = i.State.UnmarshalSSZ(buf); err != nil { + return err + } + } + // Field (1) 'Block' { buf = tail[o1:] if i.Block == nil { - i.Block = new(ethpb.BeaconBlock) + i.Block = new(ethpb.SignedBeaconBlock) } if err = i.Block.UnmarshalSSZ(buf); err != nil { return err @@ -66,30 +89,38 @@ func (i *InputBlockHeader) UnmarshalSSZ(buf []byte) error { return err } -// SizeSSZ returns the ssz encoded size in bytes for the InputBlockHeader object -func (i *InputBlockHeader) SizeSSZ() (size int) { - size = 12 +// SizeSSZ returns the ssz encoded size in bytes for the InputBlockWithPrestate object +func (i *InputBlockWithPrestate) SizeSSZ() (size int) { + size = 8 + + // Field (0) 'State' + if i.State == nil { + i.State = new(pb.BeaconState) + } + size += i.State.SizeSSZ() // Field (1) 'Block' if i.Block == nil { - i.Block = new(ethpb.BeaconBlock) + i.Block = new(ethpb.SignedBeaconBlock) } size += i.Block.SizeSSZ() return } -// HashTreeRoot ssz hashes the InputBlockHeader object -func (i *InputBlockHeader) HashTreeRoot() ([32]byte, error) { +// HashTreeRoot ssz hashes the InputBlockWithPrestate object +func (i *InputBlockWithPrestate) HashTreeRoot() ([32]byte, error) { return ssz.HashWithDefaultHasher(i) } -// HashTreeRootWith ssz hashes the InputBlockHeader object with a hasher -func (i *InputBlockHeader) HashTreeRootWith(hh *ssz.Hasher) (err error) { +// HashTreeRootWith ssz hashes the InputBlockWithPrestate object with a hasher +func (i *InputBlockWithPrestate) HashTreeRootWith(hh *ssz.Hasher) (err error) { indx := hh.Index() - // Field (0) 'StateID' - hh.PutUint64(i.StateID) + // Field (0) 'State' + if err = i.State.HashTreeRootWith(hh); err != nil { + return + } // Field (1) 'Block' if err = i.Block.HashTreeRootWith(hh); err != nil { @@ -99,407 +130,3 @@ func (i *InputBlockHeader) HashTreeRootWith(hh *ssz.Hasher) (err error) { hh.Merkleize(indx) return } - -// MarshalSSZ ssz marshals the InputAttesterSlashingWrapper object -func (i *InputAttesterSlashingWrapper) MarshalSSZ() ([]byte, error) { - return ssz.MarshalSSZ(i) -} - -// MarshalSSZTo ssz marshals the InputAttesterSlashingWrapper object to a target array -func (i *InputAttesterSlashingWrapper) MarshalSSZTo(buf []byte) (dst []byte, err error) { - dst = buf - offset := int(12) - - // Field (0) 'StateID' - dst = ssz.MarshalUint64(dst, i.StateID) - - // Offset (1) 'AttesterSlashing' - dst = ssz.WriteOffset(dst, offset) - if i.AttesterSlashing == nil { - i.AttesterSlashing = new(ethpb.AttesterSlashing) - } - offset += i.AttesterSlashing.SizeSSZ() - - // Field (1) 'AttesterSlashing' - if dst, err = i.AttesterSlashing.MarshalSSZTo(dst); err != nil { - return - } - - return -} - -// UnmarshalSSZ ssz unmarshals the InputAttesterSlashingWrapper object -func (i *InputAttesterSlashingWrapper) UnmarshalSSZ(buf []byte) error { - var err error - size := uint64(len(buf)) - if size < 12 { - return ssz.ErrSize - } - - tail := buf - var o1 uint64 - - // Field (0) 'StateID' - i.StateID = ssz.UnmarshallUint64(buf[0:8]) - - // Offset (1) 'AttesterSlashing' - if o1 = ssz.ReadOffset(buf[8:12]); o1 > size { - return ssz.ErrOffset - } - - // Field (1) 'AttesterSlashing' - { - buf = tail[o1:] - if i.AttesterSlashing == nil { - i.AttesterSlashing = new(ethpb.AttesterSlashing) - } - if err = i.AttesterSlashing.UnmarshalSSZ(buf); err != nil { - return err - } - } - return err -} - -// SizeSSZ returns the ssz encoded size in bytes for the InputAttesterSlashingWrapper object -func (i *InputAttesterSlashingWrapper) SizeSSZ() (size int) { - size = 12 - - // Field (1) 'AttesterSlashing' - if i.AttesterSlashing == nil { - i.AttesterSlashing = new(ethpb.AttesterSlashing) - } - size += i.AttesterSlashing.SizeSSZ() - - return -} - -// HashTreeRoot ssz hashes the InputAttesterSlashingWrapper object -func (i *InputAttesterSlashingWrapper) HashTreeRoot() ([32]byte, error) { - return ssz.HashWithDefaultHasher(i) -} - -// HashTreeRootWith ssz hashes the InputAttesterSlashingWrapper object with a hasher -func (i *InputAttesterSlashingWrapper) HashTreeRootWith(hh *ssz.Hasher) (err error) { - indx := hh.Index() - - // Field (0) 'StateID' - hh.PutUint64(i.StateID) - - // Field (1) 'AttesterSlashing' - if err = i.AttesterSlashing.HashTreeRootWith(hh); err != nil { - return - } - - hh.Merkleize(indx) - return -} - -// MarshalSSZ ssz marshals the InputAttestationWrapper object -func (i *InputAttestationWrapper) MarshalSSZ() ([]byte, error) { - return ssz.MarshalSSZ(i) -} - -// MarshalSSZTo ssz marshals the InputAttestationWrapper object to a target array -func (i *InputAttestationWrapper) MarshalSSZTo(buf []byte) (dst []byte, err error) { - dst = buf - offset := int(12) - - // Field (0) 'StateID' - dst = ssz.MarshalUint64(dst, i.StateID) - - // Offset (1) 'Attestation' - dst = ssz.WriteOffset(dst, offset) - if i.Attestation == nil { - i.Attestation = new(ethpb.Attestation) - } - offset += i.Attestation.SizeSSZ() - - // Field (1) 'Attestation' - if dst, err = i.Attestation.MarshalSSZTo(dst); err != nil { - return - } - - return -} - -// UnmarshalSSZ ssz unmarshals the InputAttestationWrapper object -func (i *InputAttestationWrapper) UnmarshalSSZ(buf []byte) error { - var err error - size := uint64(len(buf)) - if size < 12 { - return ssz.ErrSize - } - - tail := buf - var o1 uint64 - - // Field (0) 'StateID' - i.StateID = ssz.UnmarshallUint64(buf[0:8]) - - // Offset (1) 'Attestation' - if o1 = ssz.ReadOffset(buf[8:12]); o1 > size { - return ssz.ErrOffset - } - - // Field (1) 'Attestation' - { - buf = tail[o1:] - if i.Attestation == nil { - i.Attestation = new(ethpb.Attestation) - } - if err = i.Attestation.UnmarshalSSZ(buf); err != nil { - return err - } - } - return err -} - -// SizeSSZ returns the ssz encoded size in bytes for the InputAttestationWrapper object -func (i *InputAttestationWrapper) SizeSSZ() (size int) { - size = 12 - - // Field (1) 'Attestation' - if i.Attestation == nil { - i.Attestation = new(ethpb.Attestation) - } - size += i.Attestation.SizeSSZ() - - return -} - -// HashTreeRoot ssz hashes the InputAttestationWrapper object -func (i *InputAttestationWrapper) HashTreeRoot() ([32]byte, error) { - return ssz.HashWithDefaultHasher(i) -} - -// HashTreeRootWith ssz hashes the InputAttestationWrapper object with a hasher -func (i *InputAttestationWrapper) HashTreeRootWith(hh *ssz.Hasher) (err error) { - indx := hh.Index() - - // Field (0) 'StateID' - hh.PutUint64(i.StateID) - - // Field (1) 'Attestation' - if err = i.Attestation.HashTreeRootWith(hh); err != nil { - return - } - - hh.Merkleize(indx) - return -} - -// MarshalSSZ ssz marshals the InputDepositWrapper object -func (i *InputDepositWrapper) MarshalSSZ() ([]byte, error) { - return ssz.MarshalSSZ(i) -} - -// MarshalSSZTo ssz marshals the InputDepositWrapper object to a target array -func (i *InputDepositWrapper) MarshalSSZTo(buf []byte) (dst []byte, err error) { - dst = buf - - // Field (0) 'StateID' - dst = ssz.MarshalUint64(dst, i.StateID) - - // Field (1) 'Deposit' - if i.Deposit == nil { - i.Deposit = new(ethpb.Deposit) - } - if dst, err = i.Deposit.MarshalSSZTo(dst); err != nil { - return - } - - return -} - -// UnmarshalSSZ ssz unmarshals the InputDepositWrapper object -func (i *InputDepositWrapper) UnmarshalSSZ(buf []byte) error { - var err error - size := uint64(len(buf)) - if size != 1248 { - return ssz.ErrSize - } - - // Field (0) 'StateID' - i.StateID = ssz.UnmarshallUint64(buf[0:8]) - - // Field (1) 'Deposit' - if i.Deposit == nil { - i.Deposit = new(ethpb.Deposit) - } - if err = i.Deposit.UnmarshalSSZ(buf[8:1248]); err != nil { - return err - } - - return err -} - -// SizeSSZ returns the ssz encoded size in bytes for the InputDepositWrapper object -func (i *InputDepositWrapper) SizeSSZ() (size int) { - size = 1248 - return -} - -// HashTreeRoot ssz hashes the InputDepositWrapper object -func (i *InputDepositWrapper) HashTreeRoot() ([32]byte, error) { - return ssz.HashWithDefaultHasher(i) -} - -// HashTreeRootWith ssz hashes the InputDepositWrapper object with a hasher -func (i *InputDepositWrapper) HashTreeRootWith(hh *ssz.Hasher) (err error) { - indx := hh.Index() - - // Field (0) 'StateID' - hh.PutUint64(i.StateID) - - // Field (1) 'Deposit' - if err = i.Deposit.HashTreeRootWith(hh); err != nil { - return - } - - hh.Merkleize(indx) - return -} - -// MarshalSSZ ssz marshals the InputVoluntaryExitWrapper object -func (i *InputVoluntaryExitWrapper) MarshalSSZ() ([]byte, error) { - return ssz.MarshalSSZ(i) -} - -// MarshalSSZTo ssz marshals the InputVoluntaryExitWrapper object to a target array -func (i *InputVoluntaryExitWrapper) MarshalSSZTo(buf []byte) (dst []byte, err error) { - dst = buf - - // Field (0) 'StateID' - dst = ssz.MarshalUint64(dst, i.StateID) - - // Field (1) 'VoluntaryExit' - if i.VoluntaryExit == nil { - i.VoluntaryExit = new(ethpb.VoluntaryExit) - } - if dst, err = i.VoluntaryExit.MarshalSSZTo(dst); err != nil { - return - } - - return -} - -// UnmarshalSSZ ssz unmarshals the InputVoluntaryExitWrapper object -func (i *InputVoluntaryExitWrapper) UnmarshalSSZ(buf []byte) error { - var err error - size := uint64(len(buf)) - if size != 24 { - return ssz.ErrSize - } - - // Field (0) 'StateID' - i.StateID = ssz.UnmarshallUint64(buf[0:8]) - - // Field (1) 'VoluntaryExit' - if i.VoluntaryExit == nil { - i.VoluntaryExit = new(ethpb.VoluntaryExit) - } - if err = i.VoluntaryExit.UnmarshalSSZ(buf[8:24]); err != nil { - return err - } - - return err -} - -// SizeSSZ returns the ssz encoded size in bytes for the InputVoluntaryExitWrapper object -func (i *InputVoluntaryExitWrapper) SizeSSZ() (size int) { - size = 24 - return -} - -// HashTreeRoot ssz hashes the InputVoluntaryExitWrapper object -func (i *InputVoluntaryExitWrapper) HashTreeRoot() ([32]byte, error) { - return ssz.HashWithDefaultHasher(i) -} - -// HashTreeRootWith ssz hashes the InputVoluntaryExitWrapper object with a hasher -func (i *InputVoluntaryExitWrapper) HashTreeRootWith(hh *ssz.Hasher) (err error) { - indx := hh.Index() - - // Field (0) 'StateID' - hh.PutUint64(i.StateID) - - // Field (1) 'VoluntaryExit' - if err = i.VoluntaryExit.HashTreeRootWith(hh); err != nil { - return - } - - hh.Merkleize(indx) - return -} - -// MarshalSSZ ssz marshals the InputProposerSlashingWrapper object -func (i *InputProposerSlashingWrapper) MarshalSSZ() ([]byte, error) { - return ssz.MarshalSSZ(i) -} - -// MarshalSSZTo ssz marshals the InputProposerSlashingWrapper object to a target array -func (i *InputProposerSlashingWrapper) MarshalSSZTo(buf []byte) (dst []byte, err error) { - dst = buf - - // Field (0) 'StateID' - dst = ssz.MarshalUint64(dst, i.StateID) - - // Field (1) 'ProposerSlashing' - if i.ProposerSlashing == nil { - i.ProposerSlashing = new(ethpb.ProposerSlashing) - } - if dst, err = i.ProposerSlashing.MarshalSSZTo(dst); err != nil { - return - } - - return -} - -// UnmarshalSSZ ssz unmarshals the InputProposerSlashingWrapper object -func (i *InputProposerSlashingWrapper) UnmarshalSSZ(buf []byte) error { - var err error - size := uint64(len(buf)) - if size != 424 { - return ssz.ErrSize - } - - // Field (0) 'StateID' - i.StateID = ssz.UnmarshallUint64(buf[0:8]) - - // Field (1) 'ProposerSlashing' - if i.ProposerSlashing == nil { - i.ProposerSlashing = new(ethpb.ProposerSlashing) - } - if err = i.ProposerSlashing.UnmarshalSSZ(buf[8:424]); err != nil { - return err - } - - return err -} - -// SizeSSZ returns the ssz encoded size in bytes for the InputProposerSlashingWrapper object -func (i *InputProposerSlashingWrapper) SizeSSZ() (size int) { - size = 424 - return -} - -// HashTreeRoot ssz hashes the InputProposerSlashingWrapper object -func (i *InputProposerSlashingWrapper) HashTreeRoot() ([32]byte, error) { - return ssz.HashWithDefaultHasher(i) -} - -// HashTreeRootWith ssz hashes the InputProposerSlashingWrapper object with a hasher -func (i *InputProposerSlashingWrapper) HashTreeRootWith(hh *ssz.Hasher) (err error) { - indx := hh.Index() - - // Field (0) 'StateID' - hh.PutUint64(i.StateID) - - // Field (1) 'ProposerSlashing' - if err = i.ProposerSlashing.HashTreeRootWith(hh); err != nil { - return - } - - hh.Merkleize(indx) - return -} diff --git a/fuzz/inputs.go b/fuzz/inputs.go index 57160bb84..c92336788 100644 --- a/fuzz/inputs.go +++ b/fuzz/inputs.go @@ -2,40 +2,11 @@ package fuzz import ( ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" + pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" ) -// InputBlockHeader for fuzz testing beacon block headers. -type InputBlockHeader struct { - StateID uint64 - Block *ethpb.BeaconBlock -} - -// InputAttesterSlashingWrapper for fuzz testing attester slashing. -type InputAttesterSlashingWrapper struct { - StateID uint64 - AttesterSlashing *ethpb.AttesterSlashing -} - -// InputAttestationWrapper for fuzz testing attestations. -type InputAttestationWrapper struct { - StateID uint64 - Attestation *ethpb.Attestation -} - -// InputDepositWrapper for fuzz testing deposits. -type InputDepositWrapper struct { - StateID uint64 - Deposit *ethpb.Deposit -} - -// InputVoluntaryExitWrapper for fuzz testing voluntary exits. -type InputVoluntaryExitWrapper struct { - StateID uint64 - VoluntaryExit *ethpb.VoluntaryExit -} - -// InputProposerSlashingWrapper for fuzz testing proposer slashings. -type InputProposerSlashingWrapper struct { - StateID uint64 - ProposerSlashing *ethpb.ProposerSlashing +// InputBlockWithPrestate for fuzz testing beacon blocks. +type InputBlockWithPrestate struct { + State *pb.BeaconState + Block *ethpb.SignedBeaconBlock } diff --git a/fuzz/proposer_slashing_fuzz.go b/fuzz/proposer_slashing_fuzz.go deleted file mode 100644 index c35c03e21..000000000 --- a/fuzz/proposer_slashing_fuzz.go +++ /dev/null @@ -1,40 +0,0 @@ -// +build libfuzzer - -package fuzz - -import ( - "context" - - ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" - "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks" - stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state" - prylabs_testing "github.com/prysmaticlabs/prysm/fuzz/testing" - "github.com/prysmaticlabs/prysm/shared/params" -) - -// BeaconFuzzDeposit implements libfuzzer and beacon fuzz interface. -func BeaconFuzzProposerSlashing(b []byte) ([]byte, bool) { - params.UseMainnetConfig() - input := &InputProposerSlashingWrapper{} - if err := input.UnmarshalSSZ(b); err != nil { - return fail(err) - } - s, err := prylabs_testing.GetBeaconFuzzState(input.StateID) - if err != nil || s == nil { - return nil, false - } - st, err := stateTrie.InitializeFromProto(s) - if err != nil { - return fail(err) - } - block := ðpb.SignedBeaconBlock{ - Block: ðpb.BeaconBlock{ - Body: ðpb.BeaconBlockBody{ProposerSlashings: []*ethpb.ProposerSlashing{input.ProposerSlashing}}, - }, - } - post, err := blocks.ProcessProposerSlashings(context.Background(), st, block) - if err != nil { - return fail(err) - } - return success(post) -} diff --git a/fuzz/ssz_encoder_attestations_fuzz.go b/fuzz/ssz_encoder_attestations_fuzz.go new file mode 100644 index 000000000..8be1b2859 --- /dev/null +++ b/fuzz/ssz_encoder_attestations_fuzz.go @@ -0,0 +1,27 @@ +package fuzz + +import ( + "bytes" + + ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" + "github.com/prysmaticlabs/prysm/beacon-chain/p2p/encoder" + "github.com/prysmaticlabs/prysm/shared/params" +) + +var buf = new(bytes.Buffer) + +// SszEncoderAttestationFuzz runs network encode/decode for attestations. +func SszEncoderAttestationFuzz(b []byte) { + params.UseMainnetConfig() + buf.Reset() + input := ðpb.Attestation{} + e := encoder.SszNetworkEncoder{} + if err := e.DecodeGossip(b, input); err != nil { + _ = err + return + } + if _, err := e.EncodeGossip(buf, input); err != nil { + _ = err + return + } +} diff --git a/fuzz/state_fuzz.go b/fuzz/state_fuzz.go new file mode 100644 index 000000000..a1a616664 --- /dev/null +++ b/fuzz/state_fuzz.go @@ -0,0 +1,40 @@ +package fuzz + +import ( + "context" + + "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" + stateutil "github.com/prysmaticlabs/prysm/beacon-chain/core/state" + "github.com/prysmaticlabs/prysm/beacon-chain/state" + pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" + "github.com/prysmaticlabs/prysm/shared/featureconfig" + "github.com/prysmaticlabs/prysm/shared/params" +) + +func init() { + featureconfig.Init(&featureconfig.Flags{ + EnableSSZCache: false, + }) +} + +// BeaconStateFuzz -- +func BeaconStateFuzz(input []byte) { + params.UseMainnetConfig() + st := &pb.BeaconState{} + if err := st.UnmarshalSSZ(input); err != nil { + return + } + s, err := state.InitializeFromProtoUnsafe(st) + if err != nil { + panic(err) + } + nextEpoch := helpers.SlotToEpoch(s.Slot()) + 1 + slot, err := helpers.StartSlot(nextEpoch) + if err != nil { + return + } + if _, err := stateutil.ProcessSlots(context.Background(), s, slot); err != nil { + _ = err + return + } +} diff --git a/fuzz/voluntary_exit_corpus/.gitkeep b/fuzz/voluntary_exit_corpus/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/fuzz/voluntary_exit_fuzz.go b/fuzz/voluntary_exit_fuzz.go deleted file mode 100644 index 7ff50ba59..000000000 --- a/fuzz/voluntary_exit_fuzz.go +++ /dev/null @@ -1,31 +0,0 @@ -package fuzz - -import ( - ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" - "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks" - stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state" - prylabs_testing "github.com/prysmaticlabs/prysm/fuzz/testing" - "github.com/prysmaticlabs/prysm/shared/params" -) - -// BeaconFuzzVoluntaryExit implements libfuzzer and beacon fuzz interface. -func BeaconFuzzVoluntaryExit(b []byte) ([]byte, bool) { - params.UseMainnetConfig() - input := &InputVoluntaryExitWrapper{} - if err := input.UnmarshalSSZ(b); err != nil { - return fail(err) - } - s, err := prylabs_testing.GetBeaconFuzzState(input.StateID) - if err != nil || s == nil { - return nil, false - } - st, err := stateTrie.InitializeFromProto(s) - if err != nil { - return fail(err) - } - post, err := blocks.ProcessVoluntaryExitsNoVerifySignature(st, ðpb.BeaconBlockBody{VoluntaryExits: []*ethpb.SignedVoluntaryExit{{Exit: input.VoluntaryExit}}}) - if err != nil { - return fail(err) - } - return success(post) -} diff --git a/proto/testing/BUILD.bazel b/proto/testing/BUILD.bazel index cccf421f1..cee3e8d69 100644 --- a/proto/testing/BUILD.bazel +++ b/proto/testing/BUILD.bazel @@ -114,6 +114,7 @@ go_test( "//beacon-chain/state/stateutil:go_default_library", "//proto/beacon/p2p/v1:go_default_library", "//shared/bytesutil:go_default_library", + "//shared/params:go_default_library", "//shared/params/spectest:go_default_library", "//shared/testutil:go_default_library", "//shared/testutil/assert:go_default_library", diff --git a/scripts/upload_fuzzers.sh b/scripts/upload_fuzzers.sh new file mode 100755 index 000000000..310de1317 --- /dev/null +++ b/scripts/upload_fuzzers.sh @@ -0,0 +1,15 @@ +# Fuzzer bundle uploads +# +# This script builds the appropriate fuzzing bundles and uploads them to the google cloud bucket. +# Clusterfuzz will pick up the new fuzz bundles as fuzzing jobs are run. + +# Build targets. +bazel build --config=fuzz \ + //fuzz:block_fuzz_test_libfuzzer_bundle \ + //fuzz:state_fuzz_test_libfuzzer_bundle \ + //fuzz:ssz_encoder_attestations_test_libfuzzer_bundle + +# Upload bundles with date timestamps in the filename. +gsutil cp bazel-bin/fuzz/block_fuzz_test_libfuzzer_bundle.zip gs://builds.prysmaticlabs.appspot.com/libfuzzer_asan_blocks/fuzzer-build-$(date +%Y%m%d%H%M).zip +gsutil cp bazel-bin/fuzz/state_fuzz_test_libfuzzer_bundle.zip gs://builds.prysmaticlabs.appspot.com/libfuzzer_asan_state/fuzzer-build-$(date +%Y%m%d%H%M).zip +gsutil cp bazel-bin/fuzz/ssz_encoder_attestations_test_libfuzzer_bundle.zip gs://builds.prysmaticlabs.appspot.com/libfuzzer_asan_ssz_encoder_attestations/fuzzer-build-$(date +%Y%m%d%H%M).zip diff --git a/shared/params/spectest/config.go b/shared/params/spectest/config.go index 9aab76d7a..9b412aff6 100644 --- a/shared/params/spectest/config.go +++ b/shared/params/spectest/config.go @@ -12,7 +12,7 @@ import ( // SetConfig sets the global params for spec tests depending on the option chosen. // Provides reset function allowing to get back to the previous configuration at the end of a test. -func SetConfig(t *testing.T, config string) error { +func SetConfig(t testing.TB, config string) error { params.SetupTestConfigCleanup(t) switch config { case "minimal": diff --git a/shared/params/testutils.go b/shared/params/testutils.go index dc1e1472f..b288c1627 100644 --- a/shared/params/testutils.go +++ b/shared/params/testutils.go @@ -4,7 +4,7 @@ import "testing" // SetupTestConfigCleanup preserves configurations allowing to modify them within tests without any // restrictions, everything is restored after the test. -func SetupTestConfigCleanup(t *testing.T) { +func SetupTestConfigCleanup(t testing.TB) { prevDefaultBeaconConfig := mainnetBeaconConfig.Copy() prevBeaconConfig := beaconConfig.Copy() prevNetworkCfg := mainnetNetworkConfig.Copy() diff --git a/shared/testutil/spectest.go b/shared/testutil/spectest.go index 3bbea7b3f..b3a52f06f 100644 --- a/shared/testutil/spectest.go +++ b/shared/testutil/spectest.go @@ -42,7 +42,7 @@ func UnmarshalYaml(y []byte, dest interface{}) error { // TestFolders sets the proper config and returns the result of ReadDir // on the passed in eth2-spec-tests directory along with its path. -func TestFolders(t *testing.T, config string, folderPath string) ([]os.FileInfo, string) { +func TestFolders(t testing.TB, config string, folderPath string) ([]os.FileInfo, string) { testsFolderPath := path.Join("tests", config, "phase0", folderPath) filepath, err := bazel.Runfile(testsFolderPath) require.NoError(t, err) diff --git a/third_party/afl/BUILD.bazel b/third_party/afl/BUILD.bazel new file mode 100644 index 000000000..41c71994f --- /dev/null +++ b/third_party/afl/BUILD.bazel @@ -0,0 +1,80 @@ +package( + default_testonly = True, + default_visibility = ["//visibility:public"], +) +# Note: these libraries only compile with llvm. + +cc_library( + name = "comm_hdr", + hdrs = [ + "alloc-inl.h", + "config.h", + "debug.h", + "hash.h", + "types.h", + ], + visibility = ["//visibility:private"], +) + +CFLAGS = [ + "-O3 -funroll-loops", + "-Wall -D_FORTIFY_SOURCE=2 -g -Wno-pointer-sign", + "-DAFL_PATH=\\\"/usr/local/lib/afl\\\"", + "-DDOC_PATH=\\\"/usr/local/share/doc/afl\\\"", + "-DBIN_PATH=\\\"/usr/local/bin\\\"", +] + +LDFLAGS = ["-ldl"] + +cc_library( + name = "lib-afl-fuzz", + srcs = ["afl-fuzz.c"], + copts = CFLAGS, + linkopts = LDFLAGS, + visibility = ["//visibility:private"], + deps = [":comm_hdr"], +) + +cc_library( + name = "lib-afl-showmap", + srcs = ["afl-showmap.c"], + copts = CFLAGS, + linkopts = LDFLAGS, + visibility = ["//visibility:private"], + deps = [":comm_hdr"], +) + +cc_library( + name = "afl-llvm-rt", + srcs = ["llvm_mode/afl-llvm-rt.o.c"], + copts = ["-Wno-pointer-sign -O3"], + visibility = ["//visibility:private"], + deps = [":comm_hdr"], +) + +cc_library( + name = "fuzzing_engine", + srcs = ["afl_driver.cpp"], + copts = ["-fsanitize=address -O3"], + linkopts = ["-fsanitize=address"], + tags = ["manual"], + deps = [":afl-llvm-rt"], +) + +genrule( + name = "libs", + srcs = [ + ":lib-afl-fuzz", + ":lib-afl-showmap", + ], + outs = [ + "afl-fuzz", + "afl-showmap", + ], + cmd = """ +cp $(locations :lib-afl-fuzz) . +cp $(locations :lib-afl-showmap) . +mv liblib-afl-fuzz.a $(location afl-fuzz) +mv liblib-afl-showmap.a $(location afl-showmap) +""", +) diff --git a/third_party/afl/afl-fuzz b/third_party/afl/afl-fuzz new file mode 100755 index 0000000000000000000000000000000000000000..380285ead6ae70d6b57712246b55beebebf71e4a GIT binary patch literal 794688 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 o-C4dV2c182^*w@m4x5nHqP@KpW5-x1Whx(2nss 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�W8WPcR$gkFc(76E?V2)PsH=i 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�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 literal 0 HcmV?d00001 diff --git a/third_party/afl/afl-fuzz.c b/third_party/afl/afl-fuzz.c new file mode 100644 index 000000000..0280f1e41 --- /dev/null +++ b/third_party/afl/afl-fuzz.c @@ -0,0 +1,8099 @@ +/* + american fuzzy lop - fuzzer code + -------------------------------- + + Written and maintained by Michal Zalewski + + Forkserver design by Jann Horn + + Copyright 2013, 2014, 2015, 2016, 2017 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + This is the real deal: the program takes an instrumented binary and + attempts a variety of basic fuzzing tricks, paying close attention to + how they affect the execution path. + + */ + +#define AFL_MAIN +#define MESSAGES_TO_STDOUT + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#define _FILE_OFFSET_BITS 64 + +#include "config.h" +#include "types.h" +#include "debug.h" +#include "alloc-inl.h" +#include "hash.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__APPLE__) || defined(__FreeBSD__) || defined (__OpenBSD__) +# include +#endif /* __APPLE__ || __FreeBSD__ || __OpenBSD__ */ + +/* For systems that have sched_setaffinity; right now just Linux, but one + can hope... */ + +#ifdef __linux__ +# define HAVE_AFFINITY 1 +#endif /* __linux__ */ + +/* A toggle to export some variables when building as a library. Not very + useful for the general public. */ + +#ifdef AFL_LIB +# define EXP_ST +#else +# define EXP_ST static +#endif /* ^AFL_LIB */ + +/* Lots of globals, but mostly for the status UI and other things where it + really makes no sense to haul them around as function parameters. */ + + +EXP_ST u8 *in_dir, /* Input directory with test cases */ + *out_file, /* File to fuzz, if any */ + *out_dir, /* Working & output directory */ + *sync_dir, /* Synchronization directory */ + *sync_id, /* Fuzzer ID */ + *use_banner, /* Display banner */ + *in_bitmap, /* Input bitmap */ + *doc_path, /* Path to documentation dir */ + *target_path, /* Path to target binary */ + *orig_cmdline; /* Original command line */ + +EXP_ST u32 exec_tmout = EXEC_TIMEOUT; /* Configurable exec timeout (ms) */ +static u32 hang_tmout = EXEC_TIMEOUT; /* Timeout used for hang det (ms) */ + +EXP_ST u64 mem_limit = MEM_LIMIT; /* Memory cap for child (MB) */ + +static u32 stats_update_freq = 1; /* Stats update frequency (execs) */ + +EXP_ST u8 skip_deterministic, /* Skip deterministic stages? */ + force_deterministic, /* Force deterministic stages? */ + use_splicing, /* Recombine input files? */ + dumb_mode, /* Run in non-instrumented mode? */ + score_changed, /* Scoring for favorites changed? */ + kill_signal, /* Signal that killed the child */ + resuming_fuzz, /* Resuming an older fuzzing job? */ + timeout_given, /* Specific timeout given? */ + not_on_tty, /* stdout is not a tty */ + term_too_small, /* terminal dimensions too small */ + uses_asan, /* Target uses ASAN? */ + no_forkserver, /* Disable forkserver? */ + crash_mode, /* Crash mode! Yeah! */ + in_place_resume, /* Attempt in-place resume? */ + auto_changed, /* Auto-generated tokens changed? */ + no_cpu_meter_red, /* Feng shui on the status screen */ + no_arith, /* Skip most arithmetic ops */ + shuffle_queue, /* Shuffle input queue? */ + bitmap_changed = 1, /* Time to update bitmap? */ + qemu_mode, /* Running in QEMU mode? */ + skip_requested, /* Skip request, via SIGUSR1 */ + run_over10m, /* Run time over 10 minutes? */ + persistent_mode, /* Running in persistent mode? */ + deferred_mode, /* Deferred forkserver mode? */ + fast_cal; /* Try to calibrate faster? */ + +static s32 out_fd, /* Persistent fd for out_file */ + dev_urandom_fd = -1, /* Persistent fd for /dev/urandom */ + dev_null_fd = -1, /* Persistent fd for /dev/null */ + fsrv_ctl_fd, /* Fork server control pipe (write) */ + fsrv_st_fd; /* Fork server status pipe (read) */ + +static s32 forksrv_pid, /* PID of the fork server */ + child_pid = -1, /* PID of the fuzzed program */ + out_dir_fd = -1; /* FD of the lock file */ + +EXP_ST u8* trace_bits; /* SHM with instrumentation bitmap */ + +EXP_ST u8 virgin_bits[MAP_SIZE], /* Regions yet untouched by fuzzing */ + virgin_tmout[MAP_SIZE], /* Bits we haven't seen in tmouts */ + virgin_crash[MAP_SIZE]; /* Bits we haven't seen in crashes */ + +static u8 var_bytes[MAP_SIZE]; /* Bytes that appear to be variable */ + +static s32 shm_id; /* ID of the SHM region */ + +static volatile u8 stop_soon, /* Ctrl-C pressed? */ + clear_screen = 1, /* Window resized? */ + child_timed_out; /* Traced process timed out? */ + +EXP_ST u32 queued_paths, /* Total number of queued testcases */ + queued_variable, /* Testcases with variable behavior */ + queued_at_start, /* Total number of initial inputs */ + queued_discovered, /* Items discovered during this run */ + queued_imported, /* Items imported via -S */ + queued_favored, /* Paths deemed favorable */ + queued_with_cov, /* Paths with new coverage bytes */ + pending_not_fuzzed, /* Queued but not done yet */ + pending_favored, /* Pending favored paths */ + cur_skipped_paths, /* Abandoned inputs in cur cycle */ + cur_depth, /* Current path depth */ + max_depth, /* Max path depth */ + useless_at_start, /* Number of useless starting paths */ + var_byte_count, /* Bitmap bytes with var behavior */ + current_entry, /* Current queue entry ID */ + havoc_div = 1; /* Cycle count divisor for havoc */ + +EXP_ST u64 total_crashes, /* Total number of crashes */ + unique_crashes, /* Crashes with unique signatures */ + total_tmouts, /* Total number of timeouts */ + unique_tmouts, /* Timeouts with unique signatures */ + unique_hangs, /* Hangs with unique signatures */ + total_execs, /* Total execve() calls */ + start_time, /* Unix start time (ms) */ + last_path_time, /* Time for most recent path (ms) */ + last_crash_time, /* Time for most recent crash (ms) */ + last_hang_time, /* Time for most recent hang (ms) */ + last_crash_execs, /* Exec counter at last crash */ + queue_cycle, /* Queue round counter */ + cycles_wo_finds, /* Cycles without any new paths */ + trim_execs, /* Execs done to trim input files */ + bytes_trim_in, /* Bytes coming into the trimmer */ + bytes_trim_out, /* Bytes coming outa the trimmer */ + blocks_eff_total, /* Blocks subject to effector maps */ + blocks_eff_select; /* Blocks selected as fuzzable */ + +static u32 subseq_tmouts; /* Number of timeouts in a row */ + +static u8 *stage_name = "init", /* Name of the current fuzz stage */ + *stage_short, /* Short stage name */ + *syncing_party; /* Currently syncing with... */ + +static s32 stage_cur, stage_max; /* Stage progression */ +static s32 splicing_with = -1; /* Splicing with which test case? */ + +static u32 master_id, master_max; /* Master instance job splitting */ + +static u32 syncing_case; /* Syncing with case #... */ + +static s32 stage_cur_byte, /* Byte offset of current stage op */ + stage_cur_val; /* Value used for stage op */ + +static u8 stage_val_type; /* Value type (STAGE_VAL_*) */ + +static u64 stage_finds[32], /* Patterns found per fuzz stage */ + stage_cycles[32]; /* Execs per fuzz stage */ + +static u32 rand_cnt; /* Random number counter */ + +static u64 total_cal_us, /* Total calibration time (us) */ + total_cal_cycles; /* Total calibration cycles */ + +static u64 total_bitmap_size, /* Total bit count for all bitmaps */ + total_bitmap_entries; /* Number of bitmaps counted */ + +static s32 cpu_core_count; /* CPU core count */ + +#ifdef HAVE_AFFINITY + +static s32 cpu_aff = -1; /* Selected CPU core */ + +#endif /* HAVE_AFFINITY */ + +static FILE* plot_file; /* Gnuplot output file */ + +struct queue_entry { + + u8* fname; /* File name for the test case */ + u32 len; /* Input length */ + + u8 cal_failed, /* Calibration failed? */ + trim_done, /* Trimmed? */ + was_fuzzed, /* Had any fuzzing done yet? */ + passed_det, /* Deterministic stages passed? */ + has_new_cov, /* Triggers new coverage? */ + var_behavior, /* Variable behavior? */ + favored, /* Currently favored? */ + fs_redundant; /* Marked as redundant in the fs? */ + + u32 bitmap_size, /* Number of bits set in bitmap */ + exec_cksum; /* Checksum of the execution trace */ + + u64 exec_us, /* Execution time (us) */ + handicap, /* Number of queue cycles behind */ + depth; /* Path depth */ + + u8* trace_mini; /* Trace bytes, if kept */ + u32 tc_ref; /* Trace bytes ref count */ + + struct queue_entry *next, /* Next element, if any */ + *next_100; /* 100 elements ahead */ + +}; + +static struct queue_entry *queue, /* Fuzzing queue (linked list) */ + *queue_cur, /* Current offset within the queue */ + *queue_top, /* Top of the list */ + *q_prev100; /* Previous 100 marker */ + +static struct queue_entry* + top_rated[MAP_SIZE]; /* Top entries for bitmap bytes */ + +struct extra_data { + u8* data; /* Dictionary token data */ + u32 len; /* Dictionary token length */ + u32 hit_cnt; /* Use count in the corpus */ +}; + +static struct extra_data* extras; /* Extra tokens to fuzz with */ +static u32 extras_cnt; /* Total number of tokens read */ + +static struct extra_data* a_extras; /* Automatically selected extras */ +static u32 a_extras_cnt; /* Total number of tokens available */ + +static u8* (*post_handler)(u8* buf, u32* len); + +/* Interesting values, as per config.h */ + +static s8 interesting_8[] = { INTERESTING_8 }; +static s16 interesting_16[] = { INTERESTING_8, INTERESTING_16 }; +static s32 interesting_32[] = { INTERESTING_8, INTERESTING_16, INTERESTING_32 }; + +/* Fuzzing stages */ + +enum { + /* 00 */ STAGE_FLIP1, + /* 01 */ STAGE_FLIP2, + /* 02 */ STAGE_FLIP4, + /* 03 */ STAGE_FLIP8, + /* 04 */ STAGE_FLIP16, + /* 05 */ STAGE_FLIP32, + /* 06 */ STAGE_ARITH8, + /* 07 */ STAGE_ARITH16, + /* 08 */ STAGE_ARITH32, + /* 09 */ STAGE_INTEREST8, + /* 10 */ STAGE_INTEREST16, + /* 11 */ STAGE_INTEREST32, + /* 12 */ STAGE_EXTRAS_UO, + /* 13 */ STAGE_EXTRAS_UI, + /* 14 */ STAGE_EXTRAS_AO, + /* 15 */ STAGE_HAVOC, + /* 16 */ STAGE_SPLICE +}; + +/* Stage value types */ + +enum { + /* 00 */ STAGE_VAL_NONE, + /* 01 */ STAGE_VAL_LE, + /* 02 */ STAGE_VAL_BE +}; + +/* Execution status fault codes */ + +enum { + /* 00 */ FAULT_NONE, + /* 01 */ FAULT_TMOUT, + /* 02 */ FAULT_CRASH, + /* 03 */ FAULT_ERROR, + /* 04 */ FAULT_NOINST, + /* 05 */ FAULT_NOBITS +}; + + +/* Get unix time in milliseconds */ + +static u64 get_cur_time(void) { + + struct timeval tv; + struct timezone tz; + + gettimeofday(&tv, &tz); + + return (tv.tv_sec * 1000ULL) + (tv.tv_usec / 1000); + +} + + +/* Get unix time in microseconds */ + +static u64 get_cur_time_us(void) { + + struct timeval tv; + struct timezone tz; + + gettimeofday(&tv, &tz); + + return (tv.tv_sec * 1000000ULL) + tv.tv_usec; + +} + + +/* Generate a random number (from 0 to limit - 1). This may + have slight bias. */ + +static inline u32 UR(u32 limit) { + + if (unlikely(!rand_cnt--)) { + + u32 seed[2]; + + ck_read(dev_urandom_fd, &seed, sizeof(seed), "/dev/urandom"); + + srandom(seed[0]); + rand_cnt = (RESEED_RNG / 2) + (seed[1] % RESEED_RNG); + + } + + return random() % limit; + +} + + +/* Shuffle an array of pointers. Might be slightly biased. */ + +static void shuffle_ptrs(void** ptrs, u32 cnt) { + + u32 i; + + for (i = 0; i < cnt - 2; i++) { + + u32 j = i + UR(cnt - i); + void *s = ptrs[i]; + ptrs[i] = ptrs[j]; + ptrs[j] = s; + + } + +} + + +#ifdef HAVE_AFFINITY + +/* Build a list of processes bound to specific cores. Returns -1 if nothing + can be found. Assumes an upper bound of 4k CPUs. */ + +static void bind_to_free_cpu(void) { + + DIR* d; + struct dirent* de; + cpu_set_t c; + + u8 cpu_used[4096] = { 0 }; + u32 i; + + if (cpu_core_count < 2) return; + + if (getenv("AFL_NO_AFFINITY")) { + + WARNF("Not binding to a CPU core (AFL_NO_AFFINITY set)."); + return; + + } + + d = opendir("/proc"); + + if (!d) { + + WARNF("Unable to access /proc - can't scan for free CPU cores."); + return; + + } + + ACTF("Checking CPU core loadout..."); + + /* Introduce some jitter, in case multiple AFL tasks are doing the same + thing at the same time... */ + + usleep(R(1000) * 250); + + /* Scan all /proc//status entries, checking for Cpus_allowed_list. + Flag all processes bound to a specific CPU using cpu_used[]. This will + fail for some exotic binding setups, but is likely good enough in almost + all real-world use cases. */ + + while ((de = readdir(d))) { + + u8* fn; + FILE* f; + u8 tmp[MAX_LINE]; + u8 has_vmsize = 0; + + if (!isdigit(de->d_name[0])) continue; + + fn = alloc_printf("/proc/%s/status", de->d_name); + + if (!(f = fopen(fn, "r"))) { + ck_free(fn); + continue; + } + + while (fgets(tmp, MAX_LINE, f)) { + + u32 hval; + + /* Processes without VmSize are probably kernel tasks. */ + + if (!strncmp(tmp, "VmSize:\t", 8)) has_vmsize = 1; + + if (!strncmp(tmp, "Cpus_allowed_list:\t", 19) && + !strchr(tmp, '-') && !strchr(tmp, ',') && + sscanf(tmp + 19, "%u", &hval) == 1 && hval < sizeof(cpu_used) && + has_vmsize) { + + cpu_used[hval] = 1; + break; + + } + + } + + ck_free(fn); + fclose(f); + + } + + closedir(d); + + for (i = 0; i < cpu_core_count; i++) if (!cpu_used[i]) break; + + if (i == cpu_core_count) { + + SAYF("\n" cLRD "[-] " cRST + "Uh-oh, looks like all %u CPU cores on your system are allocated to\n" + " other instances of afl-fuzz (or similar CPU-locked tasks). Starting\n" + " another fuzzer on this machine is probably a bad plan, but if you are\n" + " absolutely sure, you can set AFL_NO_AFFINITY and try again.\n", + cpu_core_count); + + FATAL("No more free CPU cores"); + + } + + OKF("Found a free CPU core, binding to #%u.", i); + + cpu_aff = i; + + CPU_ZERO(&c); + CPU_SET(i, &c); + + if (sched_setaffinity(0, sizeof(c), &c)) + PFATAL("sched_setaffinity failed"); + +} + +#endif /* HAVE_AFFINITY */ + +#ifndef IGNORE_FINDS + +/* Helper function to compare buffers; returns first and last differing offset. We + use this to find reasonable locations for splicing two files. */ + +static void locate_diffs(u8* ptr1, u8* ptr2, u32 len, s32* first, s32* last) { + + s32 f_loc = -1; + s32 l_loc = -1; + u32 pos; + + for (pos = 0; pos < len; pos++) { + + if (*(ptr1++) != *(ptr2++)) { + + if (f_loc == -1) f_loc = pos; + l_loc = pos; + + } + + } + + *first = f_loc; + *last = l_loc; + + return; + +} + +#endif /* !IGNORE_FINDS */ + + +/* Describe integer. Uses 12 cyclic static buffers for return values. The value + returned should be five characters or less for all the integers we reasonably + expect to see. */ + +static u8* DI(u64 val) { + + static u8 tmp[12][16]; + static u8 cur; + + cur = (cur + 1) % 12; + +#define CHK_FORMAT(_divisor, _limit_mult, _fmt, _cast) do { \ + if (val < (_divisor) * (_limit_mult)) { \ + sprintf(tmp[cur], _fmt, ((_cast)val) / (_divisor)); \ + return tmp[cur]; \ + } \ + } while (0) + + /* 0-9999 */ + CHK_FORMAT(1, 10000, "%llu", u64); + + /* 10.0k - 99.9k */ + CHK_FORMAT(1000, 99.95, "%0.01fk", double); + + /* 100k - 999k */ + CHK_FORMAT(1000, 1000, "%lluk", u64); + + /* 1.00M - 9.99M */ + CHK_FORMAT(1000 * 1000, 9.995, "%0.02fM", double); + + /* 10.0M - 99.9M */ + CHK_FORMAT(1000 * 1000, 99.95, "%0.01fM", double); + + /* 100M - 999M */ + CHK_FORMAT(1000 * 1000, 1000, "%lluM", u64); + + /* 1.00G - 9.99G */ + CHK_FORMAT(1000LL * 1000 * 1000, 9.995, "%0.02fG", double); + + /* 10.0G - 99.9G */ + CHK_FORMAT(1000LL * 1000 * 1000, 99.95, "%0.01fG", double); + + /* 100G - 999G */ + CHK_FORMAT(1000LL * 1000 * 1000, 1000, "%lluG", u64); + + /* 1.00T - 9.99G */ + CHK_FORMAT(1000LL * 1000 * 1000 * 1000, 9.995, "%0.02fT", double); + + /* 10.0T - 99.9T */ + CHK_FORMAT(1000LL * 1000 * 1000 * 1000, 99.95, "%0.01fT", double); + + /* 100T+ */ + strcpy(tmp[cur], "infty"); + return tmp[cur]; + +} + + +/* Describe float. Similar to the above, except with a single + static buffer. */ + +static u8* DF(double val) { + + static u8 tmp[16]; + + if (val < 99.995) { + sprintf(tmp, "%0.02f", val); + return tmp; + } + + if (val < 999.95) { + sprintf(tmp, "%0.01f", val); + return tmp; + } + + return DI((u64)val); + +} + + +/* Describe integer as memory size. */ + +static u8* DMS(u64 val) { + + static u8 tmp[12][16]; + static u8 cur; + + cur = (cur + 1) % 12; + + /* 0-9999 */ + CHK_FORMAT(1, 10000, "%llu B", u64); + + /* 10.0k - 99.9k */ + CHK_FORMAT(1024, 99.95, "%0.01f kB", double); + + /* 100k - 999k */ + CHK_FORMAT(1024, 1000, "%llu kB", u64); + + /* 1.00M - 9.99M */ + CHK_FORMAT(1024 * 1024, 9.995, "%0.02f MB", double); + + /* 10.0M - 99.9M */ + CHK_FORMAT(1024 * 1024, 99.95, "%0.01f MB", double); + + /* 100M - 999M */ + CHK_FORMAT(1024 * 1024, 1000, "%llu MB", u64); + + /* 1.00G - 9.99G */ + CHK_FORMAT(1024LL * 1024 * 1024, 9.995, "%0.02f GB", double); + + /* 10.0G - 99.9G */ + CHK_FORMAT(1024LL * 1024 * 1024, 99.95, "%0.01f GB", double); + + /* 100G - 999G */ + CHK_FORMAT(1024LL * 1024 * 1024, 1000, "%llu GB", u64); + + /* 1.00T - 9.99G */ + CHK_FORMAT(1024LL * 1024 * 1024 * 1024, 9.995, "%0.02f TB", double); + + /* 10.0T - 99.9T */ + CHK_FORMAT(1024LL * 1024 * 1024 * 1024, 99.95, "%0.01f TB", double); + +#undef CHK_FORMAT + + /* 100T+ */ + strcpy(tmp[cur], "infty"); + return tmp[cur]; + +} + + +/* Describe time delta. Returns one static buffer, 34 chars of less. */ + +static u8* DTD(u64 cur_ms, u64 event_ms) { + + static u8 tmp[64]; + u64 delta; + s32 t_d, t_h, t_m, t_s; + + if (!event_ms) return "none seen yet"; + + delta = cur_ms - event_ms; + + t_d = delta / 1000 / 60 / 60 / 24; + t_h = (delta / 1000 / 60 / 60) % 24; + t_m = (delta / 1000 / 60) % 60; + t_s = (delta / 1000) % 60; + + sprintf(tmp, "%s days, %u hrs, %u min, %u sec", DI(t_d), t_h, t_m, t_s); + return tmp; + +} + + +/* Mark deterministic checks as done for a particular queue entry. We use the + .state file to avoid repeating deterministic fuzzing when resuming aborted + scans. */ + +static void mark_as_det_done(struct queue_entry* q) { + + u8* fn = strrchr(q->fname, '/'); + s32 fd; + + fn = alloc_printf("%s/queue/.state/deterministic_done/%s", out_dir, fn + 1); + + fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, 0600); + if (fd < 0) PFATAL("Unable to create '%s'", fn); + close(fd); + + ck_free(fn); + + q->passed_det = 1; + +} + + +/* Mark as variable. Create symlinks if possible to make it easier to examine + the files. */ + +static void mark_as_variable(struct queue_entry* q) { + + u8 *fn = strrchr(q->fname, '/') + 1, *ldest; + + ldest = alloc_printf("../../%s", fn); + fn = alloc_printf("%s/queue/.state/variable_behavior/%s", out_dir, fn); + + if (symlink(ldest, fn)) { + + s32 fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, 0600); + if (fd < 0) PFATAL("Unable to create '%s'", fn); + close(fd); + + } + + ck_free(ldest); + ck_free(fn); + + q->var_behavior = 1; + +} + + +/* Mark / unmark as redundant (edge-only). This is not used for restoring state, + but may be useful for post-processing datasets. */ + +static void mark_as_redundant(struct queue_entry* q, u8 state) { + + u8* fn; + s32 fd; + + if (state == q->fs_redundant) return; + + q->fs_redundant = state; + + fn = strrchr(q->fname, '/'); + fn = alloc_printf("%s/queue/.state/redundant_edges/%s", out_dir, fn + 1); + + if (state) { + + fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, 0600); + if (fd < 0) PFATAL("Unable to create '%s'", fn); + close(fd); + + } else { + + if (unlink(fn)) PFATAL("Unable to remove '%s'", fn); + + } + + ck_free(fn); + +} + + +/* Append new test case to the queue. */ + +static void add_to_queue(u8* fname, u32 len, u8 passed_det) { + + struct queue_entry* q = ck_alloc(sizeof(struct queue_entry)); + + q->fname = fname; + q->len = len; + q->depth = cur_depth + 1; + q->passed_det = passed_det; + + if (q->depth > max_depth) max_depth = q->depth; + + if (queue_top) { + + queue_top->next = q; + queue_top = q; + + } else q_prev100 = queue = queue_top = q; + + queued_paths++; + pending_not_fuzzed++; + + cycles_wo_finds = 0; + + if (!(queued_paths % 100)) { + + q_prev100->next_100 = q; + q_prev100 = q; + + } + + last_path_time = get_cur_time(); + +} + + +/* Destroy the entire queue. */ + +EXP_ST void destroy_queue(void) { + + struct queue_entry *q = queue, *n; + + while (q) { + + n = q->next; + ck_free(q->fname); + ck_free(q->trace_mini); + ck_free(q); + q = n; + + } + +} + + +/* Write bitmap to file. The bitmap is useful mostly for the secret + -B option, to focus a separate fuzzing session on a particular + interesting input without rediscovering all the others. */ + +EXP_ST void write_bitmap(void) { + + u8* fname; + s32 fd; + + if (!bitmap_changed) return; + bitmap_changed = 0; + + fname = alloc_printf("%s/fuzz_bitmap", out_dir); + fd = open(fname, O_WRONLY | O_CREAT | O_TRUNC, 0600); + + if (fd < 0) PFATAL("Unable to open '%s'", fname); + + ck_write(fd, virgin_bits, MAP_SIZE, fname); + + close(fd); + ck_free(fname); + +} + + +/* Read bitmap from file. This is for the -B option again. */ + +EXP_ST void read_bitmap(u8* fname) { + + s32 fd = open(fname, O_RDONLY); + + if (fd < 0) PFATAL("Unable to open '%s'", fname); + + ck_read(fd, virgin_bits, MAP_SIZE, fname); + + close(fd); + +} + + +/* Check if the current execution path brings anything new to the table. + Update virgin bits to reflect the finds. Returns 1 if the only change is + the hit-count for a particular tuple; 2 if there are new tuples seen. + Updates the map, so subsequent calls will always return 0. + + This function is called after every exec() on a fairly large buffer, so + it needs to be fast. We do this in 32-bit and 64-bit flavors. */ + +static inline u8 has_new_bits(u8* virgin_map) { + +#ifdef __x86_64__ + + u64* current = (u64*)trace_bits; + u64* virgin = (u64*)virgin_map; + + u32 i = (MAP_SIZE >> 3); + +#else + + u32* current = (u32*)trace_bits; + u32* virgin = (u32*)virgin_map; + + u32 i = (MAP_SIZE >> 2); + +#endif /* ^__x86_64__ */ + + u8 ret = 0; + + while (i--) { + + /* Optimize for (*current & *virgin) == 0 - i.e., no bits in current bitmap + that have not been already cleared from the virgin map - since this will + almost always be the case. */ + + if (unlikely(*current) && unlikely(*current & *virgin)) { + + if (likely(ret < 2)) { + + u8* cur = (u8*)current; + u8* vir = (u8*)virgin; + + /* Looks like we have not found any new bytes yet; see if any non-zero + bytes in current[] are pristine in virgin[]. */ + +#ifdef __x86_64__ + + if ((cur[0] && vir[0] == 0xff) || (cur[1] && vir[1] == 0xff) || + (cur[2] && vir[2] == 0xff) || (cur[3] && vir[3] == 0xff) || + (cur[4] && vir[4] == 0xff) || (cur[5] && vir[5] == 0xff) || + (cur[6] && vir[6] == 0xff) || (cur[7] && vir[7] == 0xff)) ret = 2; + else ret = 1; + +#else + + if ((cur[0] && vir[0] == 0xff) || (cur[1] && vir[1] == 0xff) || + (cur[2] && vir[2] == 0xff) || (cur[3] && vir[3] == 0xff)) ret = 2; + else ret = 1; + +#endif /* ^__x86_64__ */ + + } + + *virgin &= ~*current; + + } + + current++; + virgin++; + + } + + if (ret && virgin_map == virgin_bits) bitmap_changed = 1; + + return ret; + +} + + +/* Count the number of bits set in the provided bitmap. Used for the status + screen several times every second, does not have to be fast. */ + +static u32 count_bits(u8* mem) { + + u32* ptr = (u32*)mem; + u32 i = (MAP_SIZE >> 2); + u32 ret = 0; + + while (i--) { + + u32 v = *(ptr++); + + /* This gets called on the inverse, virgin bitmap; optimize for sparse + data. */ + + if (v == 0xffffffff) { + ret += 32; + continue; + } + + v -= ((v >> 1) & 0x55555555); + v = (v & 0x33333333) + ((v >> 2) & 0x33333333); + ret += (((v + (v >> 4)) & 0xF0F0F0F) * 0x01010101) >> 24; + + } + + return ret; + +} + + +#define FF(_b) (0xff << ((_b) << 3)) + +/* Count the number of bytes set in the bitmap. Called fairly sporadically, + mostly to update the status screen or calibrate and examine confirmed + new paths. */ + +static u32 count_bytes(u8* mem) { + + u32* ptr = (u32*)mem; + u32 i = (MAP_SIZE >> 2); + u32 ret = 0; + + while (i--) { + + u32 v = *(ptr++); + + if (!v) continue; + if (v & FF(0)) ret++; + if (v & FF(1)) ret++; + if (v & FF(2)) ret++; + if (v & FF(3)) ret++; + + } + + return ret; + +} + + +/* Count the number of non-255 bytes set in the bitmap. Used strictly for the + status screen, several calls per second or so. */ + +static u32 count_non_255_bytes(u8* mem) { + + u32* ptr = (u32*)mem; + u32 i = (MAP_SIZE >> 2); + u32 ret = 0; + + while (i--) { + + u32 v = *(ptr++); + + /* This is called on the virgin bitmap, so optimize for the most likely + case. */ + + if (v == 0xffffffff) continue; + if ((v & FF(0)) != FF(0)) ret++; + if ((v & FF(1)) != FF(1)) ret++; + if ((v & FF(2)) != FF(2)) ret++; + if ((v & FF(3)) != FF(3)) ret++; + + } + + return ret; + +} + + +/* Destructively simplify trace by eliminating hit count information + and replacing it with 0x80 or 0x01 depending on whether the tuple + is hit or not. Called on every new crash or timeout, should be + reasonably fast. */ + +static const u8 simplify_lookup[256] = { + + [0] = 1, + [1 ... 255] = 128 + +}; + +#ifdef __x86_64__ + +static void simplify_trace(u64* mem) { + + u32 i = MAP_SIZE >> 3; + + while (i--) { + + /* Optimize for sparse bitmaps. */ + + if (unlikely(*mem)) { + + u8* mem8 = (u8*)mem; + + mem8[0] = simplify_lookup[mem8[0]]; + mem8[1] = simplify_lookup[mem8[1]]; + mem8[2] = simplify_lookup[mem8[2]]; + mem8[3] = simplify_lookup[mem8[3]]; + mem8[4] = simplify_lookup[mem8[4]]; + mem8[5] = simplify_lookup[mem8[5]]; + mem8[6] = simplify_lookup[mem8[6]]; + mem8[7] = simplify_lookup[mem8[7]]; + + } else *mem = 0x0101010101010101ULL; + + mem++; + + } + +} + +#else + +static void simplify_trace(u32* mem) { + + u32 i = MAP_SIZE >> 2; + + while (i--) { + + /* Optimize for sparse bitmaps. */ + + if (unlikely(*mem)) { + + u8* mem8 = (u8*)mem; + + mem8[0] = simplify_lookup[mem8[0]]; + mem8[1] = simplify_lookup[mem8[1]]; + mem8[2] = simplify_lookup[mem8[2]]; + mem8[3] = simplify_lookup[mem8[3]]; + + } else *mem = 0x01010101; + + mem++; + } + +} + +#endif /* ^__x86_64__ */ + + +/* Destructively classify execution counts in a trace. This is used as a + preprocessing step for any newly acquired traces. Called on every exec, + must be fast. */ + +static const u8 count_class_lookup8[256] = { + + [0] = 0, + [1] = 1, + [2] = 2, + [3] = 4, + [4 ... 7] = 8, + [8 ... 15] = 16, + [16 ... 31] = 32, + [32 ... 127] = 64, + [128 ... 255] = 128 + +}; + +static u16 count_class_lookup16[65536]; + + +EXP_ST void init_count_class16(void) { + + u32 b1, b2; + + for (b1 = 0; b1 < 256; b1++) + for (b2 = 0; b2 < 256; b2++) + count_class_lookup16[(b1 << 8) + b2] = + (count_class_lookup8[b1] << 8) | + count_class_lookup8[b2]; + +} + + +#ifdef __x86_64__ + +static inline void classify_counts(u64* mem) { + + u32 i = MAP_SIZE >> 3; + + while (i--) { + + /* Optimize for sparse bitmaps. */ + + if (unlikely(*mem)) { + + u16* mem16 = (u16*)mem; + + mem16[0] = count_class_lookup16[mem16[0]]; + mem16[1] = count_class_lookup16[mem16[1]]; + mem16[2] = count_class_lookup16[mem16[2]]; + mem16[3] = count_class_lookup16[mem16[3]]; + + } + + mem++; + + } + +} + +#else + +static inline void classify_counts(u32* mem) { + + u32 i = MAP_SIZE >> 2; + + while (i--) { + + /* Optimize for sparse bitmaps. */ + + if (unlikely(*mem)) { + + u16* mem16 = (u16*)mem; + + mem16[0] = count_class_lookup16[mem16[0]]; + mem16[1] = count_class_lookup16[mem16[1]]; + + } + + mem++; + + } + +} + +#endif /* ^__x86_64__ */ + + +/* Get rid of shared memory (atexit handler). */ + +static void remove_shm(void) { + + shmctl(shm_id, IPC_RMID, NULL); + +} + + +/* Compact trace bytes into a smaller bitmap. We effectively just drop the + count information here. This is called only sporadically, for some + new paths. */ + +static void minimize_bits(u8* dst, u8* src) { + + u32 i = 0; + + while (i < MAP_SIZE) { + + if (*(src++)) dst[i >> 3] |= 1 << (i & 7); + i++; + + } + +} + + +/* When we bump into a new path, we call this to see if the path appears + more "favorable" than any of the existing ones. The purpose of the + "favorables" is to have a minimal set of paths that trigger all the bits + seen in the bitmap so far, and focus on fuzzing them at the expense of + the rest. + + The first step of the process is to maintain a list of top_rated[] entries + for every byte in the bitmap. We win that slot if there is no previous + contender, or if the contender has a more favorable speed x size factor. */ + +static void update_bitmap_score(struct queue_entry* q) { + + u32 i; + u64 fav_factor = q->exec_us * q->len; + + /* For every byte set in trace_bits[], see if there is a previous winner, + and how it compares to us. */ + + for (i = 0; i < MAP_SIZE; i++) + + if (trace_bits[i]) { + + if (top_rated[i]) { + + /* Faster-executing or smaller test cases are favored. */ + + if (fav_factor > top_rated[i]->exec_us * top_rated[i]->len) continue; + + /* Looks like we're going to win. Decrease ref count for the + previous winner, discard its trace_bits[] if necessary. */ + + if (!--top_rated[i]->tc_ref) { + ck_free(top_rated[i]->trace_mini); + top_rated[i]->trace_mini = 0; + } + + } + + /* Insert ourselves as the new winner. */ + + top_rated[i] = q; + q->tc_ref++; + + if (!q->trace_mini) { + q->trace_mini = ck_alloc(MAP_SIZE >> 3); + minimize_bits(q->trace_mini, trace_bits); + } + + score_changed = 1; + + } + +} + + +/* The second part of the mechanism discussed above is a routine that + goes over top_rated[] entries, and then sequentially grabs winners for + previously-unseen bytes (temp_v) and marks them as favored, at least + until the next run. The favored entries are given more air time during + all fuzzing steps. */ + +static void cull_queue(void) { + + struct queue_entry* q; + static u8 temp_v[MAP_SIZE >> 3]; + u32 i; + + if (dumb_mode || !score_changed) return; + + score_changed = 0; + + memset(temp_v, 255, MAP_SIZE >> 3); + + queued_favored = 0; + pending_favored = 0; + + q = queue; + + while (q) { + q->favored = 0; + q = q->next; + } + + /* Let's see if anything in the bitmap isn't captured in temp_v. + If yes, and if it has a top_rated[] contender, let's use it. */ + + for (i = 0; i < MAP_SIZE; i++) + if (top_rated[i] && (temp_v[i >> 3] & (1 << (i & 7)))) { + + u32 j = MAP_SIZE >> 3; + + /* Remove all bits belonging to the current entry from temp_v. */ + + while (j--) + if (top_rated[i]->trace_mini[j]) + temp_v[j] &= ~top_rated[i]->trace_mini[j]; + + top_rated[i]->favored = 1; + queued_favored++; + + if (!top_rated[i]->was_fuzzed) pending_favored++; + + } + + q = queue; + + while (q) { + mark_as_redundant(q, !q->favored); + q = q->next; + } + +} + + +/* Configure shared memory and virgin_bits. This is called at startup. */ + +EXP_ST void setup_shm(void) { + + u8* shm_str; + + if (!in_bitmap) memset(virgin_bits, 255, MAP_SIZE); + + memset(virgin_tmout, 255, MAP_SIZE); + memset(virgin_crash, 255, MAP_SIZE); + + shm_id = shmget(IPC_PRIVATE, MAP_SIZE, IPC_CREAT | IPC_EXCL | 0600); + + if (shm_id < 0) PFATAL("shmget() failed"); + + atexit(remove_shm); + + shm_str = alloc_printf("%d", shm_id); + + /* If somebody is asking us to fuzz instrumented binaries in dumb mode, + we don't want them to detect instrumentation, since we won't be sending + fork server commands. This should be replaced with better auto-detection + later on, perhaps? */ + + if (!dumb_mode) setenv(SHM_ENV_VAR, shm_str, 1); + + ck_free(shm_str); + + trace_bits = shmat(shm_id, NULL, 0); + + if (!trace_bits) PFATAL("shmat() failed"); + +} + + +/* Load postprocessor, if available. */ + +static void setup_post(void) { + + void* dh; + u8* fn = getenv("AFL_POST_LIBRARY"); + u32 tlen = 6; + + if (!fn) return; + + ACTF("Loading postprocessor from '%s'...", fn); + + dh = dlopen(fn, RTLD_NOW); + if (!dh) FATAL("%s", dlerror()); + + post_handler = dlsym(dh, "afl_postprocess"); + if (!post_handler) FATAL("Symbol 'afl_postprocess' not found."); + + /* Do a quick test. It's better to segfault now than later =) */ + + post_handler("hello", &tlen); + + OKF("Postprocessor installed successfully."); + +} + + +/* Read all testcases from the input directory, then queue them for testing. + Called at startup. */ + +static void read_testcases(void) { + + struct dirent **nl; + s32 nl_cnt; + u32 i; + u8* fn; + + /* Auto-detect non-in-place resumption attempts. */ + + fn = alloc_printf("%s/queue", in_dir); + if (!access(fn, F_OK)) in_dir = fn; else ck_free(fn); + + ACTF("Scanning '%s'...", in_dir); + + /* We use scandir() + alphasort() rather than readdir() because otherwise, + the ordering of test cases would vary somewhat randomly and would be + difficult to control. */ + + nl_cnt = scandir(in_dir, &nl, NULL, alphasort); + + if (nl_cnt < 0) { + + if (errno == ENOENT || errno == ENOTDIR) + + SAYF("\n" cLRD "[-] " cRST + "The input directory does not seem to be valid - try again. The fuzzer needs\n" + " one or more test case to start with - ideally, a small file under 1 kB\n" + " or so. The cases must be stored as regular files directly in the input\n" + " directory.\n"); + + PFATAL("Unable to open '%s'", in_dir); + + } + + if (shuffle_queue && nl_cnt > 1) { + + ACTF("Shuffling queue..."); + shuffle_ptrs((void**)nl, nl_cnt); + + } + + for (i = 0; i < nl_cnt; i++) { + + struct stat st; + + u8* fn = alloc_printf("%s/%s", in_dir, nl[i]->d_name); + u8* dfn = alloc_printf("%s/.state/deterministic_done/%s", in_dir, nl[i]->d_name); + + u8 passed_det = 0; + + free(nl[i]); /* not tracked */ + + if (lstat(fn, &st) || access(fn, R_OK)) + PFATAL("Unable to access '%s'", fn); + + /* This also takes care of . and .. */ + + if (!S_ISREG(st.st_mode) || !st.st_size || strstr(fn, "/README.txt")) { + + ck_free(fn); + ck_free(dfn); + continue; + + } + + if (st.st_size > MAX_FILE) + FATAL("Test case '%s' is too big (%s, limit is %s)", fn, + DMS(st.st_size), DMS(MAX_FILE)); + + /* Check for metadata that indicates that deterministic fuzzing + is complete for this entry. We don't want to repeat deterministic + fuzzing when resuming aborted scans, because it would be pointless + and probably very time-consuming. */ + + if (!access(dfn, F_OK)) passed_det = 1; + ck_free(dfn); + + add_to_queue(fn, st.st_size, passed_det); + + } + + free(nl); /* not tracked */ + + if (!queued_paths) { + + SAYF("\n" cLRD "[-] " cRST + "Looks like there are no valid test cases in the input directory! The fuzzer\n" + " needs one or more test case to start with - ideally, a small file under\n" + " 1 kB or so. The cases must be stored as regular files directly in the\n" + " input directory.\n"); + + FATAL("No usable test cases in '%s'", in_dir); + + } + + last_path_time = 0; + queued_at_start = queued_paths; + +} + + +/* Helper function for load_extras. */ + +static int compare_extras_len(const void* p1, const void* p2) { + struct extra_data *e1 = (struct extra_data*)p1, + *e2 = (struct extra_data*)p2; + + return e1->len - e2->len; +} + +static int compare_extras_use_d(const void* p1, const void* p2) { + struct extra_data *e1 = (struct extra_data*)p1, + *e2 = (struct extra_data*)p2; + + return e2->hit_cnt - e1->hit_cnt; +} + + +/* Read extras from a file, sort by size. */ + +static void load_extras_file(u8* fname, u32* min_len, u32* max_len, + u32 dict_level) { + + FILE* f; + u8 buf[MAX_LINE]; + u8 *lptr; + u32 cur_line = 0; + + f = fopen(fname, "r"); + + if (!f) PFATAL("Unable to open '%s'", fname); + + while ((lptr = fgets(buf, MAX_LINE, f))) { + + u8 *rptr, *wptr; + u32 klen = 0; + + cur_line++; + + /* Trim on left and right. */ + + while (isspace(*lptr)) lptr++; + + rptr = lptr + strlen(lptr) - 1; + while (rptr >= lptr && isspace(*rptr)) rptr--; + rptr++; + *rptr = 0; + + /* Skip empty lines and comments. */ + + if (!*lptr || *lptr == '#') continue; + + /* All other lines must end with '"', which we can consume. */ + + rptr--; + + if (rptr < lptr || *rptr != '"') + FATAL("Malformed name=\"value\" pair in line %u.", cur_line); + + *rptr = 0; + + /* Skip alphanumerics and dashes (label). */ + + while (isalnum(*lptr) || *lptr == '_') lptr++; + + /* If @number follows, parse that. */ + + if (*lptr == '@') { + + lptr++; + if (atoi(lptr) > dict_level) continue; + while (isdigit(*lptr)) lptr++; + + } + + /* Skip whitespace and = signs. */ + + while (isspace(*lptr) || *lptr == '=') lptr++; + + /* Consume opening '"'. */ + + if (*lptr != '"') + FATAL("Malformed name=\"keyword\" pair in line %u.", cur_line); + + lptr++; + + if (!*lptr) FATAL("Empty keyword in line %u.", cur_line); + + /* Okay, let's allocate memory and copy data between "...", handling + \xNN escaping, \\, and \". */ + + extras = ck_realloc_block(extras, (extras_cnt + 1) * + sizeof(struct extra_data)); + + wptr = extras[extras_cnt].data = ck_alloc(rptr - lptr); + + while (*lptr) { + + char* hexdigits = "0123456789abcdef"; + + switch (*lptr) { + + case 1 ... 31: + case 128 ... 255: + FATAL("Non-printable characters in line %u.", cur_line); + + case '\\': + + lptr++; + + if (*lptr == '\\' || *lptr == '"') { + *(wptr++) = *(lptr++); + klen++; + break; + } + + if (*lptr != 'x' || !isxdigit(lptr[1]) || !isxdigit(lptr[2])) + FATAL("Invalid escaping (not \\xNN) in line %u.", cur_line); + + *(wptr++) = + ((strchr(hexdigits, tolower(lptr[1])) - hexdigits) << 4) | + (strchr(hexdigits, tolower(lptr[2])) - hexdigits); + + lptr += 3; + klen++; + + break; + + default: + + *(wptr++) = *(lptr++); + klen++; + + } + + } + + extras[extras_cnt].len = klen; + + if (extras[extras_cnt].len > MAX_DICT_FILE) + FATAL("Keyword too big in line %u (%s, limit is %s)", cur_line, + DMS(klen), DMS(MAX_DICT_FILE)); + + if (*min_len > klen) *min_len = klen; + if (*max_len < klen) *max_len = klen; + + extras_cnt++; + + } + + fclose(f); + +} + + +/* Read extras from the extras directory and sort them by size. */ + +static void load_extras(u8* dir) { + + DIR* d; + struct dirent* de; + u32 min_len = MAX_DICT_FILE, max_len = 0, dict_level = 0; + u8* x; + + /* If the name ends with @, extract level and continue. */ + + if ((x = strchr(dir, '@'))) { + + *x = 0; + dict_level = atoi(x + 1); + + } + + ACTF("Loading extra dictionary from '%s' (level %u)...", dir, dict_level); + + d = opendir(dir); + + if (!d) { + + if (errno == ENOTDIR) { + load_extras_file(dir, &min_len, &max_len, dict_level); + goto check_and_sort; + } + + PFATAL("Unable to open '%s'", dir); + + } + + if (x) FATAL("Dictionary levels not supported for directories."); + + while ((de = readdir(d))) { + + struct stat st; + u8* fn = alloc_printf("%s/%s", dir, de->d_name); + s32 fd; + + if (lstat(fn, &st) || access(fn, R_OK)) + PFATAL("Unable to access '%s'", fn); + + /* This also takes care of . and .. */ + if (!S_ISREG(st.st_mode) || !st.st_size) { + + ck_free(fn); + continue; + + } + + if (st.st_size > MAX_DICT_FILE) + FATAL("Extra '%s' is too big (%s, limit is %s)", fn, + DMS(st.st_size), DMS(MAX_DICT_FILE)); + + if (min_len > st.st_size) min_len = st.st_size; + if (max_len < st.st_size) max_len = st.st_size; + + extras = ck_realloc_block(extras, (extras_cnt + 1) * + sizeof(struct extra_data)); + + extras[extras_cnt].data = ck_alloc(st.st_size); + extras[extras_cnt].len = st.st_size; + + fd = open(fn, O_RDONLY); + + if (fd < 0) PFATAL("Unable to open '%s'", fn); + + ck_read(fd, extras[extras_cnt].data, st.st_size, fn); + + close(fd); + ck_free(fn); + + extras_cnt++; + + } + + closedir(d); + +check_and_sort: + + if (!extras_cnt) FATAL("No usable files in '%s'", dir); + + qsort(extras, extras_cnt, sizeof(struct extra_data), compare_extras_len); + + OKF("Loaded %u extra tokens, size range %s to %s.", extras_cnt, + DMS(min_len), DMS(max_len)); + + if (max_len > 32) + WARNF("Some tokens are relatively large (%s) - consider trimming.", + DMS(max_len)); + + if (extras_cnt > MAX_DET_EXTRAS) + WARNF("More than %u tokens - will use them probabilistically.", + MAX_DET_EXTRAS); + +} + + + + +/* Helper function for maybe_add_auto() */ + +static inline u8 memcmp_nocase(u8* m1, u8* m2, u32 len) { + + while (len--) if (tolower(*(m1++)) ^ tolower(*(m2++))) return 1; + return 0; + +} + + +/* Maybe add automatic extra. */ + +static void maybe_add_auto(u8* mem, u32 len) { + + u32 i; + + /* Allow users to specify that they don't want auto dictionaries. */ + + if (!MAX_AUTO_EXTRAS || !USE_AUTO_EXTRAS) return; + + /* Skip runs of identical bytes. */ + + for (i = 1; i < len; i++) + if (mem[0] ^ mem[i]) break; + + if (i == len) return; + + /* Reject builtin interesting values. */ + + if (len == 2) { + + i = sizeof(interesting_16) >> 1; + + while (i--) + if (*((u16*)mem) == interesting_16[i] || + *((u16*)mem) == SWAP16(interesting_16[i])) return; + + } + + if (len == 4) { + + i = sizeof(interesting_32) >> 2; + + while (i--) + if (*((u32*)mem) == interesting_32[i] || + *((u32*)mem) == SWAP32(interesting_32[i])) return; + + } + + /* Reject anything that matches existing extras. Do a case-insensitive + match. We optimize by exploiting the fact that extras[] are sorted + by size. */ + + for (i = 0; i < extras_cnt; i++) + if (extras[i].len >= len) break; + + for (; i < extras_cnt && extras[i].len == len; i++) + if (!memcmp_nocase(extras[i].data, mem, len)) return; + + /* Last but not least, check a_extras[] for matches. There are no + guarantees of a particular sort order. */ + + auto_changed = 1; + + for (i = 0; i < a_extras_cnt; i++) { + + if (a_extras[i].len == len && !memcmp_nocase(a_extras[i].data, mem, len)) { + + a_extras[i].hit_cnt++; + goto sort_a_extras; + + } + + } + + /* At this point, looks like we're dealing with a new entry. So, let's + append it if we have room. Otherwise, let's randomly evict some other + entry from the bottom half of the list. */ + + if (a_extras_cnt < MAX_AUTO_EXTRAS) { + + a_extras = ck_realloc_block(a_extras, (a_extras_cnt + 1) * + sizeof(struct extra_data)); + + a_extras[a_extras_cnt].data = ck_memdup(mem, len); + a_extras[a_extras_cnt].len = len; + a_extras_cnt++; + + } else { + + i = MAX_AUTO_EXTRAS / 2 + + UR((MAX_AUTO_EXTRAS + 1) / 2); + + ck_free(a_extras[i].data); + + a_extras[i].data = ck_memdup(mem, len); + a_extras[i].len = len; + a_extras[i].hit_cnt = 0; + + } + +sort_a_extras: + + /* First, sort all auto extras by use count, descending order. */ + + qsort(a_extras, a_extras_cnt, sizeof(struct extra_data), + compare_extras_use_d); + + /* Then, sort the top USE_AUTO_EXTRAS entries by size. */ + + qsort(a_extras, MIN(USE_AUTO_EXTRAS, a_extras_cnt), + sizeof(struct extra_data), compare_extras_len); + +} + + +/* Save automatically generated extras. */ + +static void save_auto(void) { + + u32 i; + + if (!auto_changed) return; + auto_changed = 0; + + for (i = 0; i < MIN(USE_AUTO_EXTRAS, a_extras_cnt); i++) { + + u8* fn = alloc_printf("%s/queue/.state/auto_extras/auto_%06u", out_dir, i); + s32 fd; + + fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600); + + if (fd < 0) PFATAL("Unable to create '%s'", fn); + + ck_write(fd, a_extras[i].data, a_extras[i].len, fn); + + close(fd); + ck_free(fn); + + } + +} + + +/* Load automatically generated extras. */ + +static void load_auto(void) { + + u32 i; + + for (i = 0; i < USE_AUTO_EXTRAS; i++) { + + u8 tmp[MAX_AUTO_EXTRA + 1]; + u8* fn = alloc_printf("%s/.state/auto_extras/auto_%06u", in_dir, i); + s32 fd, len; + + fd = open(fn, O_RDONLY, 0600); + + if (fd < 0) { + + if (errno != ENOENT) PFATAL("Unable to open '%s'", fn); + ck_free(fn); + break; + + } + + /* We read one byte more to cheaply detect tokens that are too + long (and skip them). */ + + len = read(fd, tmp, MAX_AUTO_EXTRA + 1); + + if (len < 0) PFATAL("Unable to read from '%s'", fn); + + if (len >= MIN_AUTO_EXTRA && len <= MAX_AUTO_EXTRA) + maybe_add_auto(tmp, len); + + close(fd); + ck_free(fn); + + } + + if (i) OKF("Loaded %u auto-discovered dictionary tokens.", i); + else OKF("No auto-generated dictionary tokens to reuse."); + +} + + +/* Destroy extras. */ + +static void destroy_extras(void) { + + u32 i; + + for (i = 0; i < extras_cnt; i++) + ck_free(extras[i].data); + + ck_free(extras); + + for (i = 0; i < a_extras_cnt; i++) + ck_free(a_extras[i].data); + + ck_free(a_extras); + +} + + +/* Spin up fork server (instrumented mode only). The idea is explained here: + + http://lcamtuf.blogspot.com/2014/10/fuzzing-binaries-without-execve.html + + In essence, the instrumentation allows us to skip execve(), and just keep + cloning a stopped child. So, we just execute once, and then send commands + through a pipe. The other part of this logic is in afl-as.h. */ + +EXP_ST void init_forkserver(char** argv) { + + static struct itimerval it; + int st_pipe[2], ctl_pipe[2]; + int status; + s32 rlen; + + ACTF("Spinning up the fork server..."); + + if (pipe(st_pipe) || pipe(ctl_pipe)) PFATAL("pipe() failed"); + + forksrv_pid = fork(); + + if (forksrv_pid < 0) PFATAL("fork() failed"); + + if (!forksrv_pid) { + + struct rlimit r; + + /* Umpf. On OpenBSD, the default fd limit for root users is set to + soft 128. Let's try to fix that... */ + + if (!getrlimit(RLIMIT_NOFILE, &r) && r.rlim_cur < FORKSRV_FD + 2) { + + r.rlim_cur = FORKSRV_FD + 2; + setrlimit(RLIMIT_NOFILE, &r); /* Ignore errors */ + + } + + if (mem_limit) { + + r.rlim_max = r.rlim_cur = ((rlim_t)mem_limit) << 20; + +#ifdef RLIMIT_AS + + setrlimit(RLIMIT_AS, &r); /* Ignore errors */ + +#else + + /* This takes care of OpenBSD, which doesn't have RLIMIT_AS, but + according to reliable sources, RLIMIT_DATA covers anonymous + maps - so we should be getting good protection against OOM bugs. */ + + setrlimit(RLIMIT_DATA, &r); /* Ignore errors */ + +#endif /* ^RLIMIT_AS */ + + + } + + /* Dumping cores is slow and can lead to anomalies if SIGKILL is delivered + before the dump is complete. */ + + r.rlim_max = r.rlim_cur = 0; + + setrlimit(RLIMIT_CORE, &r); /* Ignore errors */ + + /* Isolate the process and configure standard descriptors. If out_file is + specified, stdin is /dev/null; otherwise, out_fd is cloned instead. */ + + setsid(); + + dup2(dev_null_fd, 1); + dup2(dev_null_fd, 2); + + if (out_file) { + + dup2(dev_null_fd, 0); + + } else { + + dup2(out_fd, 0); + close(out_fd); + + } + + /* Set up control and status pipes, close the unneeded original fds. */ + + if (dup2(ctl_pipe[0], FORKSRV_FD) < 0) PFATAL("dup2() failed"); + if (dup2(st_pipe[1], FORKSRV_FD + 1) < 0) PFATAL("dup2() failed"); + + close(ctl_pipe[0]); + close(ctl_pipe[1]); + close(st_pipe[0]); + close(st_pipe[1]); + + close(out_dir_fd); + close(dev_null_fd); + close(dev_urandom_fd); + close(fileno(plot_file)); + + /* This should improve performance a bit, since it stops the linker from + doing extra work post-fork(). */ + + if (!getenv("LD_BIND_LAZY")) setenv("LD_BIND_NOW", "1", 0); + + /* Set sane defaults for ASAN if nothing else specified. */ + + setenv("ASAN_OPTIONS", "abort_on_error=1:" + "detect_leaks=0:" + "symbolize=0:" + "allocator_may_return_null=1", 0); + + /* MSAN is tricky, because it doesn't support abort_on_error=1 at this + point. So, we do this in a very hacky way. */ + + setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":" + "symbolize=0:" + "abort_on_error=1:" + "allocator_may_return_null=1:" + "msan_track_origins=0", 0); + + execv(target_path, argv); + + /* Use a distinctive bitmap signature to tell the parent about execv() + falling through. */ + + *(u32*)trace_bits = EXEC_FAIL_SIG; + exit(0); + + } + + /* Close the unneeded endpoints. */ + + close(ctl_pipe[0]); + close(st_pipe[1]); + + fsrv_ctl_fd = ctl_pipe[1]; + fsrv_st_fd = st_pipe[0]; + + /* Wait for the fork server to come up, but don't wait too long. */ + + it.it_value.tv_sec = ((exec_tmout * FORK_WAIT_MULT) / 1000); + it.it_value.tv_usec = ((exec_tmout * FORK_WAIT_MULT) % 1000) * 1000; + + setitimer(ITIMER_REAL, &it, NULL); + + rlen = read(fsrv_st_fd, &status, 4); + + it.it_value.tv_sec = 0; + it.it_value.tv_usec = 0; + + setitimer(ITIMER_REAL, &it, NULL); + + /* If we have a four-byte "hello" message from the server, we're all set. + Otherwise, try to figure out what went wrong. */ + + if (rlen == 4) { + OKF("All right - fork server is up."); + return; + } + + if (child_timed_out) + FATAL("Timeout while initializing fork server (adjusting -t may help)"); + + if (waitpid(forksrv_pid, &status, 0) <= 0) + PFATAL("waitpid() failed"); + + if (WIFSIGNALED(status)) { + + if (mem_limit && mem_limit < 500 && uses_asan) { + + SAYF("\n" cLRD "[-] " cRST + "Whoops, the target binary crashed suddenly, before receiving any input\n" + " from the fuzzer! Since it seems to be built with ASAN and you have a\n" + " restrictive memory limit configured, this is expected; please read\n" + " %s/notes_for_asan.txt for help.\n", doc_path); + + } else if (!mem_limit) { + + SAYF("\n" cLRD "[-] " cRST + "Whoops, the target binary crashed suddenly, before receiving any input\n" + " from the fuzzer! There are several probable explanations:\n\n" + + " - The binary is just buggy and explodes entirely on its own. If so, you\n" + " need to fix the underlying problem or find a better replacement.\n\n" + +#ifdef __APPLE__ + + " - On MacOS X, the semantics of fork() syscalls are non-standard and may\n" + " break afl-fuzz performance optimizations when running platform-specific\n" + " targets. To fix this, set AFL_NO_FORKSRV=1 in the environment.\n\n" + +#endif /* __APPLE__ */ + + " - Less likely, there is a horrible bug in the fuzzer. If other options\n" + " fail, poke for troubleshooting tips.\n"); + + } else { + + SAYF("\n" cLRD "[-] " cRST + "Whoops, the target binary crashed suddenly, before receiving any input\n" + " from the fuzzer! There are several probable explanations:\n\n" + + " - The current memory limit (%s) is too restrictive, causing the\n" + " target to hit an OOM condition in the dynamic linker. Try bumping up\n" + " the limit with the -m setting in the command line. A simple way confirm\n" + " this diagnosis would be:\n\n" + +#ifdef RLIMIT_AS + " ( ulimit -Sv $[%llu << 10]; /path/to/fuzzed_app )\n\n" +#else + " ( ulimit -Sd $[%llu << 10]; /path/to/fuzzed_app )\n\n" +#endif /* ^RLIMIT_AS */ + + " Tip: you can use http://jwilk.net/software/recidivm to quickly\n" + " estimate the required amount of virtual memory for the binary.\n\n" + + " - The binary is just buggy and explodes entirely on its own. If so, you\n" + " need to fix the underlying problem or find a better replacement.\n\n" + +#ifdef __APPLE__ + + " - On MacOS X, the semantics of fork() syscalls are non-standard and may\n" + " break afl-fuzz performance optimizations when running platform-specific\n" + " targets. To fix this, set AFL_NO_FORKSRV=1 in the environment.\n\n" + +#endif /* __APPLE__ */ + + " - Less likely, there is a horrible bug in the fuzzer. If other options\n" + " fail, poke for troubleshooting tips.\n", + DMS(mem_limit << 20), mem_limit - 1); + + } + + FATAL("Fork server crashed with signal %d", WTERMSIG(status)); + + } + + if (*(u32*)trace_bits == EXEC_FAIL_SIG) + FATAL("Unable to execute target application ('%s')", argv[0]); + + if (mem_limit && mem_limit < 500 && uses_asan) { + + SAYF("\n" cLRD "[-] " cRST + "Hmm, looks like the target binary terminated before we could complete a\n" + " handshake with the injected code. Since it seems to be built with ASAN and\n" + " you have a restrictive memory limit configured, this is expected; please\n" + " read %s/notes_for_asan.txt for help.\n", doc_path); + + } else if (!mem_limit) { + + SAYF("\n" cLRD "[-] " cRST + "Hmm, looks like the target binary terminated before we could complete a\n" + " handshake with the injected code. Perhaps there is a horrible bug in the\n" + " fuzzer. Poke for troubleshooting tips.\n"); + + } else { + + SAYF("\n" cLRD "[-] " cRST + "Hmm, looks like the target binary terminated before we could complete a\n" + " handshake with the injected code. There are %s probable explanations:\n\n" + + "%s" + " - The current memory limit (%s) is too restrictive, causing an OOM\n" + " fault in the dynamic linker. This can be fixed with the -m option. A\n" + " simple way to confirm the diagnosis may be:\n\n" + +#ifdef RLIMIT_AS + " ( ulimit -Sv $[%llu << 10]; /path/to/fuzzed_app )\n\n" +#else + " ( ulimit -Sd $[%llu << 10]; /path/to/fuzzed_app )\n\n" +#endif /* ^RLIMIT_AS */ + + " Tip: you can use http://jwilk.net/software/recidivm to quickly\n" + " estimate the required amount of virtual memory for the binary.\n\n" + + " - Less likely, there is a horrible bug in the fuzzer. If other options\n" + " fail, poke for troubleshooting tips.\n", + getenv(DEFER_ENV_VAR) ? "three" : "two", + getenv(DEFER_ENV_VAR) ? + " - You are using deferred forkserver, but __AFL_INIT() is never\n" + " reached before the program terminates.\n\n" : "", + DMS(mem_limit << 20), mem_limit - 1); + + } + + FATAL("Fork server handshake failed"); + +} + + +/* Execute target application, monitoring for timeouts. Return status + information. The called program will update trace_bits[]. */ + +static u8 run_target(char** argv, u32 timeout) { + + static struct itimerval it; + static u32 prev_timed_out = 0; + + int status = 0; + u32 tb4; + + child_timed_out = 0; + + /* After this memset, trace_bits[] are effectively volatile, so we + must prevent any earlier operations from venturing into that + territory. */ + + memset(trace_bits, 0, MAP_SIZE); + MEM_BARRIER(); + + /* If we're running in "dumb" mode, we can't rely on the fork server + logic compiled into the target program, so we will just keep calling + execve(). There is a bit of code duplication between here and + init_forkserver(), but c'est la vie. */ + + if (dumb_mode == 1 || no_forkserver) { + + child_pid = fork(); + + if (child_pid < 0) PFATAL("fork() failed"); + + if (!child_pid) { + + struct rlimit r; + + if (mem_limit) { + + r.rlim_max = r.rlim_cur = ((rlim_t)mem_limit) << 20; + +#ifdef RLIMIT_AS + + setrlimit(RLIMIT_AS, &r); /* Ignore errors */ + +#else + + setrlimit(RLIMIT_DATA, &r); /* Ignore errors */ + +#endif /* ^RLIMIT_AS */ + + } + + r.rlim_max = r.rlim_cur = 0; + + setrlimit(RLIMIT_CORE, &r); /* Ignore errors */ + + /* Isolate the process and configure standard descriptors. If out_file is + specified, stdin is /dev/null; otherwise, out_fd is cloned instead. */ + + setsid(); + + dup2(dev_null_fd, 1); + dup2(dev_null_fd, 2); + + if (out_file) { + + dup2(dev_null_fd, 0); + + } else { + + dup2(out_fd, 0); + close(out_fd); + + } + + /* On Linux, would be faster to use O_CLOEXEC. Maybe TODO. */ + + close(dev_null_fd); + close(out_dir_fd); + close(dev_urandom_fd); + close(fileno(plot_file)); + + /* Set sane defaults for ASAN if nothing else specified. */ + + setenv("ASAN_OPTIONS", "abort_on_error=1:" + "detect_leaks=0:" + "symbolize=0:" + "allocator_may_return_null=1", 0); + + setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":" + "symbolize=0:" + "msan_track_origins=0", 0); + + execv(target_path, argv); + + /* Use a distinctive bitmap value to tell the parent about execv() + falling through. */ + + *(u32*)trace_bits = EXEC_FAIL_SIG; + exit(0); + + } + + } else { + + s32 res; + + /* In non-dumb mode, we have the fork server up and running, so simply + tell it to have at it, and then read back PID. */ + + if ((res = write(fsrv_ctl_fd, &prev_timed_out, 4)) != 4) { + + if (stop_soon) return 0; + RPFATAL(res, "Unable to request new process from fork server (OOM?)"); + + } + + if ((res = read(fsrv_st_fd, &child_pid, 4)) != 4) { + + if (stop_soon) return 0; + RPFATAL(res, "Unable to request new process from fork server (OOM?)"); + + } + + if (child_pid <= 0) FATAL("Fork server is misbehaving (OOM?)"); + + } + + /* Configure timeout, as requested by user, then wait for child to terminate. */ + + it.it_value.tv_sec = (timeout / 1000); + it.it_value.tv_usec = (timeout % 1000) * 1000; + + setitimer(ITIMER_REAL, &it, NULL); + + /* The SIGALRM handler simply kills the child_pid and sets child_timed_out. */ + + if (dumb_mode == 1 || no_forkserver) { + + if (waitpid(child_pid, &status, 0) <= 0) PFATAL("waitpid() failed"); + + } else { + + s32 res; + + if ((res = read(fsrv_st_fd, &status, 4)) != 4) { + + if (stop_soon) return 0; + RPFATAL(res, "Unable to communicate with fork server (OOM?)"); + + } + + } + + if (!WIFSTOPPED(status)) child_pid = 0; + + it.it_value.tv_sec = 0; + it.it_value.tv_usec = 0; + + setitimer(ITIMER_REAL, &it, NULL); + + total_execs++; + + /* Any subsequent operations on trace_bits must not be moved by the + compiler below this point. Past this location, trace_bits[] behave + very normally and do not have to be treated as volatile. */ + + MEM_BARRIER(); + + tb4 = *(u32*)trace_bits; + +#ifdef __x86_64__ + classify_counts((u64*)trace_bits); +#else + classify_counts((u32*)trace_bits); +#endif /* ^__x86_64__ */ + + prev_timed_out = child_timed_out; + + /* Report outcome to caller. */ + + if (WIFSIGNALED(status) && !stop_soon) { + + kill_signal = WTERMSIG(status); + + if (child_timed_out && kill_signal == SIGKILL) return FAULT_TMOUT; + + return FAULT_CRASH; + + } + + /* A somewhat nasty hack for MSAN, which doesn't support abort_on_error and + must use a special exit code. */ + + if (uses_asan && WEXITSTATUS(status) == MSAN_ERROR) { + kill_signal = 0; + return FAULT_CRASH; + } + + if ((dumb_mode == 1 || no_forkserver) && tb4 == EXEC_FAIL_SIG) + return FAULT_ERROR; + + return FAULT_NONE; + +} + + +/* Write modified data to file for testing. If out_file is set, the old file + is unlinked and a new one is created. Otherwise, out_fd is rewound and + truncated. */ + +static void write_to_testcase(void* mem, u32 len) { + + s32 fd = out_fd; + + if (out_file) { + + unlink(out_file); /* Ignore errors. */ + + fd = open(out_file, O_WRONLY | O_CREAT | O_EXCL, 0600); + + if (fd < 0) PFATAL("Unable to create '%s'", out_file); + + } else lseek(fd, 0, SEEK_SET); + + ck_write(fd, mem, len, out_file); + + if (!out_file) { + + if (ftruncate(fd, len)) PFATAL("ftruncate() failed"); + lseek(fd, 0, SEEK_SET); + + } else close(fd); + +} + + +/* The same, but with an adjustable gap. Used for trimming. */ + +static void write_with_gap(void* mem, u32 len, u32 skip_at, u32 skip_len) { + + s32 fd = out_fd; + u32 tail_len = len - skip_at - skip_len; + + if (out_file) { + + unlink(out_file); /* Ignore errors. */ + + fd = open(out_file, O_WRONLY | O_CREAT | O_EXCL, 0600); + + if (fd < 0) PFATAL("Unable to create '%s'", out_file); + + } else lseek(fd, 0, SEEK_SET); + + if (skip_at) ck_write(fd, mem, skip_at, out_file); + + if (tail_len) ck_write(fd, mem + skip_at + skip_len, tail_len, out_file); + + if (!out_file) { + + if (ftruncate(fd, len - skip_len)) PFATAL("ftruncate() failed"); + lseek(fd, 0, SEEK_SET); + + } else close(fd); + +} + + +static void show_stats(void); + +/* Calibrate a new test case. This is done when processing the input directory + to warn about flaky or otherwise problematic test cases early on; and when + new paths are discovered to detect variable behavior and so on. */ + +static u8 calibrate_case(char** argv, struct queue_entry* q, u8* use_mem, + u32 handicap, u8 from_queue) { + + static u8 first_trace[MAP_SIZE]; + + u8 fault = 0, new_bits = 0, var_detected = 0, + first_run = (q->exec_cksum == 0); + + u64 start_us, stop_us; + + s32 old_sc = stage_cur, old_sm = stage_max; + u32 use_tmout = exec_tmout; + u8* old_sn = stage_name; + + /* Be a bit more generous about timeouts when resuming sessions, or when + trying to calibrate already-added finds. This helps avoid trouble due + to intermittent latency. */ + + if (!from_queue || resuming_fuzz) + use_tmout = MAX(exec_tmout + CAL_TMOUT_ADD, + exec_tmout * CAL_TMOUT_PERC / 100); + + q->cal_failed++; + + stage_name = "calibration"; + stage_max = fast_cal ? 3 : CAL_CYCLES; + + /* Make sure the forkserver is up before we do anything, and let's not + count its spin-up time toward binary calibration. */ + + if (dumb_mode != 1 && !no_forkserver && !forksrv_pid) + init_forkserver(argv); + + if (q->exec_cksum) memcpy(first_trace, trace_bits, MAP_SIZE); + + start_us = get_cur_time_us(); + + for (stage_cur = 0; stage_cur < stage_max; stage_cur++) { + + u32 cksum; + + if (!first_run && !(stage_cur % stats_update_freq)) show_stats(); + + write_to_testcase(use_mem, q->len); + + fault = run_target(argv, use_tmout); + + /* stop_soon is set by the handler for Ctrl+C. When it's pressed, + we want to bail out quickly. */ + + if (stop_soon || fault != crash_mode) goto abort_calibration; + + if (!dumb_mode && !stage_cur && !count_bytes(trace_bits)) { + fault = FAULT_NOINST; + goto abort_calibration; + } + + cksum = hash32(trace_bits, MAP_SIZE, HASH_CONST); + + if (q->exec_cksum != cksum) { + + u8 hnb = has_new_bits(virgin_bits); + if (hnb > new_bits) new_bits = hnb; + + if (q->exec_cksum) { + + u32 i; + + for (i = 0; i < MAP_SIZE; i++) { + + if (!var_bytes[i] && first_trace[i] != trace_bits[i]) { + + var_bytes[i] = 1; + stage_max = CAL_CYCLES_LONG; + + } + + } + + var_detected = 1; + + } else { + + q->exec_cksum = cksum; + memcpy(first_trace, trace_bits, MAP_SIZE); + + } + + } + + } + + stop_us = get_cur_time_us(); + + total_cal_us += stop_us - start_us; + total_cal_cycles += stage_max; + + /* OK, let's collect some stats about the performance of this test case. + This is used for fuzzing air time calculations in calculate_score(). */ + + q->exec_us = (stop_us - start_us) / stage_max; + q->bitmap_size = count_bytes(trace_bits); + q->handicap = handicap; + q->cal_failed = 0; + + total_bitmap_size += q->bitmap_size; + total_bitmap_entries++; + + update_bitmap_score(q); + + /* If this case didn't result in new output from the instrumentation, tell + parent. This is a non-critical problem, but something to warn the user + about. */ + + if (!dumb_mode && first_run && !fault && !new_bits) fault = FAULT_NOBITS; + +abort_calibration: + + if (new_bits == 2 && !q->has_new_cov) { + q->has_new_cov = 1; + queued_with_cov++; + } + + /* Mark variable paths. */ + + if (var_detected) { + + var_byte_count = count_bytes(var_bytes); + + if (!q->var_behavior) { + mark_as_variable(q); + queued_variable++; + } + + } + + stage_name = old_sn; + stage_cur = old_sc; + stage_max = old_sm; + + if (!first_run) show_stats(); + + return fault; + +} + + +/* Examine map coverage. Called once, for first test case. */ + +static void check_map_coverage(void) { + + u32 i; + + if (count_bytes(trace_bits) < 100) return; + + for (i = (1 << (MAP_SIZE_POW2 - 1)); i < MAP_SIZE; i++) + if (trace_bits[i]) return; + + WARNF("Recompile binary with newer version of afl to improve coverage!"); + +} + + +/* Perform dry run of all test cases to confirm that the app is working as + expected. This is done only for the initial inputs, and only once. */ + +static void perform_dry_run(char** argv) { + + struct queue_entry* q = queue; + u32 cal_failures = 0; + u8* skip_crashes = getenv("AFL_SKIP_CRASHES"); + + while (q) { + + u8* use_mem; + u8 res; + s32 fd; + + u8* fn = strrchr(q->fname, '/') + 1; + + ACTF("Attempting dry run with '%s'...", fn); + + fd = open(q->fname, O_RDONLY); + if (fd < 0) PFATAL("Unable to open '%s'", q->fname); + + use_mem = ck_alloc_nozero(q->len); + + if (read(fd, use_mem, q->len) != q->len) + FATAL("Short read from '%s'", q->fname); + + close(fd); + + res = calibrate_case(argv, q, use_mem, 0, 1); + ck_free(use_mem); + + if (stop_soon) return; + + if (res == crash_mode || res == FAULT_NOBITS) + SAYF(cGRA " len = %u, map size = %u, exec speed = %llu us\n" cRST, + q->len, q->bitmap_size, q->exec_us); + + switch (res) { + + case FAULT_NONE: + + if (q == queue) check_map_coverage(); + + if (crash_mode) FATAL("Test case '%s' does *NOT* crash", fn); + + break; + + case FAULT_TMOUT: + + if (timeout_given) { + + /* The -t nn+ syntax in the command line sets timeout_given to '2' and + instructs afl-fuzz to tolerate but skip queue entries that time + out. */ + + if (timeout_given > 1) { + WARNF("Test case results in a timeout (skipping)"); + q->cal_failed = CAL_CHANCES; + cal_failures++; + break; + } + + SAYF("\n" cLRD "[-] " cRST + "The program took more than %u ms to process one of the initial test cases.\n" + " Usually, the right thing to do is to relax the -t option - or to delete it\n" + " altogether and allow the fuzzer to auto-calibrate. That said, if you know\n" + " what you are doing and want to simply skip the unruly test cases, append\n" + " '+' at the end of the value passed to -t ('-t %u+').\n", exec_tmout, + exec_tmout); + + FATAL("Test case '%s' results in a timeout", fn); + + } else { + + SAYF("\n" cLRD "[-] " cRST + "The program took more than %u ms to process one of the initial test cases.\n" + " This is bad news; raising the limit with the -t option is possible, but\n" + " will probably make the fuzzing process extremely slow.\n\n" + + " If this test case is just a fluke, the other option is to just avoid it\n" + " altogether, and find one that is less of a CPU hog.\n", exec_tmout); + + FATAL("Test case '%s' results in a timeout", fn); + + } + + case FAULT_CRASH: + + if (crash_mode) break; + + if (skip_crashes) { + WARNF("Test case results in a crash (skipping)"); + q->cal_failed = CAL_CHANCES; + cal_failures++; + break; + } + + if (mem_limit) { + + SAYF("\n" cLRD "[-] " cRST + "Oops, the program crashed with one of the test cases provided. There are\n" + " several possible explanations:\n\n" + + " - The test case causes known crashes under normal working conditions. If\n" + " so, please remove it. The fuzzer should be seeded with interesting\n" + " inputs - but not ones that cause an outright crash.\n\n" + + " - The current memory limit (%s) is too low for this program, causing\n" + " it to die due to OOM when parsing valid files. To fix this, try\n" + " bumping it up with the -m setting in the command line. If in doubt,\n" + " try something along the lines of:\n\n" + +#ifdef RLIMIT_AS + " ( ulimit -Sv $[%llu << 10]; /path/to/binary [...] for troubleshooting tips.\n", + DMS(mem_limit << 20), mem_limit - 1, doc_path); + + } else { + + SAYF("\n" cLRD "[-] " cRST + "Oops, the program crashed with one of the test cases provided. There are\n" + " several possible explanations:\n\n" + + " - The test case causes known crashes under normal working conditions. If\n" + " so, please remove it. The fuzzer should be seeded with interesting\n" + " inputs - but not ones that cause an outright crash.\n\n" + +#ifdef __APPLE__ + + " - On MacOS X, the semantics of fork() syscalls are non-standard and may\n" + " break afl-fuzz performance optimizations when running platform-specific\n" + " binaries. To fix this, set AFL_NO_FORKSRV=1 in the environment.\n\n" + +#endif /* __APPLE__ */ + + " - Least likely, there is a horrible bug in the fuzzer. If other options\n" + " fail, poke for troubleshooting tips.\n"); + + } + + FATAL("Test case '%s' results in a crash", fn); + + case FAULT_ERROR: + + FATAL("Unable to execute target application ('%s')", argv[0]); + + case FAULT_NOINST: + + FATAL("No instrumentation detected"); + + case FAULT_NOBITS: + + useless_at_start++; + + if (!in_bitmap && !shuffle_queue) + WARNF("No new instrumentation output, test case may be useless."); + + break; + + } + + if (q->var_behavior) WARNF("Instrumentation output varies across runs."); + + q = q->next; + + } + + if (cal_failures) { + + if (cal_failures == queued_paths) + FATAL("All test cases time out%s, giving up!", + skip_crashes ? " or crash" : ""); + + WARNF("Skipped %u test cases (%0.02f%%) due to timeouts%s.", cal_failures, + ((double)cal_failures) * 100 / queued_paths, + skip_crashes ? " or crashes" : ""); + + if (cal_failures * 5 > queued_paths) + WARNF(cLRD "High percentage of rejected test cases, check settings!"); + + } + + OKF("All test cases processed."); + +} + + +/* Helper function: link() if possible, copy otherwise. */ + +static void link_or_copy(u8* old_path, u8* new_path) { + + s32 i = link(old_path, new_path); + s32 sfd, dfd; + u8* tmp; + + if (!i) return; + + sfd = open(old_path, O_RDONLY); + if (sfd < 0) PFATAL("Unable to open '%s'", old_path); + + dfd = open(new_path, O_WRONLY | O_CREAT | O_EXCL, 0600); + if (dfd < 0) PFATAL("Unable to create '%s'", new_path); + + tmp = ck_alloc(64 * 1024); + + while ((i = read(sfd, tmp, 64 * 1024)) > 0) + ck_write(dfd, tmp, i, new_path); + + if (i < 0) PFATAL("read() failed"); + + ck_free(tmp); + close(sfd); + close(dfd); + +} + + +static void nuke_resume_dir(void); + +/* Create hard links for input test cases in the output directory, choosing + good names and pivoting accordingly. */ + +static void pivot_inputs(void) { + + struct queue_entry* q = queue; + u32 id = 0; + + ACTF("Creating hard links for all input files..."); + + while (q) { + + u8 *nfn, *rsl = strrchr(q->fname, '/'); + u32 orig_id; + + if (!rsl) rsl = q->fname; else rsl++; + + /* If the original file name conforms to the syntax and the recorded + ID matches the one we'd assign, just use the original file name. + This is valuable for resuming fuzzing runs. */ + +#ifndef SIMPLE_FILES +# define CASE_PREFIX "id:" +#else +# define CASE_PREFIX "id_" +#endif /* ^!SIMPLE_FILES */ + + if (!strncmp(rsl, CASE_PREFIX, 3) && + sscanf(rsl + 3, "%06u", &orig_id) == 1 && orig_id == id) { + + u8* src_str; + u32 src_id; + + resuming_fuzz = 1; + nfn = alloc_printf("%s/queue/%s", out_dir, rsl); + + /* Since we're at it, let's also try to find parent and figure out the + appropriate depth for this entry. */ + + src_str = strchr(rsl + 3, ':'); + + if (src_str && sscanf(src_str + 1, "%06u", &src_id) == 1) { + + struct queue_entry* s = queue; + while (src_id-- && s) s = s->next; + if (s) q->depth = s->depth + 1; + + if (max_depth < q->depth) max_depth = q->depth; + + } + + } else { + + /* No dice - invent a new name, capturing the original one as a + substring. */ + +#ifndef SIMPLE_FILES + + u8* use_name = strstr(rsl, ",orig:"); + + if (use_name) use_name += 6; else use_name = rsl; + nfn = alloc_printf("%s/queue/id:%06u,orig:%s", out_dir, id, use_name); + +#else + + nfn = alloc_printf("%s/queue/id_%06u", out_dir, id); + +#endif /* ^!SIMPLE_FILES */ + + } + + /* Pivot to the new queue entry. */ + + link_or_copy(q->fname, nfn); + ck_free(q->fname); + q->fname = nfn; + + /* Make sure that the passed_det value carries over, too. */ + + if (q->passed_det) mark_as_det_done(q); + + q = q->next; + id++; + + } + + if (in_place_resume) nuke_resume_dir(); + +} + + +#ifndef SIMPLE_FILES + +/* Construct a file name for a new test case, capturing the operation + that led to its discovery. Uses a static buffer. */ + +static u8* describe_op(u8 hnb) { + + static u8 ret[256]; + + if (syncing_party) { + + sprintf(ret, "sync:%s,src:%06u", syncing_party, syncing_case); + + } else { + + sprintf(ret, "src:%06u", current_entry); + + if (splicing_with >= 0) + sprintf(ret + strlen(ret), "+%06u", splicing_with); + + sprintf(ret + strlen(ret), ",op:%s", stage_short); + + if (stage_cur_byte >= 0) { + + sprintf(ret + strlen(ret), ",pos:%u", stage_cur_byte); + + if (stage_val_type != STAGE_VAL_NONE) + sprintf(ret + strlen(ret), ",val:%s%+d", + (stage_val_type == STAGE_VAL_BE) ? "be:" : "", + stage_cur_val); + + } else sprintf(ret + strlen(ret), ",rep:%u", stage_cur_val); + + } + + if (hnb == 2) strcat(ret, ",+cov"); + + return ret; + +} + +#endif /* !SIMPLE_FILES */ + + +/* Write a message accompanying the crash directory :-) */ + +static void write_crash_readme(void) { + + u8* fn = alloc_printf("%s/crashes/README.txt", out_dir); + s32 fd; + FILE* f; + + fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, 0600); + ck_free(fn); + + /* Do not die on errors here - that would be impolite. */ + + if (fd < 0) return; + + f = fdopen(fd, "w"); + + if (!f) { + close(fd); + return; + } + + fprintf(f, "Command line used to find this crash:\n\n" + + "%s\n\n" + + "If you can't reproduce a bug outside of afl-fuzz, be sure to set the same\n" + "memory limit. The limit used for this fuzzing session was %s.\n\n" + + "Need a tool to minimize test cases before investigating the crashes or sending\n" + "them to a vendor? Check out the afl-tmin that comes with the fuzzer!\n\n" + + "Found any cool bugs in open-source tools using afl-fuzz? If yes, please drop\n" + "me a mail at once the issues are fixed - I'd love to\n" + "add your finds to the gallery at:\n\n" + + " http://lcamtuf.coredump.cx/afl/\n\n" + + "Thanks :-)\n", + + orig_cmdline, DMS(mem_limit << 20)); /* ignore errors */ + + fclose(f); + +} + + +/* Check if the result of an execve() during routine fuzzing is interesting, + save or queue the input test case for further analysis if so. Returns 1 if + entry is saved, 0 otherwise. */ + +static u8 save_if_interesting(char** argv, void* mem, u32 len, u8 fault) { + + u8 *fn = ""; + u8 hnb; + s32 fd; + u8 keeping = 0, res; + + if (fault == crash_mode) { + + /* Keep only if there are new bits in the map, add to queue for + future fuzzing, etc. */ + + if (!(hnb = has_new_bits(virgin_bits))) { + if (crash_mode) total_crashes++; + return 0; + } + +#ifndef SIMPLE_FILES + + fn = alloc_printf("%s/queue/id:%06u,%s", out_dir, queued_paths, + describe_op(hnb)); + +#else + + fn = alloc_printf("%s/queue/id_%06u", out_dir, queued_paths); + +#endif /* ^!SIMPLE_FILES */ + + add_to_queue(fn, len, 0); + + if (hnb == 2) { + queue_top->has_new_cov = 1; + queued_with_cov++; + } + + queue_top->exec_cksum = hash32(trace_bits, MAP_SIZE, HASH_CONST); + + /* Try to calibrate inline; this also calls update_bitmap_score() when + successful. */ + + res = calibrate_case(argv, queue_top, mem, queue_cycle - 1, 0); + + if (res == FAULT_ERROR) + FATAL("Unable to execute target application"); + + fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, 0600); + if (fd < 0) PFATAL("Unable to create '%s'", fn); + ck_write(fd, mem, len, fn); + close(fd); + + keeping = 1; + + } + + switch (fault) { + + case FAULT_TMOUT: + + /* Timeouts are not very interesting, but we're still obliged to keep + a handful of samples. We use the presence of new bits in the + hang-specific bitmap as a signal of uniqueness. In "dumb" mode, we + just keep everything. */ + + total_tmouts++; + + if (unique_hangs >= KEEP_UNIQUE_HANG) return keeping; + + if (!dumb_mode) { + +#ifdef __x86_64__ + simplify_trace((u64*)trace_bits); +#else + simplify_trace((u32*)trace_bits); +#endif /* ^__x86_64__ */ + + if (!has_new_bits(virgin_tmout)) return keeping; + + } + + unique_tmouts++; + + /* Before saving, we make sure that it's a genuine hang by re-running + the target with a more generous timeout (unless the default timeout + is already generous). */ + + if (exec_tmout < hang_tmout) { + + u8 new_fault; + write_to_testcase(mem, len); + new_fault = run_target(argv, hang_tmout); + + /* A corner case that one user reported bumping into: increasing the + timeout actually uncovers a crash. Make sure we don't discard it if + so. */ + + if (!stop_soon && new_fault == FAULT_CRASH) goto keep_as_crash; + + if (stop_soon || new_fault != FAULT_TMOUT) return keeping; + + } + +#ifndef SIMPLE_FILES + + fn = alloc_printf("%s/hangs/id:%06llu,%s", out_dir, + unique_hangs, describe_op(0)); + +#else + + fn = alloc_printf("%s/hangs/id_%06llu", out_dir, + unique_hangs); + +#endif /* ^!SIMPLE_FILES */ + + unique_hangs++; + + last_hang_time = get_cur_time(); + + break; + + case FAULT_CRASH: + +keep_as_crash: + + /* This is handled in a manner roughly similar to timeouts, + except for slightly different limits and no need to re-run test + cases. */ + + total_crashes++; + + if (unique_crashes >= KEEP_UNIQUE_CRASH) return keeping; + + if (!dumb_mode) { + +#ifdef __x86_64__ + simplify_trace((u64*)trace_bits); +#else + simplify_trace((u32*)trace_bits); +#endif /* ^__x86_64__ */ + + if (!has_new_bits(virgin_crash)) return keeping; + + } + + if (!unique_crashes) write_crash_readme(); + +#ifndef SIMPLE_FILES + + fn = alloc_printf("%s/crashes/id:%06llu,sig:%02u,%s", out_dir, + unique_crashes, kill_signal, describe_op(0)); + +#else + + fn = alloc_printf("%s/crashes/id_%06llu_%02u", out_dir, unique_crashes, + kill_signal); + +#endif /* ^!SIMPLE_FILES */ + + unique_crashes++; + + last_crash_time = get_cur_time(); + last_crash_execs = total_execs; + + break; + + case FAULT_ERROR: FATAL("Unable to execute target application"); + + default: return keeping; + + } + + /* If we're here, we apparently want to save the crash or hang + test case, too. */ + + fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, 0600); + if (fd < 0) PFATAL("Unable to create '%s'", fn); + ck_write(fd, mem, len, fn); + close(fd); + + ck_free(fn); + + return keeping; + +} + + +/* When resuming, try to find the queue position to start from. This makes sense + only when resuming, and when we can find the original fuzzer_stats. */ + +static u32 find_start_position(void) { + + static u8 tmp[4096]; /* Ought to be enough for anybody. */ + + u8 *fn, *off; + s32 fd, i; + u32 ret; + + if (!resuming_fuzz) return 0; + + if (in_place_resume) fn = alloc_printf("%s/fuzzer_stats", out_dir); + else fn = alloc_printf("%s/../fuzzer_stats", in_dir); + + fd = open(fn, O_RDONLY); + ck_free(fn); + + if (fd < 0) return 0; + + i = read(fd, tmp, sizeof(tmp) - 1); (void)i; /* Ignore errors */ + close(fd); + + off = strstr(tmp, "cur_path : "); + if (!off) return 0; + + ret = atoi(off + 20); + if (ret >= queued_paths) ret = 0; + return ret; + +} + + +/* The same, but for timeouts. The idea is that when resuming sessions without + -t given, we don't want to keep auto-scaling the timeout over and over + again to prevent it from growing due to random flukes. */ + +static void find_timeout(void) { + + static u8 tmp[4096]; /* Ought to be enough for anybody. */ + + u8 *fn, *off; + s32 fd, i; + u32 ret; + + if (!resuming_fuzz) return; + + if (in_place_resume) fn = alloc_printf("%s/fuzzer_stats", out_dir); + else fn = alloc_printf("%s/../fuzzer_stats", in_dir); + + fd = open(fn, O_RDONLY); + ck_free(fn); + + if (fd < 0) return; + + i = read(fd, tmp, sizeof(tmp) - 1); (void)i; /* Ignore errors */ + close(fd); + + off = strstr(tmp, "exec_timeout : "); + if (!off) return; + + ret = atoi(off + 17); + if (ret <= 4) return; + + exec_tmout = ret; + timeout_given = 3; + +} + + +/* Update stats file for unattended monitoring. */ + +static void write_stats_file(double bitmap_cvg, double stability, double eps) { + + static double last_bcvg, last_stab, last_eps; + + u8* fn = alloc_printf("%s/fuzzer_stats", out_dir); + s32 fd; + FILE* f; + + fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600); + + if (fd < 0) PFATAL("Unable to create '%s'", fn); + + ck_free(fn); + + f = fdopen(fd, "w"); + + if (!f) PFATAL("fdopen() failed"); + + /* Keep last values in case we're called from another context + where exec/sec stats and such are not readily available. */ + + if (!bitmap_cvg && !stability && !eps) { + bitmap_cvg = last_bcvg; + stability = last_stab; + eps = last_eps; + } else { + last_bcvg = bitmap_cvg; + last_stab = stability; + last_eps = eps; + } + + fprintf(f, "start_time : %llu\n" + "last_update : %llu\n" + "fuzzer_pid : %u\n" + "cycles_done : %llu\n" + "execs_done : %llu\n" + "execs_per_sec : %0.02f\n" + "paths_total : %u\n" + "paths_favored : %u\n" + "paths_found : %u\n" + "paths_imported : %u\n" + "max_depth : %u\n" + "cur_path : %u\n" /* Must match find_start_position() */ + "pending_favs : %u\n" + "pending_total : %u\n" + "variable_paths : %u\n" + "stability : %0.02f%%\n" + "bitmap_cvg : %0.02f%%\n" + "unique_crashes : %llu\n" + "unique_hangs : %llu\n" + "last_path : %llu\n" + "last_crash : %llu\n" + "last_hang : %llu\n" + "execs_since_crash : %llu\n" + "exec_timeout : %u\n" + "afl_banner : %s\n" + "afl_version : " VERSION "\n" + "target_mode : %s%s%s%s%s%s%s\n" + "command_line : %s\n", + start_time / 1000, get_cur_time() / 1000, getpid(), + queue_cycle ? (queue_cycle - 1) : 0, total_execs, eps, + queued_paths, queued_favored, queued_discovered, queued_imported, + max_depth, current_entry, pending_favored, pending_not_fuzzed, + queued_variable, stability, bitmap_cvg, unique_crashes, + unique_hangs, last_path_time / 1000, last_crash_time / 1000, + last_hang_time / 1000, total_execs - last_crash_execs, + exec_tmout, use_banner, + qemu_mode ? "qemu " : "", dumb_mode ? " dumb " : "", + no_forkserver ? "no_forksrv " : "", crash_mode ? "crash " : "", + persistent_mode ? "persistent " : "", deferred_mode ? "deferred " : "", + (qemu_mode || dumb_mode || no_forkserver || crash_mode || + persistent_mode || deferred_mode) ? "" : "default", + orig_cmdline); + /* ignore errors */ + + fclose(f); + +} + + +/* Update the plot file if there is a reason to. */ + +static void maybe_update_plot_file(double bitmap_cvg, double eps) { + + static u32 prev_qp, prev_pf, prev_pnf, prev_ce, prev_md; + static u64 prev_qc, prev_uc, prev_uh; + + if (prev_qp == queued_paths && prev_pf == pending_favored && + prev_pnf == pending_not_fuzzed && prev_ce == current_entry && + prev_qc == queue_cycle && prev_uc == unique_crashes && + prev_uh == unique_hangs && prev_md == max_depth) return; + + prev_qp = queued_paths; + prev_pf = pending_favored; + prev_pnf = pending_not_fuzzed; + prev_ce = current_entry; + prev_qc = queue_cycle; + prev_uc = unique_crashes; + prev_uh = unique_hangs; + prev_md = max_depth; + + /* Fields in the file: + + unix_time, cycles_done, cur_path, paths_total, paths_not_fuzzed, + favored_not_fuzzed, unique_crashes, unique_hangs, max_depth, + execs_per_sec */ + + fprintf(plot_file, + "%llu, %llu, %u, %u, %u, %u, %0.02f%%, %llu, %llu, %u, %0.02f\n", + get_cur_time() / 1000, queue_cycle - 1, current_entry, queued_paths, + pending_not_fuzzed, pending_favored, bitmap_cvg, unique_crashes, + unique_hangs, max_depth, eps); /* ignore errors */ + + fflush(plot_file); + +} + + + +/* A helper function for maybe_delete_out_dir(), deleting all prefixed + files in a directory. */ + +static u8 delete_files(u8* path, u8* prefix) { + + DIR* d; + struct dirent* d_ent; + + d = opendir(path); + + if (!d) return 0; + + while ((d_ent = readdir(d))) { + + if (d_ent->d_name[0] != '.' && (!prefix || + !strncmp(d_ent->d_name, prefix, strlen(prefix)))) { + + u8* fname = alloc_printf("%s/%s", path, d_ent->d_name); + if (unlink(fname)) PFATAL("Unable to delete '%s'", fname); + ck_free(fname); + + } + + } + + closedir(d); + + return !!rmdir(path); + +} + + +/* Get the number of runnable processes, with some simple smoothing. */ + +static double get_runnable_processes(void) { + + static double res; + +#if defined(__APPLE__) || defined(__FreeBSD__) || defined (__OpenBSD__) + + /* I don't see any portable sysctl or so that would quickly give us the + number of runnable processes; the 1-minute load average can be a + semi-decent approximation, though. */ + + if (getloadavg(&res, 1) != 1) return 0; + +#else + + /* On Linux, /proc/stat is probably the best way; load averages are + computed in funny ways and sometimes don't reflect extremely short-lived + processes well. */ + + FILE* f = fopen("/proc/stat", "r"); + u8 tmp[1024]; + u32 val = 0; + + if (!f) return 0; + + while (fgets(tmp, sizeof(tmp), f)) { + + if (!strncmp(tmp, "procs_running ", 14) || + !strncmp(tmp, "procs_blocked ", 14)) val += atoi(tmp + 14); + + } + + fclose(f); + + if (!res) { + + res = val; + + } else { + + res = res * (1.0 - 1.0 / AVG_SMOOTHING) + + ((double)val) * (1.0 / AVG_SMOOTHING); + + } + +#endif /* ^(__APPLE__ || __FreeBSD__ || __OpenBSD__) */ + + return res; + +} + + +/* Delete the temporary directory used for in-place session resume. */ + +static void nuke_resume_dir(void) { + + u8* fn; + + fn = alloc_printf("%s/_resume/.state/deterministic_done", out_dir); + if (delete_files(fn, CASE_PREFIX)) goto dir_cleanup_failed; + ck_free(fn); + + fn = alloc_printf("%s/_resume/.state/auto_extras", out_dir); + if (delete_files(fn, "auto_")) goto dir_cleanup_failed; + ck_free(fn); + + fn = alloc_printf("%s/_resume/.state/redundant_edges", out_dir); + if (delete_files(fn, CASE_PREFIX)) goto dir_cleanup_failed; + ck_free(fn); + + fn = alloc_printf("%s/_resume/.state/variable_behavior", out_dir); + if (delete_files(fn, CASE_PREFIX)) goto dir_cleanup_failed; + ck_free(fn); + + fn = alloc_printf("%s/_resume/.state", out_dir); + if (rmdir(fn) && errno != ENOENT) goto dir_cleanup_failed; + ck_free(fn); + + fn = alloc_printf("%s/_resume", out_dir); + if (delete_files(fn, CASE_PREFIX)) goto dir_cleanup_failed; + ck_free(fn); + + return; + +dir_cleanup_failed: + + FATAL("_resume directory cleanup failed"); + +} + + +/* Delete fuzzer output directory if we recognize it as ours, if the fuzzer + is not currently running, and if the last run time isn't too great. */ + +static void maybe_delete_out_dir(void) { + + FILE* f; + u8 *fn = alloc_printf("%s/fuzzer_stats", out_dir); + + /* See if the output directory is locked. If yes, bail out. If not, + create a lock that will persist for the lifetime of the process + (this requires leaving the descriptor open).*/ + + out_dir_fd = open(out_dir, O_RDONLY); + if (out_dir_fd < 0) PFATAL("Unable to open '%s'", out_dir); + +#ifndef __sun + + if (flock(out_dir_fd, LOCK_EX | LOCK_NB) && errno == EWOULDBLOCK) { + + SAYF("\n" cLRD "[-] " cRST + "Looks like the job output directory is being actively used by another\n" + " instance of afl-fuzz. You will need to choose a different %s\n" + " or stop the other process first.\n", + sync_id ? "fuzzer ID" : "output location"); + + FATAL("Directory '%s' is in use", out_dir); + + } + +#endif /* !__sun */ + + f = fopen(fn, "r"); + + if (f) { + + u64 start_time, last_update; + + if (fscanf(f, "start_time : %llu\n" + "last_update : %llu\n", &start_time, &last_update) != 2) + FATAL("Malformed data in '%s'", fn); + + fclose(f); + + /* Let's see how much work is at stake. */ + + if (!in_place_resume && last_update - start_time > OUTPUT_GRACE * 60) { + + SAYF("\n" cLRD "[-] " cRST + "The job output directory already exists and contains the results of more\n" + " than %u minutes worth of fuzzing. To avoid data loss, afl-fuzz will *NOT*\n" + " automatically delete this data for you.\n\n" + + " If you wish to start a new session, remove or rename the directory manually,\n" + " or specify a different output location for this job. To resume the old\n" + " session, put '-' as the input directory in the command line ('-i -') and\n" + " try again.\n", OUTPUT_GRACE); + + FATAL("At-risk data found in '%s'", out_dir); + + } + + } + + ck_free(fn); + + /* The idea for in-place resume is pretty simple: we temporarily move the old + queue/ to a new location that gets deleted once import to the new queue/ + is finished. If _resume/ already exists, the current queue/ may be + incomplete due to an earlier abort, so we want to use the old _resume/ + dir instead, and we let rename() fail silently. */ + + if (in_place_resume) { + + u8* orig_q = alloc_printf("%s/queue", out_dir); + + in_dir = alloc_printf("%s/_resume", out_dir); + + rename(orig_q, in_dir); /* Ignore errors */ + + OKF("Output directory exists, will attempt session resume."); + + ck_free(orig_q); + + } else { + + OKF("Output directory exists but deemed OK to reuse."); + + } + + ACTF("Deleting old session data..."); + + /* Okay, let's get the ball rolling! First, we need to get rid of the entries + in /.synced/.../id:*, if any are present. */ + + if (!in_place_resume) { + + fn = alloc_printf("%s/.synced", out_dir); + if (delete_files(fn, NULL)) goto dir_cleanup_failed; + ck_free(fn); + + } + + /* Next, we need to clean up /queue/.state/ subdirectories: */ + + fn = alloc_printf("%s/queue/.state/deterministic_done", out_dir); + if (delete_files(fn, CASE_PREFIX)) goto dir_cleanup_failed; + ck_free(fn); + + fn = alloc_printf("%s/queue/.state/auto_extras", out_dir); + if (delete_files(fn, "auto_")) goto dir_cleanup_failed; + ck_free(fn); + + fn = alloc_printf("%s/queue/.state/redundant_edges", out_dir); + if (delete_files(fn, CASE_PREFIX)) goto dir_cleanup_failed; + ck_free(fn); + + fn = alloc_printf("%s/queue/.state/variable_behavior", out_dir); + if (delete_files(fn, CASE_PREFIX)) goto dir_cleanup_failed; + ck_free(fn); + + /* Then, get rid of the .state subdirectory itself (should be empty by now) + and everything matching /queue/id:*. */ + + fn = alloc_printf("%s/queue/.state", out_dir); + if (rmdir(fn) && errno != ENOENT) goto dir_cleanup_failed; + ck_free(fn); + + fn = alloc_printf("%s/queue", out_dir); + if (delete_files(fn, CASE_PREFIX)) goto dir_cleanup_failed; + ck_free(fn); + + /* All right, let's do /crashes/id:* and /hangs/id:*. */ + + if (!in_place_resume) { + + fn = alloc_printf("%s/crashes/README.txt", out_dir); + unlink(fn); /* Ignore errors */ + ck_free(fn); + + } + + fn = alloc_printf("%s/crashes", out_dir); + + /* Make backup of the crashes directory if it's not empty and if we're + doing in-place resume. */ + + if (in_place_resume && rmdir(fn)) { + + time_t cur_t = time(0); + struct tm* t = localtime(&cur_t); + +#ifndef SIMPLE_FILES + + u8* nfn = alloc_printf("%s.%04u-%02u-%02u-%02u:%02u:%02u", fn, + t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, + t->tm_hour, t->tm_min, t->tm_sec); + +#else + + u8* nfn = alloc_printf("%s_%04u%02u%02u%02u%02u%02u", fn, + t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, + t->tm_hour, t->tm_min, t->tm_sec); + +#endif /* ^!SIMPLE_FILES */ + + rename(fn, nfn); /* Ignore errors. */ + ck_free(nfn); + + } + + if (delete_files(fn, CASE_PREFIX)) goto dir_cleanup_failed; + ck_free(fn); + + fn = alloc_printf("%s/hangs", out_dir); + + /* Backup hangs, too. */ + + if (in_place_resume && rmdir(fn)) { + + time_t cur_t = time(0); + struct tm* t = localtime(&cur_t); + +#ifndef SIMPLE_FILES + + u8* nfn = alloc_printf("%s.%04u-%02u-%02u-%02u:%02u:%02u", fn, + t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, + t->tm_hour, t->tm_min, t->tm_sec); + +#else + + u8* nfn = alloc_printf("%s_%04u%02u%02u%02u%02u%02u", fn, + t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, + t->tm_hour, t->tm_min, t->tm_sec); + +#endif /* ^!SIMPLE_FILES */ + + rename(fn, nfn); /* Ignore errors. */ + ck_free(nfn); + + } + + if (delete_files(fn, CASE_PREFIX)) goto dir_cleanup_failed; + ck_free(fn); + + /* And now, for some finishing touches. */ + + fn = alloc_printf("%s/.cur_input", out_dir); + if (unlink(fn) && errno != ENOENT) goto dir_cleanup_failed; + ck_free(fn); + + fn = alloc_printf("%s/fuzz_bitmap", out_dir); + if (unlink(fn) && errno != ENOENT) goto dir_cleanup_failed; + ck_free(fn); + + if (!in_place_resume) { + fn = alloc_printf("%s/fuzzer_stats", out_dir); + if (unlink(fn) && errno != ENOENT) goto dir_cleanup_failed; + ck_free(fn); + } + + fn = alloc_printf("%s/plot_data", out_dir); + if (unlink(fn) && errno != ENOENT) goto dir_cleanup_failed; + ck_free(fn); + + OKF("Output dir cleanup successful."); + + /* Wow... is that all? If yes, celebrate! */ + + return; + +dir_cleanup_failed: + + SAYF("\n" cLRD "[-] " cRST + "Whoops, the fuzzer tried to reuse your output directory, but bumped into\n" + " some files that shouldn't be there or that couldn't be removed - so it\n" + " decided to abort! This happened while processing this path:\n\n" + + " %s\n\n" + " Please examine and manually delete the files, or specify a different\n" + " output location for the tool.\n", fn); + + FATAL("Output directory cleanup failed"); + +} + + +static void check_term_size(void); + + +/* A spiffy retro stats screen! This is called every stats_update_freq + execve() calls, plus in several other circumstances. */ + +static void show_stats(void) { + + static u64 last_stats_ms, last_plot_ms, last_ms, last_execs; + static double avg_exec; + double t_byte_ratio, stab_ratio; + + u64 cur_ms; + u32 t_bytes, t_bits; + + u32 banner_len, banner_pad; + u8 tmp[256]; + + cur_ms = get_cur_time(); + + /* If not enough time has passed since last UI update, bail out. */ + + if (cur_ms - last_ms < 1000 / UI_TARGET_HZ) return; + + /* Check if we're past the 10 minute mark. */ + + if (cur_ms - start_time > 10 * 60 * 1000) run_over10m = 1; + + /* Calculate smoothed exec speed stats. */ + + if (!last_execs) { + + avg_exec = ((double)total_execs) * 1000 / (cur_ms - start_time); + + } else { + + double cur_avg = ((double)(total_execs - last_execs)) * 1000 / + (cur_ms - last_ms); + + /* If there is a dramatic (5x+) jump in speed, reset the indicator + more quickly. */ + + if (cur_avg * 5 < avg_exec || cur_avg / 5 > avg_exec) + avg_exec = cur_avg; + + avg_exec = avg_exec * (1.0 - 1.0 / AVG_SMOOTHING) + + cur_avg * (1.0 / AVG_SMOOTHING); + + } + + last_ms = cur_ms; + last_execs = total_execs; + + /* Tell the callers when to contact us (as measured in execs). */ + + stats_update_freq = avg_exec / (UI_TARGET_HZ * 10); + if (!stats_update_freq) stats_update_freq = 1; + + /* Do some bitmap stats. */ + + t_bytes = count_non_255_bytes(virgin_bits); + t_byte_ratio = ((double)t_bytes * 100) / MAP_SIZE; + + if (t_bytes) + stab_ratio = 100 - ((double)var_byte_count) * 100 / t_bytes; + else + stab_ratio = 100; + + /* Roughly every minute, update fuzzer stats and save auto tokens. */ + + if (cur_ms - last_stats_ms > STATS_UPDATE_SEC * 1000) { + + last_stats_ms = cur_ms; + write_stats_file(t_byte_ratio, stab_ratio, avg_exec); + save_auto(); + write_bitmap(); + + } + + /* Every now and then, write plot data. */ + + if (cur_ms - last_plot_ms > PLOT_UPDATE_SEC * 1000) { + + last_plot_ms = cur_ms; + maybe_update_plot_file(t_byte_ratio, avg_exec); + + } + + /* Honor AFL_EXIT_WHEN_DONE and AFL_BENCH_UNTIL_CRASH. */ + + if (!dumb_mode && cycles_wo_finds > 100 && !pending_not_fuzzed && + getenv("AFL_EXIT_WHEN_DONE")) stop_soon = 2; + + if (total_crashes && getenv("AFL_BENCH_UNTIL_CRASH")) stop_soon = 2; + + /* If we're not on TTY, bail out. */ + + if (not_on_tty) return; + + /* Compute some mildly useful bitmap stats. */ + + t_bits = (MAP_SIZE << 3) - count_bits(virgin_bits); + + /* Now, for the visuals... */ + + if (clear_screen) { + + SAYF(TERM_CLEAR CURSOR_HIDE); + clear_screen = 0; + + check_term_size(); + + } + + SAYF(TERM_HOME); + + if (term_too_small) { + + SAYF(cBRI "Your terminal is too small to display the UI.\n" + "Please resize terminal window to at least 80x25.\n" cRST); + + return; + + } + + /* Let's start by drawing a centered banner. */ + + banner_len = (crash_mode ? 24 : 22) + strlen(VERSION) + strlen(use_banner); + banner_pad = (80 - banner_len) / 2; + memset(tmp, ' ', banner_pad); + + sprintf(tmp + banner_pad, "%s " cLCY VERSION cLGN + " (%s)", crash_mode ? cPIN "peruvian were-rabbit" : + cYEL "american fuzzy lop", use_banner); + + SAYF("\n%s\n\n", tmp); + + /* "Handy" shortcuts for drawing boxes... */ + +#define bSTG bSTART cGRA +#define bH2 bH bH +#define bH5 bH2 bH2 bH +#define bH10 bH5 bH5 +#define bH20 bH10 bH10 +#define bH30 bH20 bH10 +#define SP5 " " +#define SP10 SP5 SP5 +#define SP20 SP10 SP10 + + /* Lord, forgive me this. */ + + SAYF(SET_G1 bSTG bLT bH bSTOP cCYA " process timing " bSTG bH30 bH5 bH2 bHB + bH bSTOP cCYA " overall results " bSTG bH5 bRT "\n"); + + if (dumb_mode) { + + strcpy(tmp, cRST); + + } else { + + u64 min_wo_finds = (cur_ms - last_path_time) / 1000 / 60; + + /* First queue cycle: don't stop now! */ + if (queue_cycle == 1 || min_wo_finds < 15) strcpy(tmp, cMGN); else + + /* Subsequent cycles, but we're still making finds. */ + if (cycles_wo_finds < 25 || min_wo_finds < 30) strcpy(tmp, cYEL); else + + /* No finds for a long time and no test cases to try. */ + if (cycles_wo_finds > 100 && !pending_not_fuzzed && min_wo_finds > 120) + strcpy(tmp, cLGN); + + /* Default: cautiously OK to stop? */ + else strcpy(tmp, cLBL); + + } + + SAYF(bV bSTOP " run time : " cRST "%-34s " bSTG bV bSTOP + " cycles done : %s%-5s " bSTG bV "\n", + DTD(cur_ms, start_time), tmp, DI(queue_cycle - 1)); + + /* We want to warn people about not seeing new paths after a full cycle, + except when resuming fuzzing or running in non-instrumented mode. */ + + if (!dumb_mode && (last_path_time || resuming_fuzz || queue_cycle == 1 || + in_bitmap || crash_mode)) { + + SAYF(bV bSTOP " last new path : " cRST "%-34s ", + DTD(cur_ms, last_path_time)); + + } else { + + if (dumb_mode) + + SAYF(bV bSTOP " last new path : " cPIN "n/a" cRST + " (non-instrumented mode) "); + + else + + SAYF(bV bSTOP " last new path : " cRST "none yet " cLRD + "(odd, check syntax!) "); + + } + + SAYF(bSTG bV bSTOP " total paths : " cRST "%-5s " bSTG bV "\n", + DI(queued_paths)); + + /* Highlight crashes in red if found, denote going over the KEEP_UNIQUE_CRASH + limit with a '+' appended to the count. */ + + sprintf(tmp, "%s%s", DI(unique_crashes), + (unique_crashes >= KEEP_UNIQUE_CRASH) ? "+" : ""); + + SAYF(bV bSTOP " last uniq crash : " cRST "%-34s " bSTG bV bSTOP + " uniq crashes : %s%-6s " bSTG bV "\n", + DTD(cur_ms, last_crash_time), unique_crashes ? cLRD : cRST, + tmp); + + sprintf(tmp, "%s%s", DI(unique_hangs), + (unique_hangs >= KEEP_UNIQUE_HANG) ? "+" : ""); + + SAYF(bV bSTOP " last uniq hang : " cRST "%-34s " bSTG bV bSTOP + " uniq hangs : " cRST "%-6s " bSTG bV "\n", + DTD(cur_ms, last_hang_time), tmp); + + SAYF(bVR bH bSTOP cCYA " cycle progress " bSTG bH20 bHB bH bSTOP cCYA + " map coverage " bSTG bH bHT bH20 bH2 bH bVL "\n"); + + /* This gets funny because we want to print several variable-length variables + together, but then cram them into a fixed-width field - so we need to + put them in a temporary buffer first. */ + + sprintf(tmp, "%s%s (%0.02f%%)", DI(current_entry), + queue_cur->favored ? "" : "*", + ((double)current_entry * 100) / queued_paths); + + SAYF(bV bSTOP " now processing : " cRST "%-17s " bSTG bV bSTOP, tmp); + + sprintf(tmp, "%0.02f%% / %0.02f%%", ((double)queue_cur->bitmap_size) * + 100 / MAP_SIZE, t_byte_ratio); + + SAYF(" map density : %s%-21s " bSTG bV "\n", t_byte_ratio > 70 ? cLRD : + ((t_bytes < 200 && !dumb_mode) ? cPIN : cRST), tmp); + + sprintf(tmp, "%s (%0.02f%%)", DI(cur_skipped_paths), + ((double)cur_skipped_paths * 100) / queued_paths); + + SAYF(bV bSTOP " paths timed out : " cRST "%-17s " bSTG bV, tmp); + + sprintf(tmp, "%0.02f bits/tuple", + t_bytes ? (((double)t_bits) / t_bytes) : 0); + + SAYF(bSTOP " count coverage : " cRST "%-21s " bSTG bV "\n", tmp); + + SAYF(bVR bH bSTOP cCYA " stage progress " bSTG bH20 bX bH bSTOP cCYA + " findings in depth " bSTG bH20 bVL "\n"); + + sprintf(tmp, "%s (%0.02f%%)", DI(queued_favored), + ((double)queued_favored) * 100 / queued_paths); + + /* Yeah... it's still going on... halp? */ + + SAYF(bV bSTOP " now trying : " cRST "%-21s " bSTG bV bSTOP + " favored paths : " cRST "%-22s " bSTG bV "\n", stage_name, tmp); + + if (!stage_max) { + + sprintf(tmp, "%s/-", DI(stage_cur)); + + } else { + + sprintf(tmp, "%s/%s (%0.02f%%)", DI(stage_cur), DI(stage_max), + ((double)stage_cur) * 100 / stage_max); + + } + + SAYF(bV bSTOP " stage execs : " cRST "%-21s " bSTG bV bSTOP, tmp); + + sprintf(tmp, "%s (%0.02f%%)", DI(queued_with_cov), + ((double)queued_with_cov) * 100 / queued_paths); + + SAYF(" new edges on : " cRST "%-22s " bSTG bV "\n", tmp); + + sprintf(tmp, "%s (%s%s unique)", DI(total_crashes), DI(unique_crashes), + (unique_crashes >= KEEP_UNIQUE_CRASH) ? "+" : ""); + + if (crash_mode) { + + SAYF(bV bSTOP " total execs : " cRST "%-21s " bSTG bV bSTOP + " new crashes : %s%-22s " bSTG bV "\n", DI(total_execs), + unique_crashes ? cLRD : cRST, tmp); + + } else { + + SAYF(bV bSTOP " total execs : " cRST "%-21s " bSTG bV bSTOP + " total crashes : %s%-22s " bSTG bV "\n", DI(total_execs), + unique_crashes ? cLRD : cRST, tmp); + + } + + /* Show a warning about slow execution. */ + + if (avg_exec < 100) { + + sprintf(tmp, "%s/sec (%s)", DF(avg_exec), avg_exec < 20 ? + "zzzz..." : "slow!"); + + SAYF(bV bSTOP " exec speed : " cLRD "%-21s ", tmp); + + } else { + + sprintf(tmp, "%s/sec", DF(avg_exec)); + SAYF(bV bSTOP " exec speed : " cRST "%-21s ", tmp); + + } + + sprintf(tmp, "%s (%s%s unique)", DI(total_tmouts), DI(unique_tmouts), + (unique_hangs >= KEEP_UNIQUE_HANG) ? "+" : ""); + + SAYF (bSTG bV bSTOP " total tmouts : " cRST "%-22s " bSTG bV "\n", tmp); + + /* Aaaalmost there... hold on! */ + + SAYF(bVR bH cCYA bSTOP " fuzzing strategy yields " bSTG bH10 bH bHT bH10 + bH5 bHB bH bSTOP cCYA " path geometry " bSTG bH5 bH2 bH bVL "\n"); + + if (skip_deterministic) { + + strcpy(tmp, "n/a, n/a, n/a"); + + } else { + + sprintf(tmp, "%s/%s, %s/%s, %s/%s", + DI(stage_finds[STAGE_FLIP1]), DI(stage_cycles[STAGE_FLIP1]), + DI(stage_finds[STAGE_FLIP2]), DI(stage_cycles[STAGE_FLIP2]), + DI(stage_finds[STAGE_FLIP4]), DI(stage_cycles[STAGE_FLIP4])); + + } + + SAYF(bV bSTOP " bit flips : " cRST "%-37s " bSTG bV bSTOP " levels : " + cRST "%-10s " bSTG bV "\n", tmp, DI(max_depth)); + + if (!skip_deterministic) + sprintf(tmp, "%s/%s, %s/%s, %s/%s", + DI(stage_finds[STAGE_FLIP8]), DI(stage_cycles[STAGE_FLIP8]), + DI(stage_finds[STAGE_FLIP16]), DI(stage_cycles[STAGE_FLIP16]), + DI(stage_finds[STAGE_FLIP32]), DI(stage_cycles[STAGE_FLIP32])); + + SAYF(bV bSTOP " byte flips : " cRST "%-37s " bSTG bV bSTOP " pending : " + cRST "%-10s " bSTG bV "\n", tmp, DI(pending_not_fuzzed)); + + if (!skip_deterministic) + sprintf(tmp, "%s/%s, %s/%s, %s/%s", + DI(stage_finds[STAGE_ARITH8]), DI(stage_cycles[STAGE_ARITH8]), + DI(stage_finds[STAGE_ARITH16]), DI(stage_cycles[STAGE_ARITH16]), + DI(stage_finds[STAGE_ARITH32]), DI(stage_cycles[STAGE_ARITH32])); + + SAYF(bV bSTOP " arithmetics : " cRST "%-37s " bSTG bV bSTOP " pend fav : " + cRST "%-10s " bSTG bV "\n", tmp, DI(pending_favored)); + + if (!skip_deterministic) + sprintf(tmp, "%s/%s, %s/%s, %s/%s", + DI(stage_finds[STAGE_INTEREST8]), DI(stage_cycles[STAGE_INTEREST8]), + DI(stage_finds[STAGE_INTEREST16]), DI(stage_cycles[STAGE_INTEREST16]), + DI(stage_finds[STAGE_INTEREST32]), DI(stage_cycles[STAGE_INTEREST32])); + + SAYF(bV bSTOP " known ints : " cRST "%-37s " bSTG bV bSTOP " own finds : " + cRST "%-10s " bSTG bV "\n", tmp, DI(queued_discovered)); + + if (!skip_deterministic) + sprintf(tmp, "%s/%s, %s/%s, %s/%s", + DI(stage_finds[STAGE_EXTRAS_UO]), DI(stage_cycles[STAGE_EXTRAS_UO]), + DI(stage_finds[STAGE_EXTRAS_UI]), DI(stage_cycles[STAGE_EXTRAS_UI]), + DI(stage_finds[STAGE_EXTRAS_AO]), DI(stage_cycles[STAGE_EXTRAS_AO])); + + SAYF(bV bSTOP " dictionary : " cRST "%-37s " bSTG bV bSTOP + " imported : " cRST "%-10s " bSTG bV "\n", tmp, + sync_id ? DI(queued_imported) : (u8*)"n/a"); + + sprintf(tmp, "%s/%s, %s/%s", + DI(stage_finds[STAGE_HAVOC]), DI(stage_cycles[STAGE_HAVOC]), + DI(stage_finds[STAGE_SPLICE]), DI(stage_cycles[STAGE_SPLICE])); + + SAYF(bV bSTOP " havoc : " cRST "%-37s " bSTG bV bSTOP, tmp); + + if (t_bytes) sprintf(tmp, "%0.02f%%", stab_ratio); + else strcpy(tmp, "n/a"); + + SAYF(" stability : %s%-10s " bSTG bV "\n", (stab_ratio < 85 && var_byte_count > 40) + ? cLRD : ((queued_variable && (!persistent_mode || var_byte_count > 20)) + ? cMGN : cRST), tmp); + + if (!bytes_trim_out) { + + sprintf(tmp, "n/a, "); + + } else { + + sprintf(tmp, "%0.02f%%/%s, ", + ((double)(bytes_trim_in - bytes_trim_out)) * 100 / bytes_trim_in, + DI(trim_execs)); + + } + + if (!blocks_eff_total) { + + u8 tmp2[128]; + + sprintf(tmp2, "n/a"); + strcat(tmp, tmp2); + + } else { + + u8 tmp2[128]; + + sprintf(tmp2, "%0.02f%%", + ((double)(blocks_eff_total - blocks_eff_select)) * 100 / + blocks_eff_total); + + strcat(tmp, tmp2); + + } + + SAYF(bV bSTOP " trim : " cRST "%-37s " bSTG bVR bH20 bH2 bH2 bRB "\n" + bLB bH30 bH20 bH2 bH bRB bSTOP cRST RESET_G1, tmp); + + /* Provide some CPU utilization stats. */ + + if (cpu_core_count) { + + double cur_runnable = get_runnable_processes(); + u32 cur_utilization = cur_runnable * 100 / cpu_core_count; + + u8* cpu_color = cCYA; + + /* If we could still run one or more processes, use green. */ + + if (cpu_core_count > 1 && cur_runnable + 1 <= cpu_core_count) + cpu_color = cLGN; + + /* If we're clearly oversubscribed, use red. */ + + if (!no_cpu_meter_red && cur_utilization >= 150) cpu_color = cLRD; + +#ifdef HAVE_AFFINITY + + if (cpu_aff >= 0) { + + SAYF(SP10 cGRA "[cpu%03u:%s%3u%%" cGRA "]\r" cRST, + MIN(cpu_aff, 999), cpu_color, + MIN(cur_utilization, 999)); + + } else { + + SAYF(SP10 cGRA " [cpu:%s%3u%%" cGRA "]\r" cRST, + cpu_color, MIN(cur_utilization, 999)); + + } + +#else + + SAYF(SP10 cGRA " [cpu:%s%3u%%" cGRA "]\r" cRST, + cpu_color, MIN(cur_utilization, 999)); + +#endif /* ^HAVE_AFFINITY */ + + } else SAYF("\r"); + + /* Hallelujah! */ + + fflush(0); + +} + + +/* Display quick statistics at the end of processing the input directory, + plus a bunch of warnings. Some calibration stuff also ended up here, + along with several hardcoded constants. Maybe clean up eventually. */ + +static void show_init_stats(void) { + + struct queue_entry* q = queue; + u32 min_bits = 0, max_bits = 0; + u64 min_us = 0, max_us = 0; + u64 avg_us = 0; + u32 max_len = 0; + + if (total_cal_cycles) avg_us = total_cal_us / total_cal_cycles; + + while (q) { + + if (!min_us || q->exec_us < min_us) min_us = q->exec_us; + if (q->exec_us > max_us) max_us = q->exec_us; + + if (!min_bits || q->bitmap_size < min_bits) min_bits = q->bitmap_size; + if (q->bitmap_size > max_bits) max_bits = q->bitmap_size; + + if (q->len > max_len) max_len = q->len; + + q = q->next; + + } + + SAYF("\n"); + + if (avg_us > (qemu_mode ? 50000 : 10000)) + WARNF(cLRD "The target binary is pretty slow! See %s/perf_tips.txt.", + doc_path); + + /* Let's keep things moving with slow binaries. */ + + if (avg_us > 50000) havoc_div = 10; /* 0-19 execs/sec */ + else if (avg_us > 20000) havoc_div = 5; /* 20-49 execs/sec */ + else if (avg_us > 10000) havoc_div = 2; /* 50-100 execs/sec */ + + if (!resuming_fuzz) { + + if (max_len > 50 * 1024) + WARNF(cLRD "Some test cases are huge (%s) - see %s/perf_tips.txt!", + DMS(max_len), doc_path); + else if (max_len > 10 * 1024) + WARNF("Some test cases are big (%s) - see %s/perf_tips.txt.", + DMS(max_len), doc_path); + + if (useless_at_start && !in_bitmap) + WARNF(cLRD "Some test cases look useless. Consider using a smaller set."); + + if (queued_paths > 100) + WARNF(cLRD "You probably have far too many input files! Consider trimming down."); + else if (queued_paths > 20) + WARNF("You have lots of input files; try starting small."); + + } + + OKF("Here are some useful stats:\n\n" + + cGRA " Test case count : " cRST "%u favored, %u variable, %u total\n" + cGRA " Bitmap range : " cRST "%u to %u bits (average: %0.02f bits)\n" + cGRA " Exec timing : " cRST "%s to %s us (average: %s us)\n", + queued_favored, queued_variable, queued_paths, min_bits, max_bits, + ((double)total_bitmap_size) / (total_bitmap_entries ? total_bitmap_entries : 1), + DI(min_us), DI(max_us), DI(avg_us)); + + if (!timeout_given) { + + /* Figure out the appropriate timeout. The basic idea is: 5x average or + 1x max, rounded up to EXEC_TM_ROUND ms and capped at 1 second. + + If the program is slow, the multiplier is lowered to 2x or 3x, because + random scheduler jitter is less likely to have any impact, and because + our patience is wearing thin =) */ + + if (avg_us > 50000) exec_tmout = avg_us * 2 / 1000; + else if (avg_us > 10000) exec_tmout = avg_us * 3 / 1000; + else exec_tmout = avg_us * 5 / 1000; + + exec_tmout = MAX(exec_tmout, max_us / 1000); + exec_tmout = (exec_tmout + EXEC_TM_ROUND) / EXEC_TM_ROUND * EXEC_TM_ROUND; + + if (exec_tmout > EXEC_TIMEOUT) exec_tmout = EXEC_TIMEOUT; + + ACTF("No -t option specified, so I'll use exec timeout of %u ms.", + exec_tmout); + + timeout_given = 1; + + } else if (timeout_given == 3) { + + ACTF("Applying timeout settings from resumed session (%u ms).", exec_tmout); + + } + + /* In dumb mode, re-running every timing out test case with a generous time + limit is very expensive, so let's select a more conservative default. */ + + if (dumb_mode && !getenv("AFL_HANG_TMOUT")) + hang_tmout = MIN(EXEC_TIMEOUT, exec_tmout * 2 + 100); + + OKF("All set and ready to roll!"); + +} + + +/* Find first power of two greater or equal to val (assuming val under + 2^31). */ + +static u32 next_p2(u32 val) { + + u32 ret = 1; + while (val > ret) ret <<= 1; + return ret; + +} + + +/* Trim all new test cases to save cycles when doing deterministic checks. The + trimmer uses power-of-two increments somewhere between 1/16 and 1/1024 of + file size, to keep the stage short and sweet. */ + +static u8 trim_case(char** argv, struct queue_entry* q, u8* in_buf) { + + static u8 tmp[64]; + static u8 clean_trace[MAP_SIZE]; + + u8 needs_write = 0, fault = 0; + u32 trim_exec = 0; + u32 remove_len; + u32 len_p2; + + /* Although the trimmer will be less useful when variable behavior is + detected, it will still work to some extent, so we don't check for + this. */ + + if (q->len < 5) return 0; + + stage_name = tmp; + bytes_trim_in += q->len; + + /* Select initial chunk len, starting with large steps. */ + + len_p2 = next_p2(q->len); + + remove_len = MAX(len_p2 / TRIM_START_STEPS, TRIM_MIN_BYTES); + + /* Continue until the number of steps gets too high or the stepover + gets too small. */ + + while (remove_len >= MAX(len_p2 / TRIM_END_STEPS, TRIM_MIN_BYTES)) { + + u32 remove_pos = remove_len; + + sprintf(tmp, "trim %s/%s", DI(remove_len), DI(remove_len)); + + stage_cur = 0; + stage_max = q->len / remove_len; + + while (remove_pos < q->len) { + + u32 trim_avail = MIN(remove_len, q->len - remove_pos); + u32 cksum; + + write_with_gap(in_buf, q->len, remove_pos, trim_avail); + + fault = run_target(argv, exec_tmout); + trim_execs++; + + if (stop_soon || fault == FAULT_ERROR) goto abort_trimming; + + /* Note that we don't keep track of crashes or hangs here; maybe TODO? */ + + cksum = hash32(trace_bits, MAP_SIZE, HASH_CONST); + + /* If the deletion had no impact on the trace, make it permanent. This + isn't perfect for variable-path inputs, but we're just making a + best-effort pass, so it's not a big deal if we end up with false + negatives every now and then. */ + + if (cksum == q->exec_cksum) { + + u32 move_tail = q->len - remove_pos - trim_avail; + + q->len -= trim_avail; + len_p2 = next_p2(q->len); + + memmove(in_buf + remove_pos, in_buf + remove_pos + trim_avail, + move_tail); + + /* Let's save a clean trace, which will be needed by + update_bitmap_score once we're done with the trimming stuff. */ + + if (!needs_write) { + + needs_write = 1; + memcpy(clean_trace, trace_bits, MAP_SIZE); + + } + + } else remove_pos += remove_len; + + /* Since this can be slow, update the screen every now and then. */ + + if (!(trim_exec++ % stats_update_freq)) show_stats(); + stage_cur++; + + } + + remove_len >>= 1; + + } + + /* If we have made changes to in_buf, we also need to update the on-disk + version of the test case. */ + + if (needs_write) { + + s32 fd; + + unlink(q->fname); /* ignore errors */ + + fd = open(q->fname, O_WRONLY | O_CREAT | O_EXCL, 0600); + + if (fd < 0) PFATAL("Unable to create '%s'", q->fname); + + ck_write(fd, in_buf, q->len, q->fname); + close(fd); + + memcpy(trace_bits, clean_trace, MAP_SIZE); + update_bitmap_score(q); + + } + +abort_trimming: + + bytes_trim_out += q->len; + return fault; + +} + + +/* Write a modified test case, run program, process results. Handle + error conditions, returning 1 if it's time to bail out. This is + a helper function for fuzz_one(). */ + +EXP_ST u8 common_fuzz_stuff(char** argv, u8* out_buf, u32 len) { + + u8 fault; + + if (post_handler) { + + out_buf = post_handler(out_buf, &len); + if (!out_buf || !len) return 0; + + } + + write_to_testcase(out_buf, len); + + fault = run_target(argv, exec_tmout); + + if (stop_soon) return 1; + + if (fault == FAULT_TMOUT) { + + if (subseq_tmouts++ > TMOUT_LIMIT) { + cur_skipped_paths++; + return 1; + } + + } else subseq_tmouts = 0; + + /* Users can hit us with SIGUSR1 to request the current input + to be abandoned. */ + + if (skip_requested) { + + skip_requested = 0; + cur_skipped_paths++; + return 1; + + } + + /* This handles FAULT_ERROR for us: */ + + queued_discovered += save_if_interesting(argv, out_buf, len, fault); + + if (!(stage_cur % stats_update_freq) || stage_cur + 1 == stage_max) + show_stats(); + + return 0; + +} + + +/* Helper to choose random block len for block operations in fuzz_one(). + Doesn't return zero, provided that max_len is > 0. */ + +static u32 choose_block_len(u32 limit) { + + u32 min_value, max_value; + u32 rlim = MIN(queue_cycle, 3); + + if (!run_over10m) rlim = 1; + + switch (UR(rlim)) { + + case 0: min_value = 1; + max_value = HAVOC_BLK_SMALL; + break; + + case 1: min_value = HAVOC_BLK_SMALL; + max_value = HAVOC_BLK_MEDIUM; + break; + + default: + + if (UR(10)) { + + min_value = HAVOC_BLK_MEDIUM; + max_value = HAVOC_BLK_LARGE; + + } else { + + min_value = HAVOC_BLK_LARGE; + max_value = HAVOC_BLK_XL; + + } + + } + + if (min_value >= limit) min_value = 1; + + return min_value + UR(MIN(max_value, limit) - min_value + 1); + +} + + +/* Calculate case desirability score to adjust the length of havoc fuzzing. + A helper function for fuzz_one(). Maybe some of these constants should + go into config.h. */ + +static u32 calculate_score(struct queue_entry* q) { + + u32 avg_exec_us = total_cal_us / total_cal_cycles; + u32 avg_bitmap_size = total_bitmap_size / total_bitmap_entries; + u32 perf_score = 100; + + /* Adjust score based on execution speed of this path, compared to the + global average. Multiplier ranges from 0.1x to 3x. Fast inputs are + less expensive to fuzz, so we're giving them more air time. */ + + if (q->exec_us * 0.1 > avg_exec_us) perf_score = 10; + else if (q->exec_us * 0.25 > avg_exec_us) perf_score = 25; + else if (q->exec_us * 0.5 > avg_exec_us) perf_score = 50; + else if (q->exec_us * 0.75 > avg_exec_us) perf_score = 75; + else if (q->exec_us * 4 < avg_exec_us) perf_score = 300; + else if (q->exec_us * 3 < avg_exec_us) perf_score = 200; + else if (q->exec_us * 2 < avg_exec_us) perf_score = 150; + + /* Adjust score based on bitmap size. The working theory is that better + coverage translates to better targets. Multiplier from 0.25x to 3x. */ + + if (q->bitmap_size * 0.3 > avg_bitmap_size) perf_score *= 3; + else if (q->bitmap_size * 0.5 > avg_bitmap_size) perf_score *= 2; + else if (q->bitmap_size * 0.75 > avg_bitmap_size) perf_score *= 1.5; + else if (q->bitmap_size * 3 < avg_bitmap_size) perf_score *= 0.25; + else if (q->bitmap_size * 2 < avg_bitmap_size) perf_score *= 0.5; + else if (q->bitmap_size * 1.5 < avg_bitmap_size) perf_score *= 0.75; + + /* Adjust score based on handicap. Handicap is proportional to how late + in the game we learned about this path. Latecomers are allowed to run + for a bit longer until they catch up with the rest. */ + + if (q->handicap >= 4) { + + perf_score *= 4; + q->handicap -= 4; + + } else if (q->handicap) { + + perf_score *= 2; + q->handicap--; + + } + + /* Final adjustment based on input depth, under the assumption that fuzzing + deeper test cases is more likely to reveal stuff that can't be + discovered with traditional fuzzers. */ + + switch (q->depth) { + + case 0 ... 3: break; + case 4 ... 7: perf_score *= 2; break; + case 8 ... 13: perf_score *= 3; break; + case 14 ... 25: perf_score *= 4; break; + default: perf_score *= 5; + + } + + /* Make sure that we don't go over limit. */ + + if (perf_score > HAVOC_MAX_MULT * 100) perf_score = HAVOC_MAX_MULT * 100; + + return perf_score; + +} + + +/* Helper function to see if a particular change (xor_val = old ^ new) could + be a product of deterministic bit flips with the lengths and stepovers + attempted by afl-fuzz. This is used to avoid dupes in some of the + deterministic fuzzing operations that follow bit flips. We also + return 1 if xor_val is zero, which implies that the old and attempted new + values are identical and the exec would be a waste of time. */ + +static u8 could_be_bitflip(u32 xor_val) { + + u32 sh = 0; + + if (!xor_val) return 1; + + /* Shift left until first bit set. */ + + while (!(xor_val & 1)) { sh++; xor_val >>= 1; } + + /* 1-, 2-, and 4-bit patterns are OK anywhere. */ + + if (xor_val == 1 || xor_val == 3 || xor_val == 15) return 1; + + /* 8-, 16-, and 32-bit patterns are OK only if shift factor is + divisible by 8, since that's the stepover for these ops. */ + + if (sh & 7) return 0; + + if (xor_val == 0xff || xor_val == 0xffff || xor_val == 0xffffffff) + return 1; + + return 0; + +} + + +/* Helper function to see if a particular value is reachable through + arithmetic operations. Used for similar purposes. */ + +static u8 could_be_arith(u32 old_val, u32 new_val, u8 blen) { + + u32 i, ov = 0, nv = 0, diffs = 0; + + if (old_val == new_val) return 1; + + /* See if one-byte adjustments to any byte could produce this result. */ + + for (i = 0; i < blen; i++) { + + u8 a = old_val >> (8 * i), + b = new_val >> (8 * i); + + if (a != b) { diffs++; ov = a; nv = b; } + + } + + /* If only one byte differs and the values are within range, return 1. */ + + if (diffs == 1) { + + if ((u8)(ov - nv) <= ARITH_MAX || + (u8)(nv - ov) <= ARITH_MAX) return 1; + + } + + if (blen == 1) return 0; + + /* See if two-byte adjustments to any byte would produce this result. */ + + diffs = 0; + + for (i = 0; i < blen / 2; i++) { + + u16 a = old_val >> (16 * i), + b = new_val >> (16 * i); + + if (a != b) { diffs++; ov = a; nv = b; } + + } + + /* If only one word differs and the values are within range, return 1. */ + + if (diffs == 1) { + + if ((u16)(ov - nv) <= ARITH_MAX || + (u16)(nv - ov) <= ARITH_MAX) return 1; + + ov = SWAP16(ov); nv = SWAP16(nv); + + if ((u16)(ov - nv) <= ARITH_MAX || + (u16)(nv - ov) <= ARITH_MAX) return 1; + + } + + /* Finally, let's do the same thing for dwords. */ + + if (blen == 4) { + + if ((u32)(old_val - new_val) <= ARITH_MAX || + (u32)(new_val - old_val) <= ARITH_MAX) return 1; + + new_val = SWAP32(new_val); + old_val = SWAP32(old_val); + + if ((u32)(old_val - new_val) <= ARITH_MAX || + (u32)(new_val - old_val) <= ARITH_MAX) return 1; + + } + + return 0; + +} + + +/* Last but not least, a similar helper to see if insertion of an + interesting integer is redundant given the insertions done for + shorter blen. The last param (check_le) is set if the caller + already executed LE insertion for current blen and wants to see + if BE variant passed in new_val is unique. */ + +static u8 could_be_interest(u32 old_val, u32 new_val, u8 blen, u8 check_le) { + + u32 i, j; + + if (old_val == new_val) return 1; + + /* See if one-byte insertions from interesting_8 over old_val could + produce new_val. */ + + for (i = 0; i < blen; i++) { + + for (j = 0; j < sizeof(interesting_8); j++) { + + u32 tval = (old_val & ~(0xff << (i * 8))) | + (((u8)interesting_8[j]) << (i * 8)); + + if (new_val == tval) return 1; + + } + + } + + /* Bail out unless we're also asked to examine two-byte LE insertions + as a preparation for BE attempts. */ + + if (blen == 2 && !check_le) return 0; + + /* See if two-byte insertions over old_val could give us new_val. */ + + for (i = 0; i < blen - 1; i++) { + + for (j = 0; j < sizeof(interesting_16) / 2; j++) { + + u32 tval = (old_val & ~(0xffff << (i * 8))) | + (((u16)interesting_16[j]) << (i * 8)); + + if (new_val == tval) return 1; + + /* Continue here only if blen > 2. */ + + if (blen > 2) { + + tval = (old_val & ~(0xffff << (i * 8))) | + (SWAP16(interesting_16[j]) << (i * 8)); + + if (new_val == tval) return 1; + + } + + } + + } + + if (blen == 4 && check_le) { + + /* See if four-byte insertions could produce the same result + (LE only). */ + + for (j = 0; j < sizeof(interesting_32) / 4; j++) + if (new_val == (u32)interesting_32[j]) return 1; + + } + + return 0; + +} + + +/* Take the current entry from the queue, fuzz it for a while. This + function is a tad too long... returns 0 if fuzzed successfully, 1 if + skipped or bailed out. */ + +static u8 fuzz_one(char** argv) { + + s32 len, fd, temp_len, i, j; + u8 *in_buf, *out_buf, *orig_in, *ex_tmp, *eff_map = 0; + u64 havoc_queued, orig_hit_cnt, new_hit_cnt; + u32 splice_cycle = 0, perf_score = 100, orig_perf, prev_cksum, eff_cnt = 1; + + u8 ret_val = 1, doing_det = 0; + + u8 a_collect[MAX_AUTO_EXTRA]; + u32 a_len = 0; + +#ifdef IGNORE_FINDS + + /* In IGNORE_FINDS mode, skip any entries that weren't in the + initial data set. */ + + if (queue_cur->depth > 1) return 1; + +#else + + if (pending_favored) { + + /* If we have any favored, non-fuzzed new arrivals in the queue, + possibly skip to them at the expense of already-fuzzed or non-favored + cases. */ + + if ((queue_cur->was_fuzzed || !queue_cur->favored) && + UR(100) < SKIP_TO_NEW_PROB) return 1; + + } else if (!dumb_mode && !queue_cur->favored && queued_paths > 10) { + + /* Otherwise, still possibly skip non-favored cases, albeit less often. + The odds of skipping stuff are higher for already-fuzzed inputs and + lower for never-fuzzed entries. */ + + if (queue_cycle > 1 && !queue_cur->was_fuzzed) { + + if (UR(100) < SKIP_NFAV_NEW_PROB) return 1; + + } else { + + if (UR(100) < SKIP_NFAV_OLD_PROB) return 1; + + } + + } + +#endif /* ^IGNORE_FINDS */ + + if (not_on_tty) { + ACTF("Fuzzing test case #%u (%u total, %llu uniq crashes found)...", + current_entry, queued_paths, unique_crashes); + fflush(stdout); + } + + /* Map the test case into memory. */ + + fd = open(queue_cur->fname, O_RDONLY); + + if (fd < 0) PFATAL("Unable to open '%s'", queue_cur->fname); + + len = queue_cur->len; + + orig_in = in_buf = mmap(0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + + if (orig_in == MAP_FAILED) PFATAL("Unable to mmap '%s'", queue_cur->fname); + + close(fd); + + /* We could mmap() out_buf as MAP_PRIVATE, but we end up clobbering every + single byte anyway, so it wouldn't give us any performance or memory usage + benefits. */ + + out_buf = ck_alloc_nozero(len); + + subseq_tmouts = 0; + + cur_depth = queue_cur->depth; + + /******************************************* + * CALIBRATION (only if failed earlier on) * + *******************************************/ + + if (queue_cur->cal_failed) { + + u8 res = FAULT_TMOUT; + + if (queue_cur->cal_failed < CAL_CHANCES) { + + res = calibrate_case(argv, queue_cur, in_buf, queue_cycle - 1, 0); + + if (res == FAULT_ERROR) + FATAL("Unable to execute target application"); + + } + + if (stop_soon || res != crash_mode) { + cur_skipped_paths++; + goto abandon_entry; + } + + } + + /************ + * TRIMMING * + ************/ + + if (!dumb_mode && !queue_cur->trim_done) { + + u8 res = trim_case(argv, queue_cur, in_buf); + + if (res == FAULT_ERROR) + FATAL("Unable to execute target application"); + + if (stop_soon) { + cur_skipped_paths++; + goto abandon_entry; + } + + /* Don't retry trimming, even if it failed. */ + + queue_cur->trim_done = 1; + + if (len != queue_cur->len) len = queue_cur->len; + + } + + memcpy(out_buf, in_buf, len); + + /********************* + * PERFORMANCE SCORE * + *********************/ + + orig_perf = perf_score = calculate_score(queue_cur); + + /* Skip right away if -d is given, if we have done deterministic fuzzing on + this entry ourselves (was_fuzzed), or if it has gone through deterministic + testing in earlier, resumed runs (passed_det). */ + + if (skip_deterministic || queue_cur->was_fuzzed || queue_cur->passed_det) + goto havoc_stage; + + /* Skip deterministic fuzzing if exec path checksum puts this out of scope + for this master instance. */ + + if (master_max && (queue_cur->exec_cksum % master_max) != master_id - 1) + goto havoc_stage; + + doing_det = 1; + + /********************************************* + * SIMPLE BITFLIP (+dictionary construction) * + *********************************************/ + +#define FLIP_BIT(_ar, _b) do { \ + u8* _arf = (u8*)(_ar); \ + u32 _bf = (_b); \ + _arf[(_bf) >> 3] ^= (128 >> ((_bf) & 7)); \ + } while (0) + + /* Single walking bit. */ + + stage_short = "flip1"; + stage_max = len << 3; + stage_name = "bitflip 1/1"; + + stage_val_type = STAGE_VAL_NONE; + + orig_hit_cnt = queued_paths + unique_crashes; + + prev_cksum = queue_cur->exec_cksum; + + for (stage_cur = 0; stage_cur < stage_max; stage_cur++) { + + stage_cur_byte = stage_cur >> 3; + + FLIP_BIT(out_buf, stage_cur); + + if (common_fuzz_stuff(argv, out_buf, len)) goto abandon_entry; + + FLIP_BIT(out_buf, stage_cur); + + /* While flipping the least significant bit in every byte, pull of an extra + trick to detect possible syntax tokens. In essence, the idea is that if + you have a binary blob like this: + + xxxxxxxxIHDRxxxxxxxx + + ...and changing the leading and trailing bytes causes variable or no + changes in program flow, but touching any character in the "IHDR" string + always produces the same, distinctive path, it's highly likely that + "IHDR" is an atomically-checked magic value of special significance to + the fuzzed format. + + We do this here, rather than as a separate stage, because it's a nice + way to keep the operation approximately "free" (i.e., no extra execs). + + Empirically, performing the check when flipping the least significant bit + is advantageous, compared to doing it at the time of more disruptive + changes, where the program flow may be affected in more violent ways. + + The caveat is that we won't generate dictionaries in the -d mode or -S + mode - but that's probably a fair trade-off. + + This won't work particularly well with paths that exhibit variable + behavior, but fails gracefully, so we'll carry out the checks anyway. + + */ + + if (!dumb_mode && (stage_cur & 7) == 7) { + + u32 cksum = hash32(trace_bits, MAP_SIZE, HASH_CONST); + + if (stage_cur == stage_max - 1 && cksum == prev_cksum) { + + /* If at end of file and we are still collecting a string, grab the + final character and force output. */ + + if (a_len < MAX_AUTO_EXTRA) a_collect[a_len] = out_buf[stage_cur >> 3]; + a_len++; + + if (a_len >= MIN_AUTO_EXTRA && a_len <= MAX_AUTO_EXTRA) + maybe_add_auto(a_collect, a_len); + + } else if (cksum != prev_cksum) { + + /* Otherwise, if the checksum has changed, see if we have something + worthwhile queued up, and collect that if the answer is yes. */ + + if (a_len >= MIN_AUTO_EXTRA && a_len <= MAX_AUTO_EXTRA) + maybe_add_auto(a_collect, a_len); + + a_len = 0; + prev_cksum = cksum; + + } + + /* Continue collecting string, but only if the bit flip actually made + any difference - we don't want no-op tokens. */ + + if (cksum != queue_cur->exec_cksum) { + + if (a_len < MAX_AUTO_EXTRA) a_collect[a_len] = out_buf[stage_cur >> 3]; + a_len++; + + } + + } + + } + + new_hit_cnt = queued_paths + unique_crashes; + + stage_finds[STAGE_FLIP1] += new_hit_cnt - orig_hit_cnt; + stage_cycles[STAGE_FLIP1] += stage_max; + + /* Two walking bits. */ + + stage_name = "bitflip 2/1"; + stage_short = "flip2"; + stage_max = (len << 3) - 1; + + orig_hit_cnt = new_hit_cnt; + + for (stage_cur = 0; stage_cur < stage_max; stage_cur++) { + + stage_cur_byte = stage_cur >> 3; + + FLIP_BIT(out_buf, stage_cur); + FLIP_BIT(out_buf, stage_cur + 1); + + if (common_fuzz_stuff(argv, out_buf, len)) goto abandon_entry; + + FLIP_BIT(out_buf, stage_cur); + FLIP_BIT(out_buf, stage_cur + 1); + + } + + new_hit_cnt = queued_paths + unique_crashes; + + stage_finds[STAGE_FLIP2] += new_hit_cnt - orig_hit_cnt; + stage_cycles[STAGE_FLIP2] += stage_max; + + /* Four walking bits. */ + + stage_name = "bitflip 4/1"; + stage_short = "flip4"; + stage_max = (len << 3) - 3; + + orig_hit_cnt = new_hit_cnt; + + for (stage_cur = 0; stage_cur < stage_max; stage_cur++) { + + stage_cur_byte = stage_cur >> 3; + + FLIP_BIT(out_buf, stage_cur); + FLIP_BIT(out_buf, stage_cur + 1); + FLIP_BIT(out_buf, stage_cur + 2); + FLIP_BIT(out_buf, stage_cur + 3); + + if (common_fuzz_stuff(argv, out_buf, len)) goto abandon_entry; + + FLIP_BIT(out_buf, stage_cur); + FLIP_BIT(out_buf, stage_cur + 1); + FLIP_BIT(out_buf, stage_cur + 2); + FLIP_BIT(out_buf, stage_cur + 3); + + } + + new_hit_cnt = queued_paths + unique_crashes; + + stage_finds[STAGE_FLIP4] += new_hit_cnt - orig_hit_cnt; + stage_cycles[STAGE_FLIP4] += stage_max; + + /* Effector map setup. These macros calculate: + + EFF_APOS - position of a particular file offset in the map. + EFF_ALEN - length of a map with a particular number of bytes. + EFF_SPAN_ALEN - map span for a sequence of bytes. + + */ + +#define EFF_APOS(_p) ((_p) >> EFF_MAP_SCALE2) +#define EFF_REM(_x) ((_x) & ((1 << EFF_MAP_SCALE2) - 1)) +#define EFF_ALEN(_l) (EFF_APOS(_l) + !!EFF_REM(_l)) +#define EFF_SPAN_ALEN(_p, _l) (EFF_APOS((_p) + (_l) - 1) - EFF_APOS(_p) + 1) + + /* Initialize effector map for the next step (see comments below). Always + flag first and last byte as doing something. */ + + eff_map = ck_alloc(EFF_ALEN(len)); + eff_map[0] = 1; + + if (EFF_APOS(len - 1) != 0) { + eff_map[EFF_APOS(len - 1)] = 1; + eff_cnt++; + } + + /* Walking byte. */ + + stage_name = "bitflip 8/8"; + stage_short = "flip8"; + stage_max = len; + + orig_hit_cnt = new_hit_cnt; + + for (stage_cur = 0; stage_cur < stage_max; stage_cur++) { + + stage_cur_byte = stage_cur; + + out_buf[stage_cur] ^= 0xFF; + + if (common_fuzz_stuff(argv, out_buf, len)) goto abandon_entry; + + /* We also use this stage to pull off a simple trick: we identify + bytes that seem to have no effect on the current execution path + even when fully flipped - and we skip them during more expensive + deterministic stages, such as arithmetics or known ints. */ + + if (!eff_map[EFF_APOS(stage_cur)]) { + + u32 cksum; + + /* If in dumb mode or if the file is very short, just flag everything + without wasting time on checksums. */ + + if (!dumb_mode && len >= EFF_MIN_LEN) + cksum = hash32(trace_bits, MAP_SIZE, HASH_CONST); + else + cksum = ~queue_cur->exec_cksum; + + if (cksum != queue_cur->exec_cksum) { + eff_map[EFF_APOS(stage_cur)] = 1; + eff_cnt++; + } + + } + + out_buf[stage_cur] ^= 0xFF; + + } + + /* If the effector map is more than EFF_MAX_PERC dense, just flag the + whole thing as worth fuzzing, since we wouldn't be saving much time + anyway. */ + + if (eff_cnt != EFF_ALEN(len) && + eff_cnt * 100 / EFF_ALEN(len) > EFF_MAX_PERC) { + + memset(eff_map, 1, EFF_ALEN(len)); + + blocks_eff_select += EFF_ALEN(len); + + } else { + + blocks_eff_select += eff_cnt; + + } + + blocks_eff_total += EFF_ALEN(len); + + new_hit_cnt = queued_paths + unique_crashes; + + stage_finds[STAGE_FLIP8] += new_hit_cnt - orig_hit_cnt; + stage_cycles[STAGE_FLIP8] += stage_max; + + /* Two walking bytes. */ + + if (len < 2) goto skip_bitflip; + + stage_name = "bitflip 16/8"; + stage_short = "flip16"; + stage_cur = 0; + stage_max = len - 1; + + orig_hit_cnt = new_hit_cnt; + + for (i = 0; i < len - 1; i++) { + + /* Let's consult the effector map... */ + + if (!eff_map[EFF_APOS(i)] && !eff_map[EFF_APOS(i + 1)]) { + stage_max--; + continue; + } + + stage_cur_byte = i; + + *(u16*)(out_buf + i) ^= 0xFFFF; + + if (common_fuzz_stuff(argv, out_buf, len)) goto abandon_entry; + stage_cur++; + + *(u16*)(out_buf + i) ^= 0xFFFF; + + + } + + new_hit_cnt = queued_paths + unique_crashes; + + stage_finds[STAGE_FLIP16] += new_hit_cnt - orig_hit_cnt; + stage_cycles[STAGE_FLIP16] += stage_max; + + if (len < 4) goto skip_bitflip; + + /* Four walking bytes. */ + + stage_name = "bitflip 32/8"; + stage_short = "flip32"; + stage_cur = 0; + stage_max = len - 3; + + orig_hit_cnt = new_hit_cnt; + + for (i = 0; i < len - 3; i++) { + + /* Let's consult the effector map... */ + if (!eff_map[EFF_APOS(i)] && !eff_map[EFF_APOS(i + 1)] && + !eff_map[EFF_APOS(i + 2)] && !eff_map[EFF_APOS(i + 3)]) { + stage_max--; + continue; + } + + stage_cur_byte = i; + + *(u32*)(out_buf + i) ^= 0xFFFFFFFF; + + if (common_fuzz_stuff(argv, out_buf, len)) goto abandon_entry; + stage_cur++; + + *(u32*)(out_buf + i) ^= 0xFFFFFFFF; + + } + + new_hit_cnt = queued_paths + unique_crashes; + + stage_finds[STAGE_FLIP32] += new_hit_cnt - orig_hit_cnt; + stage_cycles[STAGE_FLIP32] += stage_max; + +skip_bitflip: + + if (no_arith) goto skip_arith; + + /********************** + * ARITHMETIC INC/DEC * + **********************/ + + /* 8-bit arithmetics. */ + + stage_name = "arith 8/8"; + stage_short = "arith8"; + stage_cur = 0; + stage_max = 2 * len * ARITH_MAX; + + stage_val_type = STAGE_VAL_LE; + + orig_hit_cnt = new_hit_cnt; + + for (i = 0; i < len; i++) { + + u8 orig = out_buf[i]; + + /* Let's consult the effector map... */ + + if (!eff_map[EFF_APOS(i)]) { + stage_max -= 2 * ARITH_MAX; + continue; + } + + stage_cur_byte = i; + + for (j = 1; j <= ARITH_MAX; j++) { + + u8 r = orig ^ (orig + j); + + /* Do arithmetic operations only if the result couldn't be a product + of a bitflip. */ + + if (!could_be_bitflip(r)) { + + stage_cur_val = j; + out_buf[i] = orig + j; + + if (common_fuzz_stuff(argv, out_buf, len)) goto abandon_entry; + stage_cur++; + + } else stage_max--; + + r = orig ^ (orig - j); + + if (!could_be_bitflip(r)) { + + stage_cur_val = -j; + out_buf[i] = orig - j; + + if (common_fuzz_stuff(argv, out_buf, len)) goto abandon_entry; + stage_cur++; + + } else stage_max--; + + out_buf[i] = orig; + + } + + } + + new_hit_cnt = queued_paths + unique_crashes; + + stage_finds[STAGE_ARITH8] += new_hit_cnt - orig_hit_cnt; + stage_cycles[STAGE_ARITH8] += stage_max; + + /* 16-bit arithmetics, both endians. */ + + if (len < 2) goto skip_arith; + + stage_name = "arith 16/8"; + stage_short = "arith16"; + stage_cur = 0; + stage_max = 4 * (len - 1) * ARITH_MAX; + + orig_hit_cnt = new_hit_cnt; + + for (i = 0; i < len - 1; i++) { + + u16 orig = *(u16*)(out_buf + i); + + /* Let's consult the effector map... */ + + if (!eff_map[EFF_APOS(i)] && !eff_map[EFF_APOS(i + 1)]) { + stage_max -= 4 * ARITH_MAX; + continue; + } + + stage_cur_byte = i; + + for (j = 1; j <= ARITH_MAX; j++) { + + u16 r1 = orig ^ (orig + j), + r2 = orig ^ (orig - j), + r3 = orig ^ SWAP16(SWAP16(orig) + j), + r4 = orig ^ SWAP16(SWAP16(orig) - j); + + /* Try little endian addition and subtraction first. Do it only + if the operation would affect more than one byte (hence the + & 0xff overflow checks) and if it couldn't be a product of + a bitflip. */ + + stage_val_type = STAGE_VAL_LE; + + if ((orig & 0xff) + j > 0xff && !could_be_bitflip(r1)) { + + stage_cur_val = j; + *(u16*)(out_buf + i) = orig + j; + + if (common_fuzz_stuff(argv, out_buf, len)) goto abandon_entry; + stage_cur++; + + } else stage_max--; + + if ((orig & 0xff) < j && !could_be_bitflip(r2)) { + + stage_cur_val = -j; + *(u16*)(out_buf + i) = orig - j; + + if (common_fuzz_stuff(argv, out_buf, len)) goto abandon_entry; + stage_cur++; + + } else stage_max--; + + /* Big endian comes next. Same deal. */ + + stage_val_type = STAGE_VAL_BE; + + + if ((orig >> 8) + j > 0xff && !could_be_bitflip(r3)) { + + stage_cur_val = j; + *(u16*)(out_buf + i) = SWAP16(SWAP16(orig) + j); + + if (common_fuzz_stuff(argv, out_buf, len)) goto abandon_entry; + stage_cur++; + + } else stage_max--; + + if ((orig >> 8) < j && !could_be_bitflip(r4)) { + + stage_cur_val = -j; + *(u16*)(out_buf + i) = SWAP16(SWAP16(orig) - j); + + if (common_fuzz_stuff(argv, out_buf, len)) goto abandon_entry; + stage_cur++; + + } else stage_max--; + + *(u16*)(out_buf + i) = orig; + + } + + } + + new_hit_cnt = queued_paths + unique_crashes; + + stage_finds[STAGE_ARITH16] += new_hit_cnt - orig_hit_cnt; + stage_cycles[STAGE_ARITH16] += stage_max; + + /* 32-bit arithmetics, both endians. */ + + if (len < 4) goto skip_arith; + + stage_name = "arith 32/8"; + stage_short = "arith32"; + stage_cur = 0; + stage_max = 4 * (len - 3) * ARITH_MAX; + + orig_hit_cnt = new_hit_cnt; + + for (i = 0; i < len - 3; i++) { + + u32 orig = *(u32*)(out_buf + i); + + /* Let's consult the effector map... */ + + if (!eff_map[EFF_APOS(i)] && !eff_map[EFF_APOS(i + 1)] && + !eff_map[EFF_APOS(i + 2)] && !eff_map[EFF_APOS(i + 3)]) { + stage_max -= 4 * ARITH_MAX; + continue; + } + + stage_cur_byte = i; + + for (j = 1; j <= ARITH_MAX; j++) { + + u32 r1 = orig ^ (orig + j), + r2 = orig ^ (orig - j), + r3 = orig ^ SWAP32(SWAP32(orig) + j), + r4 = orig ^ SWAP32(SWAP32(orig) - j); + + /* Little endian first. Same deal as with 16-bit: we only want to + try if the operation would have effect on more than two bytes. */ + + stage_val_type = STAGE_VAL_LE; + + if ((orig & 0xffff) + j > 0xffff && !could_be_bitflip(r1)) { + + stage_cur_val = j; + *(u32*)(out_buf + i) = orig + j; + + if (common_fuzz_stuff(argv, out_buf, len)) goto abandon_entry; + stage_cur++; + + } else stage_max--; + + if ((orig & 0xffff) < j && !could_be_bitflip(r2)) { + + stage_cur_val = -j; + *(u32*)(out_buf + i) = orig - j; + + if (common_fuzz_stuff(argv, out_buf, len)) goto abandon_entry; + stage_cur++; + + } else stage_max--; + + /* Big endian next. */ + + stage_val_type = STAGE_VAL_BE; + + if ((SWAP32(orig) & 0xffff) + j > 0xffff && !could_be_bitflip(r3)) { + + stage_cur_val = j; + *(u32*)(out_buf + i) = SWAP32(SWAP32(orig) + j); + + if (common_fuzz_stuff(argv, out_buf, len)) goto abandon_entry; + stage_cur++; + + } else stage_max--; + + if ((SWAP32(orig) & 0xffff) < j && !could_be_bitflip(r4)) { + + stage_cur_val = -j; + *(u32*)(out_buf + i) = SWAP32(SWAP32(orig) - j); + + if (common_fuzz_stuff(argv, out_buf, len)) goto abandon_entry; + stage_cur++; + + } else stage_max--; + + *(u32*)(out_buf + i) = orig; + + } + + } + + new_hit_cnt = queued_paths + unique_crashes; + + stage_finds[STAGE_ARITH32] += new_hit_cnt - orig_hit_cnt; + stage_cycles[STAGE_ARITH32] += stage_max; + +skip_arith: + + /********************** + * INTERESTING VALUES * + **********************/ + + stage_name = "interest 8/8"; + stage_short = "int8"; + stage_cur = 0; + stage_max = len * sizeof(interesting_8); + + stage_val_type = STAGE_VAL_LE; + + orig_hit_cnt = new_hit_cnt; + + /* Setting 8-bit integers. */ + + for (i = 0; i < len; i++) { + + u8 orig = out_buf[i]; + + /* Let's consult the effector map... */ + + if (!eff_map[EFF_APOS(i)]) { + stage_max -= sizeof(interesting_8); + continue; + } + + stage_cur_byte = i; + + for (j = 0; j < sizeof(interesting_8); j++) { + + /* Skip if the value could be a product of bitflips or arithmetics. */ + + if (could_be_bitflip(orig ^ (u8)interesting_8[j]) || + could_be_arith(orig, (u8)interesting_8[j], 1)) { + stage_max--; + continue; + } + + stage_cur_val = interesting_8[j]; + out_buf[i] = interesting_8[j]; + + if (common_fuzz_stuff(argv, out_buf, len)) goto abandon_entry; + + out_buf[i] = orig; + stage_cur++; + + } + + } + + new_hit_cnt = queued_paths + unique_crashes; + + stage_finds[STAGE_INTEREST8] += new_hit_cnt - orig_hit_cnt; + stage_cycles[STAGE_INTEREST8] += stage_max; + + /* Setting 16-bit integers, both endians. */ + + if (no_arith || len < 2) goto skip_interest; + + stage_name = "interest 16/8"; + stage_short = "int16"; + stage_cur = 0; + stage_max = 2 * (len - 1) * (sizeof(interesting_16) >> 1); + + orig_hit_cnt = new_hit_cnt; + + for (i = 0; i < len - 1; i++) { + + u16 orig = *(u16*)(out_buf + i); + + /* Let's consult the effector map... */ + + if (!eff_map[EFF_APOS(i)] && !eff_map[EFF_APOS(i + 1)]) { + stage_max -= sizeof(interesting_16); + continue; + } + + stage_cur_byte = i; + + for (j = 0; j < sizeof(interesting_16) / 2; j++) { + + stage_cur_val = interesting_16[j]; + + /* Skip if this could be a product of a bitflip, arithmetics, + or single-byte interesting value insertion. */ + + if (!could_be_bitflip(orig ^ (u16)interesting_16[j]) && + !could_be_arith(orig, (u16)interesting_16[j], 2) && + !could_be_interest(orig, (u16)interesting_16[j], 2, 0)) { + + stage_val_type = STAGE_VAL_LE; + + *(u16*)(out_buf + i) = interesting_16[j]; + + if (common_fuzz_stuff(argv, out_buf, len)) goto abandon_entry; + stage_cur++; + + } else stage_max--; + + if ((u16)interesting_16[j] != SWAP16(interesting_16[j]) && + !could_be_bitflip(orig ^ SWAP16(interesting_16[j])) && + !could_be_arith(orig, SWAP16(interesting_16[j]), 2) && + !could_be_interest(orig, SWAP16(interesting_16[j]), 2, 1)) { + + stage_val_type = STAGE_VAL_BE; + + *(u16*)(out_buf + i) = SWAP16(interesting_16[j]); + if (common_fuzz_stuff(argv, out_buf, len)) goto abandon_entry; + stage_cur++; + + } else stage_max--; + + } + + *(u16*)(out_buf + i) = orig; + + } + + new_hit_cnt = queued_paths + unique_crashes; + + stage_finds[STAGE_INTEREST16] += new_hit_cnt - orig_hit_cnt; + stage_cycles[STAGE_INTEREST16] += stage_max; + + if (len < 4) goto skip_interest; + + /* Setting 32-bit integers, both endians. */ + + stage_name = "interest 32/8"; + stage_short = "int32"; + stage_cur = 0; + stage_max = 2 * (len - 3) * (sizeof(interesting_32) >> 2); + + orig_hit_cnt = new_hit_cnt; + + for (i = 0; i < len - 3; i++) { + + u32 orig = *(u32*)(out_buf + i); + + /* Let's consult the effector map... */ + + if (!eff_map[EFF_APOS(i)] && !eff_map[EFF_APOS(i + 1)] && + !eff_map[EFF_APOS(i + 2)] && !eff_map[EFF_APOS(i + 3)]) { + stage_max -= sizeof(interesting_32) >> 1; + continue; + } + + stage_cur_byte = i; + + for (j = 0; j < sizeof(interesting_32) / 4; j++) { + + stage_cur_val = interesting_32[j]; + + /* Skip if this could be a product of a bitflip, arithmetics, + or word interesting value insertion. */ + + if (!could_be_bitflip(orig ^ (u32)interesting_32[j]) && + !could_be_arith(orig, interesting_32[j], 4) && + !could_be_interest(orig, interesting_32[j], 4, 0)) { + + stage_val_type = STAGE_VAL_LE; + + *(u32*)(out_buf + i) = interesting_32[j]; + + if (common_fuzz_stuff(argv, out_buf, len)) goto abandon_entry; + stage_cur++; + + } else stage_max--; + + if ((u32)interesting_32[j] != SWAP32(interesting_32[j]) && + !could_be_bitflip(orig ^ SWAP32(interesting_32[j])) && + !could_be_arith(orig, SWAP32(interesting_32[j]), 4) && + !could_be_interest(orig, SWAP32(interesting_32[j]), 4, 1)) { + + stage_val_type = STAGE_VAL_BE; + + *(u32*)(out_buf + i) = SWAP32(interesting_32[j]); + if (common_fuzz_stuff(argv, out_buf, len)) goto abandon_entry; + stage_cur++; + + } else stage_max--; + + } + + *(u32*)(out_buf + i) = orig; + + } + + new_hit_cnt = queued_paths + unique_crashes; + + stage_finds[STAGE_INTEREST32] += new_hit_cnt - orig_hit_cnt; + stage_cycles[STAGE_INTEREST32] += stage_max; + +skip_interest: + + /******************** + * DICTIONARY STUFF * + ********************/ + + if (!extras_cnt) goto skip_user_extras; + + /* Overwrite with user-supplied extras. */ + + stage_name = "user extras (over)"; + stage_short = "ext_UO"; + stage_cur = 0; + stage_max = extras_cnt * len; + + stage_val_type = STAGE_VAL_NONE; + + orig_hit_cnt = new_hit_cnt; + + for (i = 0; i < len; i++) { + + u32 last_len = 0; + + stage_cur_byte = i; + + /* Extras are sorted by size, from smallest to largest. This means + that we don't have to worry about restoring the buffer in + between writes at a particular offset determined by the outer + loop. */ + + for (j = 0; j < extras_cnt; j++) { + + /* Skip extras probabilistically if extras_cnt > MAX_DET_EXTRAS. Also + skip them if there's no room to insert the payload, if the token + is redundant, or if its entire span has no bytes set in the effector + map. */ + + if ((extras_cnt > MAX_DET_EXTRAS && UR(extras_cnt) >= MAX_DET_EXTRAS) || + extras[j].len > len - i || + !memcmp(extras[j].data, out_buf + i, extras[j].len) || + !memchr(eff_map + EFF_APOS(i), 1, EFF_SPAN_ALEN(i, extras[j].len))) { + + stage_max--; + continue; + + } + + last_len = extras[j].len; + memcpy(out_buf + i, extras[j].data, last_len); + + if (common_fuzz_stuff(argv, out_buf, len)) goto abandon_entry; + + stage_cur++; + + } + + /* Restore all the clobbered memory. */ + memcpy(out_buf + i, in_buf + i, last_len); + + } + + new_hit_cnt = queued_paths + unique_crashes; + + stage_finds[STAGE_EXTRAS_UO] += new_hit_cnt - orig_hit_cnt; + stage_cycles[STAGE_EXTRAS_UO] += stage_max; + + /* Insertion of user-supplied extras. */ + + stage_name = "user extras (insert)"; + stage_short = "ext_UI"; + stage_cur = 0; + stage_max = extras_cnt * len; + + orig_hit_cnt = new_hit_cnt; + + ex_tmp = ck_alloc(len + MAX_DICT_FILE); + + for (i = 0; i <= len; i++) { + + stage_cur_byte = i; + + for (j = 0; j < extras_cnt; j++) { + + if (len + extras[j].len > MAX_FILE) { + stage_max--; + continue; + } + + /* Insert token */ + memcpy(ex_tmp + i, extras[j].data, extras[j].len); + + /* Copy tail */ + memcpy(ex_tmp + i + extras[j].len, out_buf + i, len - i); + + if (common_fuzz_stuff(argv, ex_tmp, len + extras[j].len)) { + ck_free(ex_tmp); + goto abandon_entry; + } + + stage_cur++; + + } + + /* Copy head */ + ex_tmp[i] = out_buf[i]; + + } + + ck_free(ex_tmp); + + new_hit_cnt = queued_paths + unique_crashes; + + stage_finds[STAGE_EXTRAS_UI] += new_hit_cnt - orig_hit_cnt; + stage_cycles[STAGE_EXTRAS_UI] += stage_max; + +skip_user_extras: + + if (!a_extras_cnt) goto skip_extras; + + stage_name = "auto extras (over)"; + stage_short = "ext_AO"; + stage_cur = 0; + stage_max = MIN(a_extras_cnt, USE_AUTO_EXTRAS) * len; + + stage_val_type = STAGE_VAL_NONE; + + orig_hit_cnt = new_hit_cnt; + + for (i = 0; i < len; i++) { + + u32 last_len = 0; + + stage_cur_byte = i; + + for (j = 0; j < MIN(a_extras_cnt, USE_AUTO_EXTRAS); j++) { + + /* See the comment in the earlier code; extras are sorted by size. */ + + if (a_extras[j].len > len - i || + !memcmp(a_extras[j].data, out_buf + i, a_extras[j].len) || + !memchr(eff_map + EFF_APOS(i), 1, EFF_SPAN_ALEN(i, a_extras[j].len))) { + + stage_max--; + continue; + + } + + last_len = a_extras[j].len; + memcpy(out_buf + i, a_extras[j].data, last_len); + + if (common_fuzz_stuff(argv, out_buf, len)) goto abandon_entry; + + stage_cur++; + + } + + /* Restore all the clobbered memory. */ + memcpy(out_buf + i, in_buf + i, last_len); + + } + + new_hit_cnt = queued_paths + unique_crashes; + + stage_finds[STAGE_EXTRAS_AO] += new_hit_cnt - orig_hit_cnt; + stage_cycles[STAGE_EXTRAS_AO] += stage_max; + +skip_extras: + + /* If we made this to here without jumping to havoc_stage or abandon_entry, + we're properly done with deterministic steps and can mark it as such + in the .state/ directory. */ + + if (!queue_cur->passed_det) mark_as_det_done(queue_cur); + + /**************** + * RANDOM HAVOC * + ****************/ + +havoc_stage: + + stage_cur_byte = -1; + + /* The havoc stage mutation code is also invoked when splicing files; if the + splice_cycle variable is set, generate different descriptions and such. */ + + if (!splice_cycle) { + + stage_name = "havoc"; + stage_short = "havoc"; + stage_max = (doing_det ? HAVOC_CYCLES_INIT : HAVOC_CYCLES) * + perf_score / havoc_div / 100; + + } else { + + static u8 tmp[32]; + + perf_score = orig_perf; + + sprintf(tmp, "splice %u", splice_cycle); + stage_name = tmp; + stage_short = "splice"; + stage_max = SPLICE_HAVOC * perf_score / havoc_div / 100; + + } + + if (stage_max < HAVOC_MIN) stage_max = HAVOC_MIN; + + temp_len = len; + + orig_hit_cnt = queued_paths + unique_crashes; + + havoc_queued = queued_paths; + + /* We essentially just do several thousand runs (depending on perf_score) + where we take the input file and make random stacked tweaks. */ + + for (stage_cur = 0; stage_cur < stage_max; stage_cur++) { + + u32 use_stacking = 1 << (1 + UR(HAVOC_STACK_POW2)); + + stage_cur_val = use_stacking; + + for (i = 0; i < use_stacking; i++) { + + switch (UR(15 + ((extras_cnt + a_extras_cnt) ? 2 : 0))) { + + case 0: + + /* Flip a single bit somewhere. Spooky! */ + + FLIP_BIT(out_buf, UR(temp_len << 3)); + break; + + case 1: + + /* Set byte to interesting value. */ + + out_buf[UR(temp_len)] = interesting_8[UR(sizeof(interesting_8))]; + break; + + case 2: + + /* Set word to interesting value, randomly choosing endian. */ + + if (temp_len < 2) break; + + if (UR(2)) { + + *(u16*)(out_buf + UR(temp_len - 1)) = + interesting_16[UR(sizeof(interesting_16) >> 1)]; + + } else { + + *(u16*)(out_buf + UR(temp_len - 1)) = SWAP16( + interesting_16[UR(sizeof(interesting_16) >> 1)]); + + } + + break; + + case 3: + + /* Set dword to interesting value, randomly choosing endian. */ + + if (temp_len < 4) break; + + if (UR(2)) { + + *(u32*)(out_buf + UR(temp_len - 3)) = + interesting_32[UR(sizeof(interesting_32) >> 2)]; + + } else { + + *(u32*)(out_buf + UR(temp_len - 3)) = SWAP32( + interesting_32[UR(sizeof(interesting_32) >> 2)]); + + } + + break; + + case 4: + + /* Randomly subtract from byte. */ + + out_buf[UR(temp_len)] -= 1 + UR(ARITH_MAX); + break; + + case 5: + + /* Randomly add to byte. */ + + out_buf[UR(temp_len)] += 1 + UR(ARITH_MAX); + break; + + case 6: + + /* Randomly subtract from word, random endian. */ + + if (temp_len < 2) break; + + if (UR(2)) { + + u32 pos = UR(temp_len - 1); + + *(u16*)(out_buf + pos) -= 1 + UR(ARITH_MAX); + + } else { + + u32 pos = UR(temp_len - 1); + u16 num = 1 + UR(ARITH_MAX); + + *(u16*)(out_buf + pos) = + SWAP16(SWAP16(*(u16*)(out_buf + pos)) - num); + + } + + break; + + case 7: + + /* Randomly add to word, random endian. */ + + if (temp_len < 2) break; + + if (UR(2)) { + + u32 pos = UR(temp_len - 1); + + *(u16*)(out_buf + pos) += 1 + UR(ARITH_MAX); + + } else { + + u32 pos = UR(temp_len - 1); + u16 num = 1 + UR(ARITH_MAX); + + *(u16*)(out_buf + pos) = + SWAP16(SWAP16(*(u16*)(out_buf + pos)) + num); + + } + + break; + + case 8: + + /* Randomly subtract from dword, random endian. */ + + if (temp_len < 4) break; + + if (UR(2)) { + + u32 pos = UR(temp_len - 3); + + *(u32*)(out_buf + pos) -= 1 + UR(ARITH_MAX); + + } else { + + u32 pos = UR(temp_len - 3); + u32 num = 1 + UR(ARITH_MAX); + + *(u32*)(out_buf + pos) = + SWAP32(SWAP32(*(u32*)(out_buf + pos)) - num); + + } + + break; + + case 9: + + /* Randomly add to dword, random endian. */ + + if (temp_len < 4) break; + + if (UR(2)) { + + u32 pos = UR(temp_len - 3); + + *(u32*)(out_buf + pos) += 1 + UR(ARITH_MAX); + + } else { + + u32 pos = UR(temp_len - 3); + u32 num = 1 + UR(ARITH_MAX); + + *(u32*)(out_buf + pos) = + SWAP32(SWAP32(*(u32*)(out_buf + pos)) + num); + + } + + break; + + case 10: + + /* Just set a random byte to a random value. Because, + why not. We use XOR with 1-255 to eliminate the + possibility of a no-op. */ + + out_buf[UR(temp_len)] ^= 1 + UR(255); + break; + + case 11 ... 12: { + + /* Delete bytes. We're making this a bit more likely + than insertion (the next option) in hopes of keeping + files reasonably small. */ + + u32 del_from, del_len; + + if (temp_len < 2) break; + + /* Don't delete too much. */ + + del_len = choose_block_len(temp_len - 1); + + del_from = UR(temp_len - del_len + 1); + + memmove(out_buf + del_from, out_buf + del_from + del_len, + temp_len - del_from - del_len); + + temp_len -= del_len; + + break; + + } + + case 13: + + if (temp_len + HAVOC_BLK_XL < MAX_FILE) { + + /* Clone bytes (75%) or insert a block of constant bytes (25%). */ + + u8 actually_clone = UR(4); + u32 clone_from, clone_to, clone_len; + u8* new_buf; + + if (actually_clone) { + + clone_len = choose_block_len(temp_len); + clone_from = UR(temp_len - clone_len + 1); + + } else { + + clone_len = choose_block_len(HAVOC_BLK_XL); + clone_from = 0; + + } + + clone_to = UR(temp_len); + + new_buf = ck_alloc_nozero(temp_len + clone_len); + + /* Head */ + + memcpy(new_buf, out_buf, clone_to); + + /* Inserted part */ + + if (actually_clone) + memcpy(new_buf + clone_to, out_buf + clone_from, clone_len); + else + memset(new_buf + clone_to, + UR(2) ? UR(256) : out_buf[UR(temp_len)], clone_len); + + /* Tail */ + memcpy(new_buf + clone_to + clone_len, out_buf + clone_to, + temp_len - clone_to); + + ck_free(out_buf); + out_buf = new_buf; + temp_len += clone_len; + + } + + break; + + case 14: { + + /* Overwrite bytes with a randomly selected chunk (75%) or fixed + bytes (25%). */ + + u32 copy_from, copy_to, copy_len; + + if (temp_len < 2) break; + + copy_len = choose_block_len(temp_len - 1); + + copy_from = UR(temp_len - copy_len + 1); + copy_to = UR(temp_len - copy_len + 1); + + if (UR(4)) { + + if (copy_from != copy_to) + memmove(out_buf + copy_to, out_buf + copy_from, copy_len); + + } else memset(out_buf + copy_to, + UR(2) ? UR(256) : out_buf[UR(temp_len)], copy_len); + + break; + + } + + /* Values 15 and 16 can be selected only if there are any extras + present in the dictionaries. */ + + case 15: { + + /* Overwrite bytes with an extra. */ + + if (!extras_cnt || (a_extras_cnt && UR(2))) { + + /* No user-specified extras or odds in our favor. Let's use an + auto-detected one. */ + + u32 use_extra = UR(a_extras_cnt); + u32 extra_len = a_extras[use_extra].len; + u32 insert_at; + + if (extra_len > temp_len) break; + + insert_at = UR(temp_len - extra_len + 1); + memcpy(out_buf + insert_at, a_extras[use_extra].data, extra_len); + + } else { + + /* No auto extras or odds in our favor. Use the dictionary. */ + + u32 use_extra = UR(extras_cnt); + u32 extra_len = extras[use_extra].len; + u32 insert_at; + + if (extra_len > temp_len) break; + + insert_at = UR(temp_len - extra_len + 1); + memcpy(out_buf + insert_at, extras[use_extra].data, extra_len); + + } + + break; + + } + + case 16: { + + u32 use_extra, extra_len, insert_at = UR(temp_len + 1); + u8* new_buf; + + /* Insert an extra. Do the same dice-rolling stuff as for the + previous case. */ + + if (!extras_cnt || (a_extras_cnt && UR(2))) { + + use_extra = UR(a_extras_cnt); + extra_len = a_extras[use_extra].len; + + if (temp_len + extra_len >= MAX_FILE) break; + + new_buf = ck_alloc_nozero(temp_len + extra_len); + + /* Head */ + memcpy(new_buf, out_buf, insert_at); + + /* Inserted part */ + memcpy(new_buf + insert_at, a_extras[use_extra].data, extra_len); + + } else { + + use_extra = UR(extras_cnt); + extra_len = extras[use_extra].len; + + if (temp_len + extra_len >= MAX_FILE) break; + + new_buf = ck_alloc_nozero(temp_len + extra_len); + + /* Head */ + memcpy(new_buf, out_buf, insert_at); + + /* Inserted part */ + memcpy(new_buf + insert_at, extras[use_extra].data, extra_len); + + } + + /* Tail */ + memcpy(new_buf + insert_at + extra_len, out_buf + insert_at, + temp_len - insert_at); + + ck_free(out_buf); + out_buf = new_buf; + temp_len += extra_len; + + break; + + } + + } + + } + + if (common_fuzz_stuff(argv, out_buf, temp_len)) + goto abandon_entry; + + /* out_buf might have been mangled a bit, so let's restore it to its + original size and shape. */ + + if (temp_len < len) out_buf = ck_realloc(out_buf, len); + temp_len = len; + memcpy(out_buf, in_buf, len); + + /* If we're finding new stuff, let's run for a bit longer, limits + permitting. */ + + if (queued_paths != havoc_queued) { + + if (perf_score <= HAVOC_MAX_MULT * 100) { + stage_max *= 2; + perf_score *= 2; + } + + havoc_queued = queued_paths; + + } + + } + + new_hit_cnt = queued_paths + unique_crashes; + + if (!splice_cycle) { + stage_finds[STAGE_HAVOC] += new_hit_cnt - orig_hit_cnt; + stage_cycles[STAGE_HAVOC] += stage_max; + } else { + stage_finds[STAGE_SPLICE] += new_hit_cnt - orig_hit_cnt; + stage_cycles[STAGE_SPLICE] += stage_max; + } + +#ifndef IGNORE_FINDS + + /************ + * SPLICING * + ************/ + + /* This is a last-resort strategy triggered by a full round with no findings. + It takes the current input file, randomly selects another input, and + splices them together at some offset, then relies on the havoc + code to mutate that blob. */ + +retry_splicing: + + if (use_splicing && splice_cycle++ < SPLICE_CYCLES && + queued_paths > 1 && queue_cur->len > 1) { + + struct queue_entry* target; + u32 tid, split_at; + u8* new_buf; + s32 f_diff, l_diff; + + /* First of all, if we've modified in_buf for havoc, let's clean that + up... */ + + if (in_buf != orig_in) { + ck_free(in_buf); + in_buf = orig_in; + len = queue_cur->len; + } + + /* Pick a random queue entry and seek to it. Don't splice with yourself. */ + + do { tid = UR(queued_paths); } while (tid == current_entry); + + splicing_with = tid; + target = queue; + + while (tid >= 100) { target = target->next_100; tid -= 100; } + while (tid--) target = target->next; + + /* Make sure that the target has a reasonable length. */ + + while (target && (target->len < 2 || target == queue_cur)) { + target = target->next; + splicing_with++; + } + + if (!target) goto retry_splicing; + + /* Read the testcase into a new buffer. */ + + fd = open(target->fname, O_RDONLY); + + if (fd < 0) PFATAL("Unable to open '%s'", target->fname); + + new_buf = ck_alloc_nozero(target->len); + + ck_read(fd, new_buf, target->len, target->fname); + + close(fd); + + /* Find a suitable splicing location, somewhere between the first and + the last differing byte. Bail out if the difference is just a single + byte or so. */ + + locate_diffs(in_buf, new_buf, MIN(len, target->len), &f_diff, &l_diff); + + if (f_diff < 0 || l_diff < 2 || f_diff == l_diff) { + ck_free(new_buf); + goto retry_splicing; + } + + /* Split somewhere between the first and last differing byte. */ + + split_at = f_diff + UR(l_diff - f_diff); + + /* Do the thing. */ + + len = target->len; + memcpy(new_buf, in_buf, split_at); + in_buf = new_buf; + + ck_free(out_buf); + out_buf = ck_alloc_nozero(len); + memcpy(out_buf, in_buf, len); + + goto havoc_stage; + + } + +#endif /* !IGNORE_FINDS */ + + ret_val = 0; + +abandon_entry: + + splicing_with = -1; + + /* Update pending_not_fuzzed count if we made it through the calibration + cycle and have not seen this entry before. */ + + if (!stop_soon && !queue_cur->cal_failed && !queue_cur->was_fuzzed) { + queue_cur->was_fuzzed = 1; + pending_not_fuzzed--; + if (queue_cur->favored) pending_favored--; + } + + munmap(orig_in, queue_cur->len); + + if (in_buf != orig_in) ck_free(in_buf); + ck_free(out_buf); + ck_free(eff_map); + + return ret_val; + +#undef FLIP_BIT + +} + + +/* Grab interesting test cases from other fuzzers. */ + +static void sync_fuzzers(char** argv) { + + DIR* sd; + struct dirent* sd_ent; + u32 sync_cnt = 0; + + sd = opendir(sync_dir); + if (!sd) PFATAL("Unable to open '%s'", sync_dir); + + stage_max = stage_cur = 0; + cur_depth = 0; + + /* Look at the entries created for every other fuzzer in the sync directory. */ + + while ((sd_ent = readdir(sd))) { + + static u8 stage_tmp[128]; + + DIR* qd; + struct dirent* qd_ent; + u8 *qd_path, *qd_synced_path; + u32 min_accept = 0, next_min_accept; + + s32 id_fd; + + /* Skip dot files and our own output directory. */ + + if (sd_ent->d_name[0] == '.' || !strcmp(sync_id, sd_ent->d_name)) continue; + + /* Skip anything that doesn't have a queue/ subdirectory. */ + + qd_path = alloc_printf("%s/%s/queue", sync_dir, sd_ent->d_name); + + if (!(qd = opendir(qd_path))) { + ck_free(qd_path); + continue; + } + + /* Retrieve the ID of the last seen test case. */ + + qd_synced_path = alloc_printf("%s/.synced/%s", out_dir, sd_ent->d_name); + + id_fd = open(qd_synced_path, O_RDWR | O_CREAT, 0600); + + if (id_fd < 0) PFATAL("Unable to create '%s'", qd_synced_path); + + if (read(id_fd, &min_accept, sizeof(u32)) > 0) + lseek(id_fd, 0, SEEK_SET); + + next_min_accept = min_accept; + + /* Show stats */ + + sprintf(stage_tmp, "sync %u", ++sync_cnt); + stage_name = stage_tmp; + stage_cur = 0; + stage_max = 0; + + /* For every file queued by this fuzzer, parse ID and see if we have looked at + it before; exec a test case if not. */ + + while ((qd_ent = readdir(qd))) { + + u8* path; + s32 fd; + struct stat st; + + if (qd_ent->d_name[0] == '.' || + sscanf(qd_ent->d_name, CASE_PREFIX "%06u", &syncing_case) != 1 || + syncing_case < min_accept) continue; + + /* OK, sounds like a new one. Let's give it a try. */ + + if (syncing_case >= next_min_accept) + next_min_accept = syncing_case + 1; + + path = alloc_printf("%s/%s", qd_path, qd_ent->d_name); + + /* Allow this to fail in case the other fuzzer is resuming or so... */ + + fd = open(path, O_RDONLY); + + if (fd < 0) { + ck_free(path); + continue; + } + + if (fstat(fd, &st)) PFATAL("fstat() failed"); + + /* Ignore zero-sized or oversized files. */ + + if (st.st_size && st.st_size <= MAX_FILE) { + + u8 fault; + u8* mem = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + + if (mem == MAP_FAILED) PFATAL("Unable to mmap '%s'", path); + + /* See what happens. We rely on save_if_interesting() to catch major + errors and save the test case. */ + + write_to_testcase(mem, st.st_size); + + fault = run_target(argv, exec_tmout); + + if (stop_soon) return; + + syncing_party = sd_ent->d_name; + queued_imported += save_if_interesting(argv, mem, st.st_size, fault); + syncing_party = 0; + + munmap(mem, st.st_size); + + if (!(stage_cur++ % stats_update_freq)) show_stats(); + + } + + ck_free(path); + close(fd); + + } + + ck_write(id_fd, &next_min_accept, sizeof(u32), qd_synced_path); + + close(id_fd); + closedir(qd); + ck_free(qd_path); + ck_free(qd_synced_path); + + } + + closedir(sd); + +} + + +/* Handle stop signal (Ctrl-C, etc). */ + +static void handle_stop_sig(int sig) { + + stop_soon = 1; + + if (child_pid > 0) kill(child_pid, SIGKILL); + if (forksrv_pid > 0) kill(forksrv_pid, SIGKILL); + +} + + +/* Handle skip request (SIGUSR1). */ + +static void handle_skipreq(int sig) { + + skip_requested = 1; + +} + +/* Handle timeout (SIGALRM). */ + +static void handle_timeout(int sig) { + + if (child_pid > 0) { + + child_timed_out = 1; + kill(child_pid, SIGKILL); + + } else if (child_pid == -1 && forksrv_pid > 0) { + + child_timed_out = 1; + kill(forksrv_pid, SIGKILL); + + } + +} + + +/* Do a PATH search and find target binary to see that it exists and + isn't a shell script - a common and painful mistake. We also check for + a valid ELF header and for evidence of AFL instrumentation. */ + +EXP_ST void check_binary(u8* fname) { + + u8* env_path = 0; + struct stat st; + + s32 fd; + u8* f_data; + u32 f_len = 0; + + ACTF("Validating target binary..."); + + if (strchr(fname, '/') || !(env_path = getenv("PATH"))) { + + target_path = ck_strdup(fname); + if (stat(target_path, &st) || !S_ISREG(st.st_mode) || + !(st.st_mode & 0111) || (f_len = st.st_size) < 4) + FATAL("Program '%s' not found or not executable", fname); + + } else { + + while (env_path) { + + u8 *cur_elem, *delim = strchr(env_path, ':'); + + if (delim) { + + cur_elem = ck_alloc(delim - env_path + 1); + memcpy(cur_elem, env_path, delim - env_path); + delim++; + + } else cur_elem = ck_strdup(env_path); + + env_path = delim; + + if (cur_elem[0]) + target_path = alloc_printf("%s/%s", cur_elem, fname); + else + target_path = ck_strdup(fname); + + ck_free(cur_elem); + + if (!stat(target_path, &st) && S_ISREG(st.st_mode) && + (st.st_mode & 0111) && (f_len = st.st_size) >= 4) break; + + ck_free(target_path); + target_path = 0; + + } + + if (!target_path) FATAL("Program '%s' not found or not executable", fname); + + } + + if (getenv("AFL_SKIP_BIN_CHECK")) return; + + /* Check for blatant user errors. */ + + if ((!strncmp(target_path, "/tmp/", 5) && !strchr(target_path + 5, '/')) || + (!strncmp(target_path, "/var/tmp/", 9) && !strchr(target_path + 9, '/'))) + FATAL("Please don't keep binaries in /tmp or /var/tmp"); + + fd = open(target_path, O_RDONLY); + + if (fd < 0) PFATAL("Unable to open '%s'", target_path); + + f_data = mmap(0, f_len, PROT_READ, MAP_PRIVATE, fd, 0); + + if (f_data == MAP_FAILED) PFATAL("Unable to mmap file '%s'", target_path); + + close(fd); + + if (f_data[0] == '#' && f_data[1] == '!') { + + SAYF("\n" cLRD "[-] " cRST + "Oops, the target binary looks like a shell script. Some build systems will\n" + " sometimes generate shell stubs for dynamically linked programs; try static\n" + " library mode (./configure --disable-shared) if that's the case.\n\n" + + " Another possible cause is that you are actually trying to use a shell\n" + " wrapper around the fuzzed component. Invoking shell can slow down the\n" + " fuzzing process by a factor of 20x or more; it's best to write the wrapper\n" + " in a compiled language instead.\n"); + + FATAL("Program '%s' is a shell script", target_path); + + } + +#ifndef __APPLE__ + + if (f_data[0] != 0x7f || memcmp(f_data + 1, "ELF", 3)) + FATAL("Program '%s' is not an ELF binary", target_path); + +#else + + if (f_data[0] != 0xCF || f_data[1] != 0xFA || f_data[2] != 0xED) + FATAL("Program '%s' is not a 64-bit Mach-O binary", target_path); + +#endif /* ^!__APPLE__ */ + + if (!qemu_mode && !dumb_mode && + !memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) { + + SAYF("\n" cLRD "[-] " cRST + "Looks like the target binary is not instrumented! The fuzzer depends on\n" + " compile-time instrumentation to isolate interesting test cases while\n" + " mutating the input data. For more information, and for tips on how to\n" + " instrument binaries, please see %s/README.\n\n" + + " When source code is not available, you may be able to leverage QEMU\n" + " mode support. Consult the README for tips on how to enable this.\n" + + " (It is also possible to use afl-fuzz as a traditional, \"dumb\" fuzzer.\n" + " For that, you can use the -n option - but expect much worse results.)\n", + doc_path); + + FATAL("No instrumentation detected"); + + } + + if (qemu_mode && + memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) { + + SAYF("\n" cLRD "[-] " cRST + "This program appears to be instrumented with afl-gcc, but is being run in\n" + " QEMU mode (-Q). This is probably not what you want - this setup will be\n" + " slow and offer no practical benefits.\n"); + + FATAL("Instrumentation found in -Q mode"); + + } + + if (memmem(f_data, f_len, "libasan.so", 10) || + memmem(f_data, f_len, "__msan_init", 11)) uses_asan = 1; + + /* Detect persistent & deferred init signatures in the binary. */ + + if (memmem(f_data, f_len, PERSIST_SIG, strlen(PERSIST_SIG) + 1)) { + + OKF(cPIN "Persistent mode binary detected."); + setenv(PERSIST_ENV_VAR, "1", 1); + persistent_mode = 1; + + } else if (getenv("AFL_PERSISTENT")) { + + WARNF("AFL_PERSISTENT is no longer supported and may misbehave!"); + + } + + if (memmem(f_data, f_len, DEFER_SIG, strlen(DEFER_SIG) + 1)) { + + OKF(cPIN "Deferred forkserver binary detected."); + setenv(DEFER_ENV_VAR, "1", 1); + deferred_mode = 1; + + } else if (getenv("AFL_DEFER_FORKSRV")) { + + WARNF("AFL_DEFER_FORKSRV is no longer supported and may misbehave!"); + + } + + if (munmap(f_data, f_len)) PFATAL("unmap() failed"); + +} + + +/* Trim and possibly create a banner for the run. */ + +static void fix_up_banner(u8* name) { + + if (!use_banner) { + + if (sync_id) { + + use_banner = sync_id; + + } else { + + u8* trim = strrchr(name, '/'); + if (!trim) use_banner = name; else use_banner = trim + 1; + + } + + } + + if (strlen(use_banner) > 40) { + + u8* tmp = ck_alloc(44); + sprintf(tmp, "%.40s...", use_banner); + use_banner = tmp; + + } + +} + + +/* Check if we're on TTY. */ + +static void check_if_tty(void) { + + struct winsize ws; + + if (getenv("AFL_NO_UI")) { + OKF("Disabling the UI because AFL_NO_UI is set."); + not_on_tty = 1; + return; + } + + if (ioctl(1, TIOCGWINSZ, &ws)) { + + if (errno == ENOTTY) { + OKF("Looks like we're not running on a tty, so I'll be a bit less verbose."); + not_on_tty = 1; + } + + return; + } + +} + + +/* Check terminal dimensions after resize. */ + +static void check_term_size(void) { + + struct winsize ws; + + term_too_small = 0; + + if (ioctl(1, TIOCGWINSZ, &ws)) return; + + if (ws.ws_row < 25 || ws.ws_col < 80) term_too_small = 1; + +} + + + +/* Display usage hints. */ + +static void usage(u8* argv0) { + + SAYF("\n%s [ options ] -- /path/to/fuzzed_app [ ... ]\n\n" + + "Required parameters:\n\n" + + " -i dir - input directory with test cases\n" + " -o dir - output directory for fuzzer findings\n\n" + + "Execution control settings:\n\n" + + " -f file - location read by the fuzzed program (stdin)\n" + " -t msec - timeout for each run (auto-scaled, 50-%u ms)\n" + " -m megs - memory limit for child process (%u MB)\n" + " -Q - use binary-only instrumentation (QEMU mode)\n\n" + + "Fuzzing behavior settings:\n\n" + + " -d - quick & dirty mode (skips deterministic steps)\n" + " -n - fuzz without instrumentation (dumb mode)\n" + " -x dir - optional fuzzer dictionary (see README)\n\n" + + "Other stuff:\n\n" + + " -T text - text banner to show on the screen\n" + " -M / -S id - distributed mode (see parallel_fuzzing.txt)\n" + " -C - crash exploration mode (the peruvian rabbit thing)\n\n" + + "For additional tips, please consult %s/README.\n\n", + + argv0, EXEC_TIMEOUT, MEM_LIMIT, doc_path); + + exit(1); + +} + + +/* Prepare output directories and fds. */ + +EXP_ST void setup_dirs_fds(void) { + + u8* tmp; + s32 fd; + + ACTF("Setting up output directories..."); + + if (sync_id && mkdir(sync_dir, 0700) && errno != EEXIST) + PFATAL("Unable to create '%s'", sync_dir); + + if (mkdir(out_dir, 0700)) { + + if (errno != EEXIST) PFATAL("Unable to create '%s'", out_dir); + + maybe_delete_out_dir(); + + } else { + + if (in_place_resume) + FATAL("Resume attempted but old output directory not found"); + + out_dir_fd = open(out_dir, O_RDONLY); + +#ifndef __sun + + if (out_dir_fd < 0 || flock(out_dir_fd, LOCK_EX | LOCK_NB)) + PFATAL("Unable to flock() output directory."); + +#endif /* !__sun */ + + } + + /* Queue directory for any starting & discovered paths. */ + + tmp = alloc_printf("%s/queue", out_dir); + if (mkdir(tmp, 0700)) PFATAL("Unable to create '%s'", tmp); + ck_free(tmp); + + /* Top-level directory for queue metadata used for session + resume and related tasks. */ + + tmp = alloc_printf("%s/queue/.state/", out_dir); + if (mkdir(tmp, 0700)) PFATAL("Unable to create '%s'", tmp); + ck_free(tmp); + + /* Directory for flagging queue entries that went through + deterministic fuzzing in the past. */ + + tmp = alloc_printf("%s/queue/.state/deterministic_done/", out_dir); + if (mkdir(tmp, 0700)) PFATAL("Unable to create '%s'", tmp); + ck_free(tmp); + + /* Directory with the auto-selected dictionary entries. */ + + tmp = alloc_printf("%s/queue/.state/auto_extras/", out_dir); + if (mkdir(tmp, 0700)) PFATAL("Unable to create '%s'", tmp); + ck_free(tmp); + + /* The set of paths currently deemed redundant. */ + + tmp = alloc_printf("%s/queue/.state/redundant_edges/", out_dir); + if (mkdir(tmp, 0700)) PFATAL("Unable to create '%s'", tmp); + ck_free(tmp); + + /* The set of paths showing variable behavior. */ + + tmp = alloc_printf("%s/queue/.state/variable_behavior/", out_dir); + if (mkdir(tmp, 0700)) PFATAL("Unable to create '%s'", tmp); + ck_free(tmp); + + /* Sync directory for keeping track of cooperating fuzzers. */ + + if (sync_id) { + + tmp = alloc_printf("%s/.synced/", out_dir); + + if (mkdir(tmp, 0700) && (!in_place_resume || errno != EEXIST)) + PFATAL("Unable to create '%s'", tmp); + + ck_free(tmp); + + } + + /* All recorded crashes. */ + + tmp = alloc_printf("%s/crashes", out_dir); + if (mkdir(tmp, 0700)) PFATAL("Unable to create '%s'", tmp); + ck_free(tmp); + + /* All recorded hangs. */ + + tmp = alloc_printf("%s/hangs", out_dir); + if (mkdir(tmp, 0700)) PFATAL("Unable to create '%s'", tmp); + ck_free(tmp); + + /* Generally useful file descriptors. */ + + dev_null_fd = open("/dev/null", O_RDWR); + if (dev_null_fd < 0) PFATAL("Unable to open /dev/null"); + + dev_urandom_fd = open("/dev/urandom", O_RDONLY); + if (dev_urandom_fd < 0) PFATAL("Unable to open /dev/urandom"); + + /* Gnuplot output file. */ + + tmp = alloc_printf("%s/plot_data", out_dir); + fd = open(tmp, O_WRONLY | O_CREAT | O_EXCL, 0600); + if (fd < 0) PFATAL("Unable to create '%s'", tmp); + ck_free(tmp); + + plot_file = fdopen(fd, "w"); + if (!plot_file) PFATAL("fdopen() failed"); + + fprintf(plot_file, "# unix_time, cycles_done, cur_path, paths_total, " + "pending_total, pending_favs, map_size, unique_crashes, " + "unique_hangs, max_depth, execs_per_sec\n"); + /* ignore errors */ + +} + + +/* Setup the output file for fuzzed data, if not using -f. */ + +EXP_ST void setup_stdio_file(void) { + + u8* fn = alloc_printf("%s/.cur_input", out_dir); + + unlink(fn); /* Ignore errors */ + + out_fd = open(fn, O_RDWR | O_CREAT | O_EXCL, 0600); + + if (out_fd < 0) PFATAL("Unable to create '%s'", fn); + + ck_free(fn); + +} + + +/* Make sure that core dumps don't go to a program. */ + +static void check_crash_handling(void) { + +#ifdef __APPLE__ + + /* Yuck! There appears to be no simple C API to query for the state of + loaded daemons on MacOS X, and I'm a bit hesitant to do something + more sophisticated, such as disabling crash reporting via Mach ports, + until I get a box to test the code. So, for now, we check for crash + reporting the awful way. */ + + if (system("launchctl list 2>/dev/null | grep -q '\\.ReportCrash$'")) return; + + SAYF("\n" cLRD "[-] " cRST + "Whoops, your system is configured to forward crash notifications to an\n" + " external crash reporting utility. This will cause issues due to the\n" + " extended delay between the fuzzed binary malfunctioning and this fact\n" + " being relayed to the fuzzer via the standard waitpid() API.\n\n" + " To avoid having crashes misinterpreted as timeouts, please run the\n" + " following commands:\n\n" + + " SL=/System/Library; PL=com.apple.ReportCrash\n" + " launchctl unload -w ${SL}/LaunchAgents/${PL}.plist\n" + " sudo launchctl unload -w ${SL}/LaunchDaemons/${PL}.Root.plist\n"); + + if (!getenv("AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES")) + FATAL("Crash reporter detected"); + +#else + + /* This is Linux specific, but I don't think there's anything equivalent on + *BSD, so we can just let it slide for now. */ + + s32 fd = open("/proc/sys/kernel/core_pattern", O_RDONLY); + u8 fchar; + + if (fd < 0) return; + + ACTF("Checking core_pattern..."); + + if (read(fd, &fchar, 1) == 1 && fchar == '|') { + + SAYF("\n" cLRD "[-] " cRST + "Hmm, your system is configured to send core dump notifications to an\n" + " external utility. This will cause issues: there will be an extended delay\n" + " between stumbling upon a crash and having this information relayed to the\n" + " fuzzer via the standard waitpid() API.\n\n" + + " To avoid having crashes misinterpreted as timeouts, please log in as root\n" + " and temporarily modify /proc/sys/kernel/core_pattern, like so:\n\n" + + " echo core >/proc/sys/kernel/core_pattern\n"); + + if (!getenv("AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES")) + FATAL("Pipe at the beginning of 'core_pattern'"); + + } + + close(fd); + +#endif /* ^__APPLE__ */ + +} + + +/* Check CPU governor. */ + +static void check_cpu_governor(void) { + + FILE* f; + u8 tmp[128]; + u64 min = 0, max = 0; + + if (getenv("AFL_SKIP_CPUFREQ")) return; + + f = fopen("/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor", "r"); + if (!f) return; + + ACTF("Checking CPU scaling governor..."); + + if (!fgets(tmp, 128, f)) PFATAL("fgets() failed"); + + fclose(f); + + if (!strncmp(tmp, "perf", 4)) return; + + f = fopen("/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq", "r"); + + if (f) { + if (fscanf(f, "%llu", &min) != 1) min = 0; + fclose(f); + } + + f = fopen("/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq", "r"); + + if (f) { + if (fscanf(f, "%llu", &max) != 1) max = 0; + fclose(f); + } + + if (min == max) return; + + SAYF("\n" cLRD "[-] " cRST + "Whoops, your system uses on-demand CPU frequency scaling, adjusted\n" + " between %llu and %llu MHz. Unfortunately, the scaling algorithm in the\n" + " kernel is imperfect and can miss the short-lived processes spawned by\n" + " afl-fuzz. To keep things moving, run these commands as root:\n\n" + + " cd /sys/devices/system/cpu\n" + " echo performance | tee cpu*/cpufreq/scaling_governor\n\n" + + " You can later go back to the original state by replacing 'performance' with\n" + " 'ondemand'. If you don't want to change the settings, set AFL_SKIP_CPUFREQ\n" + " to make afl-fuzz skip this check - but expect some performance drop.\n", + min / 1024, max / 1024); + + FATAL("Suboptimal CPU scaling governor"); + +} + + +/* Count the number of logical CPU cores. */ + +static void get_core_count(void) { + + u32 cur_runnable = 0; + +#if defined(__APPLE__) || defined(__FreeBSD__) || defined (__OpenBSD__) + + size_t s = sizeof(cpu_core_count); + + /* On *BSD systems, we can just use a sysctl to get the number of CPUs. */ + +#ifdef __APPLE__ + + if (sysctlbyname("hw.logicalcpu", &cpu_core_count, &s, NULL, 0) < 0) + return; + +#else + + int s_name[2] = { CTL_HW, HW_NCPU }; + + if (sysctl(s_name, 2, &cpu_core_count, &s, NULL, 0) < 0) return; + +#endif /* ^__APPLE__ */ + +#else + +#ifdef HAVE_AFFINITY + + cpu_core_count = sysconf(_SC_NPROCESSORS_ONLN); + +#else + + FILE* f = fopen("/proc/stat", "r"); + u8 tmp[1024]; + + if (!f) return; + + while (fgets(tmp, sizeof(tmp), f)) + if (!strncmp(tmp, "cpu", 3) && isdigit(tmp[3])) cpu_core_count++; + + fclose(f); + +#endif /* ^HAVE_AFFINITY */ + +#endif /* ^(__APPLE__ || __FreeBSD__ || __OpenBSD__) */ + + if (cpu_core_count > 0) { + + cur_runnable = (u32)get_runnable_processes(); + +#if defined(__APPLE__) || defined(__FreeBSD__) || defined (__OpenBSD__) + + /* Add ourselves, since the 1-minute average doesn't include that yet. */ + + cur_runnable++; + +#endif /* __APPLE__ || __FreeBSD__ || __OpenBSD__ */ + + OKF("You have %u CPU core%s and %u runnable tasks (utilization: %0.0f%%).", + cpu_core_count, cpu_core_count > 1 ? "s" : "", + cur_runnable, cur_runnable * 100.0 / cpu_core_count); + + if (cpu_core_count > 1) { + + if (cur_runnable > cpu_core_count * 1.5) { + + WARNF("System under apparent load, performance may be spotty."); + + } else if (cur_runnable + 1 <= cpu_core_count) { + + OKF("Try parallel jobs - see %s/parallel_fuzzing.txt.", doc_path); + + } + + } + + } else { + + cpu_core_count = 0; + WARNF("Unable to figure out the number of CPU cores."); + + } + +} + + +/* Validate and fix up out_dir and sync_dir when using -S. */ + +static void fix_up_sync(void) { + + u8* x = sync_id; + + if (dumb_mode) + FATAL("-S / -M and -n are mutually exclusive"); + + if (skip_deterministic) { + + if (force_deterministic) + FATAL("use -S instead of -M -d"); + else + FATAL("-S already implies -d"); + + } + + while (*x) { + + if (!isalnum(*x) && *x != '_' && *x != '-') + FATAL("Non-alphanumeric fuzzer ID specified via -S or -M"); + + x++; + + } + + if (strlen(sync_id) > 32) FATAL("Fuzzer ID too long"); + + x = alloc_printf("%s/%s", out_dir, sync_id); + + sync_dir = out_dir; + out_dir = x; + + if (!force_deterministic) { + skip_deterministic = 1; + use_splicing = 1; + } + +} + + +/* Handle screen resize (SIGWINCH). */ + +static void handle_resize(int sig) { + clear_screen = 1; +} + + +/* Check ASAN options. */ + +static void check_asan_opts(void) { + u8* x = getenv("ASAN_OPTIONS"); + + if (x) { + + if (!strstr(x, "abort_on_error=1")) + FATAL("Custom ASAN_OPTIONS set without abort_on_error=1 - please fix!"); + + if (!strstr(x, "symbolize=0")) + FATAL("Custom ASAN_OPTIONS set without symbolize=0 - please fix!"); + + } + + x = getenv("MSAN_OPTIONS"); + + if (x) { + + if (!strstr(x, "exit_code=" STRINGIFY(MSAN_ERROR))) + FATAL("Custom MSAN_OPTIONS set without exit_code=" + STRINGIFY(MSAN_ERROR) " - please fix!"); + + if (!strstr(x, "symbolize=0")) + FATAL("Custom MSAN_OPTIONS set without symbolize=0 - please fix!"); + + } + +} + + +/* Detect @@ in args. */ + +EXP_ST void detect_file_args(char** argv) { + + u32 i = 0; + u8* cwd = getcwd(NULL, 0); + + if (!cwd) PFATAL("getcwd() failed"); + + while (argv[i]) { + + u8* aa_loc = strstr(argv[i], "@@"); + + if (aa_loc) { + + u8 *aa_subst, *n_arg; + + /* If we don't have a file name chosen yet, use a safe default. */ + + if (!out_file) + out_file = alloc_printf("%s/.cur_input", out_dir); + + /* Be sure that we're always using fully-qualified paths. */ + + if (out_file[0] == '/') aa_subst = out_file; + else aa_subst = alloc_printf("%s/%s", cwd, out_file); + + /* Construct a replacement argv value. */ + + *aa_loc = 0; + n_arg = alloc_printf("%s%s%s", argv[i], aa_subst, aa_loc + 2); + argv[i] = n_arg; + *aa_loc = '@'; + + if (out_file[0] != '/') ck_free(aa_subst); + + } + + i++; + + } + + free(cwd); /* not tracked */ + +} + + +/* Set up signal handlers. More complicated that needs to be, because libc on + Solaris doesn't resume interrupted reads(), sets SA_RESETHAND when you call + siginterrupt(), and does other stupid things. */ + +EXP_ST void setup_signal_handlers(void) { + + struct sigaction sa; + + sa.sa_handler = NULL; + sa.sa_flags = SA_RESTART; + sa.sa_sigaction = NULL; + + sigemptyset(&sa.sa_mask); + + /* Various ways of saying "stop". */ + + sa.sa_handler = handle_stop_sig; + sigaction(SIGHUP, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + + /* Exec timeout notifications. */ + + sa.sa_handler = handle_timeout; + sigaction(SIGALRM, &sa, NULL); + + /* Window resize */ + + sa.sa_handler = handle_resize; + sigaction(SIGWINCH, &sa, NULL); + + /* SIGUSR1: skip entry */ + + sa.sa_handler = handle_skipreq; + sigaction(SIGUSR1, &sa, NULL); + + /* Things we don't care about. */ + + sa.sa_handler = SIG_IGN; + sigaction(SIGTSTP, &sa, NULL); + sigaction(SIGPIPE, &sa, NULL); + +} + + +/* Rewrite argv for QEMU. */ + +static char** get_qemu_argv(u8* own_loc, char** argv, int argc) { + + char** new_argv = ck_alloc(sizeof(char*) * (argc + 4)); + u8 *tmp, *cp, *rsl, *own_copy; + + /* Workaround for a QEMU stability glitch. */ + + setenv("QEMU_LOG", "nochain", 1); + + memcpy(new_argv + 3, argv + 1, sizeof(char*) * argc); + + new_argv[2] = target_path; + new_argv[1] = "--"; + + /* Now we need to actually find the QEMU binary to put in argv[0]. */ + + tmp = getenv("AFL_PATH"); + + if (tmp) { + + cp = alloc_printf("%s/afl-qemu-trace", tmp); + + if (access(cp, X_OK)) + FATAL("Unable to find '%s'", tmp); + + target_path = new_argv[0] = cp; + return new_argv; + + } + + own_copy = ck_strdup(own_loc); + rsl = strrchr(own_copy, '/'); + + if (rsl) { + + *rsl = 0; + + cp = alloc_printf("%s/afl-qemu-trace", own_copy); + ck_free(own_copy); + + if (!access(cp, X_OK)) { + + target_path = new_argv[0] = cp; + return new_argv; + + } + + } else ck_free(own_copy); + + if (!access(BIN_PATH "/afl-qemu-trace", X_OK)) { + + target_path = new_argv[0] = ck_strdup(BIN_PATH "/afl-qemu-trace"); + return new_argv; + + } + + SAYF("\n" cLRD "[-] " cRST + "Oops, unable to find the 'afl-qemu-trace' binary. The binary must be built\n" + " separately by following the instructions in qemu_mode/README.qemu. If you\n" + " already have the binary installed, you may need to specify AFL_PATH in the\n" + " environment.\n\n" + + " Of course, even without QEMU, afl-fuzz can still work with binaries that are\n" + " instrumented at compile time with afl-gcc. It is also possible to use it as a\n" + " traditional \"dumb\" fuzzer by specifying '-n' in the command line.\n"); + + FATAL("Failed to locate 'afl-qemu-trace'."); + +} + + +/* Make a copy of the current command line. */ + +static void save_cmdline(u32 argc, char** argv) { + + u32 len = 1, i; + u8* buf; + + for (i = 0; i < argc; i++) + len += strlen(argv[i]) + 1; + + buf = orig_cmdline = ck_alloc(len); + + for (i = 0; i < argc; i++) { + + u32 l = strlen(argv[i]); + + memcpy(buf, argv[i], l); + buf += l; + + if (i != argc - 1) *(buf++) = ' '; + + } + + *buf = 0; + +} + + +#ifndef AFL_LIB + +/* Main entry point */ + +int main(int argc, char** argv) { + + s32 opt; + u64 prev_queued = 0; + u32 sync_interval_cnt = 0, seek_to; + u8 *extras_dir = 0; + u8 mem_limit_given = 0; + u8 exit_1 = !!getenv("AFL_BENCH_JUST_ONE"); + char** use_argv; + + struct timeval tv; + struct timezone tz; + + SAYF(cCYA "afl-fuzz " cBRI VERSION cRST " by \n"); + + doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH; + + gettimeofday(&tv, &tz); + srandom(tv.tv_sec ^ tv.tv_usec ^ getpid()); + + while ((opt = getopt(argc, argv, "+i:o:f:m:t:T:dnCB:S:M:x:Q")) > 0) + + switch (opt) { + + case 'i': /* input dir */ + + if (in_dir) FATAL("Multiple -i options not supported"); + in_dir = optarg; + + if (!strcmp(in_dir, "-")) in_place_resume = 1; + + break; + + case 'o': /* output dir */ + + if (out_dir) FATAL("Multiple -o options not supported"); + out_dir = optarg; + break; + + case 'M': { /* master sync ID */ + + u8* c; + + if (sync_id) FATAL("Multiple -S or -M options not supported"); + sync_id = ck_strdup(optarg); + + if ((c = strchr(sync_id, ':'))) { + + *c = 0; + + if (sscanf(c + 1, "%u/%u", &master_id, &master_max) != 2 || + !master_id || !master_max || master_id > master_max || + master_max > 1000000) FATAL("Bogus master ID passed to -M"); + + } + + force_deterministic = 1; + + } + + break; + + case 'S': + + if (sync_id) FATAL("Multiple -S or -M options not supported"); + sync_id = ck_strdup(optarg); + break; + + case 'f': /* target file */ + + if (out_file) FATAL("Multiple -f options not supported"); + out_file = optarg; + break; + + case 'x': /* dictionary */ + + if (extras_dir) FATAL("Multiple -x options not supported"); + extras_dir = optarg; + break; + + case 't': { /* timeout */ + + u8 suffix = 0; + + if (timeout_given) FATAL("Multiple -t options not supported"); + + if (sscanf(optarg, "%u%c", &exec_tmout, &suffix) < 1 || + optarg[0] == '-') FATAL("Bad syntax used for -t"); + + if (exec_tmout < 5) FATAL("Dangerously low value of -t"); + + if (suffix == '+') timeout_given = 2; else timeout_given = 1; + + break; + + } + + case 'm': { /* mem limit */ + + u8 suffix = 'M'; + + if (mem_limit_given) FATAL("Multiple -m options not supported"); + mem_limit_given = 1; + + if (!strcmp(optarg, "none")) { + + mem_limit = 0; + break; + + } + + if (sscanf(optarg, "%llu%c", &mem_limit, &suffix) < 1 || + optarg[0] == '-') FATAL("Bad syntax used for -m"); + + switch (suffix) { + + case 'T': mem_limit *= 1024 * 1024; break; + case 'G': mem_limit *= 1024; break; + case 'k': mem_limit /= 1024; break; + case 'M': break; + + default: FATAL("Unsupported suffix or bad syntax for -m"); + + } + + if (mem_limit < 5) FATAL("Dangerously low value of -m"); + + if (sizeof(rlim_t) == 4 && mem_limit > 2000) + FATAL("Value of -m out of range on 32-bit systems"); + + } + + break; + + case 'd': /* skip deterministic */ + + if (skip_deterministic) FATAL("Multiple -d options not supported"); + skip_deterministic = 1; + use_splicing = 1; + break; + + case 'B': /* load bitmap */ + + /* This is a secret undocumented option! It is useful if you find + an interesting test case during a normal fuzzing process, and want + to mutate it without rediscovering any of the test cases already + found during an earlier run. + + To use this mode, you need to point -B to the fuzz_bitmap produced + by an earlier run for the exact same binary... and that's it. + + I only used this once or twice to get variants of a particular + file, so I'm not making this an official setting. */ + + if (in_bitmap) FATAL("Multiple -B options not supported"); + + in_bitmap = optarg; + read_bitmap(in_bitmap); + break; + + case 'C': /* crash mode */ + + if (crash_mode) FATAL("Multiple -C options not supported"); + crash_mode = FAULT_CRASH; + break; + + case 'n': /* dumb mode */ + + if (dumb_mode) FATAL("Multiple -n options not supported"); + if (getenv("AFL_DUMB_FORKSRV")) dumb_mode = 2; else dumb_mode = 1; + + break; + + case 'T': /* banner */ + + if (use_banner) FATAL("Multiple -T options not supported"); + use_banner = optarg; + break; + + case 'Q': /* QEMU mode */ + + if (qemu_mode) FATAL("Multiple -Q options not supported"); + qemu_mode = 1; + + if (!mem_limit_given) mem_limit = MEM_LIMIT_QEMU; + + break; + + default: + + usage(argv[0]); + + } + + if (optind == argc || !in_dir || !out_dir) usage(argv[0]); + + setup_signal_handlers(); + check_asan_opts(); + + if (sync_id) fix_up_sync(); + + if (!strcmp(in_dir, out_dir)) + FATAL("Input and output directories can't be the same"); + + if (dumb_mode) { + + if (crash_mode) FATAL("-C and -n are mutually exclusive"); + if (qemu_mode) FATAL("-Q and -n are mutually exclusive"); + + } + + if (getenv("AFL_NO_FORKSRV")) no_forkserver = 1; + if (getenv("AFL_NO_CPU_RED")) no_cpu_meter_red = 1; + if (getenv("AFL_NO_ARITH")) no_arith = 1; + if (getenv("AFL_SHUFFLE_QUEUE")) shuffle_queue = 1; + if (getenv("AFL_FAST_CAL")) fast_cal = 1; + + if (getenv("AFL_HANG_TMOUT")) { + hang_tmout = atoi(getenv("AFL_HANG_TMOUT")); + if (!hang_tmout) FATAL("Invalid value of AFL_HANG_TMOUT"); + } + + if (dumb_mode == 2 && no_forkserver) + FATAL("AFL_DUMB_FORKSRV and AFL_NO_FORKSRV are mutually exclusive"); + + if (getenv("AFL_PRELOAD")) { + setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1); + setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1); + } + + if (getenv("AFL_LD_PRELOAD")) + FATAL("Use AFL_PRELOAD instead of AFL_LD_PRELOAD"); + + save_cmdline(argc, argv); + + fix_up_banner(argv[optind]); + + check_if_tty(); + + get_core_count(); + +#ifdef HAVE_AFFINITY + bind_to_free_cpu(); +#endif /* HAVE_AFFINITY */ + + check_crash_handling(); + check_cpu_governor(); + + setup_post(); + setup_shm(); + init_count_class16(); + + setup_dirs_fds(); + read_testcases(); + load_auto(); + + pivot_inputs(); + + if (extras_dir) load_extras(extras_dir); + + if (!timeout_given) find_timeout(); + + detect_file_args(argv + optind + 1); + + if (!out_file) setup_stdio_file(); + + check_binary(argv[optind]); + + start_time = get_cur_time(); + + if (qemu_mode) + use_argv = get_qemu_argv(argv[0], argv + optind, argc - optind); + else + use_argv = argv + optind; + + perform_dry_run(use_argv); + + cull_queue(); + + show_init_stats(); + + seek_to = find_start_position(); + + write_stats_file(0, 0, 0); + save_auto(); + + if (stop_soon) goto stop_fuzzing; + + /* Woop woop woop */ + + if (!not_on_tty) { + sleep(4); + start_time += 4000; + if (stop_soon) goto stop_fuzzing; + } + + while (1) { + + u8 skipped_fuzz; + + cull_queue(); + + if (!queue_cur) { + + queue_cycle++; + current_entry = 0; + cur_skipped_paths = 0; + queue_cur = queue; + + while (seek_to) { + current_entry++; + seek_to--; + queue_cur = queue_cur->next; + } + + show_stats(); + + if (not_on_tty) { + ACTF("Entering queue cycle %llu.", queue_cycle); + fflush(stdout); + } + + /* If we had a full queue cycle with no new finds, try + recombination strategies next. */ + + if (queued_paths == prev_queued) { + + if (use_splicing) cycles_wo_finds++; else use_splicing = 1; + + } else cycles_wo_finds = 0; + + prev_queued = queued_paths; + + if (sync_id && queue_cycle == 1 && getenv("AFL_IMPORT_FIRST")) + sync_fuzzers(use_argv); + + } + + skipped_fuzz = fuzz_one(use_argv); + + if (!stop_soon && sync_id && !skipped_fuzz) { + + if (!(sync_interval_cnt++ % SYNC_INTERVAL)) + sync_fuzzers(use_argv); + + } + + if (!stop_soon && exit_1) stop_soon = 2; + + if (stop_soon) break; + + queue_cur = queue_cur->next; + current_entry++; + + } + + if (queue_cur) show_stats(); + + write_bitmap(); + write_stats_file(0, 0, 0); + save_auto(); + +stop_fuzzing: + + SAYF(CURSOR_SHOW cLRD "\n\n+++ Testing aborted %s +++\n" cRST, + stop_soon == 2 ? "programmatically" : "by user"); + + /* Running for more than 30 minutes but still doing first cycle? */ + + if (queue_cycle == 1 && get_cur_time() - start_time > 30 * 60 * 1000) { + + SAYF("\n" cYEL "[!] " cRST + "Stopped during the first cycle, results may be incomplete.\n" + " (For info on resuming, see %s/README.)\n", doc_path); + + } + + fclose(plot_file); + destroy_queue(); + destroy_extras(); + ck_free(target_path); + ck_free(sync_id); + + alloc_report(); + + OKF("We're done here. Have a nice day!\n"); + + exit(0); + +} + +#endif /* !AFL_LIB */ \ No newline at end of file diff --git a/third_party/afl/afl-showmap.c b/third_party/afl/afl-showmap.c new file mode 100644 index 000000000..2e2d24bc7 --- /dev/null +++ b/third_party/afl/afl-showmap.c @@ -0,0 +1,780 @@ +/* + american fuzzy lop - map display utility + ---------------------------------------- + + Written and maintained by Michal Zalewski + + Copyright 2013, 2014, 2015, 2016, 2017 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + A very simple tool that runs the targeted binary and displays + the contents of the trace bitmap in a human-readable form. Useful in + scripts to eliminate redundant inputs and perform other checks. + + Exit code is 2 if the target program crashes; 1 if it times out or + there is a problem executing it; or 0 if execution is successful. + + */ + +#define AFL_MAIN + +#include "config.h" +#include "types.h" +#include "debug.h" +#include "alloc-inl.h" +#include "hash.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +static s32 child_pid; /* PID of the tested program */ + +static u8* trace_bits; /* SHM with instrumentation bitmap */ + +static u8 *out_file, /* Trace output file */ + *doc_path, /* Path to docs */ + *target_path, /* Path to target binary */ + *at_file; /* Substitution string for @@ */ + +static u32 exec_tmout; /* Exec timeout (ms) */ + +static u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */ + +static s32 shm_id; /* ID of the SHM region */ + +static u8 quiet_mode, /* Hide non-essential messages? */ + edges_only, /* Ignore hit counts? */ + cmin_mode, /* Generate output in afl-cmin mode? */ + binary_mode, /* Write output as a binary map */ + keep_cores; /* Allow coredumps? */ + +static volatile u8 + stop_soon, /* Ctrl-C pressed? */ + child_timed_out, /* Child timed out? */ + child_crashed; /* Child crashed? */ + +/* Classify tuple counts. Instead of mapping to individual bits, as in + afl-fuzz.c, we map to more user-friendly numbers between 1 and 8. */ + +static const u8 count_class_human[256] = { + + [0] = 0, + [1] = 1, + [2] = 2, + [3] = 3, + [4 ... 7] = 4, + [8 ... 15] = 5, + [16 ... 31] = 6, + [32 ... 127] = 7, + [128 ... 255] = 8 + +}; + +static const u8 count_class_binary[256] = { + + [0] = 0, + [1] = 1, + [2] = 2, + [3] = 4, + [4 ... 7] = 8, + [8 ... 15] = 16, + [16 ... 31] = 32, + [32 ... 127] = 64, + [128 ... 255] = 128 + +}; + +static void classify_counts(u8* mem, const u8* map) { + + u32 i = MAP_SIZE; + + if (edges_only) { + + while (i--) { + if (*mem) *mem = 1; + mem++; + } + + } else { + + while (i--) { + *mem = map[*mem]; + mem++; + } + + } + +} + + +/* Get rid of shared memory (atexit handler). */ + +static void remove_shm(void) { + + shmctl(shm_id, IPC_RMID, NULL); + +} + + +/* Configure shared memory. */ + +static void setup_shm(void) { + + u8* shm_str; + + shm_id = shmget(IPC_PRIVATE, MAP_SIZE, IPC_CREAT | IPC_EXCL | 0600); + + if (shm_id < 0) PFATAL("shmget() failed"); + + atexit(remove_shm); + + shm_str = alloc_printf("%d", shm_id); + + setenv(SHM_ENV_VAR, shm_str, 1); + + ck_free(shm_str); + + trace_bits = shmat(shm_id, NULL, 0); + + if (!trace_bits) PFATAL("shmat() failed"); + +} + +/* Write results. */ + +static u32 write_results(void) { + + s32 fd; + u32 i, ret = 0; + + u8 cco = !!getenv("AFL_CMIN_CRASHES_ONLY"), + caa = !!getenv("AFL_CMIN_ALLOW_ANY"); + + if (!strncmp(out_file, "/dev/", 5)) { + + fd = open(out_file, O_WRONLY, 0600); + if (fd < 0) PFATAL("Unable to open '%s'", out_file); + + } else if (!strcmp(out_file, "-")) { + + fd = dup(1); + if (fd < 0) PFATAL("Unable to open stdout"); + + } else { + + unlink(out_file); /* Ignore errors */ + fd = open(out_file, O_WRONLY | O_CREAT | O_EXCL, 0600); + if (fd < 0) PFATAL("Unable to create '%s'", out_file); + + } + + + if (binary_mode) { + + for (i = 0; i < MAP_SIZE; i++) + if (trace_bits[i]) ret++; + + ck_write(fd, trace_bits, MAP_SIZE, out_file); + close(fd); + + } else { + + FILE* f = fdopen(fd, "w"); + + if (!f) PFATAL("fdopen() failed"); + + for (i = 0; i < MAP_SIZE; i++) { + + if (!trace_bits[i]) continue; + ret++; + + if (cmin_mode) { + + if (child_timed_out) break; + if (!caa && child_crashed != cco) break; + + fprintf(f, "%u%u\n", trace_bits[i], i); + + } else fprintf(f, "%06u:%u\n", i, trace_bits[i]); + + } + + fclose(f); + + } + + return ret; + +} + + +/* Handle timeout signal. */ + +static void handle_timeout(int sig) { + + child_timed_out = 1; + if (child_pid > 0) kill(child_pid, SIGKILL); + +} + + +/* Execute target application. */ + +static void run_target(char** argv) { + + static struct itimerval it; + int status = 0; + + if (!quiet_mode) + SAYF("-- Program output begins --\n" cRST); + + MEM_BARRIER(); + + child_pid = fork(); + + if (child_pid < 0) PFATAL("fork() failed"); + + if (!child_pid) { + + struct rlimit r; + + if (quiet_mode) { + + s32 fd = open("/dev/null", O_RDWR); + + if (fd < 0 || dup2(fd, 1) < 0 || dup2(fd, 2) < 0) { + *(u32*)trace_bits = EXEC_FAIL_SIG; + PFATAL("Descriptor initialization failed"); + } + + close(fd); + + } + + if (mem_limit) { + + r.rlim_max = r.rlim_cur = ((rlim_t)mem_limit) << 20; + +#ifdef RLIMIT_AS + + setrlimit(RLIMIT_AS, &r); /* Ignore errors */ + +#else + + setrlimit(RLIMIT_DATA, &r); /* Ignore errors */ + +#endif /* ^RLIMIT_AS */ + + } + + if (!keep_cores) r.rlim_max = r.rlim_cur = 0; + else r.rlim_max = r.rlim_cur = RLIM_INFINITY; + + setrlimit(RLIMIT_CORE, &r); /* Ignore errors */ + + if (!getenv("LD_BIND_LAZY")) setenv("LD_BIND_NOW", "1", 0); + + setsid(); + + execv(target_path, argv); + + *(u32*)trace_bits = EXEC_FAIL_SIG; + exit(0); + + } + + /* Configure timeout, wait for child, cancel timeout. */ + + if (exec_tmout) { + + child_timed_out = 0; + it.it_value.tv_sec = (exec_tmout / 1000); + it.it_value.tv_usec = (exec_tmout % 1000) * 1000; + + } + + setitimer(ITIMER_REAL, &it, NULL); + + if (waitpid(child_pid, &status, 0) <= 0) FATAL("waitpid() failed"); + + child_pid = 0; + it.it_value.tv_sec = 0; + it.it_value.tv_usec = 0; + setitimer(ITIMER_REAL, &it, NULL); + + MEM_BARRIER(); + + /* Clean up bitmap, analyze exit condition, etc. */ + + if (*(u32*)trace_bits == EXEC_FAIL_SIG) + FATAL("Unable to execute '%s'", argv[0]); + + classify_counts(trace_bits, binary_mode ? + count_class_binary : count_class_human); + + if (!quiet_mode) + SAYF(cRST "-- Program output ends --\n"); + + if (!child_timed_out && !stop_soon && WIFSIGNALED(status)) + child_crashed = 1; + + if (!quiet_mode) { + + if (child_timed_out) + SAYF(cLRD "\n+++ Program timed off +++\n" cRST); + else if (stop_soon) + SAYF(cLRD "\n+++ Program aborted by user +++\n" cRST); + else if (child_crashed) + SAYF(cLRD "\n+++ Program killed by signal %u +++\n" cRST, WTERMSIG(status)); + + } + + +} + + +/* Handle Ctrl-C and the like. */ + +static void handle_stop_sig(int sig) { + + stop_soon = 1; + + if (child_pid > 0) kill(child_pid, SIGKILL); + +} + + +/* Do basic preparations - persistent fds, filenames, etc. */ + +static void set_up_environment(void) { + + setenv("ASAN_OPTIONS", "abort_on_error=1:" + "detect_leaks=0:" + "symbolize=0:" + "allocator_may_return_null=1", 0); + + setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":" + "symbolize=0:" + "abort_on_error=1:" + "allocator_may_return_null=1:" + "msan_track_origins=0", 0); + + if (getenv("AFL_PRELOAD")) { + setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1); + setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1); + } + +} + + +/* Setup signal handlers, duh. */ + +static void setup_signal_handlers(void) { + + struct sigaction sa; + + sa.sa_handler = NULL; + sa.sa_flags = SA_RESTART; + sa.sa_sigaction = NULL; + + sigemptyset(&sa.sa_mask); + + /* Various ways of saying "stop". */ + + sa.sa_handler = handle_stop_sig; + sigaction(SIGHUP, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + + /* Exec timeout notifications. */ + + sa.sa_handler = handle_timeout; + sigaction(SIGALRM, &sa, NULL); + +} + + +/* Detect @@ in args. */ + +static void detect_file_args(char** argv) { + + u32 i = 0; + u8* cwd = getcwd(NULL, 0); + + if (!cwd) PFATAL("getcwd() failed"); + + while (argv[i]) { + + u8* aa_loc = strstr(argv[i], "@@"); + + if (aa_loc) { + + u8 *aa_subst, *n_arg; + + if (!at_file) FATAL("@@ syntax is not supported by this tool."); + + /* Be sure that we're always using fully-qualified paths. */ + + if (at_file[0] == '/') aa_subst = at_file; + else aa_subst = alloc_printf("%s/%s", cwd, at_file); + + /* Construct a replacement argv value. */ + + *aa_loc = 0; + n_arg = alloc_printf("%s%s%s", argv[i], aa_subst, aa_loc + 2); + argv[i] = n_arg; + *aa_loc = '@'; + + if (at_file[0] != '/') ck_free(aa_subst); + + } + + i++; + + } + + free(cwd); /* not tracked */ + +} + + +/* Show banner. */ + +static void show_banner(void) { + + SAYF(cCYA "afl-showmap " cBRI VERSION cRST " by \n"); + +} + +/* Display usage hints. */ + +static void usage(u8* argv0) { + + show_banner(); + + SAYF("\n%s [ options ] -- /path/to/target_app [ ... ]\n\n" + + "Required parameters:\n\n" + + " -o file - file to write the trace data to\n\n" + + "Execution control settings:\n\n" + + " -t msec - timeout for each run (none)\n" + " -m megs - memory limit for child process (%u MB)\n" + " -Q - use binary-only instrumentation (QEMU mode)\n\n" + + "Other settings:\n\n" + + " -q - sink program's output and don't show messages\n" + " -e - show edge coverage only, ignore hit counts\n" + " -c - allow core dumps\n\n" + + "This tool displays raw tuple data captured by AFL instrumentation.\n" + "For additional help, consult %s/README.\n\n" cRST, + + argv0, MEM_LIMIT, doc_path); + + exit(1); + +} + + +/* Find binary. */ + +static void find_binary(u8* fname) { + + u8* env_path = 0; + struct stat st; + + if (strchr(fname, '/') || !(env_path = getenv("PATH"))) { + + target_path = ck_strdup(fname); + + if (stat(target_path, &st) || !S_ISREG(st.st_mode) || + !(st.st_mode & 0111) || st.st_size < 4) + FATAL("Program '%s' not found or not executable", fname); + + } else { + + while (env_path) { + + u8 *cur_elem, *delim = strchr(env_path, ':'); + + if (delim) { + + cur_elem = ck_alloc(delim - env_path + 1); + memcpy(cur_elem, env_path, delim - env_path); + delim++; + + } else cur_elem = ck_strdup(env_path); + + env_path = delim; + + if (cur_elem[0]) + target_path = alloc_printf("%s/%s", cur_elem, fname); + else + target_path = ck_strdup(fname); + + ck_free(cur_elem); + + if (!stat(target_path, &st) && S_ISREG(st.st_mode) && + (st.st_mode & 0111) && st.st_size >= 4) break; + + ck_free(target_path); + target_path = 0; + + } + + if (!target_path) FATAL("Program '%s' not found or not executable", fname); + + } + +} + + +/* Fix up argv for QEMU. */ + +static char** get_qemu_argv(u8* own_loc, char** argv, int argc) { + + char** new_argv = ck_alloc(sizeof(char*) * (argc + 4)); + u8 *tmp, *cp, *rsl, *own_copy; + + /* Workaround for a QEMU stability glitch. */ + + setenv("QEMU_LOG", "nochain", 1); + + memcpy(new_argv + 3, argv + 1, sizeof(char*) * argc); + + new_argv[2] = target_path; + new_argv[1] = "--"; + + /* Now we need to actually find qemu for argv[0]. */ + + tmp = getenv("AFL_PATH"); + + if (tmp) { + + cp = alloc_printf("%s/afl-qemu-trace", tmp); + + if (access(cp, X_OK)) + FATAL("Unable to find '%s'", tmp); + + target_path = new_argv[0] = cp; + return new_argv; + + } + + own_copy = ck_strdup(own_loc); + rsl = strrchr(own_copy, '/'); + + if (rsl) { + + *rsl = 0; + + cp = alloc_printf("%s/afl-qemu-trace", own_copy); + ck_free(own_copy); + + if (!access(cp, X_OK)) { + + target_path = new_argv[0] = cp; + return new_argv; + + } + + } else ck_free(own_copy); + + if (!access(BIN_PATH "/afl-qemu-trace", X_OK)) { + + target_path = new_argv[0] = BIN_PATH "/afl-qemu-trace"; + return new_argv; + + } + + FATAL("Unable to find 'afl-qemu-trace'."); + +} + + +/* Main entry point */ + +int main(int argc, char** argv) { + + s32 opt; + u8 mem_limit_given = 0, timeout_given = 0, qemu_mode = 0; + u32 tcnt; + char** use_argv; + + doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH; + + while ((opt = getopt(argc,argv,"+o:m:t:A:eqZQbc")) > 0) + + switch (opt) { + + case 'o': + + if (out_file) FATAL("Multiple -o options not supported"); + out_file = optarg; + break; + + case 'm': { + + u8 suffix = 'M'; + + if (mem_limit_given) FATAL("Multiple -m options not supported"); + mem_limit_given = 1; + + if (!strcmp(optarg, "none")) { + + mem_limit = 0; + break; + + } + + if (sscanf(optarg, "%llu%c", &mem_limit, &suffix) < 1 || + optarg[0] == '-') FATAL("Bad syntax used for -m"); + + switch (suffix) { + + case 'T': mem_limit *= 1024 * 1024; break; + case 'G': mem_limit *= 1024; break; + case 'k': mem_limit /= 1024; break; + case 'M': break; + + default: FATAL("Unsupported suffix or bad syntax for -m"); + + } + + if (mem_limit < 5) FATAL("Dangerously low value of -m"); + + if (sizeof(rlim_t) == 4 && mem_limit > 2000) + FATAL("Value of -m out of range on 32-bit systems"); + + } + + break; + + case 't': + + if (timeout_given) FATAL("Multiple -t options not supported"); + timeout_given = 1; + + if (strcmp(optarg, "none")) { + exec_tmout = atoi(optarg); + + if (exec_tmout < 20 || optarg[0] == '-') + FATAL("Dangerously low value of -t"); + + } + + break; + + case 'e': + + if (edges_only) FATAL("Multiple -e options not supported"); + edges_only = 1; + break; + + case 'q': + + if (quiet_mode) FATAL("Multiple -q options not supported"); + quiet_mode = 1; + break; + + case 'Z': + + /* This is an undocumented option to write data in the syntax expected + by afl-cmin. Nobody else should have any use for this. */ + + cmin_mode = 1; + quiet_mode = 1; + break; + + case 'A': + + /* Another afl-cmin specific feature. */ + at_file = optarg; + break; + + case 'Q': + + if (qemu_mode) FATAL("Multiple -Q options not supported"); + if (!mem_limit_given) mem_limit = MEM_LIMIT_QEMU; + + qemu_mode = 1; + break; + + case 'b': + + /* Secret undocumented mode. Writes output in raw binary format + similar to that dumped by afl-fuzz in test_fuzzer.cc +#include +#include +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + if (size > 0 && data[0] == 'H') + if (size > 1 && data[1] == 'I') + if (size > 2 && data[2] == '!') + __builtin_trap(); + return 0; +} +EOF +# Build your target with -fsanitize-coverage=trace-pc-guard using fresh clang. +clang -g -fsanitize-coverage=trace-pc-guard test_fuzzer.cc -c +# Build afl-llvm-rt.o.c from the AFL distribution. +clang -c -w $AFL_HOME/llvm_mode/afl-llvm-rt.o.c +# Build this file, link it with afl-llvm-rt.o.o and the target code. +clang++ afl_driver.cpp test_fuzzer.o afl-llvm-rt.o.o +# Run AFL: +rm -rf IN OUT; mkdir IN OUT; echo z > IN/z; +$AFL_HOME/afl-fuzz -i IN -o OUT ./a.out +################################################################################ +AFL_DRIVER_STDERR_DUPLICATE_FILENAME: Setting this *appends* stderr to the file +specified. If the file does not exist, it is created. This is useful for getting +stack traces (when using ASAN for example) or original error messages on hard +to reproduce bugs. Note that any content written to stderr will be written to +this file instead of stderr's usual location. + +AFL_DRIVER_CLOSE_FD_MASK: Similar to libFuzzer's -close_fd_mask behavior option. +If 1, close stdout at startup. If 2 close stderr; if 3 close both. + +*/ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +// Platform detection. Copied from FuzzerInternal.h +#ifdef __linux__ +#define LIBFUZZER_LINUX 1 +#define LIBFUZZER_APPLE 0 +#define LIBFUZZER_NETBSD 0 +#define LIBFUZZER_FREEBSD 0 +#define LIBFUZZER_OPENBSD 0 +#elif __APPLE__ +#define LIBFUZZER_LINUX 0 +#define LIBFUZZER_APPLE 1 +#define LIBFUZZER_NETBSD 0 +#define LIBFUZZER_FREEBSD 0 +#define LIBFUZZER_OPENBSD 0 +#elif __NetBSD__ +#define LIBFUZZER_LINUX 0 +#define LIBFUZZER_APPLE 0 +#define LIBFUZZER_NETBSD 1 +#define LIBFUZZER_FREEBSD 0 +#define LIBFUZZER_OPENBSD 0 +#elif __FreeBSD__ +#define LIBFUZZER_LINUX 0 +#define LIBFUZZER_APPLE 0 +#define LIBFUZZER_NETBSD 0 +#define LIBFUZZER_FREEBSD 1 +#define LIBFUZZER_OPENBSD 0 +#elif __OpenBSD__ +#define LIBFUZZER_LINUX 0 +#define LIBFUZZER_APPLE 0 +#define LIBFUZZER_NETBSD 0 +#define LIBFUZZER_FREEBSD 0 +#define LIBFUZZER_OPENBSD 1 +#else +#error "Support for your platform has not been implemented" +#endif + +// libFuzzer interface is thin, so we don't include any libFuzzer headers. +extern "C" { +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); +__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv); +} + +// Notify AFL about persistent mode. +static volatile char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##"; +extern "C" int __afl_persistent_loop(unsigned int); +static volatile char suppress_warning2 = AFL_PERSISTENT[0]; + +// Notify AFL about deferred forkserver. +static volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##"; +extern "C" void __afl_manual_init(); +static volatile char suppress_warning1 = AFL_DEFER_FORKSVR[0]; + +// Input buffer. +static const size_t kMaxAflInputSize = 1 << 20; +static uint8_t AflInputBuf[kMaxAflInputSize]; + +// Use this optionally defined function to output sanitizer messages even if +// user asks to close stderr. +__attribute__((weak)) extern "C" void __sanitizer_set_report_fd(void *); + +// Keep track of where stderr content is being written to, so that +// dup_and_close_stderr can use the correct one. +static FILE *output_file = stderr; + +// Experimental feature to use afl_driver without AFL's deferred mode. +// Needs to run before __afl_auto_init. +__attribute__((constructor(0))) static void __decide_deferred_forkserver(void) { + if (getenv("AFL_DRIVER_DONT_DEFER")) { + if (unsetenv("__AFL_DEFER_FORKSRV")) { + perror("Failed to unset __AFL_DEFER_FORKSRV"); + abort(); + } + } +} + +// If the user asks us to duplicate stderr, then do it. +static void maybe_duplicate_stderr() { + char *stderr_duplicate_filename = + getenv("AFL_DRIVER_STDERR_DUPLICATE_FILENAME"); + + if (!stderr_duplicate_filename) + return; + + FILE *stderr_duplicate_stream = + freopen(stderr_duplicate_filename, "a+", stderr); + + if (!stderr_duplicate_stream) { + fprintf( + stderr, + "Failed to duplicate stderr to AFL_DRIVER_STDERR_DUPLICATE_FILENAME"); + abort(); + } + output_file = stderr_duplicate_stream; +} + +// Most of these I/O functions were inspired by/copied from libFuzzer's code. +static void discard_output(int fd) { + FILE *temp = fopen("/dev/null", "w"); + if (!temp) + abort(); + dup2(fileno(temp), fd); + fclose(temp); +} + +static void close_stdout() { discard_output(STDOUT_FILENO); } + +// Prevent the targeted code from writing to "stderr" but allow sanitizers and +// this driver to do so. +static void dup_and_close_stderr() { + int output_fileno = fileno(output_file); + int output_fd = dup(output_fileno); + if (output_fd <= 0) + abort(); + FILE *new_output_file = fdopen(output_fd, "w"); + if (!new_output_file) + abort(); + if (!__sanitizer_set_report_fd) + return; + __sanitizer_set_report_fd(reinterpret_cast(output_fd)); + discard_output(output_fileno); +} + +static void Printf(const char *Fmt, ...) { + va_list ap; + va_start(ap, Fmt); + vfprintf(output_file, Fmt, ap); + va_end(ap); + fflush(output_file); +} + +// Close stdout and/or stderr if user asks for it. +static void maybe_close_fd_mask() { + char *fd_mask_str = getenv("AFL_DRIVER_CLOSE_FD_MASK"); + if (!fd_mask_str) + return; + int fd_mask = atoi(fd_mask_str); + if (fd_mask & 2) + dup_and_close_stderr(); + if (fd_mask & 1) + close_stdout(); +} + +// Define LLVMFuzzerMutate to avoid link failures for targets that use it +// with libFuzzer's LLVMFuzzerCustomMutator. +extern "C" size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) { + assert(false && "LLVMFuzzerMutate should not be called from afl_driver"); + return 0; +} + +// Execute any files provided as parameters. +static int ExecuteFilesOnyByOne(int argc, char **argv) { + for (int i = 1; i < argc; i++) { + std::ifstream in(argv[i], std::ios::binary); + in.seekg(0, in.end); + size_t length = in.tellg(); + in.seekg (0, in.beg); + std::cout << "Reading " << length << " bytes from " << argv[i] << std::endl; + // Allocate exactly length bytes so that we reliably catch buffer overflows. + std::vector bytes(length); + in.read(bytes.data(), bytes.size()); + assert(in); + LLVMFuzzerTestOneInput(reinterpret_cast(bytes.data()), + bytes.size()); + std::cout << "Execution successful" << std::endl; + } + return 0; +} + +int main(int argc, char **argv) { + Printf( + "======================= INFO =========================\n" + "This binary is built for AFL-fuzz.\n" + "To run the target function on individual input(s) execute this:\n" + " %s < INPUT_FILE\n" + "or\n" + " %s INPUT_FILE1 [INPUT_FILE2 ... ]\n" + "To fuzz with afl-fuzz execute this:\n" + " afl-fuzz [afl-flags] %s [-N]\n" + "afl-fuzz will run N iterations before " + "re-spawning the process (default: 1000)\n" + "======================================================\n", + argv[0], argv[0], argv[0]); + + maybe_duplicate_stderr(); + maybe_close_fd_mask(); + if (LLVMFuzzerInitialize) + LLVMFuzzerInitialize(&argc, &argv); + // Do any other expensive one-time initialization here. + + if (!getenv("AFL_DRIVER_DONT_DEFER")) + __afl_manual_init(); + + int N = 1000; + if (argc == 2 && argv[1][0] == '-') + N = atoi(argv[1] + 1); + else if(argc == 2 && (N = atoi(argv[1])) > 0) + Printf("WARNING: using the deprecated call style `%s %d`\n", argv[0], N); + else if (argc > 1) + return ExecuteFilesOnyByOne(argc, argv); + + assert(N > 0); + + // Call LLVMFuzzerTestOneInput here so that coverage caused by initialization + // on the first execution of LLVMFuzzerTestOneInput is ignored. + uint8_t dummy_input[1] = {0}; + LLVMFuzzerTestOneInput(dummy_input, 1); + + int num_runs = 0; + while (__afl_persistent_loop(N)) { + ssize_t n_read = read(0, AflInputBuf, kMaxAflInputSize); + if (n_read > 0) { + // Copy AflInputBuf into a separate buffer to let asan find buffer + // overflows. Don't use unique_ptr/etc to avoid extra dependencies. + uint8_t *copy = new uint8_t[n_read]; + memcpy(copy, AflInputBuf, n_read); + num_runs++; + LLVMFuzzerTestOneInput(copy, n_read); + delete[] copy; + } + } + Printf("%s: successfully executed %d input(s)\n", argv[0], num_runs); +} \ No newline at end of file diff --git a/third_party/afl/alloc-inl.h b/third_party/afl/alloc-inl.h new file mode 100644 index 000000000..87cc0b114 --- /dev/null +++ b/third_party/afl/alloc-inl.h @@ -0,0 +1,570 @@ +/* + american fuzzy lop - error-checking, memory-zeroing alloc routines + ------------------------------------------------------------------ + + Written and maintained by Michal Zalewski + + Copyright 2013, 2014, 2015 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + This allocator is not designed to resist malicious attackers (the canaries + are small and predictable), but provides a robust and portable way to detect + use-after-free, off-by-one writes, stale pointers, and so on. + + */ + +#ifndef _HAVE_ALLOC_INL_H +#define _HAVE_ALLOC_INL_H + +#include +#include +#include + +#include "config.h" +#include "types.h" +#include "debug.h" + +/* User-facing macro to sprintf() to a dynamically allocated buffer. */ + +#define alloc_printf(_str...) ({ \ + u8* _tmp; \ + s32 _len = snprintf(NULL, 0, _str); \ + if (_len < 0) FATAL("Whoa, snprintf() fails?!"); \ + _tmp = ck_alloc(_len + 1); \ + snprintf((char*)_tmp, _len + 1, _str); \ + _tmp; \ + }) + +/* Macro to enforce allocation limits as a last-resort defense against + integer overflows. */ + +#define ALLOC_CHECK_SIZE(_s) do { \ + if ((_s) > MAX_ALLOC) \ + ABORT("Bad alloc request: %u bytes", (_s)); \ + } while (0) + +/* Macro to check malloc() failures and the like. */ + +#define ALLOC_CHECK_RESULT(_r, _s) do { \ + if (!(_r)) \ + ABORT("Out of memory: can't allocate %u bytes", (_s)); \ + } while (0) + +/* Magic tokens used to mark used / freed chunks. */ + +#define ALLOC_MAGIC_C1 0xFF00FF00 /* Used head (dword) */ +#define ALLOC_MAGIC_F 0xFE00FE00 /* Freed head (dword) */ +#define ALLOC_MAGIC_C2 0xF0 /* Used tail (byte) */ + +/* Positions of guard tokens in relation to the user-visible pointer. */ + +#define ALLOC_C1(_ptr) (((u32*)(_ptr))[-2]) +#define ALLOC_S(_ptr) (((u32*)(_ptr))[-1]) +#define ALLOC_C2(_ptr) (((u8*)(_ptr))[ALLOC_S(_ptr)]) + +#define ALLOC_OFF_HEAD 8 +#define ALLOC_OFF_TOTAL (ALLOC_OFF_HEAD + 1) + +/* Allocator increments for ck_realloc_block(). */ + +#define ALLOC_BLK_INC 256 + +/* Sanity-checking macros for pointers. */ + +#define CHECK_PTR(_p) do { \ + if (_p) { \ + if (ALLOC_C1(_p) ^ ALLOC_MAGIC_C1) {\ + if (ALLOC_C1(_p) == ALLOC_MAGIC_F) \ + ABORT("Use after free."); \ + else ABORT("Corrupted head alloc canary."); \ + } \ + if (ALLOC_C2(_p) ^ ALLOC_MAGIC_C2) \ + ABORT("Corrupted tail alloc canary."); \ + } \ + } while (0) + +#define CHECK_PTR_EXPR(_p) ({ \ + typeof (_p) _tmp = (_p); \ + CHECK_PTR(_tmp); \ + _tmp; \ + }) + + +/* Allocate a buffer, explicitly not zeroing it. Returns NULL for zero-sized + requests. */ + +static inline void* DFL_ck_alloc_nozero(u32 size) { + + void* ret; + + if (!size) return NULL; + + ALLOC_CHECK_SIZE(size); + ret = malloc(size + ALLOC_OFF_TOTAL); + ALLOC_CHECK_RESULT(ret, size); + + ret += ALLOC_OFF_HEAD; + + ALLOC_C1(ret) = ALLOC_MAGIC_C1; + ALLOC_S(ret) = size; + ALLOC_C2(ret) = ALLOC_MAGIC_C2; + + return ret; + +} + + +/* Allocate a buffer, returning zeroed memory. */ + +static inline void* DFL_ck_alloc(u32 size) { + + void* mem; + + if (!size) return NULL; + mem = DFL_ck_alloc_nozero(size); + + return memset(mem, 0, size); + +} + + +/* Free memory, checking for double free and corrupted heap. When DEBUG_BUILD + is set, the old memory will be also clobbered with 0xFF. */ + +static inline void DFL_ck_free(void* mem) { + + if (!mem) return; + + CHECK_PTR(mem); + +#ifdef DEBUG_BUILD + + /* Catch pointer issues sooner. */ + memset(mem, 0xFF, ALLOC_S(mem)); + +#endif /* DEBUG_BUILD */ + + ALLOC_C1(mem) = ALLOC_MAGIC_F; + + free(mem - ALLOC_OFF_HEAD); + +} + + +/* Re-allocate a buffer, checking for issues and zeroing any newly-added tail. + With DEBUG_BUILD, the buffer is always reallocated to a new addresses and the + old memory is clobbered with 0xFF. */ + +static inline void* DFL_ck_realloc(void* orig, u32 size) { + + void* ret; + u32 old_size = 0; + + if (!size) { + + DFL_ck_free(orig); + return NULL; + + } + + if (orig) { + + CHECK_PTR(orig); + +#ifndef DEBUG_BUILD + ALLOC_C1(orig) = ALLOC_MAGIC_F; +#endif /* !DEBUG_BUILD */ + + old_size = ALLOC_S(orig); + orig -= ALLOC_OFF_HEAD; + + ALLOC_CHECK_SIZE(old_size); + + } + + ALLOC_CHECK_SIZE(size); + +#ifndef DEBUG_BUILD + + ret = realloc(orig, size + ALLOC_OFF_TOTAL); + ALLOC_CHECK_RESULT(ret, size); + +#else + + /* Catch pointer issues sooner: force relocation and make sure that the + original buffer is wiped. */ + + ret = malloc(size + ALLOC_OFF_TOTAL); + ALLOC_CHECK_RESULT(ret, size); + + if (orig) { + + memcpy(ret + ALLOC_OFF_HEAD, orig + ALLOC_OFF_HEAD, MIN(size, old_size)); + memset(orig + ALLOC_OFF_HEAD, 0xFF, old_size); + + ALLOC_C1(orig + ALLOC_OFF_HEAD) = ALLOC_MAGIC_F; + + free(orig); + + } + +#endif /* ^!DEBUG_BUILD */ + + ret += ALLOC_OFF_HEAD; + + ALLOC_C1(ret) = ALLOC_MAGIC_C1; + ALLOC_S(ret) = size; + ALLOC_C2(ret) = ALLOC_MAGIC_C2; + + if (size > old_size) + memset(ret + old_size, 0, size - old_size); + + return ret; + +} + + +/* Re-allocate a buffer with ALLOC_BLK_INC increments (used to speed up + repeated small reallocs without complicating the user code). */ + +static inline void* DFL_ck_realloc_block(void* orig, u32 size) { + +#ifndef DEBUG_BUILD + + if (orig) { + + CHECK_PTR(orig); + + if (ALLOC_S(orig) >= size) return orig; + + size += ALLOC_BLK_INC; + + } + +#endif /* !DEBUG_BUILD */ + + return DFL_ck_realloc(orig, size); + +} + + +/* Create a buffer with a copy of a string. Returns NULL for NULL inputs. */ + +static inline u8* DFL_ck_strdup(u8* str) { + + void* ret; + u32 size; + + if (!str) return NULL; + + size = strlen((char*)str) + 1; + + ALLOC_CHECK_SIZE(size); + ret = malloc(size + ALLOC_OFF_TOTAL); + ALLOC_CHECK_RESULT(ret, size); + + ret += ALLOC_OFF_HEAD; + + ALLOC_C1(ret) = ALLOC_MAGIC_C1; + ALLOC_S(ret) = size; + ALLOC_C2(ret) = ALLOC_MAGIC_C2; + + return memcpy(ret, str, size); + +} + + +/* Create a buffer with a copy of a memory block. Returns NULL for zero-sized + or NULL inputs. */ + +static inline void* DFL_ck_memdup(void* mem, u32 size) { + + void* ret; + + if (!mem || !size) return NULL; + + ALLOC_CHECK_SIZE(size); + ret = malloc(size + ALLOC_OFF_TOTAL); + ALLOC_CHECK_RESULT(ret, size); + + ret += ALLOC_OFF_HEAD; + + ALLOC_C1(ret) = ALLOC_MAGIC_C1; + ALLOC_S(ret) = size; + ALLOC_C2(ret) = ALLOC_MAGIC_C2; + + return memcpy(ret, mem, size); + +} + + +/* Create a buffer with a block of text, appending a NUL terminator at the end. + Returns NULL for zero-sized or NULL inputs. */ + +static inline u8* DFL_ck_memdup_str(u8* mem, u32 size) { + + u8* ret; + + if (!mem || !size) return NULL; + + ALLOC_CHECK_SIZE(size); + ret = malloc(size + ALLOC_OFF_TOTAL + 1); + ALLOC_CHECK_RESULT(ret, size); + + ret += ALLOC_OFF_HEAD; + + ALLOC_C1(ret) = ALLOC_MAGIC_C1; + ALLOC_S(ret) = size; + ALLOC_C2(ret) = ALLOC_MAGIC_C2; + + memcpy(ret, mem, size); + ret[size] = 0; + + return ret; + +} + + +#ifndef DEBUG_BUILD + +/* In non-debug mode, we just do straightforward aliasing of the above functions + to user-visible names such as ck_alloc(). */ + +#define ck_alloc DFL_ck_alloc +#define ck_alloc_nozero DFL_ck_alloc_nozero +#define ck_realloc DFL_ck_realloc +#define ck_realloc_block DFL_ck_realloc_block +#define ck_strdup DFL_ck_strdup +#define ck_memdup DFL_ck_memdup +#define ck_memdup_str DFL_ck_memdup_str +#define ck_free DFL_ck_free + +#define alloc_report() + +#else + +/* In debugging mode, we also track allocations to detect memory leaks, and the + flow goes through one more layer of indirection. */ + +/* Alloc tracking data structures: */ + +#define ALLOC_BUCKETS 4096 + +struct TRK_obj { + void *ptr; + char *file, *func; + u32 line; +}; + +#ifdef AFL_MAIN + +struct TRK_obj* TRK[ALLOC_BUCKETS]; +u32 TRK_cnt[ALLOC_BUCKETS]; + +# define alloc_report() TRK_report() + +#else + +extern struct TRK_obj* TRK[ALLOC_BUCKETS]; +extern u32 TRK_cnt[ALLOC_BUCKETS]; + +# define alloc_report() + +#endif /* ^AFL_MAIN */ + +/* Bucket-assigning function for a given pointer: */ + +#define TRKH(_ptr) (((((u32)(_ptr)) >> 16) ^ ((u32)(_ptr))) % ALLOC_BUCKETS) + + +/* Add a new entry to the list of allocated objects. */ + +static inline void TRK_alloc_buf(void* ptr, const char* file, const char* func, + u32 line) { + + u32 i, bucket; + + if (!ptr) return; + + bucket = TRKH(ptr); + + /* Find a free slot in the list of entries for that bucket. */ + + for (i = 0; i < TRK_cnt[bucket]; i++) + + if (!TRK[bucket][i].ptr) { + + TRK[bucket][i].ptr = ptr; + TRK[bucket][i].file = (char*)file; + TRK[bucket][i].func = (char*)func; + TRK[bucket][i].line = line; + return; + + } + + /* No space available - allocate more. */ + + TRK[bucket] = DFL_ck_realloc_block(TRK[bucket], + (TRK_cnt[bucket] + 1) * sizeof(struct TRK_obj)); + + TRK[bucket][i].ptr = ptr; + TRK[bucket][i].file = (char*)file; + TRK[bucket][i].func = (char*)func; + TRK[bucket][i].line = line; + + TRK_cnt[bucket]++; + +} + + +/* Remove entry from the list of allocated objects. */ + +static inline void TRK_free_buf(void* ptr, const char* file, const char* func, + u32 line) { + + u32 i, bucket; + + if (!ptr) return; + + bucket = TRKH(ptr); + + /* Find the element on the list... */ + + for (i = 0; i < TRK_cnt[bucket]; i++) + + if (TRK[bucket][i].ptr == ptr) { + + TRK[bucket][i].ptr = 0; + return; + + } + + WARNF("ALLOC: Attempt to free non-allocated memory in %s (%s:%u)", + func, file, line); + +} + + +/* Do a final report on all non-deallocated objects. */ + +static inline void TRK_report(void) { + + u32 i, bucket; + + fflush(0); + + for (bucket = 0; bucket < ALLOC_BUCKETS; bucket++) + for (i = 0; i < TRK_cnt[bucket]; i++) + if (TRK[bucket][i].ptr) + WARNF("ALLOC: Memory never freed, created in %s (%s:%u)", + TRK[bucket][i].func, TRK[bucket][i].file, TRK[bucket][i].line); + +} + + +/* Simple wrappers for non-debugging functions: */ + +static inline void* TRK_ck_alloc(u32 size, const char* file, const char* func, + u32 line) { + + void* ret = DFL_ck_alloc(size); + TRK_alloc_buf(ret, file, func, line); + return ret; + +} + + +static inline void* TRK_ck_realloc(void* orig, u32 size, const char* file, + const char* func, u32 line) { + + void* ret = DFL_ck_realloc(orig, size); + TRK_free_buf(orig, file, func, line); + TRK_alloc_buf(ret, file, func, line); + return ret; + +} + + +static inline void* TRK_ck_realloc_block(void* orig, u32 size, const char* file, + const char* func, u32 line) { + + void* ret = DFL_ck_realloc_block(orig, size); + TRK_free_buf(orig, file, func, line); + TRK_alloc_buf(ret, file, func, line); + return ret; + +} + + +static inline void* TRK_ck_strdup(u8* str, const char* file, const char* func, + u32 line) { + + void* ret = DFL_ck_strdup(str); + TRK_alloc_buf(ret, file, func, line); + return ret; + +} + + +static inline void* TRK_ck_memdup(void* mem, u32 size, const char* file, + const char* func, u32 line) { + + void* ret = DFL_ck_memdup(mem, size); + TRK_alloc_buf(ret, file, func, line); + return ret; + +} + + +static inline void* TRK_ck_memdup_str(void* mem, u32 size, const char* file, + const char* func, u32 line) { + + void* ret = DFL_ck_memdup_str(mem, size); + TRK_alloc_buf(ret, file, func, line); + return ret; + +} + + +static inline void TRK_ck_free(void* ptr, const char* file, + const char* func, u32 line) { + + TRK_free_buf(ptr, file, func, line); + DFL_ck_free(ptr); + +} + +/* Aliasing user-facing names to tracking functions: */ + +#define ck_alloc(_p1) \ + TRK_ck_alloc(_p1, __FILE__, __FUNCTION__, __LINE__) + +#define ck_alloc_nozero(_p1) \ + TRK_ck_alloc(_p1, __FILE__, __FUNCTION__, __LINE__) + +#define ck_realloc(_p1, _p2) \ + TRK_ck_realloc(_p1, _p2, __FILE__, __FUNCTION__, __LINE__) + +#define ck_realloc_block(_p1, _p2) \ + TRK_ck_realloc_block(_p1, _p2, __FILE__, __FUNCTION__, __LINE__) + +#define ck_strdup(_p1) \ + TRK_ck_strdup(_p1, __FILE__, __FUNCTION__, __LINE__) + +#define ck_memdup(_p1, _p2) \ + TRK_ck_memdup(_p1, _p2, __FILE__, __FUNCTION__, __LINE__) + +#define ck_memdup_str(_p1, _p2) \ + TRK_ck_memdup_str(_p1, _p2, __FILE__, __FUNCTION__, __LINE__) + +#define ck_free(_p1) \ + TRK_ck_free(_p1, __FILE__, __FUNCTION__, __LINE__) + +#endif /* ^!DEBUG_BUILD */ + +#endif /* ! _HAVE_ALLOC_INL_H */ \ No newline at end of file diff --git a/third_party/afl/config.h b/third_party/afl/config.h new file mode 100644 index 000000000..7ecaa3179 --- /dev/null +++ b/third_party/afl/config.h @@ -0,0 +1,350 @@ +/* + american fuzzy lop - vaguely configurable bits + ---------------------------------------------- + + Written and maintained by Michal Zalewski + + Copyright 2013, 2014, 2015, 2016 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + */ + +#ifndef _HAVE_CONFIG_H +#define _HAVE_CONFIG_H + +#include "types.h" + +/* Version string: */ + +#define VERSION "2.52b" + +/****************************************************** + * * + * Settings that may be of interest to power users: * + * * + ******************************************************/ + +/* Comment out to disable terminal colors (note that this makes afl-analyze + a lot less nice): */ + +#define USE_COLOR + +/* Comment out to disable fancy ANSI boxes and use poor man's 7-bit UI: */ + +#define FANCY_BOXES + +/* Default timeout for fuzzed code (milliseconds). This is the upper bound, + also used for detecting hangs; the actual value is auto-scaled: */ + +#define EXEC_TIMEOUT 1000 + +/* Timeout rounding factor when auto-scaling (milliseconds): */ + +#define EXEC_TM_ROUND 20 + +/* Default memory limit for child process (MB): */ + +#ifndef __x86_64__ +# define MEM_LIMIT 25 +#else +# define MEM_LIMIT 50 +#endif /* ^!__x86_64__ */ + +/* Default memory limit when running in QEMU mode (MB): */ + +#define MEM_LIMIT_QEMU 200 + +/* Number of calibration cycles per every new test case (and for test + cases that show variable behavior): */ + +#define CAL_CYCLES 8 +#define CAL_CYCLES_LONG 40 + +/* Number of subsequent timeouts before abandoning an input file: */ + +#define TMOUT_LIMIT 250 + +/* Maximum number of unique hangs or crashes to record: */ + +#define KEEP_UNIQUE_HANG 500 +#define KEEP_UNIQUE_CRASH 5000 + +/* Baseline number of random tweaks during a single 'havoc' stage: */ + +#define HAVOC_CYCLES 256 +#define HAVOC_CYCLES_INIT 1024 + +/* Maximum multiplier for the above (should be a power of two, beware + of 32-bit int overflows): */ + +#define HAVOC_MAX_MULT 16 + +/* Absolute minimum number of havoc cycles (after all adjustments): */ + +#define HAVOC_MIN 16 + +/* Maximum stacking for havoc-stage tweaks. The actual value is calculated + like this: + + n = random between 1 and HAVOC_STACK_POW2 + stacking = 2^n + + In other words, the default (n = 7) produces 2, 4, 8, 16, 32, 64, or + 128 stacked tweaks: */ + +#define HAVOC_STACK_POW2 7 + +/* Caps on block sizes for cloning and deletion operations. Each of these + ranges has a 33% probability of getting picked, except for the first + two cycles where smaller blocks are favored: */ + +#define HAVOC_BLK_SMALL 32 +#define HAVOC_BLK_MEDIUM 128 +#define HAVOC_BLK_LARGE 1500 + +/* Extra-large blocks, selected very rarely (<5% of the time): */ + +#define HAVOC_BLK_XL 32768 + +/* Probabilities of skipping non-favored entries in the queue, expressed as + percentages: */ + +#define SKIP_TO_NEW_PROB 99 /* ...when there are new, pending favorites */ +#define SKIP_NFAV_OLD_PROB 95 /* ...no new favs, cur entry already fuzzed */ +#define SKIP_NFAV_NEW_PROB 75 /* ...no new favs, cur entry not fuzzed yet */ + +/* Splicing cycle count: */ + +#define SPLICE_CYCLES 15 + +/* Nominal per-splice havoc cycle length: */ + +#define SPLICE_HAVOC 32 + +/* Maximum offset for integer addition / subtraction stages: */ + +#define ARITH_MAX 35 + +/* Limits for the test case trimmer. The absolute minimum chunk size; and + the starting and ending divisors for chopping up the input file: */ + +#define TRIM_MIN_BYTES 4 +#define TRIM_START_STEPS 16 +#define TRIM_END_STEPS 1024 + +/* Maximum size of input file, in bytes (keep under 100MB): */ + +#define MAX_FILE (1 * 1024 * 1024) + +/* The same, for the test case minimizer: */ + +#define TMIN_MAX_FILE (10 * 1024 * 1024) + +/* Block normalization steps for afl-tmin: */ + +#define TMIN_SET_MIN_SIZE 4 +#define TMIN_SET_STEPS 128 + +/* Maximum dictionary token size (-x), in bytes: */ + +#define MAX_DICT_FILE 128 + +/* Length limits for auto-detected dictionary tokens: */ + +#define MIN_AUTO_EXTRA 3 +#define MAX_AUTO_EXTRA 32 + +/* Maximum number of user-specified dictionary tokens to use in deterministic + steps; past this point, the "extras/user" step will be still carried out, + but with proportionally lower odds: */ + +#define MAX_DET_EXTRAS 200 + +/* Maximum number of auto-extracted dictionary tokens to actually use in fuzzing + (first value), and to keep in memory as candidates. The latter should be much + higher than the former. */ + +#define USE_AUTO_EXTRAS 50 +#define MAX_AUTO_EXTRAS (USE_AUTO_EXTRAS * 10) + +/* Scaling factor for the effector map used to skip some of the more + expensive deterministic steps. The actual divisor is set to + 2^EFF_MAP_SCALE2 bytes: */ + +#define EFF_MAP_SCALE2 3 + +/* Minimum input file length at which the effector logic kicks in: */ + +#define EFF_MIN_LEN 128 + +/* Maximum effector density past which everything is just fuzzed + unconditionally (%): */ + +#define EFF_MAX_PERC 90 + +/* UI refresh frequency (Hz): */ + +#define UI_TARGET_HZ 5 + +/* Fuzzer stats file and plot update intervals (sec): */ + +#define STATS_UPDATE_SEC 60 +#define PLOT_UPDATE_SEC 5 + +/* Smoothing divisor for CPU load and exec speed stats (1 - no smoothing). */ + +#define AVG_SMOOTHING 16 + +/* Sync interval (every n havoc cycles): */ + +#define SYNC_INTERVAL 5 + +/* Output directory reuse grace period (minutes): */ + +#define OUTPUT_GRACE 25 + +/* Uncomment to use simple file names (id_NNNNNN): */ + +// #define SIMPLE_FILES + +/* List of interesting values to use in fuzzing. */ + +#define INTERESTING_8 \ + -128, /* Overflow signed 8-bit when decremented */ \ + -1, /* */ \ + 0, /* */ \ + 1, /* */ \ + 16, /* One-off with common buffer size */ \ + 32, /* One-off with common buffer size */ \ + 64, /* One-off with common buffer size */ \ + 100, /* One-off with common buffer size */ \ + 127 /* Overflow signed 8-bit when incremented */ + +#define INTERESTING_16 \ + -32768, /* Overflow signed 16-bit when decremented */ \ + -129, /* Overflow signed 8-bit */ \ + 128, /* Overflow signed 8-bit */ \ + 255, /* Overflow unsig 8-bit when incremented */ \ + 256, /* Overflow unsig 8-bit */ \ + 512, /* One-off with common buffer size */ \ + 1000, /* One-off with common buffer size */ \ + 1024, /* One-off with common buffer size */ \ + 4096, /* One-off with common buffer size */ \ + 32767 /* Overflow signed 16-bit when incremented */ + +#define INTERESTING_32 \ + -2147483648LL, /* Overflow signed 32-bit when decremented */ \ + -100663046, /* Large negative number (endian-agnostic) */ \ + -32769, /* Overflow signed 16-bit */ \ + 32768, /* Overflow signed 16-bit */ \ + 65535, /* Overflow unsig 16-bit when incremented */ \ + 65536, /* Overflow unsig 16 bit */ \ + 100663045, /* Large positive number (endian-agnostic) */ \ + 2147483647 /* Overflow signed 32-bit when incremented */ + +/*********************************************************** + * * + * Really exotic stuff you probably don't want to touch: * + * * + ***********************************************************/ + +/* Call count interval between reseeding the libc PRNG from /dev/urandom: */ + +#define RESEED_RNG 10000 + +/* Maximum line length passed from GCC to 'as' and used for parsing + configuration files: */ + +#define MAX_LINE 8192 + +/* Environment variable used to pass SHM ID to the called program. */ + +#define SHM_ENV_VAR "__AFL_SHM_ID" + +/* Other less interesting, internal-only variables. */ + +#define CLANG_ENV_VAR "__AFL_CLANG_MODE" +#define AS_LOOP_ENV_VAR "__AFL_AS_LOOPCHECK" +#define PERSIST_ENV_VAR "__AFL_PERSISTENT" +#define DEFER_ENV_VAR "__AFL_DEFER_FORKSRV" + +/* In-code signatures for deferred and persistent mode. */ + +#define PERSIST_SIG "##SIG_AFL_PERSISTENT##" +#define DEFER_SIG "##SIG_AFL_DEFER_FORKSRV##" + +/* Distinctive bitmap signature used to indicate failed execution: */ + +#define EXEC_FAIL_SIG 0xfee1dead + +/* Distinctive exit code used to indicate MSAN trip condition: */ + +#define MSAN_ERROR 86 + +/* Designated file descriptors for forkserver commands (the application will + use FORKSRV_FD and FORKSRV_FD + 1): */ + +#define FORKSRV_FD 198 + +/* Fork server init timeout multiplier: we'll wait the user-selected + timeout plus this much for the fork server to spin up. */ + +#define FORK_WAIT_MULT 10 + +/* Calibration timeout adjustments, to be a bit more generous when resuming + fuzzing sessions or trying to calibrate already-added internal finds. + The first value is a percentage, the other is in milliseconds: */ + +#define CAL_TMOUT_PERC 125 +#define CAL_TMOUT_ADD 50 + +/* Number of chances to calibrate a case before giving up: */ + +#define CAL_CHANCES 3 + +/* Map size for the traced binary (2^MAP_SIZE_POW2). Must be greater than + 2; you probably want to keep it under 18 or so for performance reasons + (adjusting AFL_INST_RATIO when compiling is probably a better way to solve + problems with complex programs). You need to recompile the target binary + after changing this - otherwise, SEGVs may ensue. */ + +#define MAP_SIZE_POW2 16 +#define MAP_SIZE (1 << MAP_SIZE_POW2) + +/* Maximum allocator request size (keep well under INT_MAX): */ + +#define MAX_ALLOC 0x40000000 + +/* A made-up hashing seed: */ + +#define HASH_CONST 0xa5b35705 + +/* Constants for afl-gotcpu to control busy loop timing: */ + +#define CTEST_TARGET_MS 5000 +#define CTEST_CORE_TRG_MS 1000 +#define CTEST_BUSY_CYCLES (10 * 1000 * 1000) + +/* Uncomment this to use inferior block-coverage-based instrumentation. Note + that you need to recompile the target binary for this to have any effect: */ + +// #define COVERAGE_ONLY + +/* Uncomment this to ignore hit counts and output just one bit per tuple. + As with the previous setting, you will need to recompile the target + binary: */ + +// #define SKIP_COUNTS + +/* Uncomment this to use instrumentation data to record newly discovered paths, + but do not use them as seeds for fuzzing. This is useful for conveniently + measuring coverage that could be attained by a "dumb" fuzzing algorithm: */ + +// #define IGNORE_FINDS + +#endif /* ! _HAVE_CONFIG_H */ \ No newline at end of file diff --git a/third_party/afl/debug.h b/third_party/afl/debug.h new file mode 100644 index 000000000..61f627d9a --- /dev/null +++ b/third_party/afl/debug.h @@ -0,0 +1,251 @@ +/* + american fuzzy lop - debug / error handling macros + -------------------------------------------------- + + Written and maintained by Michal Zalewski + + Copyright 2013, 2014, 2015, 2016 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + */ + +#ifndef _HAVE_DEBUG_H +#define _HAVE_DEBUG_H + +#include + +#include "types.h" +#include "config.h" + +/******************* + * Terminal colors * + *******************/ + +#ifdef USE_COLOR + +# define cBLK "\x1b[0;30m" +# define cRED "\x1b[0;31m" +# define cGRN "\x1b[0;32m" +# define cBRN "\x1b[0;33m" +# define cBLU "\x1b[0;34m" +# define cMGN "\x1b[0;35m" +# define cCYA "\x1b[0;36m" +# define cLGR "\x1b[0;37m" +# define cGRA "\x1b[1;90m" +# define cLRD "\x1b[1;91m" +# define cLGN "\x1b[1;92m" +# define cYEL "\x1b[1;93m" +# define cLBL "\x1b[1;94m" +# define cPIN "\x1b[1;95m" +# define cLCY "\x1b[1;96m" +# define cBRI "\x1b[1;97m" +# define cRST "\x1b[0m" + +# define bgBLK "\x1b[40m" +# define bgRED "\x1b[41m" +# define bgGRN "\x1b[42m" +# define bgBRN "\x1b[43m" +# define bgBLU "\x1b[44m" +# define bgMGN "\x1b[45m" +# define bgCYA "\x1b[46m" +# define bgLGR "\x1b[47m" +# define bgGRA "\x1b[100m" +# define bgLRD "\x1b[101m" +# define bgLGN "\x1b[102m" +# define bgYEL "\x1b[103m" +# define bgLBL "\x1b[104m" +# define bgPIN "\x1b[105m" +# define bgLCY "\x1b[106m" +# define bgBRI "\x1b[107m" + +#else + +# define cBLK "" +# define cRED "" +# define cGRN "" +# define cBRN "" +# define cBLU "" +# define cMGN "" +# define cCYA "" +# define cLGR "" +# define cGRA "" +# define cLRD "" +# define cLGN "" +# define cYEL "" +# define cLBL "" +# define cPIN "" +# define cLCY "" +# define cBRI "" +# define cRST "" + +# define bgBLK "" +# define bgRED "" +# define bgGRN "" +# define bgBRN "" +# define bgBLU "" +# define bgMGN "" +# define bgCYA "" +# define bgLGR "" +# define bgGRA "" +# define bgLRD "" +# define bgLGN "" +# define bgYEL "" +# define bgLBL "" +# define bgPIN "" +# define bgLCY "" +# define bgBRI "" + +#endif /* ^USE_COLOR */ + +/************************* + * Box drawing sequences * + *************************/ + +#ifdef FANCY_BOXES + +# define SET_G1 "\x1b)0" /* Set G1 for box drawing */ +# define RESET_G1 "\x1b)B" /* Reset G1 to ASCII */ +# define bSTART "\x0e" /* Enter G1 drawing mode */ +# define bSTOP "\x0f" /* Leave G1 drawing mode */ +# define bH "q" /* Horizontal line */ +# define bV "x" /* Vertical line */ +# define bLT "l" /* Left top corner */ +# define bRT "k" /* Right top corner */ +# define bLB "m" /* Left bottom corner */ +# define bRB "j" /* Right bottom corner */ +# define bX "n" /* Cross */ +# define bVR "t" /* Vertical, branch right */ +# define bVL "u" /* Vertical, branch left */ +# define bHT "v" /* Horizontal, branch top */ +# define bHB "w" /* Horizontal, branch bottom */ + +#else + +# define SET_G1 "" +# define RESET_G1 "" +# define bSTART "" +# define bSTOP "" +# define bH "-" +# define bV "|" +# define bLT "+" +# define bRT "+" +# define bLB "+" +# define bRB "+" +# define bX "+" +# define bVR "+" +# define bVL "+" +# define bHT "+" +# define bHB "+" + +#endif /* ^FANCY_BOXES */ + +/*********************** + * Misc terminal codes * + ***********************/ + +#define TERM_HOME "\x1b[H" +#define TERM_CLEAR TERM_HOME "\x1b[2J" +#define cEOL "\x1b[0K" +#define CURSOR_HIDE "\x1b[?25l" +#define CURSOR_SHOW "\x1b[?25h" + +/************************ + * Debug & error macros * + ************************/ + +/* Just print stuff to the appropriate stream. */ + +#ifdef MESSAGES_TO_STDOUT +# define SAYF(x...) printf(x) +#else +# define SAYF(x...) fprintf(stderr, x) +#endif /* ^MESSAGES_TO_STDOUT */ + +/* Show a prefixed warning. */ + +#define WARNF(x...) do { \ + SAYF(cYEL "[!] " cBRI "WARNING: " cRST x); \ + SAYF(cRST "\n"); \ + } while (0) + +/* Show a prefixed "doing something" message. */ + +#define ACTF(x...) do { \ + SAYF(cLBL "[*] " cRST x); \ + SAYF(cRST "\n"); \ + } while (0) + +/* Show a prefixed "success" message. */ + +#define OKF(x...) do { \ + SAYF(cLGN "[+] " cRST x); \ + SAYF(cRST "\n"); \ + } while (0) + +/* Show a prefixed fatal error message (not used in afl). */ + +#define BADF(x...) do { \ + SAYF(cLRD "\n[-] " cRST x); \ + SAYF(cRST "\n"); \ + } while (0) + +/* Die with a verbose non-OS fatal error message. */ + +#define FATAL(x...) do { \ + SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD "\n[-] PROGRAM ABORT : " \ + cBRI x); \ + SAYF(cLRD "\n Location : " cRST "%s(), %s:%u\n\n", \ + __FUNCTION__, __FILE__, __LINE__); \ + exit(1); \ + } while (0) + +/* Die by calling abort() to provide a core dump. */ + +#define ABORT(x...) do { \ + SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD "\n[-] PROGRAM ABORT : " \ + cBRI x); \ + SAYF(cLRD "\n Stop location : " cRST "%s(), %s:%u\n\n", \ + __FUNCTION__, __FILE__, __LINE__); \ + abort(); \ + } while (0) + +/* Die while also including the output of perror(). */ + +#define PFATAL(x...) do { \ + fflush(stdout); \ + SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD "\n[-] SYSTEM ERROR : " \ + cBRI x); \ + SAYF(cLRD "\n Stop location : " cRST "%s(), %s:%u\n", \ + __FUNCTION__, __FILE__, __LINE__); \ + SAYF(cLRD " OS message : " cRST "%s\n", strerror(errno)); \ + exit(1); \ + } while (0) + +/* Die with FAULT() or PFAULT() depending on the value of res (used to + interpret different failure modes for read(), write(), etc). */ + +#define RPFATAL(res, x...) do { \ + if (res < 0) PFATAL(x); else FATAL(x); \ + } while (0) + +/* Error-checking versions of read() and write() that call RPFATAL() as + appropriate. */ + +#define ck_write(fd, buf, len, fn) do { \ + u32 _len = (len); \ + s32 _res = write(fd, buf, _len); \ + if (_res != _len) RPFATAL(_res, "Short write to %s", fn); \ + } while (0) + +#define ck_read(fd, buf, len, fn) do { \ + u32 _len = (len); \ + s32 _res = read(fd, buf, _len); \ + if (_res != _len) RPFATAL(_res, "Short read from %s", fn); \ + } while (0) + +#endif /* ! _HAVE_DEBUG_H */ \ No newline at end of file diff --git a/third_party/afl/hash.h b/third_party/afl/hash.h new file mode 100644 index 000000000..b99362c42 --- /dev/null +++ b/third_party/afl/hash.h @@ -0,0 +1,104 @@ +/* + american fuzzy lop - hashing function + ------------------------------------- + + The hash32() function is a variant of MurmurHash3, a good + non-cryptosafe hashing function developed by Austin Appleby. + + For simplicity, this variant does *NOT* accept buffer lengths + that are not divisible by 8 bytes. The 32-bit version is otherwise + similar to the original; the 64-bit one is a custom hack with + mostly-unproven properties. + + Austin's original code is public domain. + + Other code written and maintained by Michal Zalewski + + Copyright 2016 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + */ + +#ifndef _HAVE_HASH_H +#define _HAVE_HASH_H + +#include "types.h" + +#ifdef __x86_64__ + +#define ROL64(_x, _r) ((((u64)(_x)) << (_r)) | (((u64)(_x)) >> (64 - (_r)))) + +static inline u32 hash32(const void* key, u32 len, u32 seed) { + + const u64* data = (u64*)key; + u64 h1 = seed ^ len; + + len >>= 3; + + while (len--) { + + u64 k1 = *data++; + + k1 *= 0x87c37b91114253d5ULL; + k1 = ROL64(k1, 31); + k1 *= 0x4cf5ad432745937fULL; + + h1 ^= k1; + h1 = ROL64(h1, 27); + h1 = h1 * 5 + 0x52dce729; + + } + + h1 ^= h1 >> 33; + h1 *= 0xff51afd7ed558ccdULL; + h1 ^= h1 >> 33; + h1 *= 0xc4ceb9fe1a85ec53ULL; + h1 ^= h1 >> 33; + + return h1; + +} + +#else + +#define ROL32(_x, _r) ((((u32)(_x)) << (_r)) | (((u32)(_x)) >> (32 - (_r)))) + +static inline u32 hash32(const void* key, u32 len, u32 seed) { + + const u32* data = (u32*)key; + u32 h1 = seed ^ len; + + len >>= 2; + + while (len--) { + + u32 k1 = *data++; + + k1 *= 0xcc9e2d51; + k1 = ROL32(k1, 15); + k1 *= 0x1b873593; + + h1 ^= k1; + h1 = ROL32(h1, 13); + h1 = h1 * 5 + 0xe6546b64; + + } + + h1 ^= h1 >> 16; + h1 *= 0x85ebca6b; + h1 ^= h1 >> 13; + h1 *= 0xc2b2ae35; + h1 ^= h1 >> 16; + + return h1; + +} + +#endif /* ^__x86_64__ */ + +#endif /* !_HAVE_HASH_H */ \ No newline at end of file diff --git a/third_party/afl/llvm_mode/afl-llvm-rt.o.c b/third_party/afl/llvm_mode/afl-llvm-rt.o.c new file mode 100644 index 000000000..2c83b954f --- /dev/null +++ b/third_party/afl/llvm_mode/afl-llvm-rt.o.c @@ -0,0 +1,306 @@ +/* + american fuzzy lop - LLVM instrumentation bootstrap + --------------------------------------------------- + + Written by Laszlo Szekeres and + Michal Zalewski + + LLVM integration design comes from Laszlo Szekeres. + + Copyright 2015, 2016 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + This code is the rewrite of afl-as.h's main_payload. + +*/ + +#include "../config.h" +#include "../types.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* This is a somewhat ugly hack for the experimental 'trace-pc-guard' mode. + Basically, we need to make sure that the forkserver is initialized after + the LLVM-generated runtime initialization pass, not before. */ + +#ifdef USE_TRACE_PC +# define CONST_PRIO 5 +#else +# define CONST_PRIO 0 +#endif /* ^USE_TRACE_PC */ + + +/* Globals needed by the injected instrumentation. The __afl_area_initial region + is used for instrumentation output before __afl_map_shm() has a chance to run. + It will end up as .comm, so it shouldn't be too wasteful. */ + +u8 __afl_area_initial[MAP_SIZE]; +u8* __afl_area_ptr = __afl_area_initial; + +__thread u32 __afl_prev_loc; + + +/* Running in persistent mode? */ + +static u8 is_persistent; + + +/* SHM setup. */ + +static void __afl_map_shm(void) { + + u8 *id_str = getenv(SHM_ENV_VAR); + + /* If we're running under AFL, attach to the appropriate region, replacing the + early-stage __afl_area_initial region that is needed to allow some really + hacky .init code to work correctly in projects such as OpenSSL. */ + + if (id_str) { + + u32 shm_id = atoi(id_str); + + __afl_area_ptr = shmat(shm_id, NULL, 0); + + /* Whooooops. */ + + if (__afl_area_ptr == (void *)-1) _exit(1); + + /* Write something into the bitmap so that even with low AFL_INST_RATIO, + our parent doesn't give up on us. */ + + __afl_area_ptr[0] = 1; + + } + +} + + +/* Fork server logic. */ + +static void __afl_start_forkserver(void) { + + static u8 tmp[4]; + s32 child_pid; + + u8 child_stopped = 0; + + /* Phone home and tell the parent that we're OK. If parent isn't there, + assume we're not running in forkserver mode and just execute program. */ + + if (write(FORKSRV_FD + 1, tmp, 4) != 4) return; + + while (1) { + + u32 was_killed; + int status; + + /* Wait for parent by reading from the pipe. Abort if read fails. */ + + if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1); + + /* If we stopped the child in persistent mode, but there was a race + condition and afl-fuzz already issued SIGKILL, write off the old + process. */ + + if (child_stopped && was_killed) { + child_stopped = 0; + if (waitpid(child_pid, &status, 0) < 0) _exit(1); + } + + if (!child_stopped) { + + /* Once woken up, create a clone of our process. */ + + child_pid = fork(); + if (child_pid < 0) _exit(1); + + /* In child process: close fds, resume execution. */ + + if (!child_pid) { + + close(FORKSRV_FD); + close(FORKSRV_FD + 1); + return; + + } + + } else { + + /* Special handling for persistent mode: if the child is alive but + currently stopped, simply restart it with SIGCONT. */ + + kill(child_pid, SIGCONT); + child_stopped = 0; + + } + + /* In parent process: write PID to pipe, then wait for child. */ + + if (write(FORKSRV_FD + 1, &child_pid, 4) != 4) _exit(1); + + if (waitpid(child_pid, &status, is_persistent ? WUNTRACED : 0) < 0) + _exit(1); + + /* In persistent mode, the child stops itself with SIGSTOP to indicate + a successful run. In this case, we want to wake it up without forking + again. */ + + if (WIFSTOPPED(status)) child_stopped = 1; + + /* Relay wait status to pipe, then loop back. */ + + if (write(FORKSRV_FD + 1, &status, 4) != 4) _exit(1); + + } + +} + + +/* A simplified persistent mode handler, used as explained in README.llvm. */ + +int __afl_persistent_loop(unsigned int max_cnt) { + + static u8 first_pass = 1; + static u32 cycle_cnt; + + if (first_pass) { + + /* Make sure that every iteration of __AFL_LOOP() starts with a clean slate. + On subsequent calls, the parent will take care of that, but on the first + iteration, it's our job to erase any trace of whatever happened + before the loop. */ + + if (is_persistent) { + + memset(__afl_area_ptr, 0, MAP_SIZE); + __afl_area_ptr[0] = 1; + __afl_prev_loc = 0; + } + + cycle_cnt = max_cnt; + first_pass = 0; + return 1; + + } + + if (is_persistent) { + + if (--cycle_cnt) { + + raise(SIGSTOP); + + __afl_area_ptr[0] = 1; + __afl_prev_loc = 0; + + return 1; + + } else { + + /* When exiting __AFL_LOOP(), make sure that the subsequent code that + follows the loop is not traced. We do that by pivoting back to the + dummy output region. */ + + __afl_area_ptr = __afl_area_initial; + + } + + } + + return 0; + +} + + +/* This one can be called from user code when deferred forkserver mode + is enabled. */ + +void __afl_manual_init(void) { + + static u8 init_done; + + if (!init_done) { + + __afl_map_shm(); + __afl_start_forkserver(); + init_done = 1; + + } + +} + + +/* Proper initialization routine. */ + +__attribute__((constructor(CONST_PRIO))) void __afl_auto_init(void) { + + is_persistent = !!getenv(PERSIST_ENV_VAR); + + if (getenv(DEFER_ENV_VAR)) return; + + __afl_manual_init(); + +} + + +/* The following stuff deals with supporting -fsanitize-coverage=trace-pc-guard. + It remains non-operational in the traditional, plugin-backed LLVM mode. + For more info about 'trace-pc-guard', see README.llvm. + + The first function (__sanitizer_cov_trace_pc_guard) is called back on every + edge (as opposed to every basic block). */ + +void __sanitizer_cov_trace_pc_guard(uint32_t* guard) { + __afl_area_ptr[*guard]++; +} + + +/* Init callback. Populates instrumentation IDs. Note that we're using + ID of 0 as a special value to indicate non-instrumented bits. That may + still touch the bitmap, but in a fairly harmless way. */ + +void __sanitizer_cov_trace_pc_guard_init(uint32_t* start, uint32_t* stop) { + + u32 inst_ratio = 100; + u8* x; + + if (start == stop || *start) return; + + x = getenv("AFL_INST_RATIO"); + if (x) inst_ratio = atoi(x); + + if (!inst_ratio || inst_ratio > 100) { + fprintf(stderr, "[-] ERROR: Invalid AFL_INST_RATIO (must be 1-100).\n"); + abort(); + } + + /* Make sure that the first element in the range is always set - we use that + to avoid duplicate calls (which can happen as an artifact of the underlying + implementation in LLVM). */ + + *(start++) = R(MAP_SIZE - 1) + 1; + + while (start < stop) { + + if (R(100) < inst_ratio) *start = R(MAP_SIZE - 1) + 1; + else *start = 0; + + start++; + + } + +} \ No newline at end of file diff --git a/third_party/afl/types.h b/third_party/afl/types.h new file mode 100644 index 000000000..3e2af4b9b --- /dev/null +++ b/third_party/afl/types.h @@ -0,0 +1,86 @@ +/* + american fuzzy lop - type definitions and minor macros + ------------------------------------------------------ + + Written and maintained by Michal Zalewski + + Copyright 2013, 2014, 2015 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + */ + +#ifndef _HAVE_TYPES_H +#define _HAVE_TYPES_H + +#include +#include + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; + +/* + + Ugh. There is an unintended compiler / glibc #include glitch caused by + combining the u64 type an %llu in format strings, necessitating a workaround. + + In essence, the compiler is always looking for 'unsigned long long' for %llu. + On 32-bit systems, the u64 type (aliased to uint64_t) is expanded to + 'unsigned long long' in , so everything checks out. + + But on 64-bit systems, it is #ifdef'ed in the same file as 'unsigned long'. + Now, it only happens in circumstances where the type happens to have the + expected bit width, *but* the compiler does not know that... and complains + about 'unsigned long' being unsafe to pass to %llu. + + */ + +#ifdef __x86_64__ +typedef unsigned long long u64; +#else +typedef uint64_t u64; +#endif /* ^__x86_64__ */ + +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef int64_t s64; + +#ifndef MIN +# define MIN(_a,_b) ((_a) > (_b) ? (_b) : (_a)) +# define MAX(_a,_b) ((_a) > (_b) ? (_a) : (_b)) +#endif /* !MIN */ + +#define SWAP16(_x) ({ \ + u16 _ret = (_x); \ + (u16)((_ret << 8) | (_ret >> 8)); \ + }) + +#define SWAP32(_x) ({ \ + u32 _ret = (_x); \ + (u32)((_ret << 24) | (_ret >> 24) | \ + ((_ret << 8) & 0x00FF0000) | \ + ((_ret >> 8) & 0x0000FF00)); \ + }) + +#ifdef AFL_LLVM_PASS +# define AFL_R(x) (random() % (x)) +#else +# define R(x) (random() % (x)) +#endif /* ^AFL_LLVM_PASS */ + +#define STRINGIFY_INTERNAL(x) #x +#define STRINGIFY(x) STRINGIFY_INTERNAL(x) + +#define MEM_BARRIER() \ + __asm__ volatile("" ::: "memory") + +#define likely(_x) __builtin_expect(!!(_x), 1) +#define unlikely(_x) __builtin_expect(!!(_x), 0) + +#endif /* ! _HAVE_TYPES_H */ \ No newline at end of file diff --git a/tools/BUILD.bazel b/tools/BUILD.bazel index 9d06478ca..9f1d84395 100644 --- a/tools/BUILD.bazel +++ b/tools/BUILD.bazel @@ -11,12 +11,6 @@ alias( visibility = ["//visibility:public"], ) -sh_binary( - name = "fuzzit_wrapper", - srcs = ["fuzzit_wrapper.sh"], - data = ["@fuzzit_linux//:fuzzit"], -) - sh_binary( name = "fuzz_wrapper", srcs = ["fuzz_wrapper.sh"], diff --git a/tools/fuzzit_wrapper.sh b/tools/fuzzit_wrapper.sh deleted file mode 100755 index 2e6a213f4..000000000 --- a/tools/fuzzit_wrapper.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash - -set -e - -# run fuzzing regression or upload to Fuzzit for long running fuzzing job depending on whether FUZZIT_API_KEY is set - -FUZZIT="${TEST_SRCDIR}/fuzzit_linux/fuzzit" - -FUZZER_BINARY=$1 -FUZZIT_TARGET_NAME="$(basename $1 | sed -e s/_fuzz_test_with_libfuzzer$// -e s/_/-/g)" - -if [[ ! -z "${FUZZIT_API_KEY}" ]]; then - "${FUZZIT}" create target --skip-if-exists --public-corpus prysmaticlabs-gh/"${FUZZIT_TARGET_NAME}" - - # Run fuzzing first so this is not affected by local-regression timeout - "${FUZZIT}" create job --skip-if-not-exists --host "${PRYSM_BUILD_IMAGE}" --type fuzzing prysmaticlabs-gh/"${FUZZIT_TARGET_NAME}" "${FUZZER_BINARY}" -fi - -"${FUZZIT}" create job --skip-if-not-exists --host "${PRYSM_BUILD_IMAGE}" --type local-regression prysmaticlabs-gh/"${FUZZIT_TARGET_NAME}" "${FUZZER_BINARY}" diff --git a/tools/go/def.bzl b/tools/go/def.bzl index 66895ab38..0d1271f3e 100644 --- a/tools/go/def.bzl +++ b/tools/go/def.bzl @@ -8,7 +8,7 @@ def go_library(name, **kwargs): go_goopts = kwargs["gc_goopts"] gc_goopts += select({ - "@prysm//tools/go:libfuzz_enabled": ["-d=libfuzzer"], + "@prysm//tools/go:libfuzz_enabled": ["-d=libfuzzer,checkptr"], "//conditions:default": [], }) diff --git a/tools/go/fuzz.bzl b/tools/go/fuzz.bzl index 44e6f8091..d905e44ef 100644 --- a/tools/go/fuzz.bzl +++ b/tools/go/fuzz.bzl @@ -38,7 +38,7 @@ func main() { def _gen_fuzz_main_impl(ctx): if ctx.var.get("gotags") != "libfuzzer": fail("gotags must be set to libfuzzer. Use --config=fuzz or --config=fuzzit.") - if ctx.var.get("gc_goopts") != "-d=libfuzzer": + if "libfuzzer" not in ctx.var.get("gc_goopts"): fail("gc_goopts must be set to -d=libfuzzer. Use --config=fuzz or --config=fuzzit.") pkg = ctx.attr.target_pkg @@ -57,6 +57,40 @@ gen_fuzz_main = rule( }, ) +fuzzer_options_tpl = """[libfuzzer] +max_len=%d +""" + +def _generate_libfuzzer_config(ctx): + output_file_name = ctx.label.name + ".options" + output = fuzzer_options_tpl % ( + ctx.attr.max_len, + ) + output_file = ctx.actions.declare_file(output_file_name) + ctx.actions.write(output_file, output) + return [DefaultInfo(files = depset([output_file]))] + +gen_libfuzzer_config = rule( + implementation = _generate_libfuzzer_config, + attrs = { + "max_len": attr.int(default = 0), + }, +) + +def _upload_to_gcp_impl(ctx): + return [ + DefaultInfo(), + ] + +upload_to_gcp = rule( + implementation = _upload_to_gcp_impl, + attrs = { + "gcp_bucket": attr.string(mandatory = True), + "libfuzzer_bundle": attr.label(mandatory = True), + "afl_bundle": attr.label(mandatory = True), + }, +) + def go_fuzz_test( name, corpus, @@ -64,7 +98,8 @@ def go_fuzz_test( importpath, func = "Fuzz", repository = "", - input_size = 0, + max_len = 0, + gcp_bucket = "gs://builds.prysmaticlabs.appspot.com", size = "medium", tags = [], **kwargs): @@ -85,6 +120,10 @@ def go_fuzz_test( testonly = 1, visibility = ["//visibility:private"], ) + gen_libfuzzer_config( + name = name + "_options", + max_len = max_len, + ) go_binary( name = name + "_binary", srcs = [name + "_libfuzz_main"], @@ -117,13 +156,44 @@ def go_fuzz_test( corpus_name = corpus additional_args = [] - if input_size > 0: - additional_args += ["-max_len=%s" % input_size] + if max_len > 0: + additional_args += ["-max_len=%s" % max_len] + + native.cc_test( + name = name + "_with_afl", + linkopts = [ + "-fsanitize=address", + "-fsanitize-coverage=trace-pc-guard", + ], + linkstatic = 1, + testonly = 1, + srcs = [":" + name], + deps = [ + "@herumi_bls_eth_go_binary//:lib", + "//third_party/afl:fuzzing_engine", + ], + tags = ["manual", "fuzzer"] + tags, + ) + + native.genrule( + name = name + "_afl_bundle", + outs = [name + "_afl_bundle.zip"], + srcs = [ + "//third_party/afl:libs", + ":" + name + "_with_afl", + ], + cmd = "cp $(location :" + name + "_with_afl) fuzzer; $(location @bazel_tools//tools/zip:zipper) cf $@ $(locations //third_party/afl:libs) fuzzer", + tools = [ + "@bazel_tools//tools/zip:zipper", + ], + testonly = 1, + tags = ["manual"] + tags, + ) native.cc_test( name = name + "_with_libfuzzer", linkopts = ["-fsanitize=fuzzer,address"], - copts = ["-fsantize=fuzzer,address"], + copts = ["-fsanitize=fuzzer,address"], linkstatic = 1, testonly = 1, srcs = [":" + name], @@ -138,3 +208,26 @@ def go_fuzz_test( data = [corpus_name], timeout = "eternal", ) + + native.genrule( + name = name + "_libfuzzer_bundle", + outs = [name + "_libfuzzer_bundle.zip"], + srcs = [ + ":" + name + "_with_libfuzzer", + ":" + name + "_options", + ], + cmd = "cp $(location :" + name + "_with_libfuzzer) fuzzer; " + + "cp $(location :" + name + "_options) fuzzer.options; " + + "$(location @bazel_tools//tools/zip:zipper) cf $@ fuzzer fuzzer.options", + tools = ["@bazel_tools//tools/zip:zipper"], + testonly = 1, + tags = ["manual"] + tags, + ) + + upload_to_gcp( + name = name + "_uploader", + gcp_bucket = gcp_bucket, + afl_bundle = ":" + name + "_afl_bundle", + libfuzzer_bundle = ":" + name + "_libfuzzer_bundle", + tags = ["manual"] + tags, + )