From 3749c67a26f254b1f6dede1f6c79aef9cae0721d Mon Sep 17 00:00:00 2001 From: AdamKorcz Date: Fri, 24 Sep 2021 23:24:51 +0100 Subject: [PATCH] Fuzzing: Initial commit --- fuzz/Dockerfile | 63 +++++++++++++++++++ fuzz/conditions_fuzzer.go | 128 ++++++++++++++++++++++++++++++++++++++ fuzz/fuzz.go | 70 +++++++++++++++++++++ fuzz/tls_fuzzer.go | 17 +++++ 4 files changed, 278 insertions(+) create mode 100644 fuzz/Dockerfile create mode 100644 fuzz/conditions_fuzzer.go create mode 100644 fuzz/fuzz.go create mode 100644 fuzz/tls_fuzzer.go diff --git a/fuzz/Dockerfile b/fuzz/Dockerfile new file mode 100644 index 000000000..b83b16d02 --- /dev/null +++ b/fuzz/Dockerfile @@ -0,0 +1,63 @@ +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 && 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 diff --git a/fuzz/conditions_fuzzer.go b/fuzz/conditions_fuzzer.go new file mode 100644 index 000000000..00928797a --- /dev/null +++ b/fuzz/conditions_fuzzer.go @@ -0,0 +1,128 @@ +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" +) + +func FuzzGetterConditions(data []byte) int { + f := fuzz.NewConsumer(data) + + noOfConditions, err := f.GetInt() + if err != nil { + return 0 + } + 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 0 + } + conditions = append(conditions, c) + } + obj := &testdata.Fake{} + obj.SetConditions(conditions) + + targetCondition, err := f.GetString() + if err != nil { + return 0 + } + SetSummary(obj, targetCondition) + return 1 +} + +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 + } + _, _ = m.Match(actual) + return 1 +} + +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 +} + +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 +} + +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 +} + +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 +} diff --git a/fuzz/fuzz.go b/fuzz/fuzz.go new file mode 100644 index 000000000..8b2bf851d --- /dev/null +++ b/fuzz/fuzz.go @@ -0,0 +1,70 @@ +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" +) + +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 +} + +func FuzzLibGit2Error(data []byte) int { + err := errors.New(string(data)) + _ = gitutil.LibGit2Error(err) + return 1 +} + +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 +} diff --git a/fuzz/tls_fuzzer.go b/fuzz/tls_fuzzer.go new file mode 100644 index 000000000..9e6aa2da9 --- /dev/null +++ b/fuzz/tls_fuzzer.go @@ -0,0 +1,17 @@ +package tls + +import ( + fuzz "github.com/AdaLogics/go-fuzz-headers" + corev1 "k8s.io/api/core/v1" +) + +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 +}