fsfuzz

small fs fuzzer
git clone git://git.2f30.org/fsfuzz.git
Log | Files | Refs

commit fdd1a1c13ee619f6b23c76b67237b65f09a6920d
Author: sin <sin@2f30.org>
Date:   Tue Jun 25 23:37:02 +0100

Initial commit

Diffstat:
Makefile | 27+++++++++++++++++++++++++++
btrfs.c | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
ext4.c | 33+++++++++++++++++++++++++++++++++
fsfuzz.c | 151++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
fsfuzz.h | 31+++++++++++++++++++++++++++++++
fuzz-scripts/btrfs-fuzz.sh | 12++++++++++++
fuzz-scripts/jfs-fuzz.sh | 12++++++++++++
fuzz-scripts/reiserfs-fuzz.sh | 12++++++++++++
fuzz-scripts/xfs-fuzz.sh | 20++++++++++++++++++++
jfs.c | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
reiserfs.c | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
xfs.c | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
12 files changed, 510 insertions(+), 0 deletions(-)
diff --git a/Makefile b/Makefile @@ -0,0 +1,27 @@ +bin = fsfuzz +ver = 0.1 +CC = gcc +CFLAGS = -Wall -Wextra + +obj = fsfuzz.o \ + btrfs.o \ + xfs.o \ + jfs.o \ + ext4.o \ + reiserfs.o + +$(bin): $(obj) + @echo -e " LD\t"$@ + @$(CC) -o $@ $(obj) + +%.o: %.c + @echo -e " CC\t"$< + @$(CC) $(CFLAGS) -c -o $@ $< + +.PHONY: clean +clean: + @rm -rf $(bin) $(obj) + +.PHONY: all +all: + @make clean && make diff --git a/btrfs.c b/btrfs.c @@ -0,0 +1,53 @@ +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <err.h> + +#include "fsfuzz.h" + +int +btrfs_init(struct fsfuzz_info *fs_info + __attribute__ ((unused))) +{ + srand((unsigned int)time(NULL)); + return 0; +} + +int +btrfs_fuzz(struct fsfuzz_info *fs_info) +{ + char *p; + size_t offset; + size_t i; + + p = fs_info->img; + for (i = 0; i < 32; i++) { + /* The superblock in btrfs is at 0x10000 */ + offset = 0x10000 + (rand() % 4096); + if (offset + 3 >= fs_info->size) { + warnx("Wrong offset, ignoring"); + continue; + } + if (fs_info->verbosity) + printf("[+] Patching offset %#lx with 0xffffffff\n", + (long)offset); + p[offset + 0] = 0xff; + p[offset + 1] = 0xff; + p[offset + 2] = 0xff; + p[offset + 3] = 0xff; + } + return 0; +} + +static struct fsfuzz_ops btrfs_fuzz_ops = { + .name = "btrfs", + .init = btrfs_init, + .fuzz = btrfs_fuzz +}; + +__attribute__ ((constructor)) +static void +btrfs_register(void) +{ + fsfuzz_register(&btrfs_fuzz_ops); +} diff --git a/ext4.c b/ext4.c @@ -0,0 +1,33 @@ +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <err.h> + +#include "fsfuzz.h" + +int +ext4_init(struct fsfuzz_info *fs_info + __attribute__ ((unused))) +{ + return 0; +} + +int +ext4_fuzz(struct fsfuzz_info *fs_info + __attribute__ ((unused))) +{ + return 0; +} + +static struct fsfuzz_ops ext4_fuzz_ops = { + .name = "ext4", + .init = ext4_init, + .fuzz = ext4_fuzz +}; + +__attribute__ ((constructor)) +static void +ext4_register(void) +{ + fsfuzz_register(&ext4_fuzz_ops); +} diff --git a/fsfuzz.c b/fsfuzz.c @@ -0,0 +1,151 @@ +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <fcntl.h> +#include <unistd.h> + +#include <stdio.h> +#include <stdlib.h> +#include <err.h> +#include <errno.h> +#include <getopt.h> +#include <string.h> + +#include "fsfuzz.h" + +/* All register fuzzer operations */ +static struct fsfuzz_ops *fsfuzz_ops[16]; +/* Flag to select the filesystem type */ +static int fs_flag; +static int verbose_flag; + +void +fsfuzz_register(struct fsfuzz_ops *ops) +{ + size_t i; + + if (!ops) + errx(1, "Invalid ops structure"); + if (!ops->fuzz) + errx(1, "Unimplemented fuzz() callback, aborting"); + + for (i = 0; i < ARRAY_SIZE(fsfuzz_ops); i++) + if (!fsfuzz_ops[i]) + break; + if (i == ARRAY_SIZE(fsfuzz_ops)) + errx(1, "Blah, not enough space in fsfuzz_ops array"); + + fsfuzz_ops[i] = ops; +} + +static void +usage(const char *prog) +{ + fprintf(stderr, "usage: %s [l | f: | v | h] fs-img\n", prog); + fprintf(stderr, " -l\tlist registered fuzzers\n"); + fprintf(stderr, " -f\tfilesystem type\n"); + fprintf(stderr, " -v\tverbose output\n"); + fprintf(stderr, " -h\tthis help menu\n"); + exit(EXIT_FAILURE); +} + +static void +dump_fuzzers(void) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(fsfuzz_ops); i++) + if (fsfuzz_ops[i]) + printf("%s\n", fsfuzz_ops[i]->name); +} + +static struct fsfuzz_ops * +match_fs(const char *fs) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(fsfuzz_ops); i++) + if (fsfuzz_ops[i]) + if (!strcmp(fsfuzz_ops[i]->name, fs)) + return fsfuzz_ops[i]; + return NULL; +} + +int +main(int argc, char *argv[]) +{ + int fd; + struct stat buf; + char *p; + int c; + const char *prog; + char *fs = NULL; + struct fsfuzz_ops *fs_ops; + struct fsfuzz_info fs_info; + + setbuf(stdout, NULL); + + prog = *argv; + while ((c = getopt(argc, argv, "lhf:v")) != -1) { + switch (c) { + case 'l': + dump_fuzzers(); + return EXIT_SUCCESS; + case 'f': + fs_flag = 1; + fs = strdup(optarg); + if (!fs) + err(1, "strdup"); + break; + case 'v': + verbose_flag = 1; + break; + case 'h': + usage(prog); + break; + default: + return EXIT_FAILURE; + } + } + if (optind >= argc) + usage(prog); + + if (!fs_flag) + errx(1, "Please select the fs type via the -f flag"); + + fs_ops = match_fs(fs); + if (!fs_ops) + errx(1, "No fuzzer available for filesystem %s", fs); + + fd = open(argv[optind], O_RDWR); + if (fd < 0) + err(1, "Can't open %s", argv[optind]); + + if (fstat(fd, &buf) < 0) + err(1, "fstat"); + + p = mmap(0, buf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, + fd, 0); + if (p == MAP_FAILED) + err(1, "mmap"); + + fs_info.img = p; + fs_info.size = buf.st_size; + fs_info.verbosity = verbose_flag; + + /* We don't require init/free to be implemented */ + if (fs_ops->init) + fs_ops->init(&fs_info); + + fs_ops->fuzz(&fs_info); + + if (fs_ops->free) + fs_ops->free(&fs_info); + + if (munmap(p, buf.st_size) < 0) + err(1, "munmap"); + + close(fd); + free(fs); + return EXIT_SUCCESS; +} diff --git a/fsfuzz.h b/fsfuzz.h @@ -0,0 +1,31 @@ +#ifndef FSFUZZ_H +#define FSFUZZ_H + +#include <stddef.h> + +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +struct fsfuzz_info { + /* Pointer to actual image */ + void *img; + /* Size of image on disk */ + size_t size; + /* Number of completed fuzzing sessions */ + int genertion; + /* Verbose level */ + int verbosity; + /* Private data */ + void *priv_data; +}; + +struct fsfuzz_ops { + const char *name; + + int (*init)(struct fsfuzz_info *fs_info); + int (*free)(struct fsfuzz_info *fs_info); + int (*fuzz)(struct fsfuzz_info *fs_info); +}; + +void fsfuzz_register(struct fsfuzz_ops *ops); + +#endif diff --git a/fuzz-scripts/btrfs-fuzz.sh b/fuzz-scripts/btrfs-fuzz.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +i=0 +while :; do + dd if=/dev/zero of=btrfs-own bs=1M count=8 &>/dev/null + mkfs.btrfs btrfs-own &>/dev/null + ../fsfuzz -f btrfs btrfs-own + mount -t btrfs btrfs-own mnt/ + umount mnt/ + mv btrfs-own btrfs/btrfs-own.$i + ((i++)) +done diff --git a/fuzz-scripts/jfs-fuzz.sh b/fuzz-scripts/jfs-fuzz.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +i=0 +while :; do + dd if=/dev/zero of=jfs-own bs=1M count=16 &>/dev/null + mkfs.jfs -q jfs-own &> /dev/null + ../fsfuzz -f jfs jfs-own + mount -t jfs jfs-own mnt/ + umount mnt/ + mv jfs-own jfs/jfs-own.$i + ((i++)) +done diff --git a/fuzz-scripts/reiserfs-fuzz.sh b/fuzz-scripts/reiserfs-fuzz.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +i=0 +while :; do + dd if=/dev/zero of=reiserfs-own bs=1M count=32 &>/dev/null + mkfs.reiserfs reiserfs-own &>/dev/null + ../fsfuzz -f reiserfs reiserfs-own + mount -t reiserfs reiserfs-own mnt/ + umount mnt/ + mv reiserfs-own reiserfs/reiserfs-own.$i + ((i++)) +done diff --git a/fuzz-scripts/xfs-fuzz.sh b/fuzz-scripts/xfs-fuzz.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +i=0 +while :; do + dmesg -c &>/dev/null + dd if=/dev/zero of=xfs-own bs=1M count=32 &>/dev/null + mkfs.xfs xfs-own &>/dev/null + ../fsfuzz -f xfs xfs-own + sync + mount -t xfs xfs-own mnt/ &>/dev/null + umount mnt/ &>/dev/null + dmesg | grep -iq 'eip' # anything that looks like a bug really + if [ "$?" -eq 0 ]; then + echo Found 0day ... + cp xfs-own xfs/xfs-own.$i + dmesg &> xfs/xfs-own-log.$i + sync + ((i++)) + fi +done diff --git a/jfs.c b/jfs.c @@ -0,0 +1,53 @@ +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <err.h> + +#include "fsfuzz.h" + +int +jfs_init(struct fsfuzz_info *fs_info + __attribute__ ((unused))) +{ + srand((unsigned int)time(NULL)); + return 0; +} + +int +jfs_fuzz(struct fsfuzz_info *fs_info) +{ + char *p; + size_t offset; + size_t i; + + p = fs_info->img; + for (i = 0; i < 128; i++) { + do { + offset = 4096 + rand(); + offset %= 65536; + if (offset + 3 < fs_info->size) + break; + } while (1); + if (fs_info->verbosity) + printf("[+] Patching offset %#lx with 0xffffffff\n", + (long)offset); + p[offset + 0] = 0xff; + p[offset + 1] = 0xff; + p[offset + 2] = 0xff; + p[offset + 3] = 0xff; + } + return 0; +} + +static struct fsfuzz_ops jfs_fuzz_ops = { + .name = "jfs", + .init = jfs_init, + .fuzz = jfs_fuzz +}; + +__attribute__ ((constructor)) +static void +jfs_register(void) +{ + fsfuzz_register(&jfs_fuzz_ops); +} diff --git a/reiserfs.c b/reiserfs.c @@ -0,0 +1,53 @@ +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <err.h> + +#include "fsfuzz.h" + +int +reiserfs_init(struct fsfuzz_info *fs_info + __attribute__ ((unused))) +{ + srand((unsigned int)time(NULL)); + return 0; +} + +int +reiserfs_fuzz(struct fsfuzz_info *fs_info) +{ + char *p; + size_t offset; + size_t i; + + p = fs_info->img; + for (i = 0; i < 32; i++) { + /* The superblock in reiserfs is at 0x10000 */ + offset = 0x10000 + (rand() % 4096); + if (offset + 3 >= fs_info->size) { + warnx("Wrong offset, ignoring"); + continue; + } + if (fs_info->verbosity) + printf("[+] Patching offset %#lx with 0xffffffff\n", + (long)offset); + p[offset + 0] = 0xff; + p[offset + 1] = 0xff; + p[offset + 2] = 0xff; + p[offset + 3] = 0xff; + } + return 0; +} + +static struct fsfuzz_ops reiserfs_fuzz_ops = { + .name = "reiserfs", + .init = reiserfs_init, + .fuzz = reiserfs_fuzz +}; + +__attribute__ ((constructor)) +static void +reiserfs_register(void) +{ + fsfuzz_register(&reiserfs_fuzz_ops); +} diff --git a/xfs.c b/xfs.c @@ -0,0 +1,53 @@ +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <err.h> + +#include "fsfuzz.h" + +int +xfs_init(struct fsfuzz_info *fs_info + __attribute__ ((unused))) +{ + srand((unsigned int)time(NULL)); + return 0; +} + +int +xfs_fuzz(struct fsfuzz_info *fs_info) +{ + char *p; + size_t offset; + size_t i; + + p = fs_info->img; + for (i = 0; i < 64 * 4; i++) { + /* The superblock in xfs is at offset 0 */ + offset = rand() % (65536 * 4); + if (offset + 3 >= fs_info->size) { + warnx("Wrong offset, ignoring"); + continue; + } + if (fs_info->verbosity) + printf("[+] Patching offset %#lx with 0xffffffff\n", + (long)offset); + p[offset + 0] = 0xff; + p[offset + 1] = 0xff; + p[offset + 2] = 0xff; + p[offset + 3] = 0xff; + } + return 0; +} + +static struct fsfuzz_ops xfs_fuzz_ops = { + .name = "xfs", + .init = xfs_init, + .fuzz = xfs_fuzz +}; + +__attribute__ ((constructor)) +static void +xfs_register(void) +{ + fsfuzz_register(&xfs_fuzz_ops); +}