Skip to content

Commit

Permalink
Add fuzz tests for storage_fs (#601)
Browse files Browse the repository at this point in the history
This commit uses native go fuzzing to fuzz test implementations
of storage in storage_fs.

moved fuzzing testdata for storage_fs in separate repo

added make target and script for importing fuzz data and running all fuzz tests

Signed-off-by: Alex Stan <alexandrustan96@yahoo.ro>
  • Loading branch information
alexstan12 authored Jul 27, 2022
1 parent b5f27c5 commit 16e9822
Show file tree
Hide file tree
Showing 6 changed files with 870 additions and 12 deletions.
11 changes: 11 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -283,3 +283,14 @@ bats-metrics: binary check-skopeo $(BATS)
bats-metrics-verbose: EXTENSIONS=metrics
bats-metrics-verbose: binary check-skopeo $(BATS)
$(BATS) --trace -p --verbose-run --print-output-on-failure --show-output-of-passing-tests test/blackbox/metrics.bats

.PHONY: fuzz-all
fuzz-all: fuzztime=${1}
fuzz-all:
rm -rf test-data; \
rm -rf pkg/storage/testdata; \
git clone https://github.com/project-zot/test-data.git; \
mv test-data/storage pkg/storage/testdata; \
rm -rf test-data; \
bash test/scripts/fuzzAll.sh ${fuzztime}; \
rm -rf pkg/storage/testdata; \
13 changes: 13 additions & 0 deletions README_fuzz.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Fuzzing in Zot

This project makes use of native Go 1.18 fuzzing. An in-depth tutorial for fuzzing in Go can be found [here](https://go.dev/doc/fuzz/).
As language specifies, fuzz tests are included among unit-tests, inside the the same `*_test.go files`, in the packages they intend to fuzz. See [fuzzing for local storage](pkg/storage/local_test.go)

Zot doesn't store the test data for fuzzing in the same repo, nor it is added before fuzzing with `(*testing.F).Add` . Instead, it is stored in a separate repo called [test-data](https://github.com/project-zot/test-data).

To start fuzzing locally, one can use the Make target [fuzz-all](Makefile) .
**The default runtime for each fuzz test is 10s**, which can be overriden with the **fuzztime** variable
```
make fuzz-all fuzztime=20
```
By running this target, testdata for fuzzing gets downloaded from the previously mentioned repo and the fuzzing begins for every fuzz function that is found.
32 changes: 30 additions & 2 deletions pkg/storage/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@ import (
"errors"
"fmt"
"io"
"io/fs"
"io/ioutil"
"os"
"path"
"path/filepath"
"strings"
"sync"
"syscall"
"time"
"unicode/utf8"

apexlog "github.com/apex/log"
guuid "github.com/gofrs/uuid"
Expand Down Expand Up @@ -186,6 +189,13 @@ func (is *ImageStoreLocal) Unlock(lockStart *time.Time) {

func (is *ImageStoreLocal) initRepo(name string) error {
repoDir := path.Join(is.rootDir, name)

if !utf8.ValidString(name) {
is.log.Error().Msg("input is not valid UTF-8")

return zerr.ErrInvalidRepositoryName
}

// create "blobs" subdir
err := ensureDir(path.Join(repoDir, "blobs"), is.log)
if err != nil {
Expand Down Expand Up @@ -850,6 +860,7 @@ func (is *ImageStoreLocal) NewBlobUpload(repo string) (string, error) {
if err != nil {
return "", zerr.ErrRepoNotFound
}

defer file.Close()

return uid, nil
Expand All @@ -859,6 +870,12 @@ func (is *ImageStoreLocal) NewBlobUpload(repo string) (string, error) {
func (is *ImageStoreLocal) GetBlobUpload(repo, uuid string) (int64, error) {
blobUploadPath := is.BlobUploadPath(repo, uuid)

if !utf8.ValidString(blobUploadPath) {
is.log.Error().Msg("input is not valid UTF-8")

return -1, zerr.ErrInvalidRepositoryName
}

binfo, err := os.Stat(blobUploadPath)
if err != nil {
if os.IsNotExist(err) {
Expand Down Expand Up @@ -1673,12 +1690,23 @@ func ifOlderThan(imgStore *ImageStoreLocal, repo string, delay time.Duration) ca
}

func DirExists(d string) bool {
fi, err := os.Stat(d)
if !utf8.ValidString(d) {
return false
}

fileInfo, err := os.Stat(d)
if err != nil {
if e, ok := err.(*fs.PathError); ok && errors.Is(e.Err, syscall.ENAMETOOLONG) || //nolint: errorlint
errors.Is(e.Err, syscall.EINVAL) {
return false
}
}

if err != nil && os.IsNotExist(err) {
return false
}

if !fi.IsDir() {
if !fileInfo.IsDir() {
return false
}

Expand Down
Loading

0 comments on commit 16e9822

Please sign in to comment.