mirror of https://github.com/google/oss-fuzz.git
Test drive native fuzzing (#7104)
This commit is contained in:
parent
81f4a646b2
commit
ffcf9c0c0c
|
@ -0,0 +1,28 @@
|
|||
# Copyright 2021 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
################################################################################
|
||||
|
||||
FROM gcr.io/oss-fuzz-base/base-builder-go
|
||||
RUN git clone --depth 1 https://github.com/vitessio/vitess
|
||||
RUN go install golang.org/dl/gotip@latest \
|
||||
&& gotip download
|
||||
RUN go install github.com/AdamKorcz/go-118-fuzz-build@latest
|
||||
COPY build.sh \
|
||||
native_ossfuzz_coverage_runnger.go \
|
||||
fuzzers/tablet_manager_fuzzer_test.go \
|
||||
fuzzers/parser_fuzzer_test.go \
|
||||
fuzzers/ast_fuzzer_test.go \
|
||||
$SRC/
|
||||
WORKDIR $SRC/vitess
|
|
@ -0,0 +1,182 @@
|
|||
#!/bin/bash -eu
|
||||
# Copyright 2021 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
################################################################################
|
||||
|
||||
cd $SRC
|
||||
# Build main binary
|
||||
git clone https://github.com/AdamKorcz/go-118-fuzz-build
|
||||
cd go-118-fuzz-build
|
||||
go build
|
||||
|
||||
# Build addimport binary
|
||||
cd addimport
|
||||
go build
|
||||
|
||||
cd $SRC/vitess
|
||||
|
||||
# Remove existing non-native fuzzers to not deal with them
|
||||
rm go/vt/vtgate/vindexes/fuzz.go
|
||||
|
||||
# backup vtctl_fuzzer.go
|
||||
cp go/test/fuzzing/vtctl_fuzzer.go /tmp/
|
||||
rm -r go/test/fuzzing/*
|
||||
|
||||
mv $SRC/parser_fuzzer_test.go $SRC/vitess/go/test/fuzzing/
|
||||
mv $SRC/ast_fuzzer_test.go $SRC/vitess/go/test/fuzzing/
|
||||
mv $SRC/tablet_manager_fuzzer_test.go $SRC/vitess/go/test/fuzzing/
|
||||
|
||||
|
||||
# Disable logging for mysql conn
|
||||
# This affects the mysql fuzzers
|
||||
sed -i '/log.Errorf/c\\/\/log.Errorf' $SRC/vitess/go/mysql/conn.go
|
||||
sed -i '/log.Warningf/c\\/\/log.Warningf' $SRC/vitess/go/vt/sqlparser/parser.go
|
||||
|
||||
mv ./go/vt/vttablet/tabletmanager/vreplication/framework_test.go \
|
||||
./go/vt/vttablet/tabletmanager/vreplication/framework_fuzz.go
|
||||
|
||||
#consistent_lookup_test.go is needed for loggingVCursor
|
||||
mv ./go/vt/vtgate/vindexes/consistent_lookup_test.go \
|
||||
./go/vt/vtgate/vindexes/consistent_lookup_test_fuzz.go
|
||||
|
||||
# fake_vcursor_test.go is needed for loggingVCursor
|
||||
mv ./go/vt/vtgate/engine/fake_vcursor_test.go \
|
||||
./go/vt/vtgate/engine/fake_vcursor.go
|
||||
|
||||
# plan_test.go is needed for vschemaWrapper
|
||||
mv ./go/vt/vtgate/planbuilder/plan_test.go \
|
||||
./go/vt/vtgate/planbuilder/plan_test_fuzz.go
|
||||
|
||||
# tabletserver fuzzer
|
||||
mv ./go/vt/vttablet/tabletserver/testutils_test.go \
|
||||
./go/vt/vttablet/tabletserver/testutils_fuzz.go
|
||||
|
||||
# collation fuzzer
|
||||
mv ./go/mysql/collations/uca_test.go \
|
||||
./go/mysql/collations/uca_test_fuzz.go
|
||||
|
||||
mv $SRC/vitess/go/vt/vtgate/grpcvtgateconn/suite_test.go \
|
||||
$SRC/vitess/go/vt/vtgate/grpcvtgateconn/suite_test_fuzz.go
|
||||
mv $SRC/vitess/go/vt/vtgate/grpcvtgateconn/fuzz_flaky_test.go \
|
||||
$SRC/vitess/go/vt/vtgate/grpcvtgateconn/fuzz.go
|
||||
|
||||
# build_go_fuzz_harness rewrites a copy of the
|
||||
# fuzzer to allow for libFuzzer instrumentation
|
||||
function rewrite_go_fuzz_harness() {
|
||||
fuzzer_filename=$1
|
||||
|
||||
# Create a copy of the fuzzer to not modify the existing fuzzer
|
||||
cp $fuzzer_filename "${fuzzer_filename}"_fuzz_.go
|
||||
mv $fuzzer_filename /tmp/
|
||||
|
||||
# replace *testing.F with *go118fuzzbuildutils.F
|
||||
echo "replacing *testing.F"
|
||||
sed -i 's/f \*testing\.F/f \*go118fuzzbuildutils\.F/g' "${fuzzer_filename}"_fuzz_.go
|
||||
|
||||
# import https://github.com/AdamKorcz/go-118-fuzz-build
|
||||
# This changes the line numbers from the original fuzzer
|
||||
$SRC/go-118-fuzz-build/addimport/addimport -path "${fuzzer_filename}"_fuzz_.go
|
||||
}
|
||||
|
||||
function compile_native_go_fuzzer() {
|
||||
fuzzer=$1
|
||||
function=$2
|
||||
path=$3
|
||||
tags="-tags gofuzz"
|
||||
|
||||
if [[ $SANITIZER = *coverage* ]]; then
|
||||
echo "here we perform coverage build"
|
||||
fuzzed_package=`go list $tags -f '{{.Name}}' $path`
|
||||
abspath=`go list $tags -f {{.Dir}} $path`
|
||||
cd $abspath
|
||||
cp $SRC/native_ossfuzz_coverage_runnger.go ./"${function,,}"_test.go
|
||||
sed -i -e 's/FuzzFunction/'$function'/' ./"${function,,}"_test.go
|
||||
sed -i -e 's/mypackagebeingfuzzed/'$fuzzed_package'/' ./"${function,,}"_test.go
|
||||
sed -i -e 's/TestFuzzCorpus/Test'$function'Corpus/' ./"${function,,}"_test.go
|
||||
|
||||
# The repo is the module path/name, which is already created above in case it doesn't exist,
|
||||
# but not always the same as the module path. This is necessary to handle SIV properly.
|
||||
fuzzed_repo=$(go list $tags -f {{.Module}} "$path")
|
||||
abspath_repo=`go list -m $tags -f {{.Dir}} $fuzzed_repo || go list $tags -f {{.Dir}} $fuzzed_repo`
|
||||
# give equivalence to absolute paths in another file, as go test -cover uses golangish pkg.Dir
|
||||
echo "s=$fuzzed_repo"="$abspath_repo"= > $OUT/$fuzzer.gocovpath
|
||||
ls
|
||||
gotip test -run Test${function}Corpus -v $tags -coverpkg $fuzzed_repo/... -c -o $OUT/$fuzzer $path
|
||||
|
||||
rm ./"${function,,}"_test.go
|
||||
else
|
||||
$SRC/go-118-fuzz-build/go-118-fuzz-build -o $fuzzer.a -func $function $abs_file_dir
|
||||
$CXX $CXXFLAGS $LIB_FUZZING_ENGINE $fuzzer.a -o $OUT/$fuzzer
|
||||
fi
|
||||
}
|
||||
|
||||
# build_go_fuzzer will be the api used by users
|
||||
# The api is now placed in this build script
|
||||
# but will be moved to the base image once it
|
||||
# has reached sufficient maturity.
|
||||
function build_go_fuzzer () {
|
||||
path=$1
|
||||
function=$2
|
||||
fuzzer=$3
|
||||
tags="-tags gofuzz"
|
||||
|
||||
# Get absolute path
|
||||
abs_file_dir=$(go list $tags -f {{.Dir}} $path)
|
||||
|
||||
# TODO: Get rid of "-r" flag here
|
||||
fuzzer_filename=$(grep -r -l -s "$function" "${abs_file_dir}")
|
||||
|
||||
# test if file contains a line with "func $function" and "testing.F"
|
||||
if [ $(grep -r "func $function" $fuzzer_filename | grep "testing.F" | wc -l) -eq 1 ]
|
||||
then
|
||||
# we are dealing with a native harness
|
||||
|
||||
# Install more dependencies
|
||||
gotip get github.com/AdamKorcz/go-118-fuzz-build/utils
|
||||
gotip get google.golang.org/grpc/internal/channelz@v1.39.0
|
||||
|
||||
echo "Native harness"
|
||||
rewrite_go_fuzz_harness $fuzzer_filename
|
||||
compile_native_go_fuzzer $fuzzer $function $abs_file_dir
|
||||
# clean up
|
||||
rm "${fuzzer_filename}_fuzz_.go"
|
||||
mv /tmp/$(basename $fuzzer_filename) $fuzzer_filename
|
||||
else
|
||||
# we are dealing with a go-fuzz harness
|
||||
echo "go-fuzz harness"
|
||||
compile_go_fuzzer $path $function $fuzzer $tags
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
# build native fuzzers
|
||||
build_go_fuzzer vitess.io/vitess/go/test/fuzzing FuzzTabletManager_ExecuteFetchAsDba fuzz_tablet_manager_execute_fetch_as_dba
|
||||
build_go_fuzzer vitess.io/vitess/go/test/fuzzing FuzzParser parser_fuzzer
|
||||
build_go_fuzzer vitess.io/vitess/go/test/fuzzing FuzzIsDML is_dml_fuzzer
|
||||
build_go_fuzzer vitess.io/vitess/go/test/fuzzing FuzzNormalizer normalizer_fuzzer
|
||||
build_go_fuzzer vitess.io/vitess/go/test/fuzzing FuzzNodeFormat normalizer_fuzzer
|
||||
build_go_fuzzer vitess.io/vitess/go/test/fuzzing FuzzSplitStatementToPieces fuzz_split_statement_to_pieces
|
||||
build_go_fuzzer vitess.io/vitess/go/test/fuzzing FuzzEqualsSQLNode fuzz_equals_sql_node
|
||||
|
||||
# Delete all the native fuzzers before building the go-fuzz fuzzer(s)
|
||||
# this will not be necessary when Go 1.18 is released. The reason this
|
||||
# is needed is because go114-fuzz-build calls "go" instead of "gotip",
|
||||
# and an error will be thrown because testing.F is not recognized.
|
||||
rm $SRC/vitess/go/test/fuzzing/*_test.go
|
||||
|
||||
# build go-fuzz fuzzers
|
||||
mv /tmp/vtctl_fuzzer.go $SRC/vitess/go/test/fuzzing/
|
||||
build_go_fuzzer vitess.io/vitess/go/test/fuzzing Fuzz vtctl_fuzzer
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
// Copyright 2021 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
package fuzzing
|
||||
|
||||
import (
|
||||
fuzz "github.com/AdaLogics/go-fuzz-headers"
|
||||
|
||||
"vitess.io/vitess/go/vt/sqlparser"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func FuzzEqualsSQLNode(f *testing.F) {
|
||||
f.Fuzz(func(t *testing.T, data []byte) {
|
||||
if len(data) < 10 {
|
||||
return
|
||||
}
|
||||
f := fuzz.NewConsumer(data)
|
||||
query1, err := f.GetSQLString()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
query2, err := f.GetSQLString()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
inA, err := sqlparser.Parse(query1)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
inB, err := sqlparser.Parse(query2)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// There are 3 targets in this fuzzer:
|
||||
// 1) sqlparser.EqualsSQLNode
|
||||
// 2) sqlparser.CloneSQLNode
|
||||
// 3) sqlparser.VisitSQLNode
|
||||
|
||||
// Target 1:
|
||||
identical := sqlparser.EqualsSQLNode(inA, inA)
|
||||
if !identical {
|
||||
panic("Should be identical")
|
||||
}
|
||||
identical = sqlparser.EqualsSQLNode(inB, inB)
|
||||
if !identical {
|
||||
panic("Should be identical")
|
||||
}
|
||||
|
||||
// Target 2:
|
||||
newSQLNode := sqlparser.CloneSQLNode(inA)
|
||||
if !sqlparser.EqualsSQLNode(inA, newSQLNode) {
|
||||
panic("These two nodes should be identical")
|
||||
}
|
||||
|
||||
// Target 3:
|
||||
_ = sqlparser.VisitSQLNode(inA, func(node sqlparser.SQLNode) (bool, error) { return false, nil })
|
||||
})
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
// Copyright 2021 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
package fuzzing
|
||||
|
||||
import (
|
||||
"testing"
|
||||
querypb "vitess.io/vitess/go/vt/proto/query"
|
||||
"vitess.io/vitess/go/vt/sqlparser"
|
||||
|
||||
fuzz "github.com/AdaLogics/go-fuzz-headers"
|
||||
)
|
||||
|
||||
func FuzzIsDML(f *testing.F) {
|
||||
f.Fuzz(func(t *testing.T, data string) {
|
||||
_ = sqlparser.IsDML(data)
|
||||
})
|
||||
}
|
||||
|
||||
func FuzzNormalizer(f *testing.F) {
|
||||
f.Fuzz(func(t *testing.T, data string) {
|
||||
stmt, reservedVars, err := sqlparser.Parse2(data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
bv := make(map[string]*querypb.BindVariable)
|
||||
sqlparser.Normalize(stmt, sqlparser.NewReservedVars("bv", reservedVars), bv)
|
||||
})
|
||||
}
|
||||
|
||||
func FuzzParser(f *testing.F) {
|
||||
f.Fuzz(func(t *testing.T, data string) {
|
||||
_, _ = sqlparser.Parse(data)
|
||||
})
|
||||
}
|
||||
|
||||
func FuzzNodeFormat(f *testing.F) {
|
||||
f.Fuzz(func(t *testing.T, data []byte) {
|
||||
f := fuzz.NewConsumer(data)
|
||||
query, err := f.GetSQLString()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
node, err := sqlparser.Parse(query)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
buf := &sqlparser.TrackedBuffer{}
|
||||
err = f.GenerateStruct(buf)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
node.Format(buf)
|
||||
})
|
||||
}
|
||||
|
||||
func FuzzSplitStatementToPieces(f *testing.F) {
|
||||
f.Fuzz(func(t *testing.T, data string) {
|
||||
_, _ = sqlparser.SplitStatementToPieces(data)
|
||||
})
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
// Copyright 2021 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
package fuzzing
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"vitess.io/vitess/go/mysql"
|
||||
"vitess.io/vitess/go/mysql/fakesqldb"
|
||||
"vitess.io/vitess/go/sqltypes"
|
||||
"vitess.io/vitess/go/vt/dbconfigs"
|
||||
"vitess.io/vitess/go/vt/mysqlctl/fakemysqldaemon"
|
||||
"vitess.io/vitess/go/vt/vttablet/tabletmanager"
|
||||
"vitess.io/vitess/go/vt/vttablet/tabletservermock"
|
||||
)
|
||||
|
||||
func FuzzTabletManager_ExecuteFetchAsDba(f *testing.F) {
|
||||
f.Fuzz(func(t *testing.T, data []byte) {
|
||||
ctx := context.Background()
|
||||
cp := mysql.ConnParams{}
|
||||
db := fakesqldb.New(t)
|
||||
db.AddQueryPattern(".*", &sqltypes.Result{})
|
||||
daemon := fakemysqldaemon.NewFakeMysqlDaemon(db)
|
||||
|
||||
dbName := "dbname"
|
||||
tm := &tabletmanager.TabletManager{
|
||||
MysqlDaemon: daemon,
|
||||
DBConfigs: dbconfigs.NewTestDBConfigs(cp, cp, dbName),
|
||||
QueryServiceControl: tabletservermock.NewController(),
|
||||
}
|
||||
_, _ = tm.ExecuteFetchAsDba(ctx, data, dbName, 10, false, false)
|
||||
})
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package mypackagebeingfuzzed
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"runtime/pprof"
|
||||
"testing"
|
||||
"github.com/AdamKorcz/go-118-fuzz-build/utils"
|
||||
)
|
||||
|
||||
func TestFuzzCorpus(t *testing.T) {
|
||||
dir := os.Getenv("FUZZ_CORPUS_DIR")
|
||||
if dir == "" {
|
||||
t.Logf("No fuzzing corpus directory set")
|
||||
return
|
||||
}
|
||||
infos, err := ioutil.ReadDir(dir)
|
||||
if err != nil {
|
||||
t.Logf("Not fuzzing corpus directory %s", err)
|
||||
return
|
||||
}
|
||||
filename := ""
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
t.Error("Fuzz panicked in "+filename, r)
|
||||
}
|
||||
}()
|
||||
profname := os.Getenv("FUZZ_PROFILE_NAME")
|
||||
if profname != "" {
|
||||
f, err := os.Create(profname + ".cpu.prof")
|
||||
if err != nil {
|
||||
t.Logf("error creating profile file %s\n", err)
|
||||
} else {
|
||||
_ = pprof.StartCPUProfile(f)
|
||||
}
|
||||
}
|
||||
for i := range infos {
|
||||
filename = dir + infos[i].Name()
|
||||
data, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
t.Error("Failed to read corpus file", err)
|
||||
}
|
||||
fuzzerF := &utils.F{Data:data, T:&testing.T{}}
|
||||
FuzzFunction(fuzzerF)
|
||||
}
|
||||
if profname != "" {
|
||||
pprof.StopCPUProfile()
|
||||
f, err := os.Create(profname + ".heap.prof")
|
||||
if err != nil {
|
||||
t.Logf("error creating heap profile file %s\n", err)
|
||||
}
|
||||
if err = pprof.WriteHeapProfile(f); err != nil {
|
||||
t.Logf("error writing heap profile file %s\n", err)
|
||||
}
|
||||
f.Close()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
homepage: "https://github.com/vitessio/vitess"
|
||||
primary_contact: "adam@adalogics.com"
|
||||
auto_ccs :
|
||||
- "david@adalogics.com"
|
||||
language: go
|
||||
fuzzing_engines:
|
||||
- libfuzzer
|
||||
sanitizers:
|
||||
- address
|
||||
main_repo: 'https://github.com/vitessio/vitess'
|
Loading…
Reference in New Issue