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

Adds basic libfuzzer harness #1029

Open
wants to merge 1 commit into
base: devel
Choose a base branch
from
Open
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
27 changes: 26 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,28 @@ BENCH_PERF := $(BENCH_RUNNER:%=%.perf)
BENCH_TRACE := $(BENCH_RUNNER:%=%.trace)
BENCH_CSV := $(BENCH_RUNNER:%=%.csv)

CFLAGS += -fcallgraph-info=su
CFLAGS += -g3
CFLAGS += -I.
CFLAGS += -std=c99 -Wall -Wextra -pedantic
CFLAGS += -Wmissing-prototypes

ifneq ($(CC),clang)
CFLAGS += -fcallgraph-info=su
CFLAGS += -ftrack-macro-expansion=0
endif

ifdef FUZZ
CFLAGS += -fsanitize=fuzzer-no-link
endif

ifdef ASAN
CFLAGS += -fsanitize=address
endif

ifdef UBSAN
CFLAGS += -fsanitize=undefined
endif

ifdef DEBUG
CFLAGS += -O0
else
Expand Down Expand Up @@ -472,6 +488,14 @@ benchmarks-diff: $(BENCH_CSV)
$(BUILDDIR)/lfs: $(OBJ)
$(CC) $(CFLAGS) $^ $(LFLAGS) -o $@

# Libfuzzer is only supported on clang
ifeq ($(CC),clang)
ifdef FUZZ
$(BUILDDIR)/fuzz_mount: $(OBJ) fuzz/fuzz_mount.c
$(CC) $(CFLAGS) $^ -fsanitize=fuzzer -DCUSTOM_MUTATOR $(LFLAGS) -o $@
endif
endif

$(BUILDDIR)/liblfs.a: $(OBJ)
$(AR) rcs $@ $^

Expand Down Expand Up @@ -583,3 +607,4 @@ clean:
rm -f $(BENCH_PERF)
rm -f $(BENCH_TRACE)
rm -f $(BENCH_CSV)
rm -f fuzz_mount
111 changes: 111 additions & 0 deletions fuzz/fuzz_mount.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
#include <string.h>
#include "lfs.h"

#define STORAGE_SIZE 1024*1024

static uint8_t disk_buffer[STORAGE_SIZE];

int min(int a, int b) {
if(a < b) {
return a;
}
return b;
}

static int read(const struct lfs_config *c, lfs_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size) {
memcpy(buffer, &disk_buffer[block*c->read_size + off], size);
return 0;
}

static int prog(const struct lfs_config *cfg, lfs_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size) {
memcpy(&disk_buffer[block*cfg->read_size + off], buffer, size);
return 0;
}

static int erase(const struct lfs_config *cfg, lfs_block_t block) {
(void)cfg;
(void)block;
return 0;
}

static int sync(const struct lfs_config *cfg) {
// sync is a noop
(void)cfg;
return 0;
}

// configuration of the filesystem is provided by this struct
const struct lfs_config filesystem_cfg = {
// block device operations
.read = read,
.prog = prog,
.erase = erase,
.sync = sync,

// block device configuration
.read_size = 1024,
.prog_size = 1024,
.block_size = 1024,
.block_count = 1024,
.cache_size = 1024,
.lookahead_size = 1024,
.block_cycles = 500,
};

int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
if(size == 0) {
return -1;
}
memset(disk_buffer, 0, sizeof(disk_buffer));

// variables used by the filesystem
lfs_t lfs;

// Copy fuzzed data into fake storage device.
memcpy(disk_buffer, data, min(size, STORAGE_SIZE));

// mount the filesystem
int err = lfs_mount(&lfs, &filesystem_cfg);

if (err) {
return 0;
}

// release any resources we were using
lfs_unmount(&lfs);

return 0;
}

#ifdef CUSTOM_MUTATOR

// Forward-declare the libFuzzer's mutator callback.
size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);

size_t LLVMFuzzerCustomMutator(uint8_t *data, size_t size,
size_t max_size, unsigned int seed) {
(void)seed;
memset(disk_buffer, 0, sizeof(disk_buffer));
// variables used by the filesystem
lfs_t lfs;

// Copy fuzzed data into fake storage device.
memcpy(disk_buffer, data, min(size, STORAGE_SIZE));

// Mount the filesystem
int err = lfs_mount(&lfs, &filesystem_cfg);

// Reformat if we can't mount the filesystem
if (err) {
lfs_format(&lfs, &filesystem_cfg);
lfs_mount(&lfs, &filesystem_cfg);
}
lfs_unmount(&lfs);
memcpy(data, disk_buffer, min(STORAGE_SIZE, max_size));

return LLVMFuzzerMutate(data, size, max_size);
}

#endif // CUSTOM_MUTATOR