Skip to content

Commit

Permalink
Adds basic libfuzzer harness
Browse files Browse the repository at this point in the history
This harness simply mounts and unmounts a ramdisk
that is populated by fuzzed data. This fuzz harness
tests that littlefs is able to safely attempt to
mount a corrupted storage device.
  • Loading branch information
nathaniel-brough committed Oct 4, 2024
1 parent b78afe2 commit 2858105
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 1 deletion.
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

ifeq ($(CC),gcc)
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

0 comments on commit 2858105

Please sign in to comment.