Skip to content

Commit 65faad6

Browse files
committed
Sync with Git 2.47.2
Git 2.47.2 # -----BEGIN PGP SIGNATURE----- # # iQIzBAABCAAdFiEE4fA2sf7nIh/HeOzvsLXohpav5ssFAmdkT1sACgkQsLXohpav # 5svdhRAAq0WoZIg+33vYNNVSTm3Ux9RJslmXs3lQuhuUJ61hK/28drSLU29GH7x7 # 3nmmjp1cegnXRVLBAfoYDdzPprNNrQFQEHQEzgG/GDZw0OXn+WTZuNyrrUYoa+sd # QSLlElRj2qrpHIMOsMIBKBSNB+qjJHOMGdxcBAS768TfnQpGIpc1KJa24TxsVBzC # ScP4uvrFfPyQrqFUgiUhCeqLnO/6T5i/QAn/8cS5a1+zor5ZHSlw28TZTOxN2odo # Rulp/FtehiDEzmRowgD3M4fImAPY6Ib6VORCYASqpJFFla30tu2bQqEi6raOMTec # hg5Ibkmj6fHFONaYvoTMRkYHmtUnNgIPU/CYPwswNk8w1+PPQfJ+TYjBXOQgdTLW # F0azHBHh7NRmEHVydiF9CqjgNVRzjO4IEZfGqXNFPPMvR6UUzDaIkrpYbwXBFMin # GNPV3QISeXj9ROjJoCv0nclXETwWemykjZlD6b5krXn5TaJlFb+69qJvXrCLq5WY # EoevSqKkB9HVK9si7P8Sh1cPGOr3kfiFPmMNKFVI8l0+iDFgBywOomWNS/JEzqu1 # nN142DKdL1W/rkeMUhbX2h11CZNvHKIOy3iaA4MTOing8/eMzyUUQ73Ck7odYs4f # rZ0tTXKJhxojPvBpTxYe9SxM0bDLREiOv0zX76+sIuhbAQCmk0o= # =MNNf # -----END PGP SIGNATURE----- # gpg: Signature made Thu 19 Dec 2024 08:52:43 AM PST # gpg: using RSA key E1F036B1FEE7221FC778ECEFB0B5E88696AFE6CB # gpg: Good signature from "Junio C Hamano <[email protected]>" [ultimate] # gpg: aka "Junio C Hamano <[email protected]>" [ultimate] # gpg: aka "Junio C Hamano <[email protected]>" [ultimate] * tag 'v2.47.2': Git 2.47.2 Git 2.46.3 Git 2.45.3 Git 2.44.3 Git 2.43.6 Git 2.42.4 Git 2.41.3 Git 2.40.4 credential: disallow Carriage Returns in the protocol by default credential: sanitize the user prompt credential_format(): also encode <host>[:<port>] t7300: work around platform-specific behaviour with long paths on MinGW compat/regex: fix argument order to calloc(3) mingw: drop bogus (and unneeded) declaration of `_pgmptr` ci: remove 'Upload failed tests' directories' step from linux32 jobs
2 parents fbe8d30 + e1fbebe commit 65faad6

17 files changed

+169
-40
lines changed

Documentation/RelNotes/2.40.4.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Git v2.40.4 Release Notes
2+
=========================
3+
4+
This release lets Git refuse to accept URLs that contain control
5+
sequences. This addresses CVE-2024-50349 and CVE-2024-52006.

Documentation/RelNotes/2.41.3.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Git v2.41.3 Release Notes
2+
=========================
3+
4+
This release merges up the fix that appears in v2.40.4 to address
5+
the security issues CVE-2024-50349 and CVE-2024-52006; see the
6+
release notes for that version for details.

Documentation/RelNotes/2.42.4.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Git v2.42.4 Release Notes
2+
=========================
3+
4+
This release merges up the fix that appears in v2.40.4 and v2.41.3
5+
to address the security issues CVE-2024-50349 and CVE-2024-52006;
6+
see the release notes for these versions for details.

Documentation/RelNotes/2.43.6.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Git v2.43.6 Release Notes
2+
=========================
3+
4+
This release merges up the fix that appears in v2.40.4, v2.41.3
5+
and v2.42.4 to address the security issues CVE-2024-50349 and
6+
CVE-2024-52006; see the release notes for these versions for
7+
details.

