Skip to content

Commit c58ac44

Browse files
authored
Git fuzzing: uncomment the existing and add new targets. (#11486)
This pull request: * Uncomments fuzzing targets that were commented out * Adds the targets that were mentioned in the [audit](https://ostif.org/wp-content/uploads/2023/01/X41-OSTIF-Gitlab-Git-Security-Audit-20230117-public.pdf) done by X41 * Adds some new fuzzing targets * Fixes false positives in the build with memory sanitizer because zlib not being built with the sanitizer * Builds corpus from smaller files * Removes unnecessary memory allocations in the fuzzing harness * Fixes compiler warnings (const unsigned char)
1 parent a6f4ba6 commit c58ac44

17 files changed

+721
-174
lines changed

projects/git/Dockerfile

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ RUN apt-get update && \
2323
perl-modules libyaml-perl libz-dev python subversion tcl unzip \
2424
asciidoc docbook-xsl xmlto libssl-dev zip
2525
RUN git clone https://github.com/git/git git
26+
RUN git clone --depth 1 https://github.com/madler/zlib
2627
WORKDIR git
2728
RUN git checkout origin/next
2829
RUN git pull origin next

projects/git/Makefile.diff

+96-12
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,98 @@
11
diff --git a/Makefile b/Makefile
2-
index 6bfb62cbe9..2230b40a9f 100644
2+
index 4e255c81f2..05905e3a2e 100644
33
--- a/Makefile
44
+++ b/Makefile
5-
@@ -756,6 +756,11 @@ FUZZ_OBJS += oss-fuzz/fuzz-commit-graph.o
5+
@@ -760,6 +760,19 @@ FUZZ_OBJS += oss-fuzz/fuzz-commit-graph.o
66
FUZZ_OBJS += oss-fuzz/fuzz-date.o
77
FUZZ_OBJS += oss-fuzz/fuzz-pack-headers.o
88
FUZZ_OBJS += oss-fuzz/fuzz-pack-idx.o
99
+FUZZ_OBJS += oss-fuzz/fuzz-command.o
1010
+FUZZ_OBJS += oss-fuzz/fuzz-cmd-status.o
1111
+FUZZ_OBJS += oss-fuzz/fuzz-cmd-version.o
1212
+FUZZ_OBJS += oss-fuzz/fuzz-cmd-diff.o
13+
+FUZZ_OBJS += oss-fuzz/fuzz-credential-from-url-gently.o
14+
+FUZZ_OBJS += oss-fuzz/fuzz-url-decode-mem.o
15+
+FUZZ_OBJS += oss-fuzz/fuzz-url-end-with-slash.o
16+
+FUZZ_OBJS += oss-fuzz/fuzz-parse-attr-line.o
17+
+FUZZ_OBJS += oss-fuzz/fuzz-cmd-bundle-verify.o
18+
+FUZZ_OBJS += oss-fuzz/fuzz-cmd-unpack-objects.o
19+
+FUZZ_OBJS += oss-fuzz/fuzz-cmd-apply-check.o
20+
+FUZZ_OBJS += oss-fuzz/fuzz-cmd-tag-create.o
1321
+
1422
.PHONY: fuzz-objs
1523
fuzz-objs: $(FUZZ_OBJS)
1624

17-
@@ -1085,6 +1089,7 @@ LIB_OBJS += oid-array.o
25+
@@ -1087,6 +1100,7 @@ LIB_OBJS += oid-array.o
1826
LIB_OBJS += oidmap.o
1927
LIB_OBJS += oidset.o
2028
LIB_OBJS += oidtree.o
2129
+LIB_OBJS += oss-fuzz/fuzz-cmd-base.o
2230
LIB_OBJS += pack-bitmap-write.o
2331
LIB_OBJS += pack-bitmap.o
2432
LIB_OBJS += pack-check.o
33+
@@ -3862,10 +3876,10 @@ FUZZ_CXXFLAGS ?= $(ALL_CFLAGS)
34+
35+
.PHONY: fuzz-all
36+
37+
-$(FUZZ_PROGRAMS): %: %.o oss-fuzz/dummy-cmd-main.o $(GITLIBS) GIT-LDFLAGS
38+
- $(QUIET_LINK)$(CXX) $(FUZZ_CXXFLAGS) -o $@ $(ALL_LDFLAGS) \
39+
+$(FUZZ_PROGRAMS): all
40+
+ $(QUIET_LINK)$(CXX) $(FUZZ_CXXFLAGS) -o $@ $(ALL_LDFLAGS) $(BUILTIN_OBJS) \
41+
-Wl,--allow-multiple-definition \
42+
- $(filter %.o,$^) $(filter %.a,$^) $(LIBS) $(LIB_FUZZING_ENGINE)
43+
+ $(filter %.o,$^) $(filter %.a,$^) git.o [email protected] $(LIBS) $(LIB_FUZZING_ENGINE)
44+
45+
fuzz-all: $(FUZZ_PROGRAMS)
46+
47+
diff --git a/attr.c b/attr.c
48+
index 679e42258c..20e426726a 100644
49+
--- a/attr.c
50+
+++ b/attr.c
51+
@@ -351,7 +351,7 @@ static const char *parse_attr(const char *src, int lineno, const char *cp,
52+
return ep + strspn(ep, blank);
53+
}
54+
55+
-static struct match_attr *parse_attr_line(const char *line, const char *src,
56+
+struct match_attr *parse_attr_line(const char *line, const char *src,
57+
int lineno, unsigned flags)
58+
{
59+
size_t namelen, num_attr, i;
60+
diff --git a/builtin/bundle.c b/builtin/bundle.c
61+
index 3ad11dc5d0..2443906572 100644
62+
--- a/builtin/bundle.c
63+
+++ b/builtin/bundle.c
64+
@@ -123,7 +123,7 @@ static int open_bundle(const char *path, struct bundle_header *header,
65+
return read_bundle_header(path, header);
66+
}
67+
68+
-static int cmd_bundle_verify(int argc, const char **argv, const char *prefix) {
69+
+int cmd_bundle_verify(int argc, const char **argv, const char *prefix) {
70+
struct bundle_header header = BUNDLE_HEADER_INIT;
71+
int bundle_fd = -1;
72+
int quiet = 0;
73+
diff --git a/builtin/tag.c b/builtin/tag.c
74+
index 37473ac21f..c719ea10e7 100644
75+
--- a/builtin/tag.c
76+
+++ b/builtin/tag.c
77+
@@ -589,8 +589,11 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
78+
if (repo_get_oid(the_repository, object_ref, &object))
79+
die(_("Failed to resolve '%s' as a valid ref."), object_ref);
80+
81+
- if (strbuf_check_tag_ref(&ref, tag))
82+
- die(_("'%s' is not a valid tag name."), tag);
83+
+ if (strbuf_check_tag_ref(&ref, tag)) {
84+
+ //die(_("'%s' is not a valid tag name."), tag);
85+
+ ret = 1;
86+
+ goto cleanup;
87+
+ }
88+
89+
if (read_ref(ref.buf, &prev))
90+
oidclr(&prev);
2591
diff --git a/diff.c b/diff.c
26-
index 648f6717a5..24e42d0cd1 100644
92+
index ccfa1fca0d..97f895a122 100644
2793
--- a/diff.c
2894
+++ b/diff.c
29-
@@ -3557,7 +3557,7 @@ static void builtin_diff(const char *name_a,
95+
@@ -3654,7 +3654,7 @@ static void builtin_diff(const char *name_a,
3096
}
3197
if (fill_mmfile(o->repo, &mf1, one) < 0 ||
3298
fill_mmfile(o->repo, &mf2, two) < 0)
@@ -35,7 +101,25 @@ index 648f6717a5..24e42d0cd1 100644
35101
/* Quite common confusing case */
36102
if (mf1.size == mf2.size &&
37103
!memcmp(mf1.ptr, mf2.ptr, mf1.size)) {
38-
@@ -4009,7 +4009,7 @@ int diff_populate_filespec(struct repository *r,
104+
@@ -3837,7 +3837,7 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
105+
106+
if (fill_mmfile(o->repo, &mf1, one) < 0 ||
107+
fill_mmfile(o->repo, &mf2, two) < 0)
108+
- die("unable to read files to diff");
109+
+ return;//die("unable to read files to diff");
110+
111+
memset(&xpp, 0, sizeof(xpp));
112+
memset(&xecfg, 0, sizeof(xecfg));
113+
@@ -3900,7 +3900,7 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,
114+
115+
if (fill_mmfile(o->repo, &mf1, one) < 0 ||
116+
fill_mmfile(o->repo, &mf2, two) < 0)
117+
- die("unable to read files to diff");
118+
+ return;//die("unable to read files to diff");
119+
120+
/*
121+
* All the other codepaths check both sides, but not checking
122+
@@ -4106,7 +4106,7 @@ int diff_populate_filespec(struct repository *r,
39123
conv_flags = CONV_EOL_RNDTRP_WARN;
40124

41125
if (!DIFF_FILE_VALID(s))
@@ -44,7 +128,7 @@ index 648f6717a5..24e42d0cd1 100644
44128
if (S_ISDIR(s->mode))
45129
return -1;
46130

47-
@@ -4113,7 +4113,7 @@ int diff_populate_filespec(struct repository *r,
131+
@@ -4210,7 +4210,7 @@ int diff_populate_filespec(struct repository *r,
48132
}
49133
if (oid_object_info_extended(r, &s->oid, &info,
50134
OBJECT_INFO_LOOKUP_REPLACE))
@@ -53,7 +137,7 @@ index 648f6717a5..24e42d0cd1 100644
53137

54138
object_read:
55139
if (size_only || check_binary) {
56-
@@ -4128,7 +4128,7 @@ int diff_populate_filespec(struct repository *r,
140+
@@ -4225,7 +4225,7 @@ int diff_populate_filespec(struct repository *r,
57141
info.contentp = &s->data;
58142
if (oid_object_info_extended(r, &s->oid, &info,
59143
OBJECT_INFO_LOOKUP_REPLACE))
@@ -62,7 +146,7 @@ index 648f6717a5..24e42d0cd1 100644
62146
}
63147
s->should_free = 1;
64148
}
65-
@@ -7051,7 +7051,7 @@ size_t fill_textconv(struct repository *r,
149+
@@ -7226,7 +7226,7 @@ size_t fill_textconv(struct repository *r,
66150
return 0;
67151
}
68152
if (diff_populate_filespec(r, df, NULL))
@@ -71,7 +155,7 @@ index 648f6717a5..24e42d0cd1 100644
71155
*outbuf = df->data;
72156
return df->size;
73157
}
74-
@@ -7069,7 +7069,7 @@ size_t fill_textconv(struct repository *r,
158+
@@ -7244,7 +7244,7 @@ size_t fill_textconv(struct repository *r,
75159

76160
*outbuf = run_textconv(r, driver->textconv, df, &size);
77161
if (!*outbuf)
@@ -81,10 +165,10 @@ index 648f6717a5..24e42d0cd1 100644
81165
if (driver->textconv_cache && df->oid_valid) {
82166
/* ignore errors, as we might be in a readonly repository */
83167
diff --git a/environment.c b/environment.c
84-
index 18d042b467..7e0ba9dc47 100644
168+
index 90632a39bc..29e7c0479f 100644
85169
--- a/environment.c
86170
+++ b/environment.c
87-
@@ -265,7 +265,7 @@ void set_git_work_tree(const char *new_work_tree)
171+
@@ -271,7 +271,7 @@ void set_git_work_tree(const char *new_work_tree)
88172
strbuf_release(&realpath);
89173
return;
90174
}

projects/git/build.sh

+50-9
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@
1515
#
1616
################################################################################
1717

18+
# build zlib
19+
pushd "$SRC/zlib"
20+
./configure --static --prefix="$WORK"
21+
make -j$(nproc) CFLAGS="$CFLAGS -fPIC"
22+
make install
23+
popd
24+
export ZLIB_PATH=$WORK
25+
1826
# Enable a timeout for lockfiles rather than exit immediately. This is to
1927
# overcome in case multiple processes try to lock a file around the same
2028
# time.
@@ -25,34 +33,67 @@ make -j$(nproc) CC=$CC CXX=$CXX CFLAGS="$CFLAGS" \
2533
FUZZ_CXXFLAGS="$CXXFLAGS -Wl,--allow-multiple-definition" \
2634
LIB_FUZZING_ENGINE="common-main.o $LIB_FUZZING_ENGINE" fuzz-all
2735

28-
FUZZERS="fuzz-pack-headers fuzz-pack-idx fuzz-commit-graph"
29-
#FUZZERS="$FUZZERS fuzz-cmd-status fuzz-cmd-diff fuzz-cmd-version"
30-
#FUZZERS="$FUZZERS fuzz-command"
36+
FUZZERS=""
37+
# FUZZERS="$FUZZERS fuzz-cmd-apply-check"
38+
FUZZERS="$FUZZERS fuzz-cmd-bundle-verify"
3139
FUZZERS="$FUZZERS fuzz-cmd-diff"
40+
# FUZZERS="$FUZZERS fuzz-cmd-status"
41+
# FUZZERS="$FUZZERS fuzz-cmd-tag-create"
42+
# FUZZERS="$FUZZERS fuzz-cmd-unpack-objects"
43+
# FUZZERS="$FUZZERS fuzz-cmd-version"
44+
# FUZZERS="$FUZZERS fuzz-command"
45+
FUZZERS="$FUZZERS fuzz-commit-graph"
46+
FUZZERS="$FUZZERS fuzz-credential-from-url-gently"
47+
FUZZERS="$FUZZERS fuzz-date"
48+
FUZZERS="$FUZZERS fuzz-pack-headers"
49+
FUZZERS="$FUZZERS fuzz-pack-idx"
50+
FUZZERS="$FUZZERS fuzz-parse-attr-line"
51+
FUZZERS="$FUZZERS fuzz-url-decode-mem"
52+
FUZZERS="$FUZZERS fuzz-url-end-with-slash"
53+
3254
# copy fuzzers
3355
for fuzzer in $FUZZERS ; do
3456
cp oss-fuzz/$fuzzer $OUT
3557
done
3658

37-
# build corpora from Git's own packfiles
59+
# build commit-graph corpus
60+
ASAN_OPTIONS=detect_leaks=0 ./git commit-graph write
61+
zip -j $OUT/fuzz-commit-graph_seed_corpus .git/objects/info/commit-graph
62+
63+
# Git's own packfiles are too big for effective fuzzing
64+
# build corpora from a new repository
65+
mkdir mock-repo
66+
pushd mock-repo
67+
../git init
68+
echo "abc" > TEMP_1
69+
../git add .
70+
../git config user.email "[email protected]"
71+
../git config user.name "Your Name"
72+
../git commit -m "initial commit"
73+
../git repack
3874
zip -j $OUT/fuzz-pack-idx_seed_corpus.zip .git/objects/pack/*.idx
75+
zip -j $OUT/fuzz-cmd-unpack-objects_seed_corpus .git/objects/pack/*.pack
3976
for packfile in .git/objects/pack/*.pack ; do
4077
dd ibs=1 skip=12 if=$packfile of=$packfile.trimmed
4178
done
4279
zip -j $OUT/fuzz-pack-headers_seed_corpus.zip .git/objects/pack/*.pack.trimmed
80+
ASAN_OPTIONS=detect_leaks=0 ../git bundle create test.bundle master
81+
zip -j $OUT/fuzz-cmd-bundle-verify_seed_corpus test.bundle
82+
echo "adc\nrb\n" > TEMP_1
83+
../git diff > test.patch
84+
zip -j $OUT/fuzz-cmd-apply-check_seed_corpus test.patch
85+
popd
86+
rm -rf mock-repo
4387

44-
# build commit-graph corpus
45-
ASAN_OPTIONS=detect_leaks=0 ./git commit-graph write
46-
zip -j $OUT/fuzz-commit-graph_seed_corpus .git/objects/info/commit-graph
47-
48-
# Mute stderr
4988
for fuzzer in $FUZZERS ; do
5089
cat >$OUT/$fuzzer.options << EOF
5190
[libfuzzer]
5291
detect_leaks = 0
5392
EOF
5493
done
5594

95+
echo -e "max_len = 250\n" >> $OUT/fuzz-cmd-tag-create.options
96+
5697
# Generate existing file for temp git repository
5798
echo "TEMP1TEMP1TEMP1TEMP1" > $OUT/TEMP_1
5899
echo "TEMP2TEMP2TEMP2TEMP2" > $OUT/TEMP_2

projects/git/fuzz-cmd-apply-check.c

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/* Copyright 2024 Google LLC
2+
Licensed under the Apache License, Version 2.0 (the "License");
3+
you may not use this file except in compliance with the License.
4+
You may obtain a copy of the License at
5+
http://www.apache.org/licenses/LICENSE-2.0
6+
Unless required by applicable law or agreed to in writing, software
7+
distributed under the License is distributed on an "AS IS" BASIS,
8+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9+
See the License for the specific language governing permissions and
10+
limitations under the License.
11+
*/
12+
#include <stddef.h>
13+
#include <stdint.h>
14+
#include <unistd.h>
15+
#include "git-compat-util.h"
16+
#include "repository.h"
17+
#include "fuzz-cmd-base.h"
18+
19+
int cmd_init_db(int argc, const char **argv, const char *prefix);
20+
int cmd_apply(int argc, const char **argv, const char *prefix);
21+
22+
static int initialized = 0;
23+
24+
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
25+
{
26+
char *argv[3];
27+
28+
if (size < 1)
29+
return 0;
30+
31+
if (!initialized)
32+
{
33+
put_envs();
34+
create_templ_dir();
35+
}
36+
37+
initialize_the_repository();
38+
39+
if (!initialized)
40+
{
41+
argv[0] = "init";
42+
argv[1] = "--quiet";
43+
argv[2] = NULL;
44+
if (cmd_init_db(2, (const char **)argv, (const char *)""))
45+
exit(1);
46+
47+
initialized = 1;
48+
}
49+
50+
if (-1 == write(STDIN_FILENO, data, size))
51+
goto cleanup;
52+
53+
argv[0] = "apply";
54+
argv[1] = "-check";
55+
argv[2] = NULL;
56+
cmd_apply(2, (const char **)argv, (const char *)"");
57+
58+
cleanup:
59+
repo_clear(the_repository);
60+
return 0;
61+
}

0 commit comments

Comments
 (0)