-
Notifications
You must be signed in to change notification settings - Fork 913
GODRIVER-2550 Add fuzzer to bson packages #1077
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
daf51bc
bb4f333
00be7df
58a2afd
839da00
ee9ff08
0cfb457
7337330
41efed0
8a0d0e8
c4af531
f2398f3
86aae74
e4ab0f6
c6d97d5
55dac80
e210fb1
4a322c1
1820a5e
045dc76
aec25d1
0ee3576
26b3710
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,68 @@ | ||||||
#!/bin/bash | ||||||
|
||||||
set -o errexit # Exit the script with error if any of the commands fail | ||||||
|
||||||
FUZZTIME=10m | ||||||
|
||||||
# Change the working directory to the root of the mongo repository directory | ||||||
cd $PROJECT_DIRECTORY | ||||||
|
||||||
# Get all go test files that contain a fuzz test. | ||||||
FILES=$(grep -r --include='**_test.go' --files-with-matches 'func Fuzz' .) | ||||||
|
||||||
# For each file, run all of the fuzz tests in sequence, each for -fuzztime=FUZZTIME. | ||||||
for FILE in ${FILES} | ||||||
do | ||||||
PARENTDIR="$(dirname -- "$FILE")" | ||||||
|
||||||
# Get a list of all fuzz tests in the file. | ||||||
FUNCS=$(grep -o 'func Fuzz[A-Za-z0-9]*' $FILE | cut -d' ' -f2) | ||||||
|
||||||
# For each fuzz test in the file, run it for FUZZTIME. | ||||||
for FUNC in ${FUNCS} | ||||||
do | ||||||
echo "Fuzzing \"${FUNC}\" in \"${FILE}\"" | ||||||
|
||||||
# Create a set of directories that are already in the subdirectories testdata/fuzz/$fuzzer corpus. This | ||||||
# set will be used to differentiate between new and old corpus files. | ||||||
declare -a cset | ||||||
|
||||||
if [ -d $PARENTDIR/testdata/fuzz/$FUNC ]; then | ||||||
# Iterate over the files in the corpus directory and add them to the set. | ||||||
for SEED in $PARENTDIR/testdata/fuzz/$FUNC/* | ||||||
do | ||||||
cset+=("$SEED") | ||||||
done | ||||||
fi | ||||||
|
||||||
go test ${PARENTDIR} -run=${FUNC} -fuzz=${FUNC} -fuzztime=${FUZZTIME} || true | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we not care about the output of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will still pipe the output, but if the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there an indicator that will let us know the fuzz test caused a panic? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sounds good, thanks There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @matthewdale Yes, this should still output the results of the test. If I added a echo "before"
go test ${PARENTDIR} -run=${FUNC} -fuzz=${FUNC} -fuzztime=${FUZZTIME} || true
echo "after" The output would be
|
||||||
|
||||||
# Check if any new corpus files were generated for the fuzzer. If there are new corpus files, move them | ||||||
# to $PROJECT_DIRECTORY/fuzz/$FUNC/* so they can be tarred up and uploaded to S3. | ||||||
if [ -d $PARENTDIR/testdata/fuzz/$FUNC ]; then | ||||||
# Iterate over the files in the corpus directory and check if they are in the set. | ||||||
for CORPUS_FILE in $PARENTDIR/testdata/fuzz/$FUNC/* | ||||||
do | ||||||
# Check to see if the value for CORPUS_FILE is in cset. | ||||||
if [[ ! " ${cset[@]} " =~ " ${CORPUS_FILE} " ]]; then | ||||||
# Create the directory if it doesn't exist. | ||||||
if [ ! -d $PROJECT_DIRECTORY/fuzz/$FUNC ]; then | ||||||
mkdir -p $PROJECT_DIRECTORY/fuzz/$FUNC | ||||||
fi | ||||||
|
||||||
# Move the file to the directory. | ||||||
mv $CORPUS_FILE $PROJECT_DIRECTORY/fuzz/$FUNC | ||||||
|
||||||
echo "Moved $CORPUS_FILE to $PROJECT_DIRECTORY/fuzz/$FUNC" | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is just a log notifying the user that generated data has been moved to the file which will be tarred and put on S3. It will read like
In this case "new" seems redundant. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fair, sounds good. |
||||||
fi | ||||||
done | ||||||
fi | ||||||
done | ||||||
done | ||||||
|
||||||
# If the fuzz directory exists, then tar it up in preparation to upload to S3. | ||||||
if [ -d $PROJECT_DIRECTORY/fuzz ]; then | ||||||
echo "Tarring up fuzz directory" | ||||||
tar -czf $PROJECT_DIRECTORY/fuzz.tgz $PROJECT_DIRECTORY/fuzz | ||||||
fi | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package bson | ||
|
||
import ( | ||
"testing" | ||
) | ||
|
||
func FuzzDecode(f *testing.F) { | ||
seedBSONCorpus(f) | ||
|
||
f.Fuzz(func(t *testing.T, data []byte) { | ||
for _, typ := range []func() interface{}{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not loop over There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's a practice I took from the Go team. I think the idea is to make the type instantiation more realistic, i.e. something like this: x := interface{} // or in our case typ()
// unmarshal into &x And not like for _, x := range []interface{ ... } {
// unmarshal into &x
} |
||
func() interface{} { return new(D) }, | ||
func() interface{} { return new([]E) }, | ||
func() interface{} { return new(M) }, | ||
func() interface{} { return new(interface{}) }, | ||
func() interface{} { return make(map[string]interface{}) }, | ||
func() interface{} { return new([]interface{}) }, | ||
} { | ||
i := typ() | ||
if err := Unmarshal(data, i); err != nil { | ||
return | ||
} | ||
|
||
encoded, err := Marshal(i) | ||
if err != nil { | ||
t.Fatal("failed to marshal", err) | ||
} | ||
|
||
if err := Unmarshal(encoded, i); err != nil { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah interesting that we unmarshal, marshal and unmarshal again. What's the reasoning there? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The first unmarshal is to check the validity of the extended JSON. We only want this to generate corpus data on a panic/crash. If the value is not valid BSON and we don't crash, then this subtest if over. The first marshal is to check that we can encode valid data structures into BSON, it seems unnecessary to fuzz the encoding of invalid data structures. The last unmarshal is where we check that we can decode valid BSON, if this fails/panics/crashes then we want to know about it. |
||
t.Fatal("failed to unmarshal", err) | ||
} | ||
} | ||
}) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
go test fuzz v1 | ||
[]byte("\x10\x00\x00\x00\v\x00\x00\x00\b\x00\x00\v\x00\x00\x00\x00") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are these There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This data is different from testdata/bson-corpus. Three of these were interesting cases generated by running the fuzzer. One is BSON that encapsulates all types for an initial maximum code coverage in the style of the encoding/json fuzz test. From the documentation:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Great, thanks for the explanation. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
go test fuzz v1 | ||
[]byte("0\\x00\\x00\\x00\\x0f\\x00000\\x8a00000000000000000000000000000000000000\n") |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
go test fuzz v1 | ||
[]byte("\\x80\\x00\\x00\\x00\\x03000000\\x00s\\x00\\x00\\x00\\x0300000\\x00g\\x00\\x00\\x00\\x100z\\x000000\\x11\\x00000\\x150000\\x020\\x00\\x02\\x00\\x00\\x000\\x12\\x00\\x050\\x00\\x01\\x00\\x00\\x0000\\x050\\x00\\x01\\x00\\x00\\x0000\\x040\\x00200000\\x00\\x000\\x02\\x00\\x10\\x0000000\\x110\\x0000000000\\x020\\x00\\x02\\x00\\x00\\x000\\x00\\x050\\x00\\x01\\x00\\x00\\x0000\\x050\\x00\\x01\\x00\\x00\\x0000\\x00\\x00\\x00\\x00\n") |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
go test fuzz v1 | ||
[]byte("\\x59\\x01\\x00\\x00\\x01\\x64\\x6f\\x75\\x62\\x6c\\x65\\x00\\x9a\\x99\\x99\\x99\\x99\\x99\\xf1\\x3f\\x02\\x73\\x74\\x72\\x69\\x6e\\x67\\x00\\x06\\x00\\x00\\x00\\x68\\x65\\x6c\\x6c\\x6f\\x00\\x03\\x65\\x6d\\x62\\x65\\x64\\x64\\x65\\x64\\x00\\x4b\\x00\\x00\\x00\\x04\\x61\\x72\\x72\\x61\\x79\\x00\\x3f\\x00\\x00\\x00\\x10\\x30\\x00\\x01\\x00\\x00\\x00\\x01\\x31\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x40\\x02\\x32\\x00\\x02\\x00\\x00\\x00\\x33\\x00\\x04\\x33\\x00\\x0c\\x00\\x00\\x00\\x10\\x30\\x00\\x04\\x00\\x00\\x00\\x00\\x03\\x34\\x00\\x0d\\x00\\x00\\x00\\x03\\x35\\x00\\x05\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x05\\x62\\x69\\x6e\\x61\\x72\\x79\\x00\\x03\\x00\\x00\\x00\\x00\\x01\\x02\\x03\\x07\\x6f\\x62\\x6a\\x65\\x63\\x74\\x69\\x64\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x08\\x62\\x6f\\x6f\\x6c\\x65\\x61\\x6e\\x00\\x01\\x09\\x64\\x61\\x74\\x65\\x74\\x69\\x6d\\x65\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x0a\\x6e\\x75\\x6c\\x6c\\x00\\x0b\\x72\\x65\\x67\\x65\\x78\\x00\\x68\\x65\\x6c\\x6c\\x6f\\x00\\x69\\x00\\x0d\\x6a\\x73\\x00\\x0e\\x00\\x00\\x00\\x66\\x75\\x6e\\x63\\x74\\x69\\x6f\\x6e\\x28\\x29\\x20\\x7b\\x7d\\x00\\x0f\\x73\\x63\\x6f\\x70\\x65\\x00\\x2c\\x00\\x00\\x00\\x0e\\x00\\x00\\x00\\x66\\x75\\x6e\\x63\\x74\\x69\\x6f\\x6e\\x28\\x29\\x20\\x7b\\x7d\\x00\\x16\\x00\\x00\\x00\\x02\\x68\\x65\\x6c\\x6c\\x6f\\x00\\x06\\x00\\x00\\x00\\x77\\x6f\\x72\\x6c\\x64\\x00\\x00\\x10\\x69\\x6e\\x74\\x33\\x32\\x00\\x20\\x00\\x00\\x00\\x11\\x74\\x69\\x6d\\x65\\x73\\x74\\x61\\x6d\\x70\\x00\\x02\\x00\\x00\\x00\\x01\\x00\\x00\\x00\\x12\\x69\\x6e\\x74\\x36\\x34\\x00\\x40\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\xff\\x6d\\x69\\x6e\\x6b\\x65\\x79\\x00\\x7f\\x6d\\x61\\x78\\x6b\\x65\\x79\\x00\\x00\"\n") |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
go test fuzz v1 | ||
[]byte("\\x05\\xf0\\xff\\x00\\x7f\n") |
Uh oh!
There was an error while loading. Please reload this page.