Documentation/RelNotes/2.44.3.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Git v2.44.3 Release Notes
2+
=========================
3+
4+
This release merges up the fix that appears in v2.40.4, v2.41.3,
5+
v2.42.4 and v2.43.6 to address the security issues CVE-2024-50349
6+
and CVE-2024-52006; see the release notes for these versions
7+
for details.

Documentation/RelNotes/2.45.3.txt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
Git v2.45.3 Release Notes
22
=========================
33

4-
This primarily is to backport various small fixes accumulated on the
4+
This release merges up the fix that appears in v2.40.4, v2.41.3,
5+
v2.42.4, v2.43.6 and v2.44.3 to address the security issues
6+
CVE-2024-50349 and CVE-2024-52006; see the release notes for
7+
these versions for details.
8+
9+
This version also backports various small fixes accumulated on the
510
'master' front during the development towards Git 2.46, the next
611
feature release.
712

Documentation/RelNotes/2.46.3.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Git v2.46.3 Release Notes
2+
=========================
3+
4+
This release merges up the fix that appears in v2.40.4, v2.41.3, v2.42.4,
5+
v2.43.6, v2.44.3 and v2.45.3 to address the security issues CVE-2024-50349 and
6+
CVE-2024-52006; see the release notes for these versions for details.

Documentation/RelNotes/2.47.2.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Git v2.47.2 Release Notes
2+
=========================
3+
4+
This release merges up the fix that appears in v2.40.4, v2.41.3,
5+
v2.42.4, v2.43.6, v2.44.3, v2.45.3 and v2.46.3 to address the
6+
security issues CVE-2024-50349 and CVE-2024-52006; see the release
7+
notes for these versions for details.

Documentation/config/credential.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,17 @@ credential.useHttpPath::
2222
or https URL to be important. Defaults to false. See
2323
linkgit:gitcredentials[7] for more information.
2424

25+
credential.sanitizePrompt::
26+
By default, user names and hosts that are shown as part of the
27+
password prompt are not allowed to contain control characters (they
28+
will be URL-encoded by default). Configure this setting to `false` to
29+
override that behavior.
30+
31+
credential.protectProtocol::
32+
By default, Carriage Return characters are not allowed in the protocol
33+
that is used when Git talks to a credential helper. This setting allows
34+
users to override this default.
35+
2536
credential.username::
2637
If no username is set for a network authentication, use this username
2738
by default. See credential.<context>.* below, and

credential.c

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
#include "sigchain.h"
1414
#include "strbuf.h"
1515
#include "urlmatch.h"
16-
#include "git-compat-util.h"
16+
#include "environment.h"
1717
#include "trace2.h"
1818
#include "repository.h"
1919

@@ -130,6 +130,10 @@ static int credential_config_callback(const char *var, const char *value,
130130
}
131131
else if (!strcmp(key, "usehttppath"))
132132
c->use_http_path = git_config_bool(var, value);
133+
else if (!strcmp(key, "sanitizeprompt"))
134+
c->sanitize_prompt = git_config_bool(var, value);
135+
else if (!strcmp(key, "protectprotocol"))
136+
c->protect_protocol = git_config_bool(var, value);
133137

