mirror of https://github.com/tailscale/tailscale/
*: replace ossfuzz with go native fuzz invocations
The fuzzing actions are the longest actions in our CI right now. This would be a good and happy thing if the bulk of the time was spent fuzzing, but sadly the bulk of the time is spent doing build preparations due to the nature of the ossfuzz docker setup. Only two out of our 5 packages that contain fuzzers were ossfuzz fuzzers, the rest are Go 1.18+ fuzzers. These two are converted to go fuzzers, and then the github workflow is updated to just go test fuzz. The action setup contains two separate steps for actions-cache, one that handles the fuzzing corpus specifically so that we shuttle forward any interesting corpus over time. If the action fails, it will upload all the testdata/* directories, which will include the data necessary to commit interesting cases for permanent redistribution. Signed-off-by: James Tucker <james@tailscale.com>raggi/gofuzz
parent
b7f51a1468
commit
6c992d3e60
@ -0,0 +1,95 @@
|
|||||||
|
// Copyright (c) Tailscale Inc & AUTHORS
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
package disco
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"golang.org/x/exp/slices"
|
||||||
|
)
|
||||||
|
|
||||||
|
func FuzzDisco(f *testing.F) {
|
||||||
|
f.Fuzz(func(t *testing.T, data1 []byte) {
|
||||||
|
if data1 == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data2 := make([]byte, 0, len(data1))
|
||||||
|
|
||||||
|
m1, e1 := Parse(data1)
|
||||||
|
if m1 == nil || reflect.ValueOf(m1).IsNil() {
|
||||||
|
if e1 == nil {
|
||||||
|
t.Fatal("nil message and nil error!")
|
||||||
|
}
|
||||||
|
t.Logf("message result is actually nil, can't be serialized again")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
data2 = m1.AppendMarshal(data2)
|
||||||
|
m2, e2 := Parse(data2)
|
||||||
|
if m2 == nil || reflect.ValueOf(m2).IsNil() {
|
||||||
|
if e2 == nil {
|
||||||
|
t.Fatal("nil message and nil error!")
|
||||||
|
}
|
||||||
|
t.Errorf("second message result is actually nil!")
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("m1: %#v", m1)
|
||||||
|
t.Logf("m2: %#v", m1)
|
||||||
|
t.Logf("data1:\n%x", data1)
|
||||||
|
t.Logf("data2:\n%x", data2)
|
||||||
|
|
||||||
|
if e1 != nil && e2 != nil {
|
||||||
|
if e1.Error() != e2.Error() {
|
||||||
|
t.Errorf("error mismatch: %v != %v", e1, e2)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Explicitly ignore the case where the fuzzer made a different version
|
||||||
|
// byte, it's not interesting.
|
||||||
|
data1[1] = v0
|
||||||
|
// The protocol doesn't have a length at this layer, and so it will
|
||||||
|
// ignore meaningless trailing data such as a key that is more than 0
|
||||||
|
// bytes, but less than keylen bytes.
|
||||||
|
if len(data2) < len(data1) {
|
||||||
|
data1 = data1[:len(data2)]
|
||||||
|
}
|
||||||
|
|
||||||
|
if !bytes.Equal(data1, data2) {
|
||||||
|
t.Errorf("data mismatch:\n%x\n%x", data1, data2)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch t1 := m1.(type) {
|
||||||
|
case *Ping:
|
||||||
|
t2, ok := m2.(*Ping)
|
||||||
|
if !ok {
|
||||||
|
t.Errorf("m1 and m2 are not the same type")
|
||||||
|
}
|
||||||
|
if *t1 != *t2 {
|
||||||
|
t.Errorf("m1 and m2 are not the same")
|
||||||
|
}
|
||||||
|
case *Pong:
|
||||||
|
t2, ok := m2.(*Pong)
|
||||||
|
if !ok {
|
||||||
|
t.Errorf("m1 and m2 are not the same type")
|
||||||
|
}
|
||||||
|
if *t1 != *t2 {
|
||||||
|
t.Errorf("m1 and m2 are not the same")
|
||||||
|
}
|
||||||
|
case *CallMeMaybe:
|
||||||
|
t2, ok := m2.(*CallMeMaybe)
|
||||||
|
if !ok {
|
||||||
|
t.Errorf("m1 and m2 are not the same type")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !slices.Equal(t1.MyNumber, t2.MyNumber) {
|
||||||
|
t.Errorf("m1 and m2 are not the same")
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
t.Fatalf("unknown message type %T", m1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
@ -1,17 +0,0 @@
|
|||||||
// Copyright (c) Tailscale Inc & AUTHORS
|
|
||||||
// SPDX-License-Identifier: BSD-3-Clause
|
|
||||||
//go:build gofuzz
|
|
||||||
|
|
||||||
package disco
|
|
||||||
|
|
||||||
func Fuzz(data []byte) int {
|
|
||||||
m, _ := Parse(data)
|
|
||||||
|
|
||||||
newBytes := m.AppendMarshal(data)
|
|
||||||
parsedMarshall, _ := Parse(newBytes)
|
|
||||||
|
|
||||||
if m != parsedMarshall {
|
|
||||||
panic("Parsing error")
|
|
||||||
}
|
|
||||||
return 1
|
|
||||||
}
|
|
@ -0,0 +1,14 @@
|
|||||||
|
// Copyright (c) Tailscale Inc & AUTHORS
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
package stun
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func FuzzStun(f *testing.F) {
|
||||||
|
f.Fuzz(func(t *testing.T, data []byte) {
|
||||||
|
_, _, _ = ParseResponse(data)
|
||||||
|
|
||||||
|
_, _ = ParseBindingRequest(data)
|
||||||
|
})
|
||||||
|
}
|
@ -1,12 +0,0 @@
|
|||||||
// Copyright (c) Tailscale Inc & AUTHORS
|
|
||||||
// SPDX-License-Identifier: BSD-3-Clause
|
|
||||||
//go:build gofuzz
|
|
||||||
|
|
||||||
package stun
|
|
||||||
|
|
||||||
func FuzzStunParser(data []byte) int {
|
|
||||||
_, _, _ = ParseResponse(data)
|
|
||||||
|
|
||||||
_, _ = ParseBindingRequest(data)
|
|
||||||
return 1
|
|
||||||
}
|
|
Loading…
Reference in New Issue