😩 Mood: Upset because I dropped a pot lid on my toe two days before a race.

🎵 Soundtrack: Norman Fucking Rockwell!

📚 Reading Github Issues

Started today reading the 12 new github issues since yesterday… and there were a handful of initially seeming promising ones!!!

  • In this one someone wanted an example written about json offsets, which I jumped on. I wrote an example for it, but a contributor asked me not to submit until something else is resolved.
  • This one was an interesting tar bug about how it can sometimes use future timestamps. But changing it would break the API contract and make things less accurate, so it was closed. No bug fix.
  • This one is asking for updated docs about generics, one of the things I hope to learn more about since there is so much going on with them in the issues.
  • This one about about CSV decoding. It didn’t have reproduction steps. I tried, but wasn’t able to reproduce it.
  • This one which was asking for updates to the net docs! I was excited to jump on it, but then someone linked to a broader proposal about removing what they wanted documented. So it is already in flight.

I feel like I am Hermione just trying desperately to be useful, lurking in the issues, trying to contribute something, anything.

Back to Fuzzing

So my plan has been to dig more into fuzzing since it is a beta feature that is getting a lot of issues. However, there are very few examples that I could find about using it.

So I decided to take a step back and see if I could use go-fuzz, the external tool that developers can currently use.

🎥 I started by watching GothamGo 2015: Fuzzing Beyond Security: Automated Testing with go-fuzz by Filippo Valsorda.

Here is my fuzzing test for my terrible parser:

// +build gofuzz

package parser

func Parse(data string) {
	if len(data) == 5 {
		panic("oh no! bad size!")
	}
}

func Fuzz(data []byte) int {
	Parse(string(data))
	return 1
}

Then I made a corpus and added an example:

mkdir corpus
echo "meow" > corpus/example

Then I ran…

// build a zip file
go-fuzz-build .

// start fuzzing
time go-fuzz -bin parser-fuzz.zip -workdir=.

This results in an output like this, that I eventually had to kill

2021/09/09 17:38:57 workers: 4, corpus: 4 (3s ago), crashers: 1, restarts: 1/0, execs: 0 (0/sec), cover: 0, uptime: 3s
2021/09/09 17:39:00 workers: 4, corpus: 4 (6s ago), crashers: 1, restarts: 1/0, execs: 0 (0/sec), cover: 3, uptime: 6s
2021/09/09 17:39:03 workers: 4, corpus: 4 (9s ago), crashers: 1, restarts: 1/16, execs: 13858 (1539/sec), cover: 3, uptime: 9s
2021/09/09 17:39:06 workers: 4, corpus: 4 (12s ago), crashers: 1, restarts: 1/16, execs: 28528 (2377/sec), cover: 3, uptime: 12s
2021/09/09 17:39:09 workers: 4, corpus: 4 (15s ago), crashers: 1, restarts: 1/16, execs: 43844 (2922/sec), cover: 3, uptime: 15s
2021/09/09 17:39:12 workers: 4, corpus: 4 (18s ago), crashers: 1, restarts: 1/16, execs: 58719 (3262/sec), cover: 3, uptime: 18s
2021/09/09 17:39:15 workers: 4, corpus: 4 (21s ago), crashers: 1, restarts: 1/16, execs: 73668 (3508/sec), cover: 3, uptime: 21s
2021/09/09 17:39:18 workers: 4, corpus: 4 (24s ago), crashers: 1, restarts: 1/16, execs: 88561 (3690/sec), cover: 3, uptime: 24s
2021/09/09 17:39:21 workers: 4, corpus: 4 (27s ago), crashers: 1, restarts: 1/16, execs: 103824 (3845/sec), cover: 3, uptime: 27s
2021/09/09 17:39:24 workers: 4, corpus: 4 (30s ago), crashers: 1, restarts: 1/16, execs: 119598 (3986/sec), cover: 3, uptime: 30s
2021/09/09 17:39:27 workers: 4, corpus: 4 (33s ago), crashers: 1, restarts: 1/16, execs: 134298 (4069/sec), cover: 3, uptime: 33s
2021/09/09 17:39:30 workers: 4, corpus: 4 (36s ago), crashers: 1, restarts: 1/16, execs: 148394 (4122/sec), cover: 3, uptime: 36s
2021/09/09 17:39:33 workers: 4, corpus: 4 (39s ago), crashers: 1, restarts: 1/16, execs: 163423 (4190/sec), cover: 3, uptime: 39s
2021/09/09 17:39:36 workers: 4, corpus: 4 (42s ago), crashers: 1, restarts: 1/16, execs: 177708 (4231/sec), cover: 3, uptime: 42s

Running this made two more directories, crashers and supressions.

crashers contains information about what input caused a crash. Note that there is only one value in crashers, even though any string of length 5 would have caused my parser to panic.

$ ls crashers/
6934105ad50010b814c933314b1da6841431bc8b
6934105ad50010b814c933314b1da6841431bc8b.output
6934105ad50010b814c933314b1da6841431bc8b.quoted

$ cat crashers/66934105ad50010b814c933314b1da6841431bc8b9
00000

$ cat crashers/66934105ad50010b814c933314b1da6841431bc8b9.output
panic: oh no! bad size!

goroutine 1 [running]:
fuzz/go-fuz.Parse(...)
	/Users/adowns/workspace/amelia/go-fuz/parser.go:7
fuzz/go-fuz.Fuzz({0x4810000, 0xc000034730, 0x100a9d4})
	/Users/adowns/workspace/amelia/go-fuz/parser.go:12 +0xb8
go-fuzz-dep.Main({0xc00005cf68, 0x1, 0x105db80})
	go-fuzz-dep/main.go:36 +0x15b
main.main()
	fuzz/go-fuz/go.fuzz.main/main.go:15 +0x3b
exit status 2


$ cat crashers/66934105ad50010b814c933314b1da6841431bc8b9.quoted
"00000"

Only one crasher was recorded, because only one type of crash was found. This is recorded in the suppressions dir.

ls suppressions/
6934105ad50010b814c933314b1da6841431bc8b

cat suppressions/6934105ad50010b814c933314b1da6841431bc8b
panic: oh no! bad size!
fuzz/go-fuz.Parse
fuzz/go-fuz.Fuzz
go-fuzz-dep.Main
main.main

Go-fuzz will only record one crasher for each type of panic. There is only one panic in my bad parser (and hopefully no hidden ones) so we will only ever get one crasher and one suppression.

Did you notice that the crasher that is recorded was “00000”? That’s because the minimizer makes the crasher as simple as possible.

I wanted to try this again, and updated my parser. Now it will only panic if it is length 5 AND has a “z” in it. I also deleted everything from the supressions and crashers dirs.

// +build gofuzz

package parser

import "strings"

func Parse(data string) {
	if len(data) == 5 {
		if strings.Contains(data, "z") {
			panic("oh no! bad size!")
		}
	}
}

func Fuzz(data []byte) int {
	Parse(string(data))
	return 1 // return 1 means that is passed the check
}

Again there is only one crasher. But this time it has a z! Again it is minimized to be as simple as possible.

$ cat crashers/*quoted
"0z000"

🔍 I tried to find some good functions that I could fuzz test in the code bases I maintain, but I couldn’t find any that I found appropriate. Maybe it’s one of those things that if I knew about fuzzing then maybe I would write code so that it was easy to test with it. Also maybe our functions are way to big 😭

Now that I got the hang of go-fuzz, I hope to try out the same examples with the built in fuzzing with the gotip tomorrow.