Merge pull request #5915 from AdamKorcz/fuzz12

Fuzzing: Add fuzzers + small modifications
This commit is contained in:
Derek McGowan 2021-10-04 10:32:05 -07:00 committed by GitHub
commit d193dc2b8a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 422 additions and 2 deletions

View File

@ -18,6 +18,8 @@ package fuzz
import (
"bytes"
"context"
"sync"
"time"
fuzz "github.com/AdaLogics/go-fuzz-headers"
@ -33,7 +35,11 @@ const (
defaultAddress = "/tmp/containerd/containerd.sock"
)
func init() {
var (
initDaemon sync.Once
)
func startDaemon() {
args := []string{"--log-level", "debug"}
go func() {
// This is similar to invoking the
@ -42,6 +48,7 @@ func init() {
// for more info.
command.StartDaemonForFuzzing(args)
}()
time.Sleep(time.Second * 4)
}
func fuzzContext() (context.Context, context.CancelFunc) {
@ -51,6 +58,8 @@ func fuzzContext() (context.Context, context.CancelFunc) {
}
func FuzzContainerdImport(data []byte) int {
initDaemon.Do(startDaemon)
client, err := containerd.New(defaultAddress)
if err != nil {
return 0

View File

@ -0,0 +1,406 @@
// +build gofuzz
/*
Copyright The containerd Authors.
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 fuzz
import (
"context"
"fmt"
"io/ioutil"
"os"
"path/filepath"
fuzz "github.com/AdaLogics/go-fuzz-headers"
digest "github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
bolt "go.etcd.io/bbolt"
"github.com/containerd/containerd/containers"
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/content/local"
"github.com/containerd/containerd/images"
"github.com/containerd/containerd/leases"
"github.com/containerd/containerd/metadata"
"github.com/containerd/containerd/namespaces"
"github.com/containerd/containerd/snapshots"
"github.com/containerd/containerd/snapshots/native"
)
func testEnv() (context.Context, *bolt.DB, func(), error) {
ctx, cancel := context.WithCancel(context.Background())
ctx = namespaces.WithNamespace(ctx, "testing")
dirname, err := ioutil.TempDir("", "fuzz-")
if err != nil {
return ctx, nil, nil, err
}
db, err := bolt.Open(filepath.Join(dirname, "meta.db"), 0644, nil)
if err != nil {
return ctx, nil, nil, err
}
return ctx, db, func() {
db.Close()
_ = os.RemoveAll(dirname)
cancel()
}, nil
}
func FuzzImageStore(data []byte) int {
ctx, db, cancel, err := testEnv()
if err != nil {
return 0
}
defer cancel()
store := metadata.NewImageStore(metadata.NewDB(db, nil, nil))
f := fuzz.NewConsumer(data)
noOfOperations, err := f.GetInt()
if err != nil {
return 0
}
maxOperations := 50
for i := 0; i < noOfOperations%maxOperations; i++ {
opType, err := f.GetInt()
if err != nil {
return 0
}
if opType%1 == 0 {
i := images.Image{}
err := f.GenerateStruct(&i)
if err != nil {
return 0
}
_, _ = store.Create(ctx, i)
} else if opType%2 == 0 {
newFs, err := f.GetString()
if err != nil {
return 0
}
_, _ = store.List(ctx, newFs)
} else if opType%3 == 0 {
i := images.Image{}
err := f.GenerateStruct(&i)
if err != nil {
return 0
}
_, _ = store.Update(ctx, i)
} else if opType%4 == 0 {
name, err := f.GetString()
if err != nil {
return 0
}
_ = store.Delete(ctx, name)
}
}
return 1
}
func FuzzLeaseManager(data []byte) int {
ctx, db, cancel, err := testEnv()
if err != nil {
return 0
}
defer cancel()
lm := metadata.NewLeaseManager(metadata.NewDB(db, nil, nil))
f := fuzz.NewConsumer(data)
noOfOperations, err := f.GetInt()
if err != nil {
return 0
}
maxOperations := 50
for i := 0; i < noOfOperations%maxOperations; i++ {
opType, err := f.GetInt()
if err != nil {
return 0
}
if opType%1 == 0 {
err := db.Update(func(tx *bolt.Tx) error {
sm := make(map[string]string)
err2 := f.FuzzMap(&sm)
if err2 != nil {
return err2
}
_, _ = lm.Create(ctx, leases.WithLabels(sm))
return nil
})
if err != nil {
return 0
}
} else if opType%2 == 0 {
_, _ = lm.List(ctx)
} else if opType%3 == 0 {
l := leases.Lease{}
err := f.GenerateStruct(&l)
if err != nil {
return 0
}
r := leases.Resource{}
err = f.GenerateStruct(&r)
if err != nil {
return 0
}
db.Update(func(tx *bolt.Tx) error {
_ = lm.AddResource(metadata.WithTransactionContext(ctx, tx), l, r)
return nil
})
} else if opType%4 == 0 {
l := leases.Lease{}
err = f.GenerateStruct(&l)
if err != nil {
return 0
}
_ = lm.Delete(ctx, l)
} else if opType%5 == 0 {
l := leases.Lease{}
err := f.GenerateStruct(&l)
if err != nil {
return 0
}
r := leases.Resource{}
err = f.GenerateStruct(&r)
if err != nil {
return 0
}
_ = lm.DeleteResource(ctx, l, r)
} else if opType%6 == 0 {
l := leases.Lease{}
err := f.GenerateStruct(&l)
if err != nil {
return 0
}
_, _ = lm.ListResources(ctx, l)
}
}
return 1
}
func FuzzContainerStore(data []byte) int {
ctx, db, cancel, err := testEnv()
if err != nil {
return 0
}
defer cancel()
store := metadata.NewContainerStore(metadata.NewDB(db, nil, nil))
c := containers.Container{}
f := fuzz.NewConsumer(data)
noOfOperations, err := f.GetInt()
if err != nil {
return 0
}
maxOperations := 50
for i := 0; i < noOfOperations%maxOperations; i++ {
opType, err := f.GetInt()
if err != nil {
return 0
}
if opType%1 == 0 {
err := f.GenerateStruct(&c)
if err != nil {
return 0
}
db.Update(func(tx *bolt.Tx) error {
_, _ = store.Create(metadata.WithTransactionContext(ctx, tx), c)
return nil
})
} else if opType%2 == 0 {
filt, err := f.GetString()
if err != nil {
return 0
}
_, _ = store.List(ctx, filt)
} else if opType%3 == 0 {
id, err := f.GetString()
if err != nil {
return 0
}
_ = store.Delete(ctx, id)
} else if opType%4 == 0 {
fieldpaths, err := f.GetString()
if err != nil {
return 0
}
_, _ = store.Update(ctx, c, fieldpaths)
} else if opType%5 == 0 {
id, err := f.GetString()
if err != nil {
return 0
}
_, _ = store.Get(ctx, id)
}
}
return 1
}
type testOptions struct {
extraSnapshots map[string]func(string) (snapshots.Snapshotter, error)
}
type testOpt func(*testOptions)
func testDB(opt ...testOpt) (context.Context, *metadata.DB, func(), error) {
ctx, cancel := context.WithCancel(context.Background())
ctx = namespaces.WithNamespace(ctx, "testing")
var topts testOptions
for _, o := range opt {
o(&topts)
}
dirname, err := ioutil.TempDir("", "fuzzing-")
if err != nil {
return ctx, nil, func() { cancel() }, err
}
defer os.RemoveAll(dirname)
snapshotter, err := native.NewSnapshotter(filepath.Join(dirname, "native"))
if err != nil {
return ctx, nil, func() { cancel() }, err
}
snapshotters := map[string]snapshots.Snapshotter{
"native": snapshotter,
}
for name, fn := range topts.extraSnapshots {
snapshotter, err := fn(filepath.Join(dirname, name))
if err != nil {
return ctx, nil, func() { cancel() }, err
}
snapshotters[name] = snapshotter
}
cs, err := local.NewStore(filepath.Join(dirname, "content"))
if err != nil {
return ctx, nil, func() { cancel() }, err
}
bdb, err := bolt.Open(filepath.Join(dirname, "metadata.db"), 0644, nil)
if err != nil {
return ctx, nil, func() { cancel() }, err
}
db := metadata.NewDB(bdb, cs, snapshotters)
if err := db.Init(ctx); err != nil {
return ctx, nil, func() { cancel() }, err
}
return ctx, db, func() {
bdb.Close()
if err := os.RemoveAll(dirname); err != nil {
fmt.Println("Failed removing temp dir")
}
cancel()
}, nil
}
func FuzzContentStore(data []byte) int {
ctx, db, cancel, err := testDB()
defer cancel()
if err != nil {
return 0
}
cs := db.ContentStore()
f := fuzz.NewConsumer(data)
noOfOperations, err := f.GetInt()
if err != nil {
return 0
}
maxOperations := 50
for i := 0; i < noOfOperations%maxOperations; i++ {
opType, err := f.GetInt()
if err != nil {
return 0
}
if opType%1 == 0 {
blob, err := f.GetBytes()
if err != nil {
return 0
}
dgst := digest.FromBytes(blob)
err = dgst.Validate()
if err != nil {
return 0
}
_, _ = cs.Info(ctx, dgst)
} else if opType%2 == 0 {
info := content.Info{}
err = f.GenerateStruct(&info)
if err != nil {
return 0
}
_, _ = cs.Update(ctx, info)
} else if opType%3 == 0 {
walkFn := func(info content.Info) error {
return nil
}
_ = cs.Walk(ctx, walkFn)
} else if opType%4 == 0 {
blob, err := f.GetBytes()
if err != nil {
return 0
}
dgst := digest.FromBytes(blob)
err = dgst.Validate()
if err != nil {
return 0
}
_ = cs.Delete(ctx, dgst)
} else if opType%5 == 0 {
_, _ = cs.ListStatuses(ctx)
} else if opType%6 == 0 {
ref, err := f.GetString()
if err != nil {
return 0
}
_, _ = cs.Status(ctx, ref)
} else if opType%7 == 0 {
ref, err := f.GetString()
if err != nil {
return 0
}
_ = cs.Abort(ctx, ref)
} else if opType%8 == 0 {
desc := ocispec.Descriptor{}
err = f.GenerateStruct(&desc)
if err != nil {
return 0
}
ref, err := f.GetString()
if err != nil {
return 0
}
csWriter, err := cs.Writer(ctx,
content.WithDescriptor(desc),
content.WithRef(ref))
if err != nil {
return 0
}
defer csWriter.Close()
p, err := f.GetBytes()
if err != nil {
return 0
}
_, _ = csWriter.Write(p)
_ = csWriter.Commit(ctx, 0, csWriter.Digest())
}
}
return 1
}

View File

@ -61,6 +61,11 @@ compile_go_fuzzer github.com/containerd/containerd/contrib/fuzz FuzzCSWalk fuzz_
compile_go_fuzzer github.com/containerd/containerd/contrib/fuzz FuzzArchiveExport fuzz_archive_export
compile_go_fuzzer github.com/containerd/containerd/contrib/fuzz FuzzParseAuth fuzz_parse_auth
compile_go_fuzzer github.com/containerd/containerd/contrib/fuzz FuzzParseProcPIDStatus fuzz_parse_proc_pid_status
compile_go_fuzzer github.com/containerd/containerd/contrib/fuzz FuzzImageStore fuzz_image_store
compile_go_fuzzer github.com/containerd/containerd/contrib/fuzz FuzzLeaseManager fuzz_lease_manager
compile_go_fuzzer github.com/containerd/containerd/contrib/fuzz FuzzContainerStore fuzz_container_store
compile_go_fuzzer github.com/containerd/containerd/contrib/fuzz FuzzContentStore fuzz_content_store
# The below fuzzers require more setup than the fuzzers above.
# We need the binaries from "make".
@ -72,7 +77,7 @@ export GOARCH=amd64
# Build runc
cd $SRC/
git clone https://github.com/opencontainers/runc
git clone https://github.com/opencontainers/runc --branch release-1.0
cd runc
make
make install