diff --git a/SOURCES/git-cve-2020-5260.patch b/SOURCES/git-cve-2020-5260.patch new file mode 100644 index 0000000..20d60b7 --- /dev/null +++ b/SOURCES/git-cve-2020-5260.patch @@ -0,0 +1,201 @@ +diff -ur b/credential.c a/credential.c +--- b/credential.c 2020-04-09 09:53:10.568938942 +0200 ++++ a/credential.c 2020-04-09 12:34:56.735418779 +0200 +@@ -195,6 +195,8 @@ + { + if (!value) + return; ++ if (strchr(value, '\n')) ++ die("credential value for %s contains newline", key); + fprintf(fp, "%s=%s\n", key, value); + } + +@@ -321,8 +323,21 @@ + FREE_AND_NULL(c->password); + c->approved = 0; + } +- +-void credential_from_url(struct credential *c, const char *url) ++static int check_url_component(const char *url, int quiet, ++ const char *name, const char *value) ++{ ++ if (!value) ++ return 0; ++ if (!strchr(value, '\n')) ++ return 0; ++ ++ if (!quiet) ++ warning(_("url contains a newline in its %s component: %s"), ++ name, url); ++ return -1; ++} ++int credential_from_url_gently(struct credential *c, const char *url, ++ int quiet) + { + const char *at, *colon, *cp, *slash, *host, *proto_end; + +@@ -336,7 +351,7 @@ + */ + proto_end = strstr(url, "://"); + if (!proto_end) +- return; ++ return 0; + cp = proto_end + 3; + at = strchr(cp, '@'); + colon = strchr(cp, ':'); +@@ -371,4 +386,21 @@ + while (p > c->path && *p == '/') + *p-- = '\0'; + } ++ ++ if (check_url_component(url, quiet, "username", c->username) < 0 || ++ check_url_component(url, quiet, "password", c->password) < 0 || ++ check_url_component(url, quiet, "protocol", c->protocol) < 0 || ++ check_url_component(url, quiet, "host", c->host) < 0 || ++ check_url_component(url, quiet, "path", c->path) < 0) ++ return -1; ++ ++ return 0; ++} ++ ++void credential_from_url(struct credential *c, const char *url) ++{ ++ if (credential_from_url_gently(c, url, 0) < 0) { ++ warning(_("skipping credential lookup for url: %s"), url); ++ credential_clear(c); ++ } + } +diff -ur b/credential.h a/credential.h +--- b/credential.h 2020-04-09 09:53:10.568938942 +0200 ++++ a/credential.h 2020-04-09 10:06:07.467159059 +0200 +@@ -28,7 +28,23 @@ + + int credential_read(struct credential *, FILE *); + void credential_write(const struct credential *, FILE *); ++ ++/* ++ * Parse a url into a credential struct, replacing any existing contents. ++ * ++ * Ifthe url can't be parsed (e.g., a missing "proto://" component), the ++ * resulting credential will be empty but we'll still return success from the ++ * "gently" form. ++ * ++ * If we encounter a component which cannot be represented as a credential ++ * value (e.g., because it contains a newline), the "gently" form will return ++ * an error but leave the broken state in the credential object for further ++ * examination. The non-gentle form will issue a warning to stderr and return ++ * an empty credential. ++*/ + void credential_from_url(struct credential *, const char *url); ++int credential_from_url_gently(struct credential *, const char *url, int quiet); ++ + int credential_match(const struct credential *have, + const struct credential *want); + +diff -ur b/fsck.c a/fsck.c +--- b/fsck.c 2020-04-09 09:53:10.569938954 +0200 ++++ a/fsck.c 2020-04-09 12:29:42.713615414 +0200 +@@ -14,6 +14,7 @@ + #include "packfile.h" + #include "submodule-config.h" + #include "config.h" ++#include "credential.h" + + static struct oidset gitmodules_found = OIDSET_INIT; + static struct oidset gitmodules_done = OIDSET_INIT; +@@ -945,6 +946,19 @@ + return fsck_tag_buffer(tag, data, size, options); + } + ++static int check_submodule_url(const char *url) ++{ ++ struct credential c = CREDENTIAL_INIT; ++ int ret; ++ ++ if (looks_like_command_line_option(url)) ++ return -1; ++ ++ ret = credential_from_url_gently(&c, url, 1); ++ credential_clear(&c); ++ return ret; ++} ++ + struct fsck_gitmodules_data { + struct object *obj; + struct fsck_options *options; +@@ -969,8 +983,8 @@ + "disallowed submodule name: %s", + name); + if (!strcmp(key, "url") && value && +- looks_like_command_line_option(value)) +- data->ret |= report(data->options, data->obj, ++ check_submodule_url(value) < 0) ++ data->ret |= report(data->options, data->obj, + FSCK_MSG_GITMODULES_URL, + "disallowed submodule url: %s", + value); +diff -ur b/t/lib-credential.sh a/t/lib-credential.sh +--- b/t/lib-credential.sh 2020-04-09 09:53:10.501938148 +0200 ++++ a/t/lib-credential.sh 2020-04-09 12:28:10.369496961 +0200 +@@ -19,7 +19,7 @@ + false + fi && + test_cmp expect-stdout stdout && +- test_cmp expect-stderr stderr ++ test_i18ncmp expect-stderr stderr + } + + read_chunk() { +diff -ur b/t/t0300-credentials.sh a/t/t0300-credentials.sh +--- b/t/t0300-credentials.sh 2020-04-09 09:53:10.506938208 +0200 ++++ a/t/t0300-credentials.sh 2020-04-09 12:26:42.660434645 +0200 +@@ -309,4 +309,18 @@ + EOF + ' + ++test_expect_success 'url parser ignores embedded newlines' ' ++ check fill <<-EOF ++ url=https://one.example.com?%0ahost=two.example.com/ ++ -- ++ username=askpass-username ++ password=askpass-password ++ -- ++ warning: url contains a newline in its host component: https://one.example.com?%0ahost=two.example.com/ ++ warning: skipping credential lookup for url: https://one.example.com?%0ahost=two.example.com/ ++ askpass: Username: ++ askpass: Password: ++ EOF ++' ++ + test_done +diff -ur b/t/t7416-submodule-dash-url.sh a/t/t7416-submodule-dash-url.sh +--- b/t/t7416-submodule-dash-url.sh 2020-04-09 09:53:10.528938468 +0200 ++++ a/t/t7416-submodule-dash-url.sh 2020-04-09 12:27:15.594833539 +0200 +@@ -1,6 +1,6 @@ + #!/bin/sh + +-test_description='check handling of .gitmodule url with dash' ++test_description='check handling of disallowed .gitmodule urls' + . ./test-lib.sh + + test_expect_success 'create submodule with protected dash in url' ' +@@ -60,4 +60,19 @@ + test_i18ngrep ! "unknown option" err + ' + ++test_expect_success 'fsck rejects embedded newline in url' ' ++ git checkout --orphan newline && ++ cat >.gitmodules <<-\EOF && ++ [submodule "foo"] ++ url = "https://one.example.com?%0ahost=two.example.com/foo.git" ++ EOF ++ git add .gitmodules && ++ git commit -m "gitmodules with newline" && ++ test_when_finished "rm -rf dst" && ++ git init --bare dst && ++ git -C dst config transfer.fsckObjects true && ++ test_must_fail git push dst HEAD 2>err && ++ grep gitmodulesUrl err ++' ++ + test_done diff --git a/SPECS/git.spec b/SPECS/git.spec index 7682b74..032cc89 100644 --- a/SPECS/git.spec +++ b/SPECS/git.spec @@ -103,7 +103,7 @@ Name: %{?scl_prefix}git Version: 2.18.2 -Release: 1%{?rcrev}%{?dist} +Release: 2%{?rcrev}%{?dist} Summary: Fast Version Control System License: GPLv2 URL: https://git-scm.com/ @@ -150,6 +150,9 @@ Patch5: 0001-config-document-value-2-for-protocol.version.patch Patch7: 0001-run-command-mark-path-lookup-errors-with-ENOENT.patch # https://bugzilla.redhat.com/show_bug.cgi?id=1619113 Patch8: git-2.18.1-core-crypto-hmac.patch +# CVE-2020-5260 +# https://bugzilla.redhat.com/show_bug.cgi?id=1822020 +Patch9: git-cve-2020-5260.patch %if %{with docs} BuildRequires: asciidoc >= 8.4.1 @@ -961,6 +964,10 @@ make test || ./print-failed-test-output %{?with_docs:%{_pkgdocdir}/git-instaweb.html} %changelog +* Thu Apr 9 2020 Ondrej Pohorelsky - 2.18.2-2 +- Crafted URL containing new lines can cause credential leak +- Resolves: CVE-2020-5260 + * Tue Dec 17 2019 Ondrej Pohorelsky - 2.18.2-1 - Update to release 2.18.2 - Remote code execution in recursive clones with nested submodules