Skip to content

Commit

Permalink
Merge tag 'v2.47.2' into vfs-2.47.2
Browse files Browse the repository at this point in the history
Git 2.47.2

Signed-off-by: Johannes Schindelin <[email protected]>
  • Loading branch information
dscho committed Jan 12, 2025
2 parents 1d7817c + e1fbebe commit 5f1a078
Show file tree
Hide file tree
Showing 18 changed files with 170 additions and 41 deletions.
5 changes: 5 additions & 0 deletions Documentation/RelNotes/2.40.4.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Git v2.40.4 Release Notes
=========================

This release lets Git refuse to accept URLs that contain control
sequences. This addresses CVE-2024-50349 and CVE-2024-52006.
6 changes: 6 additions & 0 deletions Documentation/RelNotes/2.41.3.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Git v2.41.3 Release Notes
=========================

This release merges up the fix that appears in v2.40.4 to address
the security issues CVE-2024-50349 and CVE-2024-52006; see the
release notes for that version for details.
6 changes: 6 additions & 0 deletions Documentation/RelNotes/2.42.4.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Git v2.42.4 Release Notes
=========================

This release merges up the fix that appears in v2.40.4 and v2.41.3
to address the security issues CVE-2024-50349 and CVE-2024-52006;
see the release notes for these versions for details.
7 changes: 7 additions & 0 deletions Documentation/RelNotes/2.43.6.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Git v2.43.6 Release Notes
=========================

This release merges up the fix that appears in v2.40.4, v2.41.3
and v2.42.4 to address the security issues CVE-2024-50349 and
CVE-2024-52006; see the release notes for these versions for
details.
7 changes: 7 additions & 0 deletions Documentation/RelNotes/2.44.3.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Git v2.44.3 Release Notes
=========================

This release merges up the fix that appears in v2.40.4, v2.41.3,
v2.42.4 and v2.43.6 to address the security issues CVE-2024-50349
and CVE-2024-52006; see the release notes for these versions
for details.
7 changes: 6 additions & 1 deletion Documentation/RelNotes/2.45.3.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
Git v2.45.3 Release Notes
=========================

This primarily is to backport various small fixes accumulated on the
This release merges up the fix that appears in v2.40.4, v2.41.3,
v2.42.4, v2.43.6 and v2.44.3 to address the security issues
CVE-2024-50349 and CVE-2024-52006; see the release notes for
these versions for details.

This version also backports various small fixes accumulated on the
'master' front during the development towards Git 2.46, the next
feature release.

Expand Down
6 changes: 6 additions & 0 deletions Documentation/RelNotes/2.46.3.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Git v2.46.3 Release Notes
=========================

This release merges up the fix that appears in v2.40.4, v2.41.3, v2.42.4,
v2.43.6, v2.44.3 and v2.45.3 to address the security issues CVE-2024-50349 and
CVE-2024-52006; see the release notes for these versions for details.
7 changes: 7 additions & 0 deletions Documentation/RelNotes/2.47.2.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Git v2.47.2 Release Notes
=========================

This release merges up the fix that appears in v2.40.4, v2.41.3,
v2.42.4, v2.43.6, v2.44.3, v2.45.3 and v2.46.3 to address the
security issues CVE-2024-50349 and CVE-2024-52006; see the release
notes for these versions for details.
11 changes: 11 additions & 0 deletions Documentation/config/credential.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,17 @@ credential.useHttpPath::
or https URL to be important. Defaults to false. See
linkgit:gitcredentials[7] for more information.

credential.sanitizePrompt::
By default, user names and hosts that are shown as part of the
password prompt are not allowed to contain control characters (they
will be URL-encoded by default). Configure this setting to `false` to
override that behavior.

credential.protectProtocol::
By default, Carriage Return characters are not allowed in the protocol
that is used when Git talks to a credential helper. This setting allows
users to override this default.

credential.username::
If no username is set for a network authentication, use this username
by default. See credential.<context>.* below, and
Expand Down
51 changes: 32 additions & 19 deletions credential.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
#include "sigchain.h"
#include "strbuf.h"
#include "urlmatch.h"
#include "git-compat-util.h"
#include "environment.h"
#include "trace2.h"
#include "repository.h"

