make+scripts+docs: update fuzzing script and make fuzz

This commit is contained in:
Conner 2022-08-21 20:28:12 -04:00 committed by Matt Morehouse
parent 404e18afab
commit 25a7bb8b86
No known key found for this signature in database
GPG Key ID: CC8ECA224831C982
4 changed files with 39 additions and 109 deletions

View File

@ -6,17 +6,12 @@ TOOLS_DIR := tools
BTCD_PKG := github.com/btcsuite/btcd
GOACC_PKG := github.com/ory/go-acc
GOIMPORTS_PKG := github.com/rinchsan/gosimports/cmd/gosimports
GOFUZZ_BUILD_PKG := github.com/dvyukov/go-fuzz/go-fuzz-build
GOFUZZ_PKG := github.com/dvyukov/go-fuzz/go-fuzz
GOFUZZ_DEP_PKG := github.com/dvyukov/go-fuzz/go-fuzz-dep
GO_BIN := ${GOPATH}/bin
BTCD_BIN := $(GO_BIN)/btcd
GOIMPORTS_BIN := $(GO_BIN)/gosimports
GOMOBILE_BIN := GO111MODULE=off $(GO_BIN)/gomobile
GOACC_BIN := $(GO_BIN)/go-acc
GOFUZZ_BUILD_BIN := $(GO_BIN)/go-fuzz-build
GOFUZZ_BIN := $(GO_BIN)/go-fuzz
MOBILE_BUILD_DIR :=${GOPATH}/src/$(MOBILE_PKG)/build
IOS_BUILD_DIR := $(MOBILE_BUILD_DIR)/ios
@ -232,13 +227,10 @@ flakehunter-parallel:
# =============
# FUZZING
# =============
fuzz-build: $(GOFUZZ_BUILD_BIN) $(GOFUZZ_DEP_BIN)
@$(call print, "Creating fuzz harnesses for packages '$(FUZZPKG)'.")
scripts/fuzz.sh build "$(FUZZPKG)"
fuzz-run: $(GOFUZZ_BIN)
fuzz: $(GOFUZZ_BIN)
@$(call print, "Fuzzing packages '$(FUZZPKG)'.")
scripts/fuzz.sh run "$(FUZZPKG)" "$(FUZZ_TEST_RUN_TIME)" "$(FUZZ_TEST_TIMEOUT)" "$(FUZZ_NUM_PROCESSES)" "$(FUZZ_BASE_WORKDIR)"
scripts/fuzz.sh run "$(FUZZPKG)" "$(FUZZ_TEST_RUN_TIME)" "$(FUZZ_NUM_PROCESSES)"
# =========
# UTILITIES

View File

