From 6b148d35744c21db145769a966a3016ae1e1e087 Mon Sep 17 00:00:00 2001 From: Book Moons <35854232+bookmoons@users.noreply.github.com> Date: Thu, 29 Aug 2019 01:15:04 -0400 Subject: [PATCH 1/6] Define fuzz targets --- server/server_fuzz.go | 128 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 server/server_fuzz.go diff --git a/server/server_fuzz.go b/server/server_fuzz.go new file mode 100644 index 0000000..b97ea88 --- /dev/null +++ b/server/server_fuzz.go @@ -0,0 +1,128 @@ +// +build gofuzz + +package server + +import ( + "crypto/tls" + "io/ioutil" + "net" + "strings" +) + +// FuzzProfile tests the profile server. +func FuzzProfile(fuzz []byte) int { + if len(fuzz) == 0 { + return -1 + } + server, err := New(EnableProfiler()) + if err != nil { + panic(err.Error()) + } + server.Run() + defer server.profileListener.Close() + defer server.httpListener.Close() + address := server.profileListener.Addr + connection, err := net.Dial("tcp", address) + if err != nil { + panic(err.Error()) + } + _, err = connection.Write(fuzz) + if err != nil { + return 0 + } + response, err := ioutil.ReadAll(connection) + if err != nil { + return 0 + } + err = connection.Close() + if err != nil { + return 0 + } + fields := strings.Fields(string(response)) + if len(fields) < 2 { + panic("invalid HTTP response") + } + code := fields[1] + if code == "500" { + panic("server panicked") + } + return 1 +} + +// FuzzHTTP tests the HTTP server. +func FuzzHTTP(fuzz []byte) int { + if len(fuzz) == 0 { + return -1 + } + server, err := New(Listener("localhost")) + if err != nil { + panic(err.Error()) + } + server.Run() + defer server.httpListener.Close() + address := server.httpListener.Addr + connection, err := net.Dial("tcp", address) + if err != nil { + panic(err.Error()) + } + _, err = connection.Write(fuzz) + if err != nil { + return 0 + } + response, err := ioutil.ReadAll(connection) + if err != nil { + return 0 + } + err = connection.Close() + if err != nil { + return 0 + } + fields := strings.Fields(string(response)) + if len(fields) < 2 { + panic("invalid HTTP response") + } + code := fields[1] + if code == "500" { + panic("server panicked") + } + return 1 +} + +// FuzzHTTPS tests the HTTPS server. +func FuzzHTTPS(fuzz []byte) int { + if len(fuzz) == 0 { + return -1 + } + server, err := New(TLSListener("localhost", true)) + if err != nil { + panic(err.Error()) + } + server.Run() + defer server.httpsListener.Close() + address := server.httpsListener.Addr + connection, err := tls.Dial("tcp", address, nil) + if err != nil { + panic(err.Error()) + } + _, err = connection.Write(fuzz) + if err != nil { + return 0 + } + response, err := ioutil.ReadAll(connection) + if err != nil { + return 0 + } + err = connection.Close() + if err != nil { + return 0 + } + fields := strings.Fields(string(response)) + if len(fields) < 2 { + panic("invalid HTTP response") + } + code := fields[1] + if code == "500" { + panic("server panicked") + } + return 1 +} From 76f00c5d043b44e949ead60de5a3174605d8101c Mon Sep 17 00:00:00 2001 From: Book Moons <35854232+bookmoons@users.noreply.github.com> Date: Thu, 29 Aug 2019 01:17:28 -0400 Subject: [PATCH 2/6] Configure Fuzzit --- .travis.yml | 15 +++++++++++++++ fuzzit.sh | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100755 fuzzit.sh diff --git a/.travis.yml b/.travis.yml index 1e9b611..025c019 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,9 @@ sudo: false os: - linux +services: + - docker + go: - 1.10.x - 1.11.x @@ -19,6 +22,18 @@ script: - go vet ./... - go test ./... +jobs: + include: + - stage: Fuzz regression + go: 1.12.x + dist: bionic + script: ./fuzzit.sh local-regression + - stage: Fuzz + if: branch = master AND type IN (push) + go: 1.12.x + dist: bionic + script: ./fuzzit.sh fuzzing + before_deploy: - mkdir -p release - "GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags -a -tags netgo -ldflags '-s -w -extldflags -static' -o release/transfersh-$TRAVIS_TAG-linux-amd64" diff --git a/fuzzit.sh b/fuzzit.sh new file mode 100755 index 0000000..1daa39c --- /dev/null +++ b/fuzzit.sh @@ -0,0 +1,38 @@ +#!/bin/bash +set -xe + +# Validate arguments +if [ "$#" -ne 1 ]; then + echo "Usage: $0 " + exit 1 +fi +if [ -z "$FUZZIT_API_KEY" ]; then + echo "Set FUZZIT_API_KEY to your Fuzzit API key" + exit 2 +fi + +# Configure +ROOT=./server +TYPE=$1 + +# Setup +export GO111MODULE="off" +go get -u github.com/dvyukov/go-fuzz/go-fuzz github.com/dvyukov/go-fuzz/go-fuzz-build +go get -d -v -u ./... +if [ ! -f fuzzit ]; then + wget -q -O fuzzit https://github.com/fuzzitdev/fuzzit/releases/download/v2.4.29/fuzzit_Linux_x86_64 + chmod a+x fuzzit +fi + +# Fuzz +function fuzz { + FUNC=Fuzz$1 + TARGET=$2 + DIR=${3:-$ROOT} + go-fuzz-build -libfuzzer -func $FUNC -o fuzzer.a $DIR + clang -fsanitize=fuzzer fuzzer.a -o fuzzer + ./fuzzit create job --type $TYPE $TARGET fuzzer +} +fuzz Profile profile +fuzz HTTP http +fuzz HTTPS https From 806006a0b8abfa695720332bdb86eaae297dd899 Mon Sep 17 00:00:00 2001 From: Book Moons <35854232+bookmoons@users.noreply.github.com> Date: Thu, 29 Aug 2019 01:35:08 -0400 Subject: [PATCH 3/6] Add Fuzzit badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 912cc85..96528e7 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# transfer.sh [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/dutchcoders/transfer.sh?utm_source=badge&utm_medium=badge&utm_campaign=&utm_campaign=pr-badge&utm_content=badge) [![Go Report Card](https://goreportcard.com/badge/github.com/dutchcoders/transfer.sh)](https://goreportcard.com/report/github.com/dutchcoders/transfer.sh) [![Docker pulls](https://img.shields.io/docker/pulls/dutchcoders/transfer.sh.svg)](https://hub.docker.com/r/dutchcoders/transfer.sh/) [![Build Status](https://travis-ci.org/dutchcoders/transfer.sh.svg?branch=master)](https://travis-ci.org/dutchcoders/transfer.sh) +# transfer.sh [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/dutchcoders/transfer.sh?utm_source=badge&utm_medium=badge&utm_campaign=&utm_campaign=pr-badge&utm_content=badge) [![Go Report Card](https://goreportcard.com/badge/github.com/dutchcoders/transfer.sh)](https://goreportcard.com/report/github.com/dutchcoders/transfer.sh) [![Docker pulls](https://img.shields.io/docker/pulls/dutchcoders/transfer.sh.svg)](https://hub.docker.com/r/dutchcoders/transfer.sh/) [![Build Status](https://travis-ci.org/dutchcoders/transfer.sh.svg?branch=master)](https://travis-ci.org/dutchcoders/transfer.sh) [![Fuzzit Status](https://app.fuzzit.dev/badge?org_id=transfer.sh)](https://app.fuzzit.dev/orgs/transfer.sh/dashboard) Easy and fast file sharing from the command-line. This code contains the server with everything you need to create your own instance. From 071ecb491c8b1a0b988b9caa4b4f275c43efe59e Mon Sep 17 00:00:00 2001 From: Book Moons <35854232+bookmoons@users.noreply.github.com> Date: Thu, 29 Aug 2019 03:23:12 -0400 Subject: [PATCH 4/6] fuzz: Remove API key requirement Prevents use of public corpus without API key. --- fuzzit.sh | 4 ---- 1 file changed, 4 deletions(-) diff --git a/fuzzit.sh b/fuzzit.sh index 1daa39c..90e823e 100755 --- a/fuzzit.sh +++ b/fuzzit.sh @@ -6,10 +6,6 @@ if [ "$#" -ne 1 ]; then echo "Usage: $0 " exit 1 fi -if [ -z "$FUZZIT_API_KEY" ]; then - echo "Set FUZZIT_API_KEY to your Fuzzit API key" - exit 2 -fi # Configure ROOT=./server From b40e9d1fb8643a0e180b9c3d6e338d3e21566f4d Mon Sep 17 00:00:00 2001 From: Book Moons <35854232+bookmoons@users.noreply.github.com> Date: Thu, 29 Aug 2019 03:37:00 -0400 Subject: [PATCH 5/6] fuzz: Qualify target ID Includes org name in target ID. --- fuzzit.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fuzzit.sh b/fuzzit.sh index 90e823e..2f1b4f6 100755 --- a/fuzzit.sh +++ b/fuzzit.sh @@ -8,6 +8,7 @@ if [ "$#" -ne 1 ]; then fi # Configure +NAME=transfersh ROOT=./server TYPE=$1 @@ -27,7 +28,7 @@ function fuzz { DIR=${3:-$ROOT} go-fuzz-build -libfuzzer -func $FUNC -o fuzzer.a $DIR clang -fsanitize=fuzzer fuzzer.a -o fuzzer - ./fuzzit create job --type $TYPE $TARGET fuzzer + ./fuzzit create job --type $TYPE $NAME/$TARGET fuzzer } fuzz Profile profile fuzz HTTP http From 8c5ef8f2e15ef6adb32e02fb7500dfc10c3e754e Mon Sep 17 00:00:00 2001 From: Andrea Spacca Date: Sat, 31 Aug 2019 11:41:34 +0200 Subject: [PATCH 6/6] Fuzz local storage test --- .travis.yml | 4 +- fuzzit.sh | 4 +- server/server_fuzz.go | 156 ++++++++++++++++-------------------------- 3 files changed, 62 insertions(+), 102 deletions(-) diff --git a/.travis.yml b/.travis.yml index 025c019..6e1f47a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,7 +29,7 @@ jobs: dist: bionic script: ./fuzzit.sh local-regression - stage: Fuzz - if: branch = master AND type IN (push) + if: branch = fuzz AND type IN (push) go: 1.12.x dist: bionic script: ./fuzzit.sh fuzzing @@ -53,5 +53,5 @@ deploy: skip_cleanup: true on: tags: true - go: tip + go: 1.12.x overwrite: true diff --git a/fuzzit.sh b/fuzzit.sh index 2f1b4f6..5e503e9 100755 --- a/fuzzit.sh +++ b/fuzzit.sh @@ -30,6 +30,4 @@ function fuzz { clang -fsanitize=fuzzer fuzzer.a -o fuzzer ./fuzzit create job --type $TYPE $NAME/$TARGET fuzzer } -fuzz Profile profile -fuzz HTTP http -fuzz HTTPS https +fuzz LocalStorage local-storage diff --git a/server/server_fuzz.go b/server/server_fuzz.go index b97ea88..7a01c8b 100644 --- a/server/server_fuzz.go +++ b/server/server_fuzz.go @@ -3,126 +3,88 @@ package server import ( - "crypto/tls" - "io/ioutil" - "net" - "strings" + "bytes" + "io" + "math/rand" + "reflect" ) -// FuzzProfile tests the profile server. -func FuzzProfile(fuzz []byte) int { - if len(fuzz) == 0 { +const applicationOctetStream = "application/octet-stream" + +// FuzzLocalStorage tests the Local Storage. +func FuzzLocalStorage(fuzz []byte) int { + var fuzzLength = uint64(len(fuzz)) + if fuzzLength == 0 { return -1 } - server, err := New(EnableProfiler()) - if err != nil { - panic(err.Error()) - } - server.Run() - defer server.profileListener.Close() - defer server.httpListener.Close() - address := server.profileListener.Addr - connection, err := net.Dial("tcp", address) - if err != nil { - panic(err.Error()) - } - _, err = connection.Write(fuzz) - if err != nil { - return 0 - } - response, err := ioutil.ReadAll(connection) - if err != nil { - return 0 - } - err = connection.Close() + + storage, err := NewLocalStorage("/tmp", nil) if err != nil { - return 0 + panic("unable to create local storage") } - fields := strings.Fields(string(response)) - if len(fields) < 2 { - panic("invalid HTTP response") - } - code := fields[1] - if code == "500" { - panic("server panicked") - } - return 1 -} -// FuzzHTTP tests the HTTP server. -func FuzzHTTP(fuzz []byte) int { - if len(fuzz) == 0 { - return -1 - } - server, err := New(Listener("localhost")) + token := Encode(10000000 + int64(rand.Intn(1000000000))) + filename := Encode(10000000 + int64(rand.Intn(1000000000))) + ".bin" + + input := bytes.NewReader(fuzz) + err = storage.Put(token, filename, input, applicationOctetStream, fuzzLength) if err != nil { - panic(err.Error()) + panic("unable to save file") } - server.Run() - defer server.httpListener.Close() - address := server.httpListener.Addr - connection, err := net.Dial("tcp", address) + + contentType, contentLength, err := storage.Head(token, filename) if err != nil { - panic(err.Error()) + panic("not visible through head") } - _, err = connection.Write(fuzz) - if err != nil { - return 0 + + if contentType != applicationOctetStream { + panic("incorrect content type") } - response, err := ioutil.ReadAll(connection) - if err != nil { - return 0 + + if contentLength != fuzzLength { + panic("incorrect content length") } - err = connection.Close() + + output, contentType, contentLength, err := storage.Get(token, filename) if err != nil { - return 0 - } - fields := strings.Fields(string(response)) - if len(fields) < 2 { - panic("invalid HTTP response") - } - code := fields[1] - if code == "500" { - panic("server panicked") + panic("not visible through get") } - return 1 -} -// FuzzHTTPS tests the HTTPS server. -func FuzzHTTPS(fuzz []byte) int { - if len(fuzz) == 0 { - return -1 + if contentType != applicationOctetStream { + panic("incorrect content type") } - server, err := New(TLSListener("localhost", true)) - if err != nil { - panic(err.Error()) + + if contentLength != fuzzLength { + panic("incorrect content length") } - server.Run() - defer server.httpsListener.Close() - address := server.httpsListener.Addr - connection, err := tls.Dial("tcp", address, nil) - if err != nil { - panic(err.Error()) + + var length uint64 + b := make([]byte, len(fuzz)) + for { + n, err := output.Read(b) + length += uint64(n) + if err == io.EOF { + break + } } - _, err = connection.Write(fuzz) - if err != nil { - return 0 + + if !reflect.DeepEqual(b, fuzz) { + panic("incorrect content body") } - response, err := ioutil.ReadAll(connection) - if err != nil { - return 0 + + if length != fuzzLength { + panic("incorrect content length") } - err = connection.Close() + + err = storage.Delete(token, filename) if err != nil { - return 0 - } - fields := strings.Fields(string(response)) - if len(fields) < 2 { - panic("invalid HTTP response") + panic("unable to delete file") } - code := fields[1] - if code == "500" { - panic("server panicked") + + _, _, err = storage.Head(token, filename) + if !storage.IsNotExist(err) { + panic("file not deleted") } + return 1 }