summaryrefslogtreecommitdiffstats
path: root/meta/recipes-devtools/git/git/CVE-2020-11008-4.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-devtools/git/git/CVE-2020-11008-4.patch')
-rw-r--r--meta/recipes-devtools/git/git/CVE-2020-11008-4.patch173
1 files changed, 173 insertions, 0 deletions
diff --git a/meta/recipes-devtools/git/git/CVE-2020-11008-4.patch b/meta/recipes-devtools/git/git/CVE-2020-11008-4.patch
new file mode 100644
index 0000000000..14e23466d4
--- /dev/null
+++ b/meta/recipes-devtools/git/git/CVE-2020-11008-4.patch
@@ -0,0 +1,173 @@
+From f8bf7099379990ad974c1ca8f51e1f28bf18cf2a Mon Sep 17 00:00:00 2001
+From: Jeff King <peff@peff.net>
+Date: Sat, 18 Apr 2020 20:50:48 -0700
+Subject: [PATCH 07/12] credential: refuse to operate when missing host or
+ protocol
+
+The credential helper protocol was designed to be very flexible: the
+fields it takes as input are treated as a pattern, and any missing
+fields are taken as wildcards. This allows unusual things like:
+
+ echo protocol=https | git credential reject
+
+to delete all stored https credentials (assuming the helpers themselves
+treat the input that way). But when helpers are invoked automatically by
+Git, this flexibility works against us. If for whatever reason we don't
+have a "host" field, then we'd match _any_ host. When you're filling a
+credential to send to a remote server, this is almost certainly not what
+you want.
+
+Prevent this at the layer that writes to the credential helper. Add a
+check to the credential API that the host and protocol are always passed
+in, and add an assertion to the credential_write function that speaks
+credential helper protocol to be doubly sure.
+
+There are a few ways this can be triggered in practice:
+
+ - the "git credential" command passes along arbitrary credential
+ parameters it reads from stdin.
+
+ - until the previous patch, when the host field of a URL is empty, we
+ would leave it unset (rather than setting it to the empty string)
+
+ - a URL like "example.com/foo.git" is treated by curl as if "http://"
+ was present, but our parser sees it as a non-URL and leaves all
+ fields unset
+
+ - the recent fix for URLs with embedded newlines blanks the URL but
+ otherwise continues. Rather than having the desired effect of
+ looking up no credential at all, many helpers will return _any_
+ credential
+
+Our earlier test for an embedded newline didn't catch this because it
+only checked that the credential was cleared, but didn't configure an
+actual helper. Configuring the "verbatim" helper in the test would show
+that it is invoked (it's obviously a silly helper which doesn't look at
+its input, but the point is that it shouldn't be run at all). Since
+we're switching this case to die(), we don't need to bother with a
+helper. We can see the new behavior just by checking that the operation
+fails.
+
+We'll add new tests covering partial input as well (these can be
+triggered through various means with url-parsing, but it's simpler to
+just check them directly, as we know we are covered even if the url
+parser changes behavior in the future).
+
+[jn: changed to die() instead of logging and showing a manual
+ username/password prompt]
+
+Reported-by: Carlo Arenas <carenas@gmail.com>
+Signed-off-by: Jeff King <peff@peff.net>
+Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
+
+Upstream-Status: Backport
+CVE: CVE-2020-11008 (4)
+Signed-off-by: Li Zhou <li.zhou@windriver.com>
+---
+ credential.c | 20 ++++++++++++++------
+ t/t0300-credentials.sh | 34 ++++++++++++++++++++++++++--------
+ 2 files changed, 40 insertions(+), 14 deletions(-)
+
+diff --git a/credential.c b/credential.c
+index f2413ce..e08ed84 100644
+--- a/credential.c
++++ b/credential.c
+@@ -89,6 +89,11 @@ static int proto_is_http(const char *s)
+
+ static void credential_apply_config(struct credential *c)
+ {
++ if (!c->host)
++ die(_("refusing to work with credential missing host field"));
++ if (!c->protocol)
++ die(_("refusing to work with credential missing protocol field"));
++
+ if (c->configured)
+ return;
+ git_config(credential_config_callback, c);
+@@ -191,8 +196,11 @@ int credential_read(struct credential *c, FILE *fp)
+ return 0;
+ }
+
+-static void credential_write_item(FILE *fp, const char *key, const char *value)
++static void credential_write_item(FILE *fp, const char *key, const char *value,
++ int required)
+ {
++ if (!value && required)
++ BUG("credential value for %s is missing", key);
+ if (!value)
+ return;
+ if (strchr(value, '\n'))
+@@ -202,11 +210,11 @@ static void credential_write_item(FILE *fp, const char *key, const char *value)
+
+ void credential_write(const struct credential *c, FILE *fp)
+ {
+- credential_write_item(fp, "protocol", c->protocol);
+- credential_write_item(fp, "host", c->host);
+- credential_write_item(fp, "path", c->path);
+- credential_write_item(fp, "username", c->username);
+- credential_write_item(fp, "password", c->password);
++ credential_write_item(fp, "protocol", c->protocol, 1);
++ credential_write_item(fp, "host", c->host, 1);
++ credential_write_item(fp, "path", c->path, 0);
++ credential_write_item(fp, "username", c->username, 0);
++ credential_write_item(fp, "password", c->password, 0);
+ }
+
+ static int run_credential_helper(struct credential *c,
+diff --git a/t/t0300-credentials.sh b/t/t0300-credentials.sh
+index 1c1010b..646f845 100755
+--- a/t/t0300-credentials.sh
++++ b/t/t0300-credentials.sh
+@@ -400,18 +400,16 @@ test_expect_success 'empty helper spec resets helper list' '
+ EOF
+ '
+
+-test_expect_success 'url parser ignores embedded newlines' '
+- check fill <<-EOF
++test_expect_success 'url parser rejects embedded newlines' '
++ test_must_fail git credential fill 2>stderr <<-\EOF &&
+ url=https://one.example.com?%0ahost=two.example.com/
+- --
+- username=askpass-username
+- password=askpass-password
+- --
++ EOF
++ cat >expect <<-\EOF &&
+ 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:
++ fatal: refusing to work with credential missing host field
+ EOF
++ test_i18ncmp expect stderr
+ '
+
+ test_expect_success 'host-less URLs are parsed as empty host' '
+@@ -431,4 +429,24 @@ test_expect_success 'host-less URLs are parsed as empty host' '
+ EOF
+ '
+
++test_expect_success 'credential system refuses to work with missing host' '
++ test_must_fail git credential fill 2>stderr <<-\EOF &&
++ protocol=http
++ EOF
++ cat >expect <<-\EOF &&
++ fatal: refusing to work with credential missing host field
++ EOF
++ test_i18ncmp expect stderr
++'
++
++test_expect_success 'credential system refuses to work with missing protocol' '
++ test_must_fail git credential fill 2>stderr <<-\EOF &&
++ host=example.com
++ EOF
++ cat >expect <<-\EOF &&
++ fatal: refusing to work with credential missing protocol field
++ EOF
++ test_i18ncmp expect stderr
++'
++
+ test_done
+--
+1.9.1
+