diff options
-rw-r--r-- | fuzzers/config_file_fuzzer.c | 75 | ||||
-rw-r--r-- | fuzzers/corpora/config_file/git2.dat | 11 | ||||
-rw-r--r-- | src/mailmap.c | 2 | ||||
-rw-r--r-- | src/remote.c | 4 | ||||
-rw-r--r-- | src/revwalk.c | 2 | ||||
-rw-r--r-- | src/transports/http.c | 2 | ||||
-rw-r--r-- | src/transports/smart_pkt.c | 16 | ||||
-rw-r--r-- | src/worktree.c | 2 | ||||
-rw-r--r-- | tests/index/conflicts.c | 42 | ||||
-rw-r--r-- | tests/worktree/worktree.c | 4 |
10 files changed, 145 insertions, 15 deletions
diff --git a/fuzzers/config_file_fuzzer.c b/fuzzers/config_file_fuzzer.c new file mode 100644 index 000000000..30a47bf2e --- /dev/null +++ b/fuzzers/config_file_fuzzer.c @@ -0,0 +1,75 @@ +/* + * libgit2 config file parser fuzz 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 <git2.h> + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <limits.h> +#include <errno.h> + +#define UNUSED(x) (void)(x) + +int foreach_cb(const git_config_entry *entry, void *payload) +{ + UNUSED(entry); + UNUSED(payload); + + return 0; +} + +static char path[] = "/tmp/git.XXXXXX"; +static int fd = -1; + +int LLVMFuzzerInitialize(int *argc, char ***argv) +{ + UNUSED(argc); + UNUSED(argv); + + if (git_libgit2_init() < 0) + abort(); + fd = mkstemp(path); + if (fd < 0) { + abort(); + } + + return 0; +} + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + git_config *cfg = NULL; + int err = 0; + size_t total = 0; + + if (ftruncate(fd, 0) !=0 ) { + abort(); + } + if (lseek(fd, 0, SEEK_SET) != 0) { + abort(); + } + + while (total < size) { + ssize_t written = write(fd, data, size); + if (written < 0 && errno != EINTR) + abort(); + if (written < 0) + continue; + total += written; + } + + err = git_config_open_ondisk(&cfg, path); + if (err == 0) { + git_config_foreach(cfg, foreach_cb, NULL); + git_config_free(cfg); + } + + return 0; +} diff --git a/fuzzers/corpora/config_file/git2.dat b/fuzzers/corpora/config_file/git2.dat new file mode 100644 index 000000000..e5561545f --- /dev/null +++ b/fuzzers/corpora/config_file/git2.dat @@ -0,0 +1,11 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true +[remote "origin"] + url = git@github.com:libgit2/libgit2 + fetch = +refs/heads/*:refs/remotes/origin/* +[branch "master"] + remote = origin + merge = refs/heads/master diff --git a/src/mailmap.c b/src/mailmap.c index fe4d452d5..1f725b30d 100644 --- a/src/mailmap.c +++ b/src/mailmap.c @@ -225,7 +225,7 @@ int git_mailmap_add_entry( static int mailmap_add_buffer(git_mailmap *mm, const char *buf, size_t len) { - int error; + int error = 0; git_parse_ctx ctx; /* Scratch buffers containing the real parsed names & emails */ diff --git a/src/remote.c b/src/remote.c index ca73ede5f..9c0e88ac0 100644 --- a/src/remote.c +++ b/src/remote.c @@ -428,7 +428,7 @@ static int get_optional_config( int git_remote_lookup(git_remote **out, git_repository *repo, const char *name) { - git_remote *remote; + git_remote *remote = NULL; git_buf buf = GIT_BUF_INIT; const char *val; int error = 0; @@ -510,7 +510,7 @@ int git_remote_lookup(git_remote **out, git_repository *repo, const char *name) if ((error = get_optional_config(NULL, config, &buf, refspec_cb, &data)) < 0) goto cleanup; - if (download_tags_value(remote, config) < 0) + if ((error = download_tags_value(remote, config)) < 0) goto cleanup; if ((error = lookup_remote_prune_config(remote, config, name)) < 0) diff --git a/src/revwalk.c b/src/revwalk.c index be647af3a..da84a4471 100644 --- a/src/revwalk.c +++ b/src/revwalk.c @@ -550,7 +550,7 @@ cleanup: static int prepare_walk(git_revwalk *walk) { - int error; + int error = 0; git_commit_list *list, *commits = NULL; git_commit_list_node *next; diff --git a/src/transports/http.c b/src/transports/http.c index ea3e57a49..bc3ab18e2 100644 --- a/src/transports/http.c +++ b/src/transports/http.c @@ -142,7 +142,7 @@ static int auth_context_match( } if (!scheme) - return 0; + return -1; /* See if authentication has already started for this scheme */ git_vector_foreach(&t->auth_contexts, i, c) { diff --git a/src/transports/smart_pkt.c b/src/transports/smart_pkt.c index 1cc4252d5..00798c396 100644 --- a/src/transports/smart_pkt.c +++ b/src/transports/smart_pkt.c @@ -282,7 +282,7 @@ static int ok_pkt(git_pkt **out, const char *line, size_t len) static int ng_pkt(git_pkt **out, const char *line, size_t len) { git_pkt_ng *pkt; - const char *ptr; + const char *ptr, *eol; size_t alloclen; pkt = git__malloc(sizeof(*pkt)); @@ -291,11 +291,13 @@ static int ng_pkt(git_pkt **out, const char *line, size_t len) pkt->ref = NULL; pkt->type = GIT_PKT_NG; + eol = line + len; + if (len < 3) goto out_err; line += 3; /* skip "ng " */ - len -= 3; - if (!(ptr = memchr(line, ' ', len))) + + if (!(ptr = memchr(line, ' ', eol - line))) goto out_err; len = ptr - line; @@ -306,11 +308,11 @@ static int ng_pkt(git_pkt **out, const char *line, size_t len) memcpy(pkt->ref, line, len); pkt->ref[len] = '\0'; - if (len < 1) - goto out_err; line = ptr + 1; - len -= 1; - if (!(ptr = memchr(line, '\n', len))) + if (line >= eol) + goto out_err; + + if (!(ptr = memchr(line, '\n', eol - line))) goto out_err; len = ptr - line; diff --git a/src/worktree.c b/src/worktree.c index 610fd7ee3..e06cdfb8d 100644 --- a/src/worktree.c +++ b/src/worktree.c @@ -426,7 +426,7 @@ int git_worktree_unlock(git_worktree *wt) assert(wt); if (!git_worktree_is_locked(NULL, wt)) - return 0; + return 1; if (git_buf_joinpath(&path, wt->gitdir_path, "locked") < 0) return -1; diff --git a/tests/index/conflicts.c b/tests/index/conflicts.c index 367d5b5bc..27fbe2b05 100644 --- a/tests/index/conflicts.c +++ b/tests/index/conflicts.c @@ -91,6 +91,48 @@ void test_index_conflicts__add_fixes_incorrect_stage(void) cl_assert(git_index_entry_stage(conflict_entry[2]) == 3); } +void test_index_conflicts__add_detects_invalid_filemode(void) +{ + git_index_entry ancestor_entry, our_entry, their_entry; + git_index_entry *conflict_entry[3]; + int i; + + cl_assert(git_index_entrycount(repo_index) == 8); + + memset(&ancestor_entry, 0x0, sizeof(git_index_entry)); + memset(&our_entry, 0x0, sizeof(git_index_entry)); + memset(&their_entry, 0x0, sizeof(git_index_entry)); + + conflict_entry[0] = &ancestor_entry; + conflict_entry[1] = &our_entry; + conflict_entry[2] = &their_entry; + + for (i = 0; i < 3; i++) { + ancestor_entry.path = "test-one.txt"; + ancestor_entry.mode = 0100644; + GIT_IDXENTRY_STAGE_SET(&ancestor_entry, 3); + git_oid_fromstr(&ancestor_entry.id, CONFLICTS_ONE_ANCESTOR_OID); + + our_entry.path = "test-one.txt"; + our_entry.mode = 0100644; + GIT_IDXENTRY_STAGE_SET(&our_entry, 1); + git_oid_fromstr(&our_entry.id, CONFLICTS_ONE_OUR_OID); + + their_entry.path = "test-one.txt"; + their_entry.mode = 0100644; + GIT_IDXENTRY_STAGE_SET(&their_entry, 2); + git_oid_fromstr(&their_entry.id, CONFLICTS_ONE_THEIR_OID); + + /* Corrupt the conflict entry's mode */ + conflict_entry[i]->mode = 027431745; + + cl_git_fail(git_index_conflict_add(repo_index, &ancestor_entry, &our_entry, &their_entry)); + } + + cl_assert(git_index_entrycount(repo_index) == 8); +} + + void test_index_conflicts__add_removes_stage_zero(void) { git_index_entry ancestor_entry, our_entry, their_entry; diff --git a/tests/worktree/worktree.c b/tests/worktree/worktree.c index 6935f6005..73a6a0193 100644 --- a/tests/worktree/worktree.c +++ b/tests/worktree/worktree.c @@ -477,7 +477,7 @@ void test_worktree_worktree__unlock_unlocked_worktree(void) cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); cl_assert(!git_worktree_is_locked(NULL, wt)); - cl_assert(git_worktree_unlock(wt) == 0); + cl_assert_equal_i(1, git_worktree_unlock(wt)); cl_assert(!wt->locked); git_worktree_free(wt); @@ -490,7 +490,7 @@ void test_worktree_worktree__unlock_locked_worktree(void) cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); cl_git_pass(git_worktree_lock(wt, NULL)); cl_assert(git_worktree_is_locked(NULL, wt)); - cl_git_pass(git_worktree_unlock(wt)); + cl_assert_equal_i(0, git_worktree_unlock(wt)); cl_assert(!wt->locked); git_worktree_free(wt); |