diff --git a/SPECS/libgit2/CVE-2026-53583.patch b/SPECS/libgit2/CVE-2026-53583.patch new file mode 100644 index 00000000000..c0033255256 --- /dev/null +++ b/SPECS/libgit2/CVE-2026-53583.patch @@ -0,0 +1,57 @@ +From f8a22238ad56fd5458aa9e4ce840ba6169870e1a Mon Sep 17 00:00:00 2001 +From: Edward Thomson +Date: Mon, 1 Jun 2026 10:41:21 +0100 +Subject: [PATCH] Fix inverted IP SubjectAltName comparison in OpenSSL backend + +The verify_server_cert() function in the OpenSSL TLS backend incorrectly +uses !!memcmp() to compare IP SubjectAltName entries. Since memcmp() +returns 0 for matching buffers and non-zero for mismatches, the !! +operator inverts the logic: matching IPs result in matched=0 (rejected) +while mismatched IPs result in matched=1 (accepted). This allows a +MITM attacker with a valid CA-signed certificate containing any IP SAN +to bypass hostname verification for IP-literal HTTPS URLs. + +Reported-by: Pavel Kohout, Aisle Research, www.aisle.com +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: https://github.com/libgit2/libgit2/commit/647dcb432980b84ede4cb5a008bbd1ccb4ead03d.patch +--- + src/libgit2/streams/openssl.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/src/libgit2/streams/openssl.c b/src/libgit2/streams/openssl.c +index 9db911e..3a10e4a 100644 +--- a/src/libgit2/streams/openssl.c ++++ b/src/libgit2/streams/openssl.c +@@ -374,6 +374,7 @@ static int verify_server_cert(SSL *ssl, const char *host) + struct in6_addr addr6; + struct in_addr addr4; + void *addr = NULL; ++ size_t addrlen = 0; + int i = -1, j, error = 0; + + if (SSL_get_verify_result(ssl) != X509_V_OK) { +@@ -385,10 +386,12 @@ static int verify_server_cert(SSL *ssl, const char *host) + if (p_inet_pton(AF_INET, host, &addr4)) { + type = GEN_IPADD; + addr = &addr4; ++ addrlen = sizeof(addr4); + } else { + if (p_inet_pton(AF_INET6, host, &addr6)) { + type = GEN_IPADD; + addr = &addr6; ++ addrlen = sizeof(addr6); + } + } + +@@ -423,7 +426,7 @@ static int verify_server_cert(SSL *ssl, const char *host) + matched = !!check_host_name(host, name); + } else if (type == GEN_IPADD) { + /* Here name isn't so much a name but a binary representation of the IP */ +- matched = addr && !!memcmp(name, addr, namelen); ++ matched = (addr && namelen == addrlen && memcmp(name, addr, namelen) == 0); + } + } + } +-- +2.45.4 + diff --git a/SPECS/libgit2/CVE-2026-53584.patch b/SPECS/libgit2/CVE-2026-53584.patch new file mode 100644 index 00000000000..37838cdf3c7 --- /dev/null +++ b/SPECS/libgit2/CVE-2026-53584.patch @@ -0,0 +1,368 @@ +From c9989e2b215e3323d9da923f683fa41af7daa021 Mon Sep 17 00:00:00 2001 +From: Edward Thomson +Date: Mon, 1 Jun 2026 10:57:12 +0100 +Subject: [PATCH] submodule: check paths for escaping + +Ensure that we do not try to load a submodule who has a filesystem path +that points outside of our repository. + +This prevents a crafted repository with a submodule whose path contains +traversal components (e.g. "../") can cause the library to create +directories outside the repository's working tree. + +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: https://github.com/libgit2/libgit2/commit/419637d3587396f5d139d6d88480eab3cd81e7a1.patch +--- + src/libgit2/submodule.c | 92 +++++++++++++++++---- + src/util/fs_path.h | 20 ++--- + tests/libgit2/submodule/escape.c | 60 +++++++++++++- + tests/libgit2/submodule/submodule_helpers.c | 1 + + 4 files changed, 148 insertions(+), 25 deletions(-) + +diff --git a/src/libgit2/submodule.c b/src/libgit2/submodule.c +index 95ea84f..9e0bf3a 100644 +--- a/src/libgit2/submodule.c ++++ b/src/libgit2/submodule.c +@@ -77,6 +77,7 @@ static void submodule_get_index_status(unsigned int *, git_submodule *); + static void submodule_get_wd_status(unsigned int *, git_submodule *, git_repository *, git_submodule_ignore_t); + static void submodule_update_from_index_entry(git_submodule *sm, const git_index_entry *ie); + static void submodule_update_from_head_data(git_submodule *sm, mode_t mode, const git_oid *id); ++static int path_is_valid(git_repository *repo, const char *path); + + static int submodule_cmp(const void *a, const void *b) + { +@@ -213,6 +214,7 @@ static int load_submodule_names(git_strmap **out, git_repository *repo, git_conf + + while ((error = git_config_next(&entry, iter)) == 0) { + const char *fdot, *ldot; ++ + fdot = strchr(entry->name, '.'); + ldot = strrchr(entry->name, '.'); + +@@ -225,6 +227,7 @@ static int load_submodule_names(git_strmap **out, git_repository *repo, git_conf + + git_str_clear(&buf); + git_str_put(&buf, fdot + 1, ldot - fdot - 1); ++ + isvalid = git_submodule_name_is_valid(repo, buf.ptr, 0); + if (isvalid < 0) { + error = isvalid; +@@ -233,6 +236,14 @@ static int load_submodule_names(git_strmap **out, git_repository *repo, git_conf + if (!isvalid) + continue; + ++ isvalid = path_is_valid(repo, entry->value); ++ if (isvalid < 0) { ++ error = isvalid; ++ goto out; ++ } ++ if (!isvalid) ++ continue; ++ + if ((error = git_strmap_set(names, git__strdup(entry->value), git_str_detach(&buf))) < 0) { + git_error_set(GIT_ERROR_NOMEMORY, "error inserting submodule into hash table"); + error = -1; +@@ -294,9 +305,9 @@ int git_submodule__lookup_with_cache( + const char *name, /* trailing slash is allowed */ + git_strmap *cache) + { +- int error; +- unsigned int location; + git_submodule *sm; ++ unsigned int location; ++ int error; + + GIT_ASSERT_ARG(repo); + GIT_ASSERT_ARG(name); +@@ -319,7 +330,17 @@ int git_submodule__lookup_with_cache( + if ((error = submodule_alloc(&sm, repo, name)) < 0) + return error; + +- if ((error = git_submodule_reload(sm, false)) < 0) { ++ /* ++ * Only try to reload if they gave us a valid _name_; if this is a ++ * path, we'll do some lookups then try to reload to populate. ++ */ ++ if (git_submodule_name_is_valid(sm->repo, name, 0) <= 0) { ++ error = GIT_ENOTFOUND; ++ } else { ++ error = git_submodule_reload(sm, false); ++ } ++ ++ if (error < 0 && error != GIT_ENOTFOUND) { + git_submodule_free(sm); + return error; + } +@@ -378,6 +399,7 @@ int git_submodule__lookup_with_cache( + /* If we still haven't found it, do the WD check */ + if (location == 0 || location == GIT_SUBMODULE_STATUS_IN_WD) { + git_submodule_free(sm); ++ git_error_set(GIT_ERROR_SUBMODULE, "invalid submodule name: '%s'", name); + error = GIT_ENOTFOUND; + + /* If it's not configured, we still check if there's a repo at the path */ +@@ -429,6 +451,26 @@ int git_submodule_name_is_valid(git_repository *repo, const char *name, int flag + return isvalid; + } + ++static int path_is_valid(git_repository *repo, const char *path) ++{ ++ git_str buf = GIT_STR_INIT; ++ int flags = GIT_FS_PATH_REJECT_FILESYSTEM_DEFAULTS & ~GIT_FS_PATH_REJECT_EMPTY_COMPONENT; ++ int error, isvalid; ++ ++ /* Avoid allocating a new string if we can avoid it */ ++ if (strchr(path, '\\') != NULL) { ++ if ((error = git_fs_path_normalize_slashes(&buf, path)) < 0) ++ return error; ++ } else { ++ git_str_attach_notowned(&buf, path, strlen(path)); ++ } ++ ++ isvalid = git_path_is_valid(repo, buf.ptr, 0, flags); ++ git_str_dispose(&buf); ++ ++ return isvalid; ++} ++ + static void submodule_free_dup(void *sm) + { + git_submodule_free(sm); +@@ -1338,11 +1380,11 @@ int git_submodule_update(git_submodule *sm, int init, git_submodule_update_optio + /* Get the status of the submodule to determine if it is already initialized */ + if ((error = git_submodule_status(&submodule_status, sm->repo, sm->name, GIT_SUBMODULE_IGNORE_UNSPECIFIED)) < 0) + goto done; +- ++ + /* If the submodule is configured but hasn't been added, skip it */ + if (submodule_status == GIT_SUBMODULE_STATUS_IN_CONFIG) + goto done; +- ++ + /* + * If submodule work dir is not already initialized, check to see + * what we need to do (initialize, clone, return error...) +@@ -1671,18 +1713,34 @@ static int submodule_update_head(git_submodule *submodule) + return 0; + } + ++static int submodule_name_error(const char *name) ++{ ++ git_error_set(GIT_ERROR_SUBMODULE, ++ "invalid value for submodule name: '%s'", name); ++ return GIT_EINVALID; ++} ++ ++static int submodule_config_error(const char *property, const char *value) ++{ ++ git_error_set(GIT_ERROR_SUBMODULE, ++ "invalid value for submodule '%s' property: '%s'", property, value); ++ return GIT_EINVALID; ++} ++ + int git_submodule_reload(git_submodule *sm, int force) + { + git_config *mods = NULL; +- int error; ++ int valid, error = 0; + + GIT_UNUSED(force); + + GIT_ASSERT_ARG(sm); + +- if ((error = git_submodule_name_is_valid(sm->repo, sm->name, 0)) <= 0) ++ if ((valid = git_submodule_name_is_valid(sm->repo, sm->name, 0)) <= 0) { + /* This should come with a warning, but we've no API for that */ ++ error = valid ? valid : submodule_name_error(sm->name); + goto out; ++ } + + if (git_repository_is_bare(sm->repo)) + goto out; +@@ -1705,6 +1763,12 @@ int git_submodule_reload(git_submodule *sm, int force) + (error = submodule_update_head(sm)) < 0) + goto out; + ++ if ((valid = path_is_valid(sm->repo, sm->path)) <= 0) { ++ /* This should come with a warning, but we've no API for that */ ++ error = valid ? valid : submodule_config_error("path", sm->path); ++ goto out; ++ } ++ + out: + git_config_free(mods); + return error; +@@ -1888,13 +1952,6 @@ void git_submodule_free(git_submodule *sm) + GIT_REFCOUNT_DEC(sm, submodule_release); + } + +-static int submodule_config_error(const char *property, const char *value) +-{ +- git_error_set(GIT_ERROR_INVALID, +- "invalid value for submodule '%s' property: '%s'", property, value); +- return -1; +-} +- + int git_submodule_parse_ignore(git_submodule_ignore_t *out, const char *value) + { + int val; +@@ -2093,6 +2150,13 @@ static int submodule_load_each(const git_config_entry *entry, void *payload) + goto done; + } + ++ isvalid = path_is_valid(data->repo, sm->path); ++ if (isvalid <= 0) { ++ git_submodule_free(sm); ++ error = isvalid; ++ goto done; ++ } ++ + if ((error = git_strmap_set(map, sm->name, sm)) < 0) + goto done; + +diff --git a/src/util/fs_path.h b/src/util/fs_path.h +index e5ca673..31da593 100644 +--- a/src/util/fs_path.h ++++ b/src/util/fs_path.h +@@ -609,18 +609,18 @@ extern int git_fs_path_from_url_or_path(git_str *local_path_out, const char *url + */ + #ifdef GIT_WIN32 + # define GIT_FS_PATH_REJECT_FILESYSTEM_DEFAULTS \ +- GIT_FS_PATH_REJECT_EMPTY_COMPONENT | \ +- GIT_FS_PATH_REJECT_TRAVERSAL | \ +- GIT_FS_PATH_REJECT_BACKSLASH | \ +- GIT_FS_PATH_REJECT_TRAILING_DOT | \ +- GIT_FS_PATH_REJECT_TRAILING_SPACE | \ +- GIT_FS_PATH_REJECT_TRAILING_COLON | \ +- GIT_FS_PATH_REJECT_DOS_PATHS | \ +- GIT_FS_PATH_REJECT_NT_CHARS ++ (GIT_FS_PATH_REJECT_EMPTY_COMPONENT | \ ++ GIT_FS_PATH_REJECT_TRAVERSAL | \ ++ GIT_FS_PATH_REJECT_BACKSLASH | \ ++ GIT_FS_PATH_REJECT_TRAILING_DOT | \ ++ GIT_FS_PATH_REJECT_TRAILING_SPACE | \ ++ GIT_FS_PATH_REJECT_TRAILING_COLON | \ ++ GIT_FS_PATH_REJECT_DOS_PATHS | \ ++ GIT_FS_PATH_REJECT_NT_CHARS) + #else + # define GIT_FS_PATH_REJECT_FILESYSTEM_DEFAULTS \ +- GIT_FS_PATH_REJECT_EMPTY_COMPONENT | \ +- GIT_FS_PATH_REJECT_TRAVERSAL ++ (GIT_FS_PATH_REJECT_EMPTY_COMPONENT | \ ++ GIT_FS_PATH_REJECT_TRAVERSAL) + #endif + + /** +diff --git a/tests/libgit2/submodule/escape.c b/tests/libgit2/submodule/escape.c +index bcd52b5..e644f83 100644 +--- a/tests/libgit2/submodule/escape.c ++++ b/tests/libgit2/submodule/escape.c +@@ -16,6 +16,9 @@ void test_submodule_escape__cleanup(void) + #define EVIL_SM_NAME_WINDOWS "..\\\\..\\\\modules\\\\evil" + #define EVIL_SM_NAME_WINDOWS_UNESC "..\\..\\modules\\evil" + ++#define ESCAPE_SM_NAME "escape" ++#define ESCAPE_SM_PATH "../escape-target" ++ + static int find_evil(git_submodule *sm, const char *name, void *payload) + { + int *foundit = (int *) payload; +@@ -23,7 +26,8 @@ static int find_evil(git_submodule *sm, const char *name, void *payload) + GIT_UNUSED(sm); + + if (!git__strcmp(EVIL_SM_NAME, name) || +- !git__strcmp(EVIL_SM_NAME_WINDOWS_UNESC, name)) ++ !git__strcmp(EVIL_SM_NAME_WINDOWS_UNESC, name) || ++ !git__strcmp(ESCAPE_SM_NAME, name)) + *foundit = true; + + return 0; +@@ -49,7 +53,9 @@ void test_submodule_escape__from_gitdir(void) + foundit = 0; + cl_git_pass(git_submodule_foreach(g_repo, find_evil, &foundit)); + cl_assert_equal_i(0, foundit); ++ + cl_git_fail_with(GIT_ENOTFOUND, git_submodule_lookup(&sm, g_repo, EVIL_SM_NAME)); ++ + /* + * We do know about this as it's in the index and HEAD, but the data is + * incomplete as there is no configured data for it (we pretend it +@@ -83,7 +89,9 @@ void test_submodule_escape__from_gitdir_windows(void) + foundit = 0; + cl_git_pass(git_submodule_foreach(g_repo, find_evil, &foundit)); + cl_assert_equal_i(0, foundit); ++ + cl_git_fail_with(GIT_ENOTFOUND, git_submodule_lookup(&sm, g_repo, EVIL_SM_NAME_WINDOWS_UNESC)); ++ + /* + * We do know about this as it's in the index and HEAD, but the data is + * incomplete as there is no configured data for it (we pretend it +@@ -96,3 +104,53 @@ void test_submodule_escape__from_gitdir_windows(void) + cl_assert_equal_i(GIT_SUBMODULE_STATUS_IN_INDEX | GIT_SUBMODULE_STATUS_IN_HEAD, sm_location); + git_submodule_free(sm); + } ++ ++void test_submodule_escape__from_path_cannot_be_enumerated(void) ++{ ++ git_str buf = GIT_STR_INIT; ++ int foundit; ++ ++ g_repo = setup_fixture_submodule_simple(); ++ ++ cl_git_pass(git_str_joinpath(&buf, git_repository_workdir(g_repo), ".gitmodules")); ++ cl_git_rewritefile(buf.ptr, ++ "[submodule \"" ESCAPE_SM_NAME "\"]\n" ++ " path = " ESCAPE_SM_PATH "\n" ++ " url = https://github.com/libgit2/TestGitRepository.git\n"); ++ git_str_dispose(&buf); ++ ++ foundit = 0; ++ cl_git_pass(git_submodule_foreach(g_repo, find_evil, &foundit)); ++ cl_assert_equal_i(0, foundit); ++} ++ ++void test_submodule_escape__from_path_cannot_be_lookedup(void) ++{ ++ git_str buf = GIT_STR_INIT; ++ git_submodule *sm; ++ ++ g_repo = setup_fixture_submodule_simple(); ++ ++ cl_git_pass(git_str_joinpath(&buf, git_repository_workdir(g_repo), ".gitmodules")); ++ cl_git_rewritefile(buf.ptr, ++ "[submodule \"" ESCAPE_SM_NAME "\"]\n" ++ " path = " ESCAPE_SM_PATH "\n" ++ " url = https://github.com/libgit2/TestGitRepository.git\n"); ++ git_str_dispose(&buf); ++ ++ cl_git_fail_with(GIT_EINVALID, git_submodule_lookup(&sm, g_repo, ESCAPE_SM_NAME)); ++ cl_git_fail_with(GIT_EINVALID, git_submodule_lookup(&sm, g_repo, ESCAPE_SM_PATH)); ++} ++ ++void test_submodule_escape__during_add(void) ++{ ++ git_submodule *sm; ++ ++ g_repo = setup_fixture_submodule_simple(); ++ ++ cl_git_fail_with(GIT_EINVALID, git_submodule_add_setup( ++ &sm, g_repo, ++ "https://github.com/libgit2/TestGitRepository.git", ++ ESCAPE_SM_PATH, ++ 1)); ++} +diff --git a/tests/libgit2/submodule/submodule_helpers.c b/tests/libgit2/submodule/submodule_helpers.c +index b8fc9f6..d62c734 100644 +--- a/tests/libgit2/submodule/submodule_helpers.c ++++ b/tests/libgit2/submodule/submodule_helpers.c +@@ -4,6 +4,7 @@ + #include "posix.h" + #include "submodule_helpers.h" + #include "git2/sys/repository.h" ++#include "submodule.h" + + /* rewrite gitmodules -> .gitmodules + * rewrite the empty or relative urls inside each module +-- +2.45.4 + diff --git a/SPECS/libgit2/CVE-2026-53585.patch b/SPECS/libgit2/CVE-2026-53585.patch new file mode 100644 index 00000000000..f9c1d2714b1 --- /dev/null +++ b/SPECS/libgit2/CVE-2026-53585.patch @@ -0,0 +1,121 @@ +From 34d571630fd3a0380a7ff746a0d40bac45a87f1a Mon Sep 17 00:00:00 2001 +From: AllSpark +Date: Fri, 21 Aug 2026 14:33:04 +0000 +Subject: [PATCH] settings: introduce GIT_OPT_SET_PACK_MAX_OBJECT_SIZE + +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: AI Backport of https://github.com/libgit2/libgit2/commit/c1896f06df22cc0ca5658df3a8f6cd7ede4cd6ae.patch +--- + include/git2/common.h | 14 +++++++++++++- + src/libgit2/delta.c | 8 ++++++++ + src/libgit2/indexer.c | 5 +++-- + src/libgit2/libgit2.c | 9 +++++++++ + 4 files changed, 33 insertions(+), 3 deletions(-) + +diff --git a/include/git2/common.h b/include/git2/common.h +index ab6bc13..ab7bcc7 100644 +--- a/include/git2/common.h ++++ b/include/git2/common.h +@@ -228,7 +228,9 @@ typedef enum { + GIT_OPT_SET_SERVER_CONNECT_TIMEOUT, + GIT_OPT_GET_SERVER_CONNECT_TIMEOUT, + GIT_OPT_SET_SERVER_TIMEOUT, +- GIT_OPT_GET_SERVER_TIMEOUT ++ GIT_OPT_GET_SERVER_TIMEOUT, ++ GIT_OPT_GET_PACK_MAX_OBJECT_SIZE, ++ GIT_OPT_SET_PACK_MAX_OBJECT_SIZE + } git_libgit2_opt_t; + + /** +@@ -505,6 +507,16 @@ typedef enum { + * > connections and is not supported by SSH. Set to 0 to use the + * > system default. + * ++ * opts(GIT_OPT_GET_PACK_MAX_OBJECT_SIZE, size_t *out) ++ * > Gets the maximum size of a declared packfile object. This can ++ * > be used to limit maximum memory usage when fetching from a ++ * > remote. ++ * ++ * opts(GIT_OPT_SET_PACK_MAX_OBJECT_SIZE, size_t object_size) ++ * > Set the maximum size of an object that libgit2 will allow in ++ * > a pack file when downloading a pack file from a remote. ++ * > The default is 2 GiB. ++ * + * @param option Option key + * @param ... value to set the option + * @return 0 on success, <0 on failure +diff --git a/src/libgit2/delta.c b/src/libgit2/delta.c +index 2d2c5fa..fdebea8 100644 +--- a/src/libgit2/delta.c ++++ b/src/libgit2/delta.c +@@ -13,6 +13,8 @@ + #define RABIN_SHIFT 23 + #define RABIN_WINDOW 16 + ++extern size_t git_indexer__max_object_size; ++ + static const unsigned int T[256] = { + 0x00000000, 0xab59b4d1, 0x56b369a2, 0xfdeadd73, 0x063f6795, 0xad66d344, + 0x508c0e37, 0xfbd5bae6, 0x0c7ecf2a, 0xa7277bfb, 0x5acda688, 0xf1941259, +@@ -561,6 +563,12 @@ int git_delta_apply( + return -1; + } + ++ if (res_sz > git_indexer__max_object_size) { ++ git_error_set(GIT_ERROR_INVALID, ++ "failed to apply delta: overly large object"); ++ return -1; ++ } ++ + GIT_ERROR_CHECK_ALLOC_ADD(&alloc_sz, res_sz, 1); + res_dp = git__malloc(alloc_sz); + GIT_ERROR_CHECK_ALLOC(res_dp); +diff --git a/src/libgit2/indexer.c b/src/libgit2/indexer.c +index e559a19..430b7d4 100644 +--- a/src/libgit2/indexer.c ++++ b/src/libgit2/indexer.c +@@ -24,10 +24,11 @@ + #include "zstream.h" + #include "object.h" + +-size_t git_indexer__max_objects = UINT32_MAX; +- + #define UINT31_MAX (0x7FFFFFFF) + ++size_t git_indexer__max_objects = UINT32_MAX; ++size_t git_indexer__max_object_size = UINT31_MAX; ++ + struct entry { + git_oid oid; + uint32_t crc; +diff --git a/src/libgit2/libgit2.c b/src/libgit2/libgit2.c +index ce28714..9302701 100644 +--- a/src/libgit2/libgit2.c ++++ b/src/libgit2/libgit2.c +@@ -45,6 +45,7 @@ extern size_t git_mwindow__window_size; + extern size_t git_mwindow__mapped_limit; + extern size_t git_mwindow__file_limit; + extern size_t git_indexer__max_objects; ++extern size_t git_indexer__max_object_size; + extern bool git_disable_pack_keep_file_checks; + extern int git_odb__packed_priority; + extern int git_odb__loose_priority; +@@ -373,6 +374,14 @@ int git_libgit2_opts(int key, ...) + *(va_arg(ap, size_t *)) = git_indexer__max_objects; + break; + ++ case GIT_OPT_SET_PACK_MAX_OBJECT_SIZE: ++ git_indexer__max_object_size = va_arg(ap, size_t); ++ break; ++ ++ case GIT_OPT_GET_PACK_MAX_OBJECT_SIZE: ++ *(va_arg(ap, size_t *)) = git_indexer__max_object_size; ++ break; ++ + case GIT_OPT_DISABLE_PACK_KEEP_FILE_CHECKS: + git_disable_pack_keep_file_checks = (va_arg(ap, int) != 0); + break; + +-- +2.45.4 + diff --git a/SPECS/libgit2/CVE-2026-53586.patch b/SPECS/libgit2/CVE-2026-53586.patch new file mode 100644 index 00000000000..07f892a5909 --- /dev/null +++ b/SPECS/libgit2/CVE-2026-53586.patch @@ -0,0 +1,166 @@ +From b3e86afce96395d81bcd6442565444422eefed66 Mon Sep 17 00:00:00 2001 +From: Edward Thomson +Date: Mon, 1 Jun 2026 16:50:11 +0100 +Subject: [PATCH] http: give auth callback current host + +When calling an authentication callback for the http transport, give +the URL of the current host that we're talking to, not the host that we +were initially given. This is important during a redirect, so that +callers know who they're actually providing a username/password to. + +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: https://github.com/libgit2/libgit2/commit/c1507abc44647b3acd832a33a5b1c8c9f5ba8821.patch +--- + ci/test.sh | 4 ++++ + src/libgit2/transports/http.c | 8 +++---- + tests/libgit2/online/clone.c | 44 +++++++++++++++++++++++++++++++++++ + 3 files changed, 52 insertions(+), 4 deletions(-) + +diff --git a/ci/test.sh b/ci/test.sh +index ee6801a..2a4271d 100755 +--- a/ci/test.sh ++++ b/ci/test.sh +@@ -271,11 +271,15 @@ if [ -z "$SKIP_ONLINE_TESTS" ]; then + + export GITTEST_REMOTE_REDIRECT_INITIAL="http://localhost:9000/initial-redirect/libgit2/TestGitRepository" + export GITTEST_REMOTE_REDIRECT_SUBSEQUENT="http://localhost:9000/subsequent-redirect/libgit2/TestGitRepository" ++ export GITTEST_REMOTE_REDIRECT_AUTHENTICATION="http://localhost:9000/initial-redirect/libgit2/private-repository" ++ export GITTEST_REMOTE_REDIRECT_TARGET="https://github.com/libgit2/private-repository" + export GITTEST_REMOTE_SPEED_SLOW="http://localhost:9000/speed-9600/test.git" + export GITTEST_REMOTE_SPEED_TIMESOUT="http://localhost:9000/speed-0.5/test.git" + run_test online + unset GITTEST_REMOTE_REDIRECT_INITIAL + unset GITTEST_REMOTE_REDIRECT_SUBSEQUENT ++ unset GITTEST_REMOTE_REDIRECT_AUTHENTICATION ++ unset GITTEST_REMOTE_REDIRECT_TARGET + unset GITTEST_REMOTE_SPEED_SLOW + unset GITTEST_REMOTE_SPEED_TIMESOUT + +diff --git a/src/libgit2/transports/http.c b/src/libgit2/transports/http.c +index 8437674..cab9cad 100644 +--- a/src/libgit2/transports/http.c ++++ b/src/libgit2/transports/http.c +@@ -131,12 +131,12 @@ GIT_INLINE(void) free_cred(git_credential **cred) + static int handle_auth( + http_server *server, + const char *server_type, +- const char *url, + unsigned int allowed_schemetypes, + unsigned int allowed_credtypes, + git_credential_acquire_cb callback, + void *callback_payload) + { ++ git_str server_url = GIT_STR_INIT; + int error = 1; + + if (server->cred) +@@ -155,7 +155,8 @@ static int handle_auth( + } + + if (error > 0 && callback) { +- error = callback(&server->cred, url, server->url.username, allowed_credtypes, callback_payload); ++ if ((error = git_net_url_fmt(&server_url, &server->url)) == 0) ++ error = callback(&server->cred, server_url.ptr, server->url.username, allowed_credtypes, callback_payload); + + /* treat GIT_PASSTHROUGH as if callback isn't set */ + if (error == GIT_PASSTHROUGH) +@@ -170,6 +171,7 @@ static int handle_auth( + if (!error) + server->auth_schemetypes = allowed_schemetypes; + ++ git_str_dispose(&server_url); + return error; + } + +@@ -189,7 +191,6 @@ GIT_INLINE(int) handle_remote_auth( + return handle_auth( + &transport->server, + SERVER_TYPE_REMOTE, +- transport->owner->url, + response->server_auth_schemetypes, + response->server_auth_credtypes, + connect_opts->callbacks.credentials, +@@ -212,7 +213,6 @@ GIT_INLINE(int) handle_proxy_auth( + return handle_auth( + &transport->proxy, + SERVER_TYPE_PROXY, +- connect_opts->proxy_opts.url, + response->server_auth_schemetypes, + response->proxy_auth_credtypes, + connect_opts->proxy_opts.credentials, +diff --git a/tests/libgit2/online/clone.c b/tests/libgit2/online/clone.c +index 5789e96..ef46fa7 100644 +--- a/tests/libgit2/online/clone.c ++++ b/tests/libgit2/online/clone.c +@@ -35,6 +35,8 @@ static char *_remote_proxy_selfsigned = NULL; + static char *_remote_expectcontinue = NULL; + static char *_remote_redirect_initial = NULL; + static char *_remote_redirect_subsequent = NULL; ++static char *_remote_redirect_authentication = NULL; ++static char *_remote_redirect_target = NULL; + static char *_remote_speed_timesout = NULL; + static char *_remote_speed_slow = NULL; + +@@ -90,6 +92,8 @@ void test_online_clone__initialize(void) + _remote_expectcontinue = cl_getenv("GITTEST_REMOTE_EXPECTCONTINUE"); + _remote_redirect_initial = cl_getenv("GITTEST_REMOTE_REDIRECT_INITIAL"); + _remote_redirect_subsequent = cl_getenv("GITTEST_REMOTE_REDIRECT_SUBSEQUENT"); ++ _remote_redirect_authentication = cl_getenv("GITTEST_REMOTE_REDIRECT_AUTHENTICATION"); ++ _remote_redirect_target = cl_getenv("GITTEST_REMOTE_REDIRECT_TARGET"); + _remote_speed_timesout = cl_getenv("GITTEST_REMOTE_SPEED_TIMESOUT"); + _remote_speed_slow = cl_getenv("GITTEST_REMOTE_SPEED_SLOW"); + +@@ -133,6 +137,8 @@ void test_online_clone__cleanup(void) + git__free(_remote_expectcontinue); + git__free(_remote_redirect_initial); + git__free(_remote_redirect_subsequent); ++ git__free(_remote_redirect_authentication); ++ git__free(_remote_redirect_target); + git__free(_remote_speed_timesout); + git__free(_remote_speed_slow); + +@@ -1386,3 +1392,41 @@ void test_online_clone__timeout_configurable_succeeds_slowly(void) + cl_git_pass(git_clone(&g_repo, _remote_speed_slow, "./slow-but-successful", NULL)); + #endif + } ++ ++#ifndef GIT_WINHTTP ++static int ensure_correct_host( ++ git_credential **cred, ++ const char *url, ++ const char *user, ++ unsigned int allowed_types, ++ void *data) ++{ ++ char **given_url = (char **)data; ++ ++ GIT_UNUSED(cred); ++ GIT_UNUSED(user); ++ GIT_UNUSED(allowed_types); ++ ++ *given_url = git__strdup(url); ++ return given_url ? GIT_PASSTHROUGH : -1; ++} ++#endif ++ ++void test_online_clone__redirect_authentication_is_current_host(void) ++{ ++#ifndef GIT_WINHTTP ++ char *given_url; ++ ++ if (!_remote_redirect_authentication || !_remote_redirect_target) ++ cl_skip(); ++ ++ g_options.fetch_opts.callbacks.credentials = ensure_correct_host; ++ g_options.fetch_opts.callbacks.payload = &given_url; ++ ++ cl_git_fail_with(GIT_EAUTH, git_clone(&g_repo, _remote_redirect_authentication, "./redirect_authentication", &g_options)); ++ ++ cl_assert_equal_s(_remote_redirect_target, given_url); ++ ++ git__free(given_url); ++#endif ++} +-- +2.45.4 + diff --git a/SPECS/libgit2/CVE-2026-53587.patch b/SPECS/libgit2/CVE-2026-53587.patch new file mode 100644 index 00000000000..6fda170b1dd --- /dev/null +++ b/SPECS/libgit2/CVE-2026-53587.patch @@ -0,0 +1,32 @@ +From 06d1f5abe28b4d34cdb6ac6043975470e8ef6d2e Mon Sep 17 00:00:00 2001 +From: Edward Thomson +Date: Mon, 1 Jun 2026 13:19:17 +0100 +Subject: [PATCH] transport: ensure we were given enough caps + +When given capabilities, we check for the object-format capability; we +need to ensure that the current packet buffer is large enough before +actually doing the check. + +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: https://github.com/libgit2/libgit2/commit/2c0ce8c0132ac38ab0db28239462a671e2e5440e.patch +--- + 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 3307acf..8549886 100644 +--- a/src/libgit2/transports/smart_pkt.c ++++ b/src/libgit2/transports/smart_pkt.c +@@ -236,7 +236,8 @@ static int set_data( + len > (size_t)((caps - line) + 1)) { + caps++; + +- if (strncmp(caps, "object-format=", CONST_STRLEN("object-format=")) == 0) ++ if (len - (caps - line) >= CONST_STRLEN("object-format=") && ++ strncmp(caps, "object-format=", CONST_STRLEN("object-format=")) == 0) + format_str = caps + CONST_STRLEN("object-format="); + else if ((format_str = strstr(caps, " object-format=")) != NULL) + format_str += CONST_STRLEN(" object-format="); +-- +2.45.4 + diff --git a/SPECS/libgit2/libgit2.spec b/SPECS/libgit2/libgit2.spec index 7bfc949eceb..d306aedb27d 100644 --- a/SPECS/libgit2/libgit2.spec +++ b/SPECS/libgit2/libgit2.spec @@ -1,12 +1,17 @@ Summary: C implementation of the Git core methods as a library with a solid API Name: libgit2 Version: 1.7.2 -Release: 1%{?dist} +Release: 2%{?dist} License: GPLv2 with exceptions Vendor: Microsoft Corporation Distribution: Azure Linux URL: https://libgit2.org/ Source0: https://github.com/libgit2/libgit2/archive/v%{version}/%{name}-%{version}.tar.gz +Patch0: CVE-2026-53583.patch +Patch1: CVE-2026-53584.patch +Patch2: CVE-2026-53585.patch +Patch3: CVE-2026-53586.patch +Patch4: CVE-2026-53587.patch BuildRequires: cmake >= 3.5.1 BuildRequires: gcc @@ -79,6 +84,9 @@ popd %{_bindir}/git2 %changelog +* Fri Aug 21 2026 Azure Linux Security Servicing Account - 1.7.2-2 +- Patch for CVE-2026-53587, CVE-2026-53586, CVE-2026-53585, CVE-2026-53584, CVE-2026-53583 + * Thu Feb 15 2024 Yash Panchal - 1.7.2-1 - Update to 1.7.2