Skip to content
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

Fuzzing: Initial commit #150

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions fuzz/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
FROM golang:1.16-buster as builder
RUN set -eux; \
apt-get update \
&& apt-get upgrade -y \
&& apt-get install -y \
clang \
curl \
vim

RUN git clone https://github.com/fluxcd/pkg /workspace
RUN mkdir /workspace/fuzzing


RUN go get -u github.com/dvyukov/go-fuzz/go-fuzz@latest github.com/dvyukov/go-fuzz/go-fuzz-build@latest
RUN go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest
RUN go get github.com/AdaLogics/go-fuzz-headers

RUN go get golang.org/x/sync

WORKDIR /workspace/fuzzing
COPY fuzz.go /workspace/fuzzing/
COPY conditions_fuzzer.go /workspace/runtime/conditions/
COPY tls_fuzzer.go /workspace/runtime/tls/
RUN cd /workspace/fuzzing && go mod init fuzzing && go mod tidy && go mod download && go mod tidy
RUN go mod download github.com/dvyukov/go-fuzz


# Build the fuzzers
RUN mkdir /fuzzers

RUN go-fuzz-build -libfuzzer -func=FuzzUntar\
&& clang -o /fuzzers/FuzzUntar reflect-fuzz.a \
-fsanitize=fuzzer
RUN go-fuzz-build -libfuzzer -func=FuzzLibGit2Error\
&& clang -o /fuzzers/FuzzLibGit2Error reflect-fuzz.a \
-fsanitize=fuzzer
RUN go-fuzz-build -libfuzzer -func=FuzzEventInfof\
&& clang -o /fuzzers/FuzzEventInfof reflect-fuzz.a \
-fsanitize=fuzzer

WORKDIR /workspace/runtime/tls
RUN go get github.com/AdaLogics/go-fuzz-headers
RUN go get github.com/dvyukov/go-fuzz/go-fuzz-dep
RUN go-fuzz-build -libfuzzer -func=FuzzTlsConfig\
&& clang -o /fuzzers/FuzzTlsConfig reflect-fuzz.a \
-fsanitize=fuzzer

WORKDIR /workspace/runtime/conditions
RUN go-fuzz-build -libfuzzer -func=FuzzGetterConditions\
&& clang -o /fuzzers/FuzzGetterConditions reflect-fuzz.a \
-fsanitize=fuzzer
RUN go-fuzz-build -libfuzzer -func=FuzzConditionsMatch\
&& clang -o /fuzzers/FuzzConditionsMatch reflect-fuzz.a \
-fsanitize=fuzzer
RUN go-fuzz-build -libfuzzer -func=FuzzPatchApply\
&& clang -o /fuzzers/FuzzPatchApply reflect-fuzz.a \
-fsanitize=fuzzer
RUN go-fuzz-build -libfuzzer -func=FuzzConditionsUnstructured\
&& clang -o /fuzzers/FuzzConditionsUnstructured reflect-fuzz.a \
-fsanitize=fuzzer

#RUN /fuzzers/FuzzLibGit2Error
161 changes: 161 additions & 0 deletions fuzz/conditions_fuzzer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
//go:build gofuzz
// +build gofuzz