134138
return 0;
135139
}
@@ -227,7 +231,8 @@ static void credential_format(struct credential *c, struct strbuf *out)
227231
strbuf_addch(out, '@');
228232
}
229233
if (c->host)
230-
strbuf_addstr(out, c->host);
234+
strbuf_add_percentencode(out, c->host,
235+
STRBUF_ENCODE_HOST_AND_PORT);
231236
if (c->path) {
232237
strbuf_addch(out, '/');
233238
strbuf_add_percentencode(out, c->path, 0);
@@ -241,7 +246,10 @@ static char *credential_ask_one(const char *what, struct credential *c,
241246
struct strbuf prompt = STRBUF_INIT;
242247
char *r;
243248

244-
credential_describe(c, &desc);
249+
if (c->sanitize_prompt)
250+
credential_format(c, &desc);
251+
else
252+
credential_describe(c, &desc);
245253
if (desc.len)
246254
strbuf_addf(&prompt, "%s for '%s': ", what, desc.buf);
247255
else
@@ -382,7 +390,8 @@ int credential_read(struct credential *c, FILE *fp,
382390
return 0;
383391
}
384392

385-
static void credential_write_item(FILE *fp, const char *key, const char *value,
393+
static void credential_write_item(const struct credential *c,
394+
FILE *fp, const char *key, const char *value,
386395
int required)
387396
{
388397
if (!value && required)
@@ -391,41 +400,45 @@ static void credential_write_item(FILE *fp, const char *key, const char *value,
391400
return;
392401
if (strchr(value, '\n'))
393402
die("credential value for %s contains newline", key);
403+
if (c->protect_protocol && strchr(value, '\r'))
404+
die("credential value for %s contains carriage return\n"
405+
"If this is intended, set `credential.protectProtocol=false`",
406+
key);
394407
fprintf(fp, "%s=%s\n", key, value);
395408
}
396409

397410
void credential_write(const struct credential *c, FILE *fp,
398411
enum credential_op_type op_type)
399412
{
400413
if (credential_has_capability(&c->capa_authtype, op_type))
401-
credential_write_item(fp, "capability[]", "authtype", 0);
414+
credential_write_item(c, fp, "capability[]", "authtype", 0);
402415
if (credential_has_capability(&c->capa_state, op_type))
403-
credential_write_item(fp, "capability[]", "state", 0);
416+
credential_write_item(c, fp, "capability[]", "state", 0);
404417

405418
if (credential_has_capability(&c->capa_authtype, op_type)) {
406-
credential_write_item(fp, "authtype", c->authtype, 0);
407-
credential_write_item(fp, "credential", c->credential, 0);
419+
credential_write_item(c, fp, "authtype", c->authtype, 0);
420+
credential_write_item(c, fp, "credential", c->credential, 0);
408421
if (c->ephemeral)
409-
credential_write_item(fp, "ephemeral", "1", 0);
422+
credential_write_item(c, fp, "ephemeral", "1", 0);
410423
}
411-
credential_write_item(fp, "protocol", c->protocol, 1);
412-
credential_write_item(fp, "host", c->host, 1);
413-
credential_write_item(fp, "path", c->path, 0);
414-
credential_write_item(fp, "username", c->username, 0);
415-
credential_write_item(fp, "password", c->password, 0);
416-
credential_write_item(fp, "oauth_refresh_token", c->oauth_refresh_token, 0);
424+
credential_write_item(c, fp, "protocol", c->protocol, 1);
425+
credential_write_item(c, fp, "host", c->host, 1);
426+
credential_write_item(c, fp, "path", c->path, 0);
427+
credential_write_item(c, fp, "username", c->username, 0);
428+
credential_write_item(c, fp, "password", c->password, 0);
429+
credential_write_item(c, fp, "oauth_refresh_token", c->oauth_refresh_token, 0);
417430
if (c->password_expiry_utc != TIME_MAX) {
418431
char *s = xstrfmt("%"PRItime, c->password_expiry_utc);
419-
credential_write_item(fp, "password_expiry_utc", s, 0);
432+
credential_write_item(c, fp, "password_expiry_utc", s, 0);
420433
free(s);
421434
}
422435
for (size_t i = 0; i < c->wwwauth_headers.nr; i++)
423-
credential_write_item(fp, "wwwauth[]", c->wwwauth_headers.v[i], 0);
436+
credential_write_item(c, fp, "wwwauth[]", c->wwwauth_headers.v[i], 0);
424437
if (credential_has_capability(&c->capa_state, op_type)) {
425438
if (c->multistage)
426-
credential_write_item(fp, "continue", "1", 0);
439+
credential_write_item(c, fp, "continue", "1", 0);
427440
for (size_t i = 0; i < c->state_headers_to_send.nr; i++)
428-
credential_write_item(fp, "state[]", c->state_headers_to_send.v[i], 0);
441+
credential_write_item(c, fp, "state[]", c->state_headers_to_send.v[i], 0);
429442
}
430443
}
431444

credential.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,9 @@ struct credential {
168168
multistage: 1,
169169
quit:1,
170170
use_http_path:1,
171-
username_from_proto:1;
171+
username_from_proto:1,
172+
sanitize_prompt:1,
173+
protect_protocol:1;
172174

173175
struct credential_capability capa_authtype;
174176
struct credential_capability capa_state;
@@ -195,6 +197,8 @@ struct credential {
195197
.wwwauth_headers = STRVEC_INIT, \
196198
.state_headers = STRVEC_INIT, \
197199
.state_headers_to_send = STRVEC_INIT, \
200+
.sanitize_prompt = 1, \
201+
.protect_protocol = 1, \
198202
}
199203

200204
/* Initialize a credential structure, setting all fields to empty. */

strbuf.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,9 @@ void strbuf_add_percentencode(struct strbuf *dst, const char *src, int flags)
497497
unsigned char ch = src[i];
498498
if (ch <= 0x1F || ch >= 0x7F ||
499499
(ch == '/' && (flags & STRBUF_ENCODE_SLASH)) ||
500-
strchr(URL_UNSAFE_CHARS, ch))
500+
((flags & STRBUF_ENCODE_HOST_AND_PORT) ?
501+
!isalnum(ch) && !strchr("-.:[]", ch) :
502+
!!strchr(URL_UNSAFE_CHARS, ch)))
501503
strbuf_addf(dst, "%%%02X", (unsigned char)ch);
502504
else
503505
strbuf_addch(dst, ch);

strbuf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,7 @@ void strbuf_expand_bad_format(const char *format, const char *command);
356356
void strbuf_addbuf_percentquote(struct strbuf *dst, const struct strbuf *src);
357357

358358
#define STRBUF_ENCODE_SLASH 1
359+
#define STRBUF_ENCODE_HOST_AND_PORT 2
359360

360361
/**
361362
* Append the contents of a string to a strbuf, percent-encoding any characters

t/t0300-credentials.sh

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ test_expect_success 'setup helper scripts' '
7676
test -z "$pexpiry" || echo password_expiry_utc=$pexpiry
7777
EOF
7878
79+
write_script git-credential-cntrl-in-username <<-\EOF &&
80+
printf "username=\\007latrix Lestrange\\n"
81+
EOF
82+
7983
PATH="$PWD:$PATH"
8084
'
8185

@@ -696,6 +700,19 @@ test_expect_success 'match percent-encoded values in username' '
696700
EOF
697701
'
698702

703+
test_expect_success 'match percent-encoded values in hostname' '
704+
test_config "credential.https://a%20b%20c/.helper" "$HELPER" &&
705+
check fill <<-\EOF
706+
url=https://a b c/
707+
--
708+
protocol=https
709+
host=a b c
710+
username=foo
711+
password=bar
712+
--
713+
EOF
714+
'
715+
699716
test_expect_success 'fetch with multiple path components' '
700717
test_unconfig credential.helper &&
701718
test_config credential.https://example.com/foo/repo.git.helper "verbatim foo bar" &&
@@ -885,6 +902,22 @@ test_expect_success 'url parser rejects embedded newlines' '
885902
test_cmp expect stderr
886903
'
887904

905+
test_expect_success 'url parser rejects embedded carriage returns' '
906+
test_config credential.helper "!true" &&
907+
test_must_fail git credential fill 2>stderr <<-\EOF &&
908+
url=https://example%0d.com/
909+
EOF
910+
cat >expect <<-\EOF &&
911+
fatal: credential value for host contains carriage return
912+
If this is intended, set `credential.protectProtocol=false`
913+
EOF
914+
test_cmp expect stderr &&
915+
GIT_ASKPASS=true \
916+
git -c credential.protectProtocol=false credential fill <<-\EOF
917+
url=https://example%0d.com/
918+
EOF
919+
'
920+
888921
test_expect_success 'host-less URLs are parsed as empty host' '
889922
check fill "verbatim foo bar" <<-\EOF
890923
url=cert:///path/to/cert.pem
@@ -994,4 +1027,20 @@ test_expect_success 'credential config with partial URLs' '
9941027
test_grep "skipping credential lookup for key" stderr
9951028
'
9961029

1030+
BEL="$(printf '\007')"
1031+
1032+
test_expect_success 'interactive prompt is sanitized' '
1033+
check fill cntrl-in-username <<-EOF
1034+
protocol=https
1035+
host=example.org
1036+
--
1037+
protocol=https
1038+
host=example.org
1039+
username=${BEL}latrix Lestrange
1040+
password=askpass-password
1041+
--
1042+
askpass: Password for ${SQ}https://%07latrix%[email protected]${SQ}:
1043+
EOF
1044+
'
1045+
9971046
test_done

t/t5541-http-push-smart.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ test_expect_success 'push over smart http with auth' '
343343
git push "$HTTPD_URL"/auth/smart/test_repo.git &&
344344
git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git" \
345345
log -1 --format=%s >actual &&
346-
expect_askpass both user@host &&
346+
expect_askpass both user%40host &&
347347
test_cmp expect actual
348348
'
349349

@@ -355,7 +355,7 @@ test_expect_success 'push to auth-only-for-push repo' '
355355
git push "$HTTPD_URL"/auth-push/smart/test_repo.git &&
356356
git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git" \
357357
log -1 --format=%s >actual &&
358-
expect_askpass both user@host &&
358+
expect_askpass both user%40host &&
359359
test_cmp expect actual
360360
'
361361

@@ -385,7 +385,7 @@ test_expect_success 'push into half-auth-complete requires password' '
385385
git push "$HTTPD_URL/half-auth-complete/smart/half-auth.git" &&
386386
git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/half-auth.git" \
387387
log -1 --format=%s >actual &&
388-
expect_askpass both user@host &&
388+
expect_askpass both user%40host &&
389389
test_cmp expect actual
390390
'
391391

t/t5550-http-fetch-dumb.sh

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -111,13 +111,13 @@ test_expect_success 'http auth can use user/pass in URL' '
111111
test_expect_success 'http auth can use just user in URL' '
112112
set_askpass wrong pass@host &&
113113
git clone "$HTTPD_URL_USER/auth/dumb/repo.git" clone-auth-pass &&
114-
expect_askpass pass user@host
114+
expect_askpass pass user%40host
115115
'
116116

117117
test_expect_success 'http auth can request both user and pass' '
118118
set_askpass user@host pass@host &&
119119
git clone "$HTTPD_URL/auth/dumb/repo.git" clone-auth-both &&
120-
expect_askpass both user@host
120+
expect_askpass both user%40host
121121
'
122122

123123
test_expect_success 'http auth respects credential helper config' '
@@ -135,14 +135,14 @@ test_expect_success 'http auth can get username from config' '
135135
test_config_global "credential.$HTTPD_URL.username" user@host &&
136136
set_askpass wrong pass@host &&
137137
git clone "$HTTPD_URL/auth/dumb/repo.git" clone-auth-user &&
138-
expect_askpass pass user@host
138+
expect_askpass pass user%40host
139139
'
140140

141141
test_expect_success 'configured username does not override URL' '
142142
test_config_global "credential.$HTTPD_URL.username" wrong &&
143143
set_askpass wrong pass@host &&
144144
git clone "$HTTPD_URL_USER/auth/dumb/repo.git" clone-auth-user2 &&
145-
expect_askpass pass user@host
145+
expect_askpass pass user%40host
146146
'
147147

148148
test_expect_success 'set up repo with http submodules' '
@@ -163,7 +163,7 @@ test_expect_success 'cmdline credential config passes to submodule via clone' '
163163
set_askpass wrong pass@host &&
164164
git -c "credential.$HTTPD_URL.username=user@host" \
165165
clone --recursive super super-clone &&
166-
expect_askpass pass user@host
166+
expect_askpass pass user%40host
167167
'
168168

169169
test_expect_success 'cmdline credential config passes submodule via fetch' '
@@ -174,7 +174,7 @@ test_expect_success 'cmdline credential config passes submodule via fetch' '
174174
git -C super-clone \
175175
-c "credential.$HTTPD_URL.username=user@host" \
176176
fetch --recurse-submodules &&
177-
expect_askpass pass user@host
177+
expect_askpass pass user%40host
178178
'
179179

180180
test_expect_success 'cmdline credential config passes submodule update' '
@@ -191,7 +191,7 @@ test_expect_success 'cmdline credential config passes submodule update' '
191191
git -C super-clone \
192192
-c "credential.$HTTPD_URL.username=user@host" \
193193
submodule update &&
194-
expect_askpass pass user@host
194+
expect_askpass pass user%40host
195195
'
196196

197197
test_expect_success 'fetch changes via http' '

0 commit comments

Comments
 (0)