Skip to content

Instantly share code, notes, and snippets.

@rc-mattschwager
Last active December 8, 2022 17:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rc-mattschwager/e802fcaec17ff17b281c1f0e5d7cec28 to your computer and use it in GitHub Desktop.
Save rc-mattschwager/e802fcaec17ff17b281c1f0e5d7cec28 to your computer and use it in GitHub Desktop.
Code for "Fuzzing Golang msgpack for fun and panic" blog post
module msgpackfuzz
go 1.17
require (
github.com/dvyukov/go-fuzz v0.0.0-20220726122315-1d375ef9f9f6 // indirect
github.com/dvyukov/go-fuzz-corpus v0.0.0-20190920191254-c42c1b2914c7 // indirect
github.com/elazarl/go-bindata-assetfs v1.0.1 // indirect
github.com/shamaton/msgpack/v2 v2.1.0 // indirect
github.com/stephens2424/writerset v1.0.2 // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/sys v0.0.0-20220818161305-2296e01440c6 // indirect
golang.org/x/tools v0.1.12 // indirect
)
package main
import (
"flag"
"fmt"
"os"
"path/filepath"
"reflect"
"github.com/shamaton/msgpack/v2"
)
type Primitive struct {
Nil *int
Bool bool
Int int
Uint uint
Float32 float32
Float64 float64
String string
Bytes []byte
}
type Struct struct {
Int int
String string
}
type Container struct {
Array []int
Map map[string]int
Nested Struct
}
func generateCorpus(directory string) {
primitives := []Primitive{
Primitive{Nil: nil, Bool: true, Int: -100, Uint: 0, Float32: 3.1415, Float64: -3.1415, String: "foo", Bytes: []byte("bar")},
Primitive{Nil: nil, Bool: false, Int: 0, Uint: 100, Float32: 3.1415, Float64: -3.1415, String: "", Bytes: []byte("")},
Primitive{Nil: nil, Bool: false, Int: 1000, Uint: 1000, Float32: 3.1415, Float64: -3.1415, String: "\n", Bytes: []byte("\n")},
}
containers := []Container{
Container{Array: []int{1, 2, 3, 4, 5}, Map: map[string]int{"1": 1, "2": 2, "3": 3}, Nested: Struct{Int: 42, String: "bar"}},
Container{Array: []int{}, Map: map[string]int{}, Nested: Struct{Int: 0, String: ""}},
}
for i, primitive := range primitives {
data, err := msgpack.Marshal(primitive)
if err != nil {
panic(err)
}
r := Primitive{}
err = msgpack.Unmarshal(data, &r)
if err != nil {
panic(err)
}
if !reflect.DeepEqual(r, primitive) {
panic("r != primitive")
}
filename := filepath.Join(directory, fmt.Sprintf("primitive-%d.mp", i))
err = os.WriteFile(filename, data, 0644)
if err != nil {
panic(err)
}
}
for i, container := range containers {
data, err := msgpack.Marshal(container)
if err != nil {
panic(err)
}
r := Container{}
err = msgpack.Unmarshal(data, &r)
if err != nil {
panic(err)
}
if !reflect.DeepEqual(r, container) {
panic("r != container")
}
filename := filepath.Join(directory, fmt.Sprintf("container-%d.mp", i))
err = os.WriteFile(filename, data, 0644)
if err != nil {
panic(err)
}
}
}
func Fuzz(data []byte) int {
var r interface{}
err := msgpack.Unmarshal(data, &r)
if err != nil {
return 0
}
return 1
}
func main() {
var generate = flag.Bool("generate", false, "Generate corpus directory")
var filename = flag.String("filename", "", "Unmarshal filename")
flag.Parse()
if *generate {
corpusDir := "corpus"
err := os.MkdirAll(corpusDir, 0755)
if err != nil {
panic(err)
}
generateCorpus(corpusDir)
return
}
if *filename == "" {
fmt.Println("Specify a msgpack file with '-filename' to unmarshal")
return
}
data, err := os.ReadFile(*filename)
if err != nil {
panic(err)
}
var r interface{}
err = msgpack.Unmarshal(data, &r)
if err != nil {
panic(err)
}
fmt.Println(r)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment