From 1619a0a2bf5f9b894d80e7eb33526c33378dfeae Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 17 Nov 2023 16:25:06 +0000 Subject: [PATCH 1/6] transport: safely handle messages with no caps If there are no caps, don't try to advance past the first NULL to look for object-format. This prevents a possible out-of-bounds read. --- src/libgit2/transports/smart_pkt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libgit2/transports/smart_pkt.c b/src/libgit2/transports/smart_pkt.c index 5fce42175be..6743c160f3b 100644 --- a/src/libgit2/transports/smart_pkt.c +++ b/src/libgit2/transports/smart_pkt.c @@ -226,7 +226,8 @@ static int set_data( GIT_ASSERT_ARG(data); - if ((caps = memchr(line, '\0', len)) != NULL) { + if ((caps = memchr(line, '\0', len)) != NULL && + len > (size_t)((caps - line) + 1)) { caps++; if (strncmp(caps, "object-format=", CONST_STRLEN("object-format=")) == 0) From c9d31b711e8906cf248566f43142f20b03e20cbf Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 17 Nov 2023 16:54:47 +0000 Subject: [PATCH 2/6] revparse: fix parsing bug for trailing `@` When parsing a revspec that ends with a trailing `@`, explicitly stop parsing. Introduce a sentinel variable to explicitly stop parsing. Prior to this, we would set `spec` to `HEAD`, but were looping on the value of `spec[pos]`, so we would continue walking the (new) `spec` at offset `pos`, looking for a NUL. This is obviously an out-of-bounds read. Credit to Michael Rodler (@f0rki) and Amazon AWS Security. --- src/libgit2/revparse.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libgit2/revparse.c b/src/libgit2/revparse.c index 964afe378da..06d92f82bf2 100644 --- a/src/libgit2/revparse.c +++ b/src/libgit2/revparse.c @@ -701,6 +701,7 @@ static int revparse( git_object *base_rev = NULL; bool should_return_reference = true; + bool parsed = false; GIT_ASSERT_ARG(object_out); GIT_ASSERT_ARG(reference_out); @@ -710,7 +711,7 @@ static int revparse( *object_out = NULL; *reference_out = NULL; - while (spec[pos]) { + while (!parsed && spec[pos]) { switch (spec[pos]) { case '^': should_return_reference = false; @@ -817,6 +818,8 @@ static int revparse( break; } else if (spec[pos+1] == '\0') { spec = "HEAD"; + identifier_len = 4; + parsed = true; break; } /* fall through */ From 05cf155d7b3081da79808b89961c5b02371b4b83 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 16 Dec 2023 11:14:58 +0000 Subject: [PATCH 3/6] index: test adding two identical slash-prefix paths Ensure that we can `git_index_add` a slash-prefixed path, followed by re-adding the same path. The original entry should be replaced by the new entry. --- tests/libgit2/index/add.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/libgit2/index/add.c b/tests/libgit2/index/add.c index b0c3bd2b7ae..588a2ad148c 100644 --- a/tests/libgit2/index/add.c +++ b/tests/libgit2/index/add.c @@ -82,3 +82,27 @@ void test_index_add__invalid_entries_succeeds_by_default(void) test_add_entry(true, valid_commit_id, GIT_FILEMODE_LINK); } +void test_index_add__two_slash_prefixed(void) +{ + git_index_entry one = {{0}}, two = {{0}}; + const git_index_entry *result; + size_t orig_count; + + orig_count = git_index_entrycount(g_index); + + cl_git_pass(git_oid__fromstr(&one.id, "fa49b077972391ad58037050f2a75f74e3671e92", GIT_OID_SHA1)); + one.path = "/a"; + one.mode = GIT_FILEMODE_BLOB; + + cl_git_pass(git_oid__fromstr(&two.id, "3697d64be941a53d4ae8f6a271e4e3fa56b022cc", GIT_OID_SHA1)); + two.path = "/a"; + two.mode = GIT_FILEMODE_BLOB; + + cl_git_pass(git_index_add(g_index, &one)); + cl_git_pass(git_index_add(g_index, &two)); + + cl_assert_equal_i(orig_count + 1, git_index_entrycount(g_index)); + + cl_assert(result = git_index_get_bypath(g_index, "/a", 0)); + cl_assert_equal_oid(&two.id, &result->id); +} From eb4c1716cd92bf56f2770653a915d5fc01eab8f3 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 16 Dec 2023 11:19:07 +0000 Subject: [PATCH 4/6] index: correct index has_dir_name check `has_dir_name` is used to check for directory/file collisions, and attempts to determine whether the index contains a file with a directory name that is a proper subset of the new index entry that we're trying to add. To determine directory name, the function would walk the path string backwards to identify a `/`, stopping at the end of the string. However, the function assumed that the strings did not start with a `/`. If the paths contain only a single `/` at the beginning of the string, then the function would continue the loop, erroneously, when they should have stopped at the first character. Correct the order of the tests to terminate properly. Credit to Michael Rodler (@f0rki) and Amazon AWS Security. --- src/libgit2/index.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libgit2/index.c b/src/libgit2/index.c index d4532c005d0..9306b96dba5 100644 --- a/src/libgit2/index.c +++ b/src/libgit2/index.c @@ -1148,10 +1148,13 @@ static int has_dir_name(git_index *index, size_t len, pos; for (;;) { - if (*--slash == '/') - break; + slash--; + if (slash <= entry->path) return 0; + + if (*slash == '/') + break; } len = slash - name; From a8a98be887ff4e74ce86b8c60602c000d2887ee2 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 12 Jan 2024 10:44:28 +0000 Subject: [PATCH 5/6] v1.6.5: add changelog --- docs/changelog.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/changelog.md b/docs/changelog.md index d970b48e9dc..80b156326bc 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,3 +1,20 @@ +v1.6.5 +------ + +## What's Changed + +This release fixes three bugs that can cause undefined behavior when given well-crafted inputs, either in input files or over network connections. These bugs may be able to be leveraged to cause denial of service attacks or unauthorized code execution. + +Two of these issues were discovered and reported by security engineers at Amazon Web Services. We thank the AWS Security team for their efforts to identify these issues, provide helpful reproduction cases, and responsibly disclose their findings. + +### Security fixes + +* transport: safely handle messages with no caps +* revparse: fix parsing bug for trailing `@` +* index: correct index has_dir_name check + +**Full Changelog**: https://github.com/libgit2/libgit2/compare/v1.6.4...v1.6.5 + v1.6.4 ------ From 155578578b78efc6bae7383a708d470eb206e36a Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 12 Jan 2024 10:45:16 +0000 Subject: [PATCH 6/6] v1.6.5: update version numbers --- CMakeLists.txt | 2 +- include/git2/version.h | 4 ++-- package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f2e0236721..2bec5378745 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ cmake_minimum_required(VERSION 3.5.1) -project(libgit2 VERSION "1.6.4" LANGUAGES C) +project(libgit2 VERSION "1.6.5" LANGUAGES C) # Add find modules to the path set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake") diff --git a/include/git2/version.h b/include/git2/version.h index 97221e459fa..b36835a2cbf 100644 --- a/include/git2/version.h +++ b/include/git2/version.h @@ -11,7 +11,7 @@ * The version string for libgit2. This string follows semantic * versioning (v2) guidelines. */ -#define LIBGIT2_VERSION "1.6.4" +#define LIBGIT2_VERSION "1.6.5" /** The major version number for this version of libgit2. */ #define LIBGIT2_VER_MAJOR 1 @@ -20,7 +20,7 @@ #define LIBGIT2_VER_MINOR 6 /** The revision ("teeny") version number for this version of libgit2. */ -#define LIBGIT2_VER_REVISION 4 +#define LIBGIT2_VER_REVISION 5 /** The Windows DLL patch number for this version of libgit2. */ #define LIBGIT2_VER_PATCH 0 diff --git a/package.json b/package.json index 9695f90d90c..4c70c2ed4cc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "libgit2", - "version": "1.6.4", + "version": "1.6.5", "repo": "https://github.com/libgit2/libgit2", "description": " A cross-platform, linkable library implementation of Git that you can use in your application.", "install": "mkdir build && cd build && cmake .. && cmake --build ."