erofs-utils: add a prelimitary fuzzer

Signed-off-by: Gao Xiang <hsiangkao@aol.com>
diff --git a/include/erofs/config.h b/include/erofs/config.h
index 05fe6b2..9eab8c7 100644
--- a/include/erofs/config.h
+++ b/include/erofs/config.h
@@ -14,6 +14,7 @@
 struct erofs_configure {
 	const char *c_version;
 	int c_dbg_lvl;
+	unsigned int c_fuzz_trapcount;
 	bool c_dry_run;
 	bool c_legacy_compress;
 
diff --git a/include/erofs/fuzzer.h b/include/erofs/fuzzer.h
new file mode 100644
index 0000000..9be456f
--- /dev/null
+++ b/include/erofs/fuzzer.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * erofs_utils/include/erofs/fuzzer.h
+ *
+ * Copyright (C) 2018 HUAWEI, Inc.
+ *             http://www.huawei.com/
+ */
+#ifndef __EROFS_FUZZER_H
+#define __EROFS_FUZZER_H
+
+#include "internal.h"
+
+void erofs_fuzz(void *buf, unsigned int length);
+
+#endif
+
diff --git a/lib/Makefile.am b/lib/Makefile.am
index dea82f7..72a8b05 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -2,7 +2,7 @@
 # Makefile.am
 
 noinst_LTLIBRARIES = liberofs.la
-liberofs_la_SOURCES = config.c io.c cache.c inode.c compress.c compressor.c
+liberofs_la_SOURCES = config.c io.c cache.c inode.c compress.c compressor.c fuzzer.c
 liberofs_la_CFLAGS = -Wall -Werror -I$(top_srcdir)/include
 if ENABLE_LZ4
 liberofs_la_CFLAGS += ${LZ4_CFLAGS}
diff --git a/lib/compress.c b/lib/compress.c
index a977c87..437e816 100644
--- a/lib/compress.c
+++ b/lib/compress.c
@@ -16,6 +16,7 @@
 #include "erofs/cache.h"
 #include "erofs/compress.h"
 #include "compressor.h"
+#include "erofs/fuzzer.h"
 
 static struct erofs_compress compresshandle;
 static int compressionlevel;
@@ -478,6 +479,8 @@
 							  legacymetasize, 12);
 		DBG_BUGON(ret);
 	}
+
+	erofs_fuzz(inode->compressmeta, inode->extent_isize);
 	return 0;
 
 err_bdrop:
diff --git a/lib/config.c b/lib/config.c
index 2e91b92..ee72e83 100644
--- a/lib/config.c
+++ b/lib/config.c
@@ -20,6 +20,7 @@
 	cfg.c_version  = PACKAGE_VERSION;
 	cfg.c_dry_run  = false;
 	cfg.c_legacy_compress = false;
+	cfg.c_fuzz_trapcount = 0;
 	cfg.c_compr_level_master = -1;
 	sbi.requirements = EROFS_REQUIREMENT_LZ4_0PADDING;
 }
diff --git a/lib/fuzzer.c b/lib/fuzzer.c
new file mode 100644
index 0000000..079d38d
--- /dev/null
+++ b/lib/fuzzer.c
@@ -0,0 +1,39 @@
+#include <unistd.h>
+#include "erofs/config.h"
+#include "erofs/fuzzer.h"
+#include "erofs/print.h"
+
+void erofs_fuzz(void *buf, unsigned int length)
+{
+	int fd, ret;
+	unsigned int a1, a2;
+
+	/* whether the fuzzer is disabled */
+	if (!cfg.c_fuzz_trapcount)
+		return;
+
+	/* whether this field should be fuzzed */
+	if (cfg.c_fuzz_trapcount-- != 1)
+		return;
+
+	fd = open("/dev/urandom", O_RDONLY);
+
+	do {
+		ret = read(fd, &a1, sizeof(a1));
+		a1 %= length;
+
+		ret = read(fd, &a2, sizeof(a2));
+		a2 %= length;
+	} while (a1 == a2);
+
+	if (a1 > a2) {
+		const unsigned int t = a1;
+
+		a1 = a2;
+		a2 = t;
+	}
+	ret = read(fd, buf + a1, a2 - a1);
+	erofs_err("fuzzed!");
+	close(fd);
+}
+
diff --git a/lib/inode.c b/lib/inode.c
index 581f263..202c757 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -18,6 +18,7 @@
 #include "erofs/cache.h"
 #include "erofs/io.h"
 #include "erofs/compress.h"
+#include "erofs/fuzzer.h"
 
 struct erofs_sb_info sbi;
 
@@ -213,6 +214,8 @@
 		head = list_next_entry(head, d_child);
 	}
 	memset(buf + q, 0, size - q);
+
+	erofs_fuzz(buf, size);
 }
 
 static int write_dirblock(unsigned int q, struct erofs_dentry *head,
@@ -393,6 +396,8 @@
 		break;
 	}
 
+	erofs_fuzz(&v1, sizeof(struct erofs_inode_v1));
+
 	ret = dev_write(&v1, off, sizeof(struct erofs_inode_v1));
 	if (ret)
 		return false;
diff --git a/mkfs/main.c b/mkfs/main.c
index 75e1d47..941a2a3 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -19,6 +19,7 @@
 #include "erofs/inode.h"
 #include "erofs/io.h"
 #include "erofs/compress.h"
+#include "erofs/fuzzer.h"
 
 #define EROFS_SUPER_END (EROFS_SUPER_OFFSET + sizeof(struct erofs_super_block))
 
@@ -79,7 +80,7 @@
 {
 	int opt, i;
 
-	while ((opt = getopt(argc, argv, "d:z:E:")) != -1) {
+	while ((opt = getopt(argc, argv, "d:z:E:F:")) != -1) {
 		switch (opt) {
 		case 'z':
 			if (!optarg) {
@@ -113,6 +114,9 @@
 				return opt;
 			break;
 
+		case 'F':
+			cfg.c_fuzz_trapcount = atoi(optarg);
+			break;
 		default: /* '?' */
 			return -EINVAL;
 		}
@@ -175,6 +179,7 @@
 			  erofs_strerror(-errno));
 		return -ENOMEM;
 	}
+	erofs_fuzz(&sb, sizeof(struct erofs_super_block));
 	memcpy(buf + EROFS_SUPER_OFFSET, &sb, sizeof(sb));
 
 	bh->fsprivate = buf;