summaryrefslogtreecommitdiff
path: root/fuzzers/packfile_fuzzer.c
blob: aeba9575c3e10aac1f9ed52ef0da9f34b1afd182 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/*
 * libgit2 packfile fuzzer target.
 *
 * Copyright (C) the libgit2 contributors. All rights reserved.
 *
 * This file is part of libgit2, distributed under the GNU GPL v2 with
 * a Linking Exception. For full terms see the included COPYING file.
 */

#include <stdio.h>

#include "git2.h"
#include "git2/sys/mempack.h"
#include "common.h"
#include "str.h"

#include "standalone_driver.h"

static git_odb *odb = NULL;
static git_odb_backend *mempack = NULL;

/* Arbitrary object to seed the ODB. */
static const unsigned char base_obj[] = { 07, 076 };
static const unsigned int base_obj_len = 2;

int LLVMFuzzerInitialize(int *argc, char ***argv)
{
	GIT_UNUSED(argc);
	GIT_UNUSED(argv);

	if (git_libgit2_init() < 0) {
		fprintf(stderr, "Failed to initialize libgit2\n");
		abort();
	}
	if (git_libgit2_opts(GIT_OPT_SET_PACK_MAX_OBJECTS, 10000000) < 0) {
		fprintf(stderr, "Failed to limit maximum pack object count\n");
		abort();
	}

#ifdef GIT_EXPERIMENTAL_SHA256
	if (git_odb_new(&odb, NULL) < 0) {
		fprintf(stderr, "Failed to create the odb\n");
		abort();
	}
#else
	if (git_odb_new(&odb) < 0) {
		fprintf(stderr, "Failed to create the odb\n");
		abort();
	}
#endif

	if (git_mempack_new(&mempack) < 0) {
		fprintf(stderr, "Failed to create the mempack\n");
		abort();
	}
	if (git_odb_add_backend(odb, mempack, 999) < 0) {
		fprintf(stderr, "Failed to add the mempack\n");
		abort();
	}
	return 0;
}

int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
	git_indexer_progress stats = {0, 0};
	git_indexer *indexer = NULL;
	git_str path = GIT_STR_INIT;
	git_oid oid;
	bool append_hash = false;
	int error;

	if (size == 0)
		return 0;

	if (!odb || !mempack) {
		fprintf(stderr, "Global state not initialized\n");
		abort();
	}
	git_mempack_reset(mempack);

	if (git_odb_write(&oid, odb, base_obj, base_obj_len, GIT_OBJECT_BLOB) < 0) {
		fprintf(stderr, "Failed to add an object to the odb\n");
		abort();
	}

#ifdef GIT_EXPERIMENTAL_SHA256
	error = git_indexer_new(&indexer, ".", GIT_OID_SHA1, NULL);
#else
	error = git_indexer_new(&indexer, ".", 0, odb, NULL);
#endif

	if (error < 0) {
		fprintf(stderr, "Failed to create the indexer: %s\n",
			git_error_last()->message);
		abort();
	}

	/*
	 * If the first byte in the stream has the high bit set, append the
	 * SHA1 hash so that the packfile is somewhat valid.
	 */
	append_hash = *data & 0x80;
	++data;
	--size;

	if (git_indexer_append(indexer, data, size, &stats) < 0)
		goto cleanup;
	if (append_hash) {
#ifdef GIT_EXPERIMENTAL_SHA256
		if (git_odb_hash(&oid, data, size, GIT_OBJECT_BLOB, GIT_OID_SHA1) < 0) {
			fprintf(stderr, "Failed to compute the SHA1 hash\n");
			abort();
		}
#else
		if (git_odb_hash(&oid, data, size, GIT_OBJECT_BLOB) < 0) {
			fprintf(stderr, "Failed to compute the SHA1 hash\n");
			abort();
		}
#endif

		if (git_indexer_append(indexer, &oid.id, GIT_OID_SHA1_SIZE, &stats) < 0) {
			goto cleanup;
		}
	}
	if (git_indexer_commit(indexer, &stats) < 0)
		goto cleanup;

	if (git_str_printf(&path, "pack-%s.idx", git_indexer_name(indexer)) < 0)
		goto cleanup;
	p_unlink(git_str_cstr(&path));

	git_str_clear(&path);

	if (git_str_printf(&path, "pack-%s.pack", git_indexer_name(indexer)) < 0)
		goto cleanup;
	p_unlink(git_str_cstr(&path));

cleanup:
	git_mempack_reset(mempack);
	git_indexer_free(indexer);
	git_str_dispose(&path);
	return 0;
}