/*
Copyright 2021 The Flux 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 conditions

import (
fuzz "github.com/AdaLogics/go-fuzz-headers"
"github.com/fluxcd/pkg/runtime/conditions/testdata"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)

// FuzzGetterConditions implements a fuzzer that
// targets SetSummary()
func FuzzGetterConditions(data []byte) int {
f := fuzz.NewConsumer(data)

// Create slice of metav1.Condition
noOfConditions, err := f.GetInt()
if err != nil {
return 0
}
maxNoOfConditions := 30
conditions := make([]metav1.Condition, 0)

// Add Conditions in the slice
for i := 0; i < noOfConditions%maxNoOfConditions; i++ {
c := metav1.Condition{}
err = f.GenerateStruct(&c)
if err != nil {
return 0
}
conditions = append(conditions, c)
}
obj := &testdata.Fake{}
obj.SetConditions(conditions)

targetCondition, err := f.GetString()
if err != nil {
return 0
}

// Call the target
SetSummary(obj, targetCondition)
return 1
}

// FuzzConditionsMatch implements a fuzzer that
// that targets Match()
func FuzzConditionsMatch(data []byte) int {
f := fuzz.NewConsumer(data)
condition := metav1.Condition{}
err := f.GenerateStruct(&condition)
if err != nil {
return 0
}
m := MatchCondition(condition)

actual := metav1.Condition{}
err = f.GenerateStruct(&actual)
if err != nil {
return 0
}

// Call the target
_, _ = m.Match(actual)
return 1
}

// newGetter allows the fuzzer to create a Getter
// This is just a utility
func newGetter(f *fuzz.ConsumeFuzzer) (Getter, error) {
obj := &testdata.Fake{}
noOfConditions, err := f.GetInt()
if err != nil {
return obj, err
}
maxNoOfConditions := 30
conditions := make([]metav1.Condition, 0)
for i := 0; i < noOfConditions%maxNoOfConditions; i++ {
c := metav1.Condition{}
err = f.GenerateStruct(&c)
if err != nil {
return obj, err
}
conditions = append(conditions, c)
}

obj.SetConditions(conditions)
return obj, nil
}

// newSetter allows the fuzzer to create a Setter
// This is just a utility
func newSetter(f *fuzz.ConsumeFuzzer) (Setter, error) {
obj := &testdata.Fake{}
noOfConditions, err := f.GetInt()
if err != nil {
return obj, err
}
maxNoOfConditions := 30
conditions := make([]metav1.Condition, 0)
for i := 0; i < noOfConditions%maxNoOfConditions; i++ {
c := metav1.Condition{}
err = f.GenerateStruct(&c)
if err != nil {
return obj, err
}
conditions = append(conditions, c)
}
obj.SetConditions(conditions)
return obj, nil
}

// FuzzPatchApply implements a fuzzer that targets patch.Apply
func FuzzPatchApply(data []byte) int {
f := fuzz.NewConsumer(data)

before, err := newGetter(f)
if err != nil {
return 0
}
after, err := newGetter(f)
if err != nil {
return 0
}
patch := NewPatch(before, after)

setter, err := newSetter(f)
if err != nil {
return 0
}
_ = patch.Apply(setter)
return 1
}

// FuzzConditionsUnstructured implements a fuzzer
// that targets GetConditions()
func FuzzConditionsUnstructured(data []byte) int {
u := &unstructured.Unstructured{}
f := fuzz.NewConsumer(data)
err := f.GenerateStruct(u)
if err != nil {
return 0
}
g := UnstructuredGetter(u)
_ = g.GetConditions()
return 1
}
91 changes: 91 additions & 0 deletions fuzz/fuzz.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
//go:build gofuzz
// +build gofuzz

/*
Copyright 2021 The Flux 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 fuzzing

import (
"bytes"
"encoding/json"
"errors"
fuzz "github.com/AdaLogics/go-fuzz-headers"
"github.com/fluxcd/pkg/gitutil"
"github.com/fluxcd/pkg/runtime/events"
"github.com/fluxcd/pkg/untar"
"io"
corev1 "k8s.io/api/core/v1"
"net/http"
"net/http/httptest"
"os"
)

// FuzzUntar implements a fuzzer that
// targets untar.Untar()
func FuzzUntar(data []byte) int {
r := bytes.NewReader(data)
tmpDir, err := os.MkdirTemp("", "dir-")
if err != nil {
return 0
}
defer os.RemoveAll(tmpDir)
_, _ = untar.Untar(r, tmpDir)
return 1
}

// FuzzLibGit2Error implements a fuzzer that
// targets gitutil.LibGit2Error
func FuzzLibGit2Error(data []byte) int {
err := errors.New(string(data))
_ = gitutil.LibGit2Error(err)
return 1
}

// FuzzEventInfof implements a fuzzer that
// targets eventRecorder.EventInfof()
func FuzzEventInfof(data []byte) int {
f := fuzz.NewConsumer(data)
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
b, err := io.ReadAll(r.Body)
if err != nil {
return
}

var payload events.Event
err = json.Unmarshal(b, &payload)
if err != nil {
return
}
}))
defer ts.Close()
eventRecorder, err := events.NewRecorder(ts.URL, "test-controller")
if err != nil {
return 0
}
eventRecorder.Client.RetryMax = 2
obj := corev1.ObjectReference{}
err = f.GenerateStruct(&obj)
if err != nil {
return 0
}
severity, err := f.GetString()
if err != nil {
return 0
}
reason, err := f.GetString()
if err != nil {
return 0
}
_ = eventRecorder.EventInfof(obj, nil, severity, reason, obj.Name)
return 1
}
34 changes: 34 additions & 0 deletions fuzz/tls_fuzzer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//go:build gofuzz
// +build gofuzz

/*
Copyright 2021 The Flux 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 tls

import (
fuzz "github.com/AdaLogics/go-fuzz-headers"
corev1 "k8s.io/api/core/v1"
)

// FuzzTlsConfig implements a fuzzer that
// targets ConfigFromSecret()
func FuzzTlsConfig(data []byte) int {
secret := &corev1.Secret{}
f := fuzz.NewConsumer(data)
err := f.GenerateStruct(secret)
if err != nil {
return 0
}
_, _ = ConfigFromSecret(secret)
return 1
}