Skip to content

Commit 99cb64c

Browse files
committed
Sync with 2.44.3
* maint-2.44: 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 c2b3f2b + 2f323bb commit 99cb64c

16 files changed

+144
-39
lines changed

.github/workflows/main.yml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -365,12 +365,6 @@ jobs:
365365
with:
366366
name: failed-tests-${{matrix.vector.jobname}}
367367
path: ${{env.FAILED_TEST_ARTIFACTS}}
368-
- name: Upload failed tests' directories
369-
if: failure() && env.FAILED_TEST_ARTIFACTS != '' && matrix.vector.jobname == 'linux32'
370-
uses: actions/upload-artifact@v1 # cannot be upgraded because Node.js Actions aren't supported in this container
371-
with:
372-
name: failed-tests-${{matrix.vector.jobname}}
373-
path: ${{env.FAILED_TEST_ARTIFACTS}}
374368
static-analysis:
375369
needs: ci-config
376370
if: needs.ci-config.outputs.enabled == 'yes'

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/config/credential.txt

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

17+
credential.sanitizePrompt::
18+
By default, user names and hosts that are shown as part of the
19+
password prompt are not allowed to contain control characters (they
20+
will be URL-encoded by default). Configure this setting to `false` to
21+
override that behavior.
22+
23+
credential.protectProtocol::
24+
By default, Carriage Return characters are not allowed in the protocol
25+
that is used when Git talks to a credential helper. This setting allows
26+
users to override this default.
27+
1728
credential.username::
1829
If no username is set for a network authentication, use this username
1930
by default. See credential.<context>.* below, and

credential.c

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#include "sigchain.h"
1111
#include "strbuf.h"
1212
#include "urlmatch.h"
13-
#include "git-compat-util.h"
13+
#include "environment.h"
1414

