Generating inputs to a program in the fuzzing target
Fuzzing provides automated testing where a fuzzing engine continuously generates inputs to a program in the fuzzing target. The fuzzing feature of Go supports several built-in types.
With fuzzing, random data is run against your test to find issues such as bugs, vulnerabilities, or crash-causing inputs. For example, some examples of vulnerabilities that can be found by fuzzing are SQL injection, buffer overflow, denial of service, and cross-site scripting attacks.
In the unit test, you must add each input to the test. Fuzzing comes up with inputs for your code so that you can generate more input with less work.
Example
Before the testing begins, you need to create two files go.mod and fz_test.go. Here is a module example: module example/fuzz/go 1.18. The following example shows how to perform testing using fuzzing.
package main
import (
"fmt"
"hash/crc32"
"testing"
)
func Foo(d1 string, d2 []byte) (err error) {
crc32a := crc32.MakeTable(0x235312AB)
crc32b := crc32.MakeTable(0xC342f421)
a := crc32.Checksum([]byte(d1), crc32a)
b := crc32.Checksum(d2, crc32b)
if len(d1) > 4 && len(d2) > 4 {
if a == b {
err = fmt.Errorf("Collision %q, %q crc32 %08x", d1, d2, a)
}
}
return
}
func FuzzFoo(f *testing.F) {
fmt.Printf("Into FuzzFoo\n")
testcases := []string{"test-1", "test-2", "test-3", "test-4"}
for _, tc := range testcases {
fmt.Printf("Adding %s %s\n", tc, []byte{1, 2, 3, 4})
f.Add(tc, []byte{1, 2, 3, 4})
}
f.Fuzz(func(t *testing.T, data string, data2 []byte) {
err := Foo(data, data2)
if err != nil {
t.Errorf("Error: %s\n", err)
}
})
}
When the test fails, a directory called "testdata" will be created, which contains files related to the failure detected. If you rerun the test, the test data that produces that failure will be loaded and the particular test case will be rerun, because it is assumed that you fixed the code and want to run it again for verification.
go test
without -fuzz
argument:go test -v
=== RUN FuzzFoo
Into FuzzFoo
Adding test-1
Adding test-2
Adding test-3
Adding test-4
=== RUN FuzzFoo/seed#0
=== RUN FuzzFoo/seed#1
=== RUN FuzzFoo/seed#2
=== RUN FuzzFoo/seed#3
--- PASS: FuzzFoo (0.00s)
--- PASS: FuzzFoo/seed#0 (0.00s)
--- PASS: FuzzFoo/seed#1 (0.00s)
--- PASS: FuzzFoo/seed#2 (0.00s)
--- PASS: FuzzFoo/seed#3 (0.00s)
PASS
ok example/fuzz 0.130s
#go test -fuzz=Fuzz -v
=== FUZZ FuzzFoo
Into FuzzFoo
Adding test-1
Adding test-2
Adding test-3
Adding test-4
warning: the test binary was not built with coverage instrumentation, so fuzzing will run without coverage guidance and may be inefficient
fuzz: elapsed: 0s, testing seed corpus: 0/4 completed
fuzz: elapsed: 0s, testing seed corpus: 4/4 completed, now fuzzing with 8 workers
fuzz: elapsed: 3s, execs: 216667 (72195/sec)
fuzz: elapsed: 6s, execs: 580526 (121314/sec)
fuzz: elapsed: 9s, execs: 1083897 (167774/sec)
fuzz: elapsed: 12s, execs: 1716489 (210884/sec)
fuzz: elapsed: 15s, execs: 2449549 (244323/sec)
fuzz: elapsed: 18s, execs: 3182631 (244356/sec)
fuzz: elapsed: 21s, execs: 3914517 (244028/sec)
fuzz: elapsed: 24s, execs: 4644885 (243418/sec)
fuzz: minimizing 86-byte failing input file
fuzz: elapsed: 26s, minimizing
--- FAIL: FuzzFoo (26.34s)
--- FAIL: FuzzFoo (0.00s)
fz_test.go:33: Error: Collision "\xff\xff\xff\xff\x00", "\xff\xff\xff\xff\x00" crc32 ffffffff
Failing input written to testdata/fuzz/FuzzFoo/9402ce22f976a53cf5cd596e4b00b4e090f629d6a33f166cc8e0fd161fcf8022
To re-run:
go test -run=FuzzFoo/9402ce22f976a53cf5cd596e4b00b4e090f629d6a33f166cc8e0fd161fcf8022
FAIL
exit status 1
FAIL example/fuzz 27.258s
testdata
directory will be created:#find testdata
testdata
testdata/fuzz
testdata/fuzz/FuzzFoo
testdata/fuzz/FuzzFoo/9402ce22f976a53cf5cd596e4b00b4e090f629d6a33f166cc8e0fd161fcf8022
#go test -fuzz=Fuzz -v
=== FUZZ FuzzFoo
Into FuzzFoo
Adding test-1
Adding test-2
Adding test-3
Adding test-4
warning: the test binary was not built with coverage instrumentation, so fuzzing will run without coverage guidance and may be inefficient
fuzz: elapsed: 0s, testing seed corpus: 0/5 completed
failure while testing seed corpus entry: FuzzFoo/9402ce22f976a53cf5cd596e4b00b4e090f629d6a33f166cc8e0fd161fcf8022
fuzz: elapsed: 2s, testing seed corpus: 4/5 completed
--- FAIL: FuzzFoo (1.82s)
--- FAIL: FuzzFoo (0.00s)
fz_test.go:33: Error: Collision "\xff\xff\xff\xff\x00", "\xff\xff\xff\xff\x00" crc32 ffffffff
FAIL
exit status 1
FAIL example/fuzz 3.144s
SMFLIMxx
to use fuzzing. To implement the values in SMFLIMxx, issue the z/OS® command "SET SMFLIM=(xx)
", and then update
the system PARMLIB member IEASYSxx
to include a statement to imitate SMFLIM at IPL
time.