@@ -2,6 +2,8 @@
/fuzz_corpora
/fuzz-pack-headers
/fuzz-pack-idx
+/fuzz-cmd-base
+/fuzz-cmd-status
/GIT-BUILD-OPTIONS
/GIT-CFLAGS
/GIT-LDFLAGS
@@ -686,9 +686,10 @@ SCRIPTS = $(SCRIPT_SH_GEN) \
ETAGS_TARGET = TAGS
-FUZZ_OBJS += fuzz-commit-graph.o
-FUZZ_OBJS += fuzz-pack-headers.o
-FUZZ_OBJS += fuzz-pack-idx.o
+FUZZ_OBJS += oss-fuzz/fuzz-commit-graph.o
+FUZZ_OBJS += oss-fuzz/fuzz-pack-headers.o
+FUZZ_OBJS += oss-fuzz/fuzz-pack-idx.o
+FUZZ_OBJS += oss-fuzz/fuzz-cmd-status.o
.PHONY: fuzz-objs
fuzz-objs: $(FUZZ_OBJS)
@@ -1009,6 +1010,7 @@ LIB_OBJS += oid-array.o
LIB_OBJS += oidmap.o
LIB_OBJS += oidset.o
LIB_OBJS += oidtree.o
+LIB_OBJS += oss-fuzz/fuzz-cmd-base.o
LIB_OBJS += pack-bitmap-write.o
LIB_OBJS += pack-bitmap.o
LIB_OBJS += pack-check.o
new file mode 100644
@@ -0,0 +1,159 @@
+#include "cache.h"
+#include "fuzz-cmd-base.h"
+
+
+/*
+ * This function is used to randomize the content of a file with the
+ * random data. The random data normally come from the fuzzing engine
+ * LibFuzzer in order to create randomization of the git file worktree
+ * and possibly messing up of certain git config file to fuzz different
+ * git command execution logic. Return -1 if it fails to create the file.
+ */
+int randomize_git_file(char *dir, char *name, char *data, int size)
+{
+ FILE *fp;
+ int ret = 0;
+ struct strbuf fname = STRBUF_INIT;
+
+ strbuf_addf(&fname, "%s/%s", dir, name);
+
+ fp = fopen(fname.buf, "wb");
+ if (fp)
+ {
+ fwrite(data, 1, size, fp);
+ }
+ else
+ {
+ ret = -1;
+ }
+
+ fclose(fp);
+ strbuf_release(&fname);
+
+ return ret;
+}
+
+/*
+ * This function is a variant of the above function which takes
+ * a set of target files to be processed. These target file are
+ * passing to the above function one by one for content rewrite.
+ * The data is equally divided for each of the files, and the
+ * remaining bytes (if not divisible) will be ignored.
+ */
+void randomize_git_files(char *dir, char *name_set[],
+ int files_count, char *data, int size)
+{
+ int i;
+ int data_size = size / files_count;
+ char *data_chunk = xmallocz_gently(data_size);
+
+ if (!data_chunk)
+ {
+ return;
+ }
+
+ for (i = 0; i < files_count; i++)
+ {
+ memcpy(data_chunk, data + (i * data_size), data_size);
+ randomize_git_file(dir, name_set[i], data_chunk, data_size);
+ }
+ free(data_chunk);
+}
+
+/*
+ * Instead of randomizing the content of existing files. This helper
+ * function helps generate a temp file with random file name before
+ * passing to the above functions to get randomized content for later
+ * fuzzing of git command.
+ */
+void generate_random_file(char *data, int size)
+{
+ unsigned char *hash = xmallocz_gently(size);
+ char *data_chunk = xmallocz_gently(size);
+ struct strbuf fname = STRBUF_INIT;
+
+ if (!hash || !data_chunk)
+ {
+ return;
+ }
+
+ memcpy(hash, data, size);
+ memcpy(data_chunk, data + size, size);
+
+ strbuf_addf(&fname, "TEMP-%s-TEMP", hash_to_hex(hash));
+ randomize_git_file(".", fname.buf, data_chunk, size);
+
+ free(hash);
+ free(data_chunk);
+ strbuf_release(&fname);
+}
+
+/*
+ * This function helps to generate random commit and build up a
+ * worktree with randomization to provide a target for the fuzzing
+ * of git commands.
+ */
+void generate_commit(char *data, int size) {
+ char *data_chunk = xmallocz_gently(size * 2);
+
+ if (!data_chunk)
+ {
+ return;
+ }
+
+ memcpy(data_chunk, data, size * 2);
+ generate_random_file(data_chunk, size);
+
+ free(data_chunk);
+
+ if (system("git add TEMP-*-TEMP") || system("git commit -m\"New Commit\""))
+ {
+ // Just skip the commit if fails
+ return;
+ }
+}
+
+/*
+ * In some cases, there maybe some fuzzing logic that will mess
+ * up with the git repository and its configuration and settings.
+ * This function integrates into the fuzzing processing and
+ * reset the git repository into the default
+ * base settings befire each round of fuzzing.
+ */
+int reset_git_folder(void)
+{
+ int ret = 0;
+
+ ret += system("rm -rf ./.git");
+ ret += system("rm -f ./TEMP-*-TEMP");
+
+ if (system("git init") ||
+ system("git config --global user.name \"FUZZ\"") ||
+ system("git config --global user.email \"FUZZ@LOCALHOST\"") ||
+ system("git config --global --add safe.directory '*'") ||
+ system("git add ./TEMP_1 ./TEMP_2") ||
+ system("git commit -m\"First Commit\""))
+ {
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * This helper function returns the maximum number of commit can
+ * be generated by the provided random data without reusing the
+ * data to increase randomization of the fuzzing target and allow
+ * more path of fuzzing to be covered.
+ */
+int get_max_commit_count(int data_size, int git_files_count, int hash_size)
+{
+ int count = (data_size - 4 - git_files_count * 2) / (hash_size * 2);
+
+ if (count > 20)
+ {
+ count = 20;
+ }
+
+ return count;
+}
new file mode 100644
@@ -0,0 +1,14 @@
+#ifndef FUZZ_CMD_BASE_H
+#define FUZZ_CMD_BASE_H
+
+#define HASH_SIZE 20
+
+int randomize_git_file(char *dir, char *name, char *data, int size);
+void randomize_git_files(char *dir, char *name_set[],
+ int files_count, char *data, int size);
+void generate_random_file(char *data, int size);
+void generate_commit(char *data, int size);
+int reset_git_folder(void);
+int get_max_commit_count(int data_size, int git_files_count, int hash_size);
+
+#endif
new file mode 100644
@@ -0,0 +1,79 @@
+#include "builtin.h"
+#include "repository.h"
+#include "fuzz-cmd-base.h"
+
+int cmd_status(int argc, const char **argv, const char *prefix);
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ int i;
+ int no_of_commit;
+ int max_commit_count;
+ char *argv[2];
+ char *data_chunk;
+ char *basedir = "./.git";
+
+ /*
+ * Initialize the repository
+ */
+ initialize_the_repository();
+
+ max_commit_count = get_max_commit_count(size, 0, HASH_SIZE);
+
+ /*
+ * End this round of fuzzing if the data is not large enough
+ */
+ if (size <= (HASH_SIZE * 2 + 4) || reset_git_folder())
+ {
+ repo_clear(the_repository);
+ return 0;
+ }
+
+
+ /*
+ * Generate random commit
+ */
+ no_of_commit = (*((int *)data)) % max_commit_count + 1;
+ data += 4;
+ size -= 4;
+
+ data_chunk = xmallocz_gently(HASH_SIZE * 2);
+
+ if (!data_chunk)
+ {
+ repo_clear(the_repository);
+ return 0;
+ }
+
+ for (i = 0; i < no_of_commit; i++)
+ {
+ memcpy(data_chunk, data, HASH_SIZE * 2);
+ generate_commit(data_chunk, HASH_SIZE);
+ data += (HASH_SIZE * 2);
+ size -= (HASH_SIZE * 2);
+ }
+
+ free(data_chunk);
+
+ /*
+ * Final preparing of the repository settings
+ */
+ repo_clear(the_repository);
+ if (repo_init(the_repository, basedir, "."))
+ {
+ repo_clear(the_repository);
+ return 0;
+ }
+
+ /*
+ * Calling target git command
+ */
+ argv[0] = "status";
+ argv[1] = "-v";
+ cmd_status(2, (const char **)argv, (const char *)"");
+
+ repo_clear(the_repository);
+ return 0;
+}
similarity index 100%
rename from fuzz-commit-graph.c
rename to oss-fuzz/fuzz-commit-graph.c
similarity index 100%
rename from fuzz-pack-headers.c
rename to oss-fuzz/fuzz-pack-headers.c
similarity index 100%
rename from fuzz-pack-idx.c
rename to oss-fuzz/fuzz-pack-idx.c