1515
void credential_init(struct credential *c)
1616
{
@@ -74,6 +74,10 @@ static int credential_config_callback(const char *var, const char *value,
7474
}
7575
else if (!strcmp(key, "usehttppath"))
7676
c->use_http_path = git_config_bool(var, value);
77+
else if (!strcmp(key, "sanitizeprompt"))
78+
c->sanitize_prompt = git_config_bool(var, value);
79+
else if (!strcmp(key, "protectprotocol"))
80+
c->protect_protocol = git_config_bool(var, value);
7781

7882
return 0;
7983
}
@@ -171,7 +175,8 @@ static void credential_format(struct credential *c, struct strbuf *out)
171175
strbuf_addch(out, '@');
172176
}
173177
if (c->host)
174-
strbuf_addstr(out, c->host);
178+
strbuf_add_percentencode(out, c->host,
179+
STRBUF_ENCODE_HOST_AND_PORT);
175180
if (c->path) {
176181
strbuf_addch(out, '/');
177182
strbuf_add_percentencode(out, c->path, 0);
@@ -185,7 +190,10 @@ static char *credential_ask_one(const char *what, struct credential *c,
185190
struct strbuf prompt = STRBUF_INIT;
186191
char *r;
187192

188-
credential_describe(c, &desc);
193+
if (c->sanitize_prompt)
194+
credential_format(c, &desc);
195+
else
196+
credential_describe(c, &desc);
189197
if (desc.len)
190198
strbuf_addf(&prompt, "%s for '%s': ", what, desc.buf);
191199
else
@@ -268,7 +276,8 @@ int credential_read(struct credential *c, FILE *fp)
268276
return 0;
269277
}
270278

271-
static void credential_write_item(FILE *fp, const char *key, const char *value,
279+
static void credential_write_item(const struct credential *c,
280+
FILE *fp, const char *key, const char *value,
272281
int required)
273282
{
274283
if (!value && required)
@@ -277,24 +286,28 @@ static void credential_write_item(FILE *fp, const char *key, const char *value,
277286
return;
278287
if (strchr(value, '\n'))
279288
die("credential value for %s contains newline", key);
289+
if (c->protect_protocol && strchr(value, '\r'))
290+
die("credential value for %s contains carriage return\n"
291+
"If this is intended, set `credential.protectProtocol=false`",
292+
key);
280293
fprintf(fp, "%s=%s\n", key, value);
281294
}
282295

283296
void credential_write(const struct credential *c, FILE *fp)
284297
{
285-
credential_write_item(fp, "protocol", c->protocol, 1);
286-
credential_write_item(fp, "host", c->host, 1);
287-
credential_write_item(fp, "path", c->path, 0);
288-
credential_write_item(fp, "username", c->username, 0);
289-
credential_write_item(fp, "password", c->password, 0);
290-
credential_write_item(fp, "oauth_refresh_token", c->oauth_refresh_token, 0);
298+
credential_write_item(c, fp, "protocol", c->protocol, 1);
299+
credential_write_item(c, fp, "host", c->host, 1);
300+
credential_write_item(c, fp, "path", c->path, 0);
301+
credential_write_item(c, fp, "username", c->username, 0);
302+
credential_write_item(c, fp, "password", c->password, 0);
303+
credential_write_item(c, fp, "oauth_refresh_token", c->oauth_refresh_token, 0);
291304
if (c->password_expiry_utc != TIME_MAX) {
292305
char *s = xstrfmt("%"PRItime, c->password_expiry_utc);
293-
credential_write_item(fp, "password_expiry_utc", s, 0);
306+
credential_write_item(c, fp, "password_expiry_utc", s, 0);
294307
free(s);
295308
}
296309
for (size_t i = 0; i < c->wwwauth_headers.nr; i++)
297-
credential_write_item(fp, "wwwauth[]", c->wwwauth_headers.v[i], 0);
310+
credential_write_item(c, fp, "wwwauth[]", c->wwwauth_headers.v[i], 0);
298311
}
299312

300313
static int run_credential_helper(struct credential *c,

credential.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,9 @@ struct credential {
134134
configured:1,
135135
quit:1,
136136
use_http_path:1,
137-
username_from_proto:1;
137+
username_from_proto:1,
138+
sanitize_prompt:1,
139+
protect_protocol:1;
138140

139141
char *username;
140142
char *password;
@@ -149,6 +151,8 @@ struct credential {
149151
.helpers = STRING_LIST_INIT_DUP, \
150152
.password_expiry_utc = TIME_MAX, \
151153
.wwwauth_headers = STRVEC_INIT, \
154+
.sanitize_prompt = 1, \
155+
.protect_protocol = 1, \
152156
}
153157

154158
/* 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
@@ -486,7 +486,9 @@ void strbuf_add_percentencode(struct strbuf *dst, const char *src, int flags)
486486
unsigned char ch = src[i];
487487
if (ch <= 0x1F || ch >= 0x7F ||
488488
(ch == '/' && (flags & STRBUF_ENCODE_SLASH)) ||
489-
strchr(URL_UNSAFE_CHARS, ch))
489+
((flags & STRBUF_ENCODE_HOST_AND_PORT) ?
490+
!isalnum(ch) && !strchr("-.:[]", ch) :
491+
!!strchr(URL_UNSAFE_CHARS, ch)))
490492
strbuf_addf(dst, "%%%02X", (unsigned char)ch);
491493
else
492494
strbuf_addch(dst, ch);

strbuf.h

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

353353
#define STRBUF_ENCODE_SLASH 1
354+
#define STRBUF_ENCODE_HOST_AND_PORT 2
354355

355356
/**
356357
* 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
@@ -45,6 +45,10 @@ test_expect_success 'setup helper scripts' '
4545
test -z "$pexpiry" || echo password_expiry_utc=$pexpiry
4646
EOF
4747
48+
write_script git-credential-cntrl-in-username <<-\EOF &&
49+
printf "username=\\007latrix Lestrange\\n"
50+
EOF
51+
4852
PATH="$PWD:$PATH"
4953
'
5054

@@ -532,6 +536,19 @@ test_expect_success 'match percent-encoded values in username' '
532536
EOF
533537
'
534538

539+
test_expect_success 'match percent-encoded values in hostname' '
540+
test_config "credential.https://a%20b%20c/.helper" "$HELPER" &&
541+
check fill <<-\EOF
542+
url=https://a b c/
543+
--
544+
protocol=https
545+
host=a b c
546+
username=foo
547+
password=bar
548+
--
549+
EOF
550+
'
551+
535552
test_expect_success 'fetch with multiple path components' '
536553
test_unconfig credential.helper &&
537554
test_config credential.https://example.com/foo/repo.git.helper "verbatim foo bar" &&
@@ -721,6 +738,22 @@ test_expect_success 'url parser rejects embedded newlines' '
721738
test_cmp expect stderr
722739
'
723740

741+
test_expect_success 'url parser rejects embedded carriage returns' '
742+
test_config credential.helper "!true" &&
743+
test_must_fail git credential fill 2>stderr <<-\EOF &&
744+
url=https://example%0d.com/
745+
EOF
746+
cat >expect <<-\EOF &&
747+
fatal: credential value for host contains carriage return
748+
If this is intended, set `credential.protectProtocol=false`
749+
EOF
750+
test_cmp expect stderr &&
751+
GIT_ASKPASS=true \
752+
git -c credential.protectProtocol=false credential fill <<-\EOF
753+
url=https://example%0d.com/
754+
EOF
755+
'
756+
724757
test_expect_success 'host-less URLs are parsed as empty host' '
725758
check fill "verbatim foo bar" <<-\EOF
726759
url=cert:///path/to/cert.pem
@@ -830,4 +863,20 @@ test_expect_success 'credential config with partial URLs' '
830863
test_grep "skipping credential lookup for key" stderr
831864
'
832865

866+
BEL="$(printf '\007')"
867+
868+
test_expect_success 'interactive prompt is sanitized' '
869+
check fill cntrl-in-username <<-EOF
870+
protocol=https
871+
host=example.org
872+
--
873+
protocol=https
874+
host=example.org
875+
username=${BEL}latrix Lestrange
876+
password=askpass-password
877+
--
878+
askpass: Password for ${SQ}https://%07latrix%[email protected]${SQ}:
879+
EOF
880+
'
881+
833882
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
@@ -90,13 +90,13 @@ test_expect_success 'http auth can use user/pass in URL' '
9090
test_expect_success 'http auth can use just user in URL' '
9191
set_askpass wrong pass@host &&
9292
git clone "$HTTPD_URL_USER/auth/dumb/repo.git" clone-auth-pass &&
93-
expect_askpass pass user@host
93+
expect_askpass pass user%40host
9494
'
9595

9696
test_expect_success 'http auth can request both user and pass' '
9797
set_askpass user@host pass@host &&
9898
git clone "$HTTPD_URL/auth/dumb/repo.git" clone-auth-both &&
99-
expect_askpass both user@host
99+
expect_askpass both user%40host
100100
'
101101

102102
test_expect_success 'http auth respects credential helper config' '
@@ -114,14 +114,14 @@ test_expect_success 'http auth can get username from config' '
114114
test_config_global "credential.$HTTPD_URL.username" user@host &&
115115
set_askpass wrong pass@host &&
116116
git clone "$HTTPD_URL/auth/dumb/repo.git" clone-auth-user &&
117-
expect_askpass pass user@host
117+
expect_askpass pass user%40host
118118
'
119119

120120
test_expect_success 'configured username does not override URL' '
121121
test_config_global "credential.$HTTPD_URL.username" wrong &&
122122
set_askpass wrong pass@host &&
123123
git clone "$HTTPD_URL_USER/auth/dumb/repo.git" clone-auth-user2 &&
124-
expect_askpass pass user@host
124+
expect_askpass pass user%40host
125125
'
126126

127127
test_expect_success 'set up repo with http submodules' '
@@ -142,7 +142,7 @@ test_expect_success 'cmdline credential config passes to submodule via clone' '
142142
set_askpass wrong pass@host &&
143143
git -c "credential.$HTTPD_URL.username=user@host" \
144144
clone --recursive super super-clone &&
145-
expect_askpass pass user@host
145+
expect_askpass pass user%40host
146146
'
147147

148148
test_expect_success 'cmdline credential config passes submodule via fetch' '
@@ -153,7 +153,7 @@ test_expect_success 'cmdline credential config passes submodule via fetch' '
153153
git -C super-clone \
154154
-c "credential.$HTTPD_URL.username=user@host" \
155155
fetch --recurse-submodules &&
156-
expect_askpass pass user@host
156+
expect_askpass pass user%40host
157157
'
158158

159159
test_expect_success 'cmdline credential config passes submodule update' '
@@ -170,7 +170,7 @@ test_expect_success 'cmdline credential config passes submodule update' '
170170
git -C super-clone \
171171
-c "credential.$HTTPD_URL.username=user@host" \
172172
submodule update &&
173-
expect_askpass pass user@host
173+
expect_askpass pass user%40host
174174
'
175175

176176
test_expect_success 'fetch changes via http' '

0 commit comments

Comments
 (0)