diff options
Diffstat (limited to 'meta/recipes-devtools/git/git/0002-credential-detect-unrepresentable-values-when-parsin.patch')
-rw-r--r-- | meta/recipes-devtools/git/git/0002-credential-detect-unrepresentable-values-when-parsin.patch | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/meta/recipes-devtools/git/git/0002-credential-detect-unrepresentable-values-when-parsin.patch b/meta/recipes-devtools/git/git/0002-credential-detect-unrepresentable-values-when-parsin.patch new file mode 100644 index 0000000000..a9b7348ef7 --- /dev/null +++ b/meta/recipes-devtools/git/git/0002-credential-detect-unrepresentable-values-when-parsin.patch | |||
@@ -0,0 +1,156 @@ | |||
1 | From 43803880b954a020dbffa5250a5b7fd893442c7c Mon Sep 17 00:00:00 2001 | ||
2 | From: Jeff King <peff@peff.net> | ||
3 | Date: Thu, 12 Mar 2020 01:31:11 -0400 | ||
4 | Subject: [PATCH 02/12] credential: detect unrepresentable values when parsing | ||
5 | urls | ||
6 | |||
7 | The credential protocol can't represent newlines in values, but URLs can | ||
8 | embed percent-encoded newlines in various components. A previous commit | ||
9 | taught the low-level writing routines to die() when encountering this, | ||
10 | but we can be a little friendlier to the user by detecting them earlier | ||
11 | and handling them gracefully. | ||
12 | |||
13 | This patch teaches credential_from_url() to notice such components, | ||
14 | issue a warning, and blank the credential (which will generally result | ||
15 | in prompting the user for a username and password). We blank the whole | ||
16 | credential in this case. Another option would be to blank only the | ||
17 | invalid component. However, we're probably better off not feeding a | ||
18 | partially-parsed URL result to a credential helper. We don't know how a | ||
19 | given helper would handle it, so we're better off to err on the side of | ||
20 | matching nothing rather than something unexpected. | ||
21 | |||
22 | The die() call in credential_write() is _probably_ impossible to reach | ||
23 | after this patch. Values should end up in credential structs only by URL | ||
24 | parsing (which is covered here), or by reading credential protocol input | ||
25 | (which by definition cannot read a newline into a value). But we should | ||
26 | definitely keep the low-level check, as it's our final and most accurate | ||
27 | line of defense against protocol injection attacks. Arguably it could | ||
28 | become a BUG(), but it probably doesn't matter much either way. | ||
29 | |||
30 | Note that the public interface of credential_from_url() grows a little | ||
31 | more than we need here. We'll use the extra flexibility in a future | ||
32 | patch to help fsck catch these cases. | ||
33 | |||
34 | Upstream-Status: Backport | ||
35 | |||
36 | Signed-off-by: Li Zhou <li.zhou@windriver.com> | ||
37 | --- | ||
38 | credential.c | 36 ++++++++++++++++++++++++++++++++++-- | ||
39 | credential.h | 16 ++++++++++++++++ | ||
40 | t/t0300-credentials.sh | 12 ++++++++++-- | ||
41 | 3 files changed, 60 insertions(+), 4 deletions(-) | ||
42 | |||
43 | diff --git a/credential.c b/credential.c | ||
44 | index a79aff0..2482382 100644 | ||
45 | --- a/credential.c | ||
46 | +++ b/credential.c | ||
47 | @@ -324,7 +324,22 @@ void credential_reject(struct credential *c) | ||
48 | c->approved = 0; | ||
49 | } | ||
50 | |||
51 | -void credential_from_url(struct credential *c, const char *url) | ||
52 | +static int check_url_component(const char *url, int quiet, | ||
53 | + const char *name, const char *value) | ||
54 | +{ | ||
55 | + if (!value) | ||
56 | + return 0; | ||
57 | + if (!strchr(value, '\n')) | ||
58 | + return 0; | ||
59 | + | ||
60 | + if (!quiet) | ||
61 | + warning(_("url contains a newline in its %s component: %s"), | ||
62 | + name, url); | ||
63 | + return -1; | ||
64 | +} | ||
65 | + | ||
66 | +int credential_from_url_gently(struct credential *c, const char *url, | ||
67 | + int quiet) | ||
68 | { | ||
69 | const char *at, *colon, *cp, *slash, *host, *proto_end; | ||
70 | |||
71 | @@ -338,7 +353,7 @@ void credential_from_url(struct credential *c, const char *url) | ||
72 | */ | ||
73 | proto_end = strstr(url, "://"); | ||
74 | if (!proto_end) | ||
75 | - return; | ||
76 | + return 0; | ||
77 | cp = proto_end + 3; | ||
78 | at = strchr(cp, '@'); | ||
79 | colon = strchr(cp, ':'); | ||
80 | @@ -373,4 +388,21 @@ void credential_from_url(struct credential *c, const char *url) | ||
81 | while (p > c->path && *p == '/') | ||
82 | *p-- = '\0'; | ||
83 | } | ||
84 | + | ||
85 | + if (check_url_component(url, quiet, "username", c->username) < 0 || | ||
86 | + check_url_component(url, quiet, "password", c->password) < 0 || | ||
87 | + check_url_component(url, quiet, "protocol", c->protocol) < 0 || | ||
88 | + check_url_component(url, quiet, "host", c->host) < 0 || | ||
89 | + check_url_component(url, quiet, "path", c->path) < 0) | ||
90 | + return -1; | ||
91 | + | ||
92 | + return 0; | ||
93 | +} | ||
94 | + | ||
95 | +void credential_from_url(struct credential *c, const char *url) | ||
96 | +{ | ||
97 | + if (credential_from_url_gently(c, url, 0) < 0) { | ||
98 | + warning(_("skipping credential lookup for url: %s"), url); | ||
99 | + credential_clear(c); | ||
100 | + } | ||
101 | } | ||
102 | diff --git a/credential.h b/credential.h | ||
103 | index 6b0cd16..122a23c 100644 | ||
104 | --- a/credential.h | ||
105 | +++ b/credential.h | ||
106 | @@ -28,7 +28,23 @@ struct credential { | ||
107 | |||
108 | int credential_read(struct credential *, FILE *); | ||
109 | void credential_write(const struct credential *, FILE *); | ||
110 | + | ||
111 | +/* | ||
112 | + * Parse a url into a credential struct, replacing any existing contents. | ||
113 | + * | ||
114 | + * Ifthe url can't be parsed (e.g., a missing "proto://" component), the | ||
115 | + * resulting credential will be empty but we'll still return success from the | ||
116 | + * "gently" form. | ||
117 | + * | ||
118 | + * If we encounter a component which cannot be represented as a credential | ||
119 | + * value (e.g., because it contains a newline), the "gently" form will return | ||
120 | + * an error but leave the broken state in the credential object for further | ||
121 | + * examination. The non-gentle form will issue a warning to stderr and return | ||
122 | + * an empty credential. | ||
123 | + */ | ||
124 | void credential_from_url(struct credential *, const char *url); | ||
125 | +int credential_from_url_gently(struct credential *, const char *url, int quiet); | ||
126 | + | ||
127 | int credential_match(const struct credential *have, | ||
128 | const struct credential *want); | ||
129 | |||
130 | diff --git a/t/t0300-credentials.sh b/t/t0300-credentials.sh | ||
131 | index 26f3c3a..b9c0f1f 100755 | ||
132 | --- a/t/t0300-credentials.sh | ||
133 | +++ b/t/t0300-credentials.sh | ||
134 | @@ -308,9 +308,17 @@ test_expect_success 'empty helper spec resets helper list' ' | ||
135 | EOF | ||
136 | ' | ||
137 | |||
138 | -test_expect_success 'url parser rejects embedded newlines' ' | ||
139 | - test_must_fail git credential fill <<-\EOF | ||
140 | +test_expect_success 'url parser ignores embedded newlines' ' | ||
141 | + check fill <<-EOF | ||
142 | url=https://one.example.com?%0ahost=two.example.com/ | ||
143 | + -- | ||
144 | + username=askpass-username | ||
145 | + password=askpass-password | ||
146 | + -- | ||
147 | + warning: url contains a newline in its host component: https://one.example.com?%0ahost=two.example.com/ | ||
148 | + warning: skipping credential lookup for url: https://one.example.com?%0ahost=two.example.com/ | ||
149 | + askpass: Username: | ||
150 | + askpass: Password: | ||
151 | EOF | ||
152 | ' | ||
153 | |||
154 | -- | ||
155 | 1.9.1 | ||
156 | |||