Expand Down Expand Up @@ -129,6 +129,10 @@ static int credential_config_callback(const char *var, const char *value,
}
else if (!strcmp(key, "usehttppath"))
c->use_http_path = git_config_bool(var, value);
else if (!strcmp(key, "sanitizeprompt"))
c->sanitize_prompt = git_config_bool(var, value);
else if (!strcmp(key, "protectprotocol"))
c->protect_protocol = git_config_bool(var, value);

return 0;
}
Expand Down Expand Up @@ -226,7 +230,8 @@ static void credential_format(struct credential *c, struct strbuf *out)
strbuf_addch(out, '@');
}
if (c->host)
strbuf_addstr(out, c->host);
strbuf_add_percentencode(out, c->host,
STRBUF_ENCODE_HOST_AND_PORT);
if (c->path) {
strbuf_addch(out, '/');
strbuf_add_percentencode(out, c->path, 0);
Expand All @@ -240,7 +245,10 @@ static char *credential_ask_one(const char *what, struct credential *c,
struct strbuf prompt = STRBUF_INIT;
char *r;

credential_describe(c, &desc);
if (c->sanitize_prompt)
credential_format(c, &desc);
else
credential_describe(c, &desc);
if (desc.len)
strbuf_addf(&prompt, "%s for '%s': ", what, desc.buf);
else
Expand Down Expand Up @@ -381,7 +389,8 @@ 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(const struct credential *c,
FILE *fp, const char *key, const char *value,
int required)
{
if (!value && required)
Expand All @@ -390,41 +399,45 @@ static void credential_write_item(FILE *fp, const char *key, const char *value,
return;
if (strchr(value, '\n'))
die("credential value for %s contains newline", key);
if (c->protect_protocol && strchr(value, '\r'))
die("credential value for %s contains carriage return\n"
"If this is intended, set `credential.protectProtocol=false`",
key);
fprintf(fp, "%s=%s\n", key, value);
}

void credential_write(const struct credential *c, FILE *fp,
enum credential_op_type op_type)
{
if (credential_has_capability(&c->capa_authtype, op_type))
credential_write_item(fp, "capability[]", "authtype", 0);
credential_write_item(c, fp, "capability[]", "authtype", 0);
if (credential_has_capability(&c->capa_state, op_type))
credential_write_item(fp, "capability[]", "state", 0);
credential_write_item(c, fp, "capability[]", "state", 0);

if (credential_has_capability(&c->capa_authtype, op_type)) {
credential_write_item(fp, "authtype", c->authtype, 0);
credential_write_item(fp, "credential", c->credential, 0);
credential_write_item(c, fp, "authtype", c->authtype, 0);
credential_write_item(c, fp, "credential", c->credential, 0);
if (c->ephemeral)
credential_write_item(fp, "ephemeral", "1", 0);
credential_write_item(c, fp, "ephemeral", "1", 0);
}
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);
credential_write_item(fp, "oauth_refresh_token", c->oauth_refresh_token, 0);
credential_write_item(c, fp, "protocol", c->protocol, 1);
credential_write_item(c, fp, "host", c->host, 1);
credential_write_item(c, fp, "path", c->path, 0);
credential_write_item(c, fp, "username", c->username, 0);
credential_write_item(c, fp, "password", c->password, 0);
credential_write_item(c, fp, "oauth_refresh_token", c->oauth_refresh_token, 0);
if (c->password_expiry_utc != TIME_MAX) {
char *s = xstrfmt("%"PRItime, c->password_expiry_utc);
credential_write_item(fp, "password_expiry_utc", s, 0);
credential_write_item(c, fp, "password_expiry_utc", s, 0);
free(s);
}
for (size_t i = 0; i < c->wwwauth_headers.nr; i++)
credential_write_item(fp, "wwwauth[]", c->wwwauth_headers.v[i], 0);
credential_write_item(c, fp, "wwwauth[]", c->wwwauth_headers.v[i], 0);
if (credential_has_capability(&c->capa_state, op_type)) {
if (c->multistage)
credential_write_item(fp, "continue", "1", 0);
credential_write_item(c, fp, "continue", "1", 0);
for (size_t i = 0; i < c->state_headers_to_send.nr; i++)
credential_write_item(fp, "state[]", c->state_headers_to_send.v[i], 0);
credential_write_item(c, fp, "state[]", c->state_headers_to_send.v[i], 0);
}
}

Expand Down
6 changes: 5 additions & 1 deletion credential.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,9 @@ struct credential {
multistage: 1,
quit:1,
use_http_path:1,
username_from_proto:1;
username_from_proto:1,
sanitize_prompt:1,
protect_protocol:1;

struct credential_capability capa_authtype;
struct credential_capability capa_state;
Expand All @@ -195,6 +197,8 @@ struct credential {
.wwwauth_headers = STRVEC_INIT, \
.state_headers = STRVEC_INIT, \
.state_headers_to_send = STRVEC_INIT, \
.sanitize_prompt = 1, \
.protect_protocol = 1, \
}

/* Initialize a credential structure, setting all fields to empty. */
Expand Down
4 changes: 3 additions & 1 deletion strbuf.c
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,9 @@ void strbuf_add_percentencode(struct strbuf *dst, const char *src, int flags)
unsigned char ch = src[i];
if (ch <= 0x1F || ch >= 0x7F ||
(ch == '/' && (flags & STRBUF_ENCODE_SLASH)) ||
strchr(URL_UNSAFE_CHARS, ch))
((flags & STRBUF_ENCODE_HOST_AND_PORT) ?
!isalnum(ch) && !strchr("-.:[]", ch) :
!!strchr(URL_UNSAFE_CHARS, ch)))
strbuf_addf(dst, "%%%02X", (unsigned char)ch);
else
strbuf_addch(dst, ch);
Expand Down
1 change: 1 addition & 0 deletions strbuf.h
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,7 @@ void strbuf_expand_bad_format(const char *format, const char *command);
void strbuf_addbuf_percentquote(struct strbuf *dst, const struct strbuf *src);

#define STRBUF_ENCODE_SLASH 1
#define STRBUF_ENCODE_HOST_AND_PORT 2

/**
* Append the contents of a string to a strbuf, percent-encoding any characters
Expand Down
49 changes: 49 additions & 0 deletions t/t0300-credentials.sh
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ test_expect_success 'setup helper scripts' '
test -z "$pexpiry" || echo password_expiry_utc=$pexpiry
EOF
write_script git-credential-cntrl-in-username <<-\EOF &&
printf "username=\\007latrix Lestrange\\n"
EOF
PATH="$PWD$PATH_SEP$PATH"
'

Expand Down Expand Up @@ -697,6 +701,19 @@ test_expect_success 'match percent-encoded values in username' '
EOF
'

test_expect_success 'match percent-encoded values in hostname' '
test_config "credential.https://a%20b%20c/.helper" "$HELPER" &&
check fill <<-\EOF
url=https://a b c/
--
protocol=https
host=a b c
username=foo
password=bar
--
EOF
'

test_expect_success 'fetch with multiple path components' '
test_unconfig credential.helper &&
test_config credential.https://example.com/foo/repo.git.helper "verbatim foo bar" &&
Expand Down Expand Up @@ -886,6 +903,22 @@ test_expect_success 'url parser rejects embedded newlines' '
test_cmp expect stderr
'

test_expect_success 'url parser rejects embedded carriage returns' '
test_config credential.helper "!true" &&
test_must_fail git credential fill 2>stderr <<-\EOF &&
url=https://example%0d.com/
EOF
cat >expect <<-\EOF &&
fatal: credential value for host contains carriage return
If this is intended, set `credential.protectProtocol=false`
EOF
test_cmp expect stderr &&
GIT_ASKPASS=true \
git -c credential.protectProtocol=false credential fill <<-\EOF
url=https://example%0d.com/
EOF
'

test_expect_success 'host-less URLs are parsed as empty host' '
check fill "verbatim foo bar" <<-\EOF
url=cert:///path/to/cert.pem
Expand Down Expand Up @@ -995,4 +1028,20 @@ test_expect_success 'credential config with partial URLs' '
test_grep "skipping credential lookup for key" stderr
'

BEL="$(printf '\007')"

test_expect_success 'interactive prompt is sanitized' '
check fill cntrl-in-username <<-EOF
protocol=https
host=example.org
--
protocol=https
host=example.org
username=${BEL}latrix Lestrange
password=askpass-password
--
askpass: Password for ${SQ}https://%07latrix%[email protected]${SQ}:
EOF
'

test_done
6 changes: 3 additions & 3 deletions t/t5541-http-push-smart.sh
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ test_expect_success 'push over smart http with auth' '
git push "$HTTPD_URL"/auth/smart/test_repo.git &&
git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git" \
log -1 --format=%s >actual &&
expect_askpass both user@host &&
expect_askpass both user%40host &&
test_cmp expect actual
'

Expand All @@ -356,7 +356,7 @@ test_expect_success 'push to auth-only-for-push repo' '
git push "$HTTPD_URL"/auth-push/smart/test_repo.git &&
git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git" \
log -1 --format=%s >actual &&
expect_askpass both user@host &&
expect_askpass both user%40host &&
test_cmp expect actual
'

Expand Down Expand Up @@ -386,7 +386,7 @@ test_expect_success 'push into half-auth-complete requires password' '
git push "$HTTPD_URL/half-auth-complete/smart/half-auth.git" &&
git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/half-auth.git" \
log -1 --format=%s >actual &&
expect_askpass both user@host &&
expect_askpass both user%40host &&
test_cmp expect actual
'

Expand Down
14 changes: 7 additions & 7 deletions t/t5550-http-fetch-dumb.sh
Original file line number Diff line number Diff line change
Expand Up @@ -112,13 +112,13 @@ test_expect_success 'http auth can use user/pass in URL' '
test_expect_success 'http auth can use just user in URL' '
set_askpass wrong pass@host &&
git clone "$HTTPD_URL_USER/auth/dumb/repo.git" clone-auth-pass &&
expect_askpass pass user@host
expect_askpass pass user%40host
'

test_expect_success 'http auth can request both user and pass' '
set_askpass user@host pass@host &&
git clone "$HTTPD_URL/auth/dumb/repo.git" clone-auth-both &&
expect_askpass both user@host
expect_askpass both user%40host
'

test_expect_success 'http auth respects credential helper config' '
Expand All @@ -136,14 +136,14 @@ test_expect_success 'http auth can get username from config' '
test_config_global "credential.$HTTPD_URL.username" user@host &&
set_askpass wrong pass@host &&
git clone "$HTTPD_URL/auth/dumb/repo.git" clone-auth-user &&
expect_askpass pass user@host
expect_askpass pass user%40host
'

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

test_expect_success 'set up repo with http submodules' '
Expand All @@ -164,7 +164,7 @@ test_expect_success 'cmdline credential config passes to submodule via clone' '
set_askpass wrong pass@host &&
git -c "credential.$HTTPD_URL.username=user@host" \
clone --recursive super super-clone &&
expect_askpass pass user@host
expect_askpass pass user%40host
'

test_expect_success 'cmdline credential config passes submodule via fetch' '
Expand All @@ -175,7 +175,7 @@ test_expect_success 'cmdline credential config passes submodule via fetch' '
git -C super-clone \
-c "credential.$HTTPD_URL.username=user@host" \
fetch --recurse-submodules &&
expect_askpass pass user@host
expect_askpass pass user%40host
'

test_expect_success 'cmdline credential config passes submodule update' '
Expand All @@ -192,7 +192,7 @@ test_expect_success 'cmdline credential config passes submodule update' '
git -C super-clone \
-c "credential.$HTTPD_URL.username=user@host" \
submodule update &&
expect_askpass pass user@host
expect_askpass pass user%40host
'

test_expect_success 'fetch changes via http' '
Expand Down
Loading

0 comments on commit 5f1a078

Please sign in to comment.