@ -1,43 +1,40 @@
# Fuzzing LND #
The `fuzz` package is organized into subpackages which are named after the `lnd` package they test. Each subpackage has its own set of fuzz targets.
## Setup and Installation ##
This section will cover setup and installation of the fuzzing binaries.
* The following is a command to build all fuzzing harnesses:
The following runs all fuzz tests on default settings:
```shell
$ make fuzz-build
$ make fuzz
```
* This may take a while since this will create zip files associated with each fuzzing target.
* The following is a command to run all fuzzing harnesses for 30 seconds:
The following runs all fuzz tests inside the lnwire package, each for a total of 1 minute, using 4 procs.
It is recommended that processes be set to the number of processor cores in the system:
```shell
$ make fuzz-run
$ make fuzz pkg=lnwire fuzztime=1m parallel=4
```
Alternatively, individual fuzz tests can be ran manually by setting the working directory to the location of the .go file holding the fuzz tests.
The go test command can only test one fuzz test at a time:
```shell
$ cd lnwire
$ go test -fuzz=FuzzAcceptChannel -fuzztime=1m -parallel=4
```
The following can be used to show all fuzz tests in the working directory:
```shell
$ cd lnwire
$ go test -list=Fuzz.*
```
`go-fuzz` will print out log lines every couple of seconds. Example output:
```text
2017/09/19 17:44:23 workers: 8, corpus: 23 (3s ago), crashers: 1, restarts: 1/748, execs: 400690 (16694/sec), cover: 394, uptime: 24s
Fuzz tests can be ran as normal tests, which only runs the seed corpus:
```shell
$ cd lnwire
$ go test -run=FuzzAcceptChannel -parallel=4
```
Corpus is the number of items in the corpus. `go-fuzz` may add valid inputs to
the corpus in an attempt to gain more coverage. Crashers is the number of inputs
resulting in a crash. The inputs, and their outputs are logged by default in:
`fuzz/<package>/<harness>/crashers`. `go-fuzz` also creates a `suppressions` directory
of stacktraces to ignore so that it doesn't create duplicate stacktraces.
Cover is a number representing edge coverage of the program being fuzzed.
The generated corpus values can be found in the $(go env GOCACHE)/fuzz directory.
## Options ##
Several parameters can be appended to the end of the make commands to tune the build process or the way the fuzzer runs.
- `run_time` specifies how long each fuzz harness runs for. The default is 30 seconds.
- `timeout` specifies how long an individual testcase can run before raising an error. The default is 20 seconds.
- `processes` specifies the number of parallel processes to use while running the harnesses.
- `pkg` specifies the `lnd` packages to build or fuzz. The default is to build and run all available packages (`brontide lnwire wtwire zpay32`). This can be changed to build/run against individual packages.
- `base_workdir` specifies the workspace of the fuzzer. This folder will contain the corpus, crashers, and suppressions.
- `fuzztime` specifies how long each fuzz test runs for, corresponding to the `go test -fuzztime` option. The default is 30s.
- `parallel` specifies the number of parallel processes to use while running the harnesses, corresponding to the `go test -parallel` option.
- `pkg` specifies the `lnd` packages to build or fuzz. The default is to build and run all available packages (`brontide lnwire watchtower/wtwire zpay32`). This can be changed to build/run against individual packages.
## Corpus ##
Fuzzing generally works best with a corpus that is of minimal size while achieving the maximum coverage. `go-fuzz` automatically minimizes the corpus in-memory before fuzzing so a large corpus shouldn't make a difference.
Fuzzing generally works best with a corpus that is of minimal size while achieving the maximum coverage.
## Disclosure ##
If you find any crashers that affect LND security, please disclose with the information found [here](https://github.com/lightningnetwork/lnd/#security).

View File

@ -1,8 +1,6 @@
FUZZPKG = brontide lnwire wtwire zpay32
FUZZ_TEST_RUN_TIME = 30
FUZZ_TEST_TIMEOUT = 20
FUZZPKG = brontide lnwire watchtower/wtwire zpay32
FUZZ_TEST_RUN_TIME = 30s
FUZZ_NUM_PROCESSES = 4
FUZZ_BASE_WORKDIR = $(shell pwd)/fuzz
# If specific package is being fuzzed, construct the full name of the
# subpackage.
@ -12,23 +10,12 @@ endif
# The default run time per fuzz test is pretty low and normally will be
# overwritten by a user depending on the time they have available.
ifneq ($(run_time),)
FUZZ_TEST_RUN_TIME := $(run_time)
endif
# If the timeout needs to be increased, overwrite the default value.
ifneq ($(timeout),)
FUZZ_TEST_TIMEOUT := $(timeout)
ifneq ($(fuzztime),)
FUZZ_TEST_RUN_TIME := $(fuzztime)
endif
# Overwrites the number of parallel processes. Should be set to the number of
# processor cores in a system.
ifneq ($(processes),)
FUZZ_NUM_PROCESSES := $(processes)
endif
# Overwrite the base work directory for the fuzz run. Can be used to supply any
# previously generated corpus.
ifneq ($(base_workdir),)
FUZZ_BASE_WORKDIR := $(base_workdir)
ifneq ($(parallel),)
FUZZ_NUM_PROCESSES := $(parallel)
endif

View File

@ -2,58 +2,17 @@
set -e
function build_fuzz() {
PACKAGES=$1
for pkg in $PACKAGES; do
pushd fuzz/$pkg
for file in *.go; do
if [[ "$file" == "fuzz_utils.go" ]]; then
continue
fi
NAME=$(echo $file | sed 's/\.go$//1')
echo "Building zip file for $pkg/$NAME"
go-fuzz-build -func "Fuzz_$NAME" -o "$pkg-$NAME-fuzz.zip" "github.com/lightningnetwork/lnd/fuzz/$pkg"
done
popd
done
}
# timeout is a cross platform alternative to the GNU timeout command that
# unfortunately isn't available on macOS by default.
timeout() {
time=$1
$2 &
pid=$!
sleep $time
kill -s SIGINT $pid
}
function run_fuzz() {
PACKAGES=$1
RUN_TIME=$2
TIMEOUT=$3
PROCS=$4
BASE_WORKDIR=$5
NUM_WORKERS=$3
for pkg in $PACKAGES; do
pushd fuzz/$pkg
pushd $pkg
for file in *.go; do
if [[ "$file" == "fuzz_utils.go" ]]; then
continue
fi
NAME=$(echo $file | sed 's/\.go$//1')
WORKDIR=$BASE_WORKDIR/$pkg/$NAME
mkdir -p $WORKDIR
echo "Running fuzzer $pkg-$NAME-fuzz.zip with $PROCS processors for $RUN_TIME seconds"
COMMAND="go-fuzz -bin=$pkg-$NAME-fuzz.zip -workdir=$WORKDIR -procs=$PROCS -timeout=$TIMEOUT"
echo "$COMMAND"
timeout "$RUN_TIME" "$COMMAND"
go test -list=Fuzz.* | grep Fuzz | while read line; do
echo ----- Fuzz testing $pkg:$line for $2 with $3 workers -----
go test -fuzz=^$line\$ -fuzztime=$2 -parallel=$3
done
popd
@ -63,8 +22,7 @@ function run_fuzz() {
# usage prints the usage of the whole script.
function usage() {
echo "Usage: "
echo "fuzz.sh build <packages>"
echo "fuzz.sh run <packages> <run_time> <timeout>"
echo "fuzz.sh run <packages> <run_time>"
}
# Extract the sub command and remove it from the list of parameters by shifting
@ -75,10 +33,6 @@ shift
# Call the function corresponding to the specified sub command or print the
# usage if the sub command was not found.
case $SUBCOMMAND in
build)
echo "Building fuzz packages"
build_fuzz "$@"
;;
run)
echo "Running fuzzer"
run_fuzz "$@"