]> git.ipfire.org Git - thirdparty/git.git/log
thirdparty/git.git
4 months agogit_inflate(): skip zlib_post_call() sanity check on Z_NEED_DICT
Jeff King [Tue, 25 Feb 2025 06:30:26 +0000 (01:30 -0500)] 
git_inflate(): skip zlib_post_call() sanity check on Z_NEED_DICT

This fixes a case where malformed object input can cause us to hit a
BUG() call in the git-zlib.c code.

The zlib format allows the use of preset dictionaries to reduce the size
of deflated data. The checksum of the dictionary is computed by the
deflate code and goes into the stream. On the inflating side, zlib sees
the dictionary checksum and returns Z_NEED_DICT, asking the caller to
provide the dictionary data via inflateSetDictionary().

This should never happen in Git, because we never provide a dictionary
for deflating (and if we get a stream that mentions a dictionary, we
have no idea how to provide it). So normally Z_NEED_DICT is a hard error
for us. But something interesting happens if we _do_ happen to see it
(e.g., because of a corrupt or malicious input).

In git_inflate() as we loop over calls to zlib's inflate(), we translate
between our large-integer git_zstream values and zlib's native z_stream
types, copying in and out with zlib_pre_call() and zlib_post_call(). In
zlib_post_call() we have a few sanity checks, including one that checks
that the number of bytes consumed by zlib (as measured by it moving the
"next_in" pointer) is equal to the movement of its "total_in" count.

But these do not correspond when we see Z_NEED_DICT! Zlib consumes the
bytes from the input buffer but it does not increment total_in. And so
we hit the BUG("total_in mismatch") call.

There are a few options here:

  - We could ditch that BUG() check. It is making too many assumptions
    about how zlib updates these values. But it does have value in most
    cases as a sanity check on the values we're copying.

  - We could skip the zlib_post_call() entirely when we see Z_NEED_DICT.
    We know that it's hard error for us, so we should just send the
    status up the stack and let the caller bail.

    The downside is that if we ever did want to support dictionaries,
    we couldn't (the git_zstream will be out of sync, since we never
    copied its values back from the z_stream).

  - We could continue to call zlib_post_call(), but skip just that BUG()
    check if the status is Z_NEED_DICT. This keeps git_inflate() as a
    thin wrapper around inflate(), and would let us later support
    dictionaries for some calls if we wanted to.

This patch uses the third approach. It seems like the least-surprising
thing to keep git_inflate() a close to inflate() as possible. And while
it makes the diff a bit larger (since we have to pass the status down to
to the zlib_post_call() function), it's a static local function, and
every caller by definition will have just made a zlib call (and so will
have a status integer).

Co-authored-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
4 months agounpack_loose_header(): fix infinite loop on broken zlib input
Jeff King [Tue, 25 Feb 2025 06:29:58 +0000 (01:29 -0500)] 
unpack_loose_header(): fix infinite loop on broken zlib input

When reading a loose object, we first try to expand the first 32 bytes
to read the type+size header. This is enough for any of the normal Git
types. But since 46f034483e (sha1_file: support reading from a loose
object of unknown type, 2015-05-03), the caller can also ask us to parse
any unknown names, which can be much longer. In this case we keep
inflating until we find the NUL at the end of the header, or hit
Z_STREAM_END.

But what if zlib can't make forward progress? For example, if the loose
object file is truncated, we'll have no more data to feed it. It will
return Z_BUF_ERROR, and we'll just loop infinitely, calling
git_inflate() over and over but never seeing new bytes nor an
end-of-stream marker.

We can fix this by only looping when we think we can make forward
progress. This will always be Z_OK in this case. In other code we might
also be able to continue on Z_BUF_ERROR, but:

  - We will never see Z_BUF_ERROR because the output buffer is full; we
    always feed a fresh 32-byte buffer on each call to git_inflate().

  - We may see Z_BUF_ERROR if we run out of input. But since we've fed
    the whole mmap'd buffer to zlib, if it runs out of input there is
    nothing more we can do.

So if we don't see Z_OK (and didn't see the end-of-header NUL, otherwise
we'd have broken out of the loop), then we should stop looping and
return an error.

The test case shows an example where the input is truncated (which gives
us the input Z_BUF_ERROR case above).

Although we do operate on objects we might get from an untrusted remote,
I don't think the security implications of this bug are too great. It
can only trigger if both of these are true:

  - You're reading a loose object whose on-disk representation was
    written by an attacker. So fetching an object (or receiving a push)
    are mostly OK, because even with unpack-objects it is our local,
    trusted code that writes out the object file. The exception may be
    fetching from an untrusted local repo, or using dumb-http, which
    copies objects verbatim. But...

  - The only code path which triggers the inflate loop is cat-file's
    --allow-unknown-type option. This is unlikely to be called at all
    outside of debugging. But I also suspect that objects with
    non-standard types (or that are truncated) would not survive the
    usual fetch/receive checks in the first place.

So I think it would be quite hard to trick somebody into running the
infinite loop, and we can just fix the bug.

Co-authored-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
4 months agounpack_loose_header(): report headers without NUL as "bad"
Jeff King [Tue, 25 Feb 2025 06:29:40 +0000 (01:29 -0500)] 
unpack_loose_header(): report headers without NUL as "bad"

If a caller asks us to read the whole loose object header value into a
strbuf (e.g., via "cat-file --allow-unknown-type"), we'll keep reading
until we see a NUL byte marking the end of the header.

If we hit Z_STREAM_END before seeing the NUL, we obviously have to stop.
But we return ULHR_TOO_LONG, which doesn't make any sense. The "too
long" return code is used in the normal, 32-byte limited mode to
indicate that we stopped looking. There is no such thing as "too long"
here, as we'd keep reading forever until we see the end of stream or the
NUL.

Instead, we should return ULHR_BAD. The loose object has no NUL marking
the end of header, so it is malformed. The behavior difference is
slight; in either case we'd consider the object unreadable and refuse to
go further. The only difference is the specific error message we
produce.

There's no test case here, as we'd need to generate a valid zlib stream
without a NUL. That's not something Git will do without writing new
custom code. And in the next patch we'll fix another bug in this area
which will make this easier to do (and we will test it then).

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
4 months agounpack_loose_header(): simplify next_out assignment
Jeff King [Tue, 25 Feb 2025 06:29:00 +0000 (01:29 -0500)] 
unpack_loose_header(): simplify next_out assignment

When using OBJECT_INFO_ALLOW_UNKNOWN_TYPE to unpack a header that
doesn't fit into our initial 32-byte buffer, we loop over calls
git_inflate(), feeding it our buffer to the "next_out" pointer each
time. As the code is written, we reset next_out after each inflate call
(and after reading the output), ready for the next loop.

This isn't wrong, but there are a few advantages to setting up
"next_out" right before each inflate call, rather than after:

  1. It drops a few duplicated lines of code.

  2. It makes it obvious that we always feed a fresh buffer on each call
     (and thus can never see Z_BUF_ERROR due to due to a lack of output
     space).

  3. After we exit the loop, we'll leave stream->next_out pointing to
     the end of the fetched data (this is how zlib callers find out how
     much data is in the buffer). This doesn't matter in practice, since
     nobody looks at it again. But it's probably the least-surprising
     thing to do, as it matches how next_out is left when the whole
     thing fits in the initial 32-byte buffer (and we don't enter the
     loop at all).

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
4 months agoloose_object_info(): BUG() on inflating content with unknown type
Jeff King [Tue, 25 Feb 2025 06:28:24 +0000 (01:28 -0500)] 
loose_object_info(): BUG() on inflating content with unknown type

After unpack_loose_header() returns, it will have inflated not only the
object header, but possibly some bytes of the object content. When we
call unpack_loose_rest() to extract the actual content, it finds those
extra bytes by skipping past the header's terminating NUL in the buffer.
Like this:

  int bytes = strlen(buffer) + 1;
  n = stream->total_out - bytes;
  ...
  memcpy(buf, (char *) buffer + bytes, n);

This won't work with the OBJECT_INFO_ALLOW_UNKNOWN_TYPE flag, as there
we allow a header of arbitrary size. We put into a strbuf, but feed only
the final 32-byte chunk we read to unpack_loose_rest(). In that case
stream->total_out may unexpectedly large, and thus our "n" will be
large, causing an out-of-bounds read (we do check it against our
allocated buffer size, which prevents an out-of-bounds write).

Probably this could be made to work by feeding the strbuf to
unpack_loose_rest(), along with adjusting some types (e.g., "bytes"
would need to be a size_t, since it is no longer operating on a 32-byte
buffer).

But I don't think it's possible to actually trigger this in practice.
The only caller who passes ALLOW_UNKNOWN_TYPE is cat-file, which only
allows it with the "-t" and "-s" options (neither of which access the
content). There is one way you can _almost_ trigger it: the oid compat
routines (i.e., accessing sha1 via sha256 names and vice versa) will
convert objects on the fly (which requires access to the content) using
the same flags that were passed in. So in theory this:

  t='some very large type field that causes an extra inflate call'
  sha1_oid=$(git hash-object -w -t "$t" file)
  sha256_oid=$(git rev-parse --output-object-format=sha256 $sha1_oid)
  git cat-file --allow-unknown-type -s $sha256_oid

would try to access the content. But it doesn't work, because using
compat objects requires an entry in the .git/objects/loose-object-idx
file, and we don't generate such an entry for non-standard types (see
the "compat" section of write_object_file_literally()).

If we use "t=blob" instead, then it does access the compat object, but
it doesn't trigger the problem (because "blob" is a standard short type
name, and it fits in the initial 32-byte buffer).

So given that this is almost a memory error bug, I think it's worth
addressing. But because we can't actually trigger the situation, I'm
hesitant to try a fix that we can't run. Instead let's document the
restriction and protect ourselves from the out-of-bounds read by adding
a BUG() check.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
7 months agoGit 2.44.3 v2.44.3
Johannes Schindelin [Tue, 29 Oct 2024 23:55:00 +0000 (00:55 +0100)] 
Git 2.44.3

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
7 months agoSync with 2.43.6
Johannes Schindelin [Tue, 29 Oct 2024 23:54:59 +0000 (00:54 +0100)] 
Sync with 2.43.6

* maint-2.43:
  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

7 months agoGit 2.43.6 v2.43.6
Johannes Schindelin [Tue, 29 Oct 2024 23:52:18 +0000 (00:52 +0100)] 
Git 2.43.6

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
7 months agoSync with 2.42.4
Johannes Schindelin [Tue, 29 Oct 2024 23:52:16 +0000 (00:52 +0100)] 
Sync with 2.42.4

* maint-2.42:
  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

7 months agoGit 2.42.4 v2.42.4
Johannes Schindelin [Tue, 29 Oct 2024 23:39:06 +0000 (00:39 +0100)] 
Git 2.42.4

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
7 months agoSync with 2.41.3
Johannes Schindelin [Tue, 29 Oct 2024 23:39:04 +0000 (00:39 +0100)] 
Sync with 2.41.3

* maint-2.41:
  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

7 months agoGit 2.41.3 v2.41.3
Johannes Schindelin [Tue, 29 Oct 2024 23:27:54 +0000 (00:27 +0100)] 
Git 2.41.3

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
7 months agoSync with 2.40.4
Johannes Schindelin [Tue, 29 Oct 2024 23:27:52 +0000 (00:27 +0100)] 
Sync with 2.40.4

* maint-2.40:
  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

7 months agoGit 2.40.4 v2.40.4
Johannes Schindelin [Tue, 29 Oct 2024 23:17:53 +0000 (00:17 +0100)] 
Git 2.40.4

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
7 months agoMerge branch 'disallow-control-characters-in-credential-urls-by-default'
Johannes Schindelin [Tue, 29 Oct 2024 22:52:11 +0000 (23:52 +0100)] 
Merge branch 'disallow-control-characters-in-credential-urls-by-default'

This addresses two vulnerabilities:

- CVE-2024-50349:

Printing unsanitized URLs when asking for credentials made the
user susceptible to crafted URLs (e.g. in recursive clones) that
mislead the user into typing in passwords for trusted sites that
would then be sent to untrusted sites instead.

- CVE-2024-52006

Git may pass on Carriage Returns via the credential protocol to
credential helpers which use line-reading functions that
interpret said Carriage Returns as line endings, even though Git
did not intend that.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
7 months agocredential: disallow Carriage Returns in the protocol by default
Johannes Schindelin [Mon, 4 Nov 2024 13:48:22 +0000 (14:48 +0100)] 
credential: disallow Carriage Returns in the protocol by default

While Git has documented that the credential protocol is line-based,
with newlines as terminators, the exact shape of a newline has not been
documented.

From Git's perspective, which is firmly rooted in the Linux ecosystem,
it is clear that "a newline" means a Line Feed character.

However, even Git's credential protocol respects Windows line endings
(a Carriage Return character followed by a Line Feed character, "CR/LF")
by virtue of using `strbuf_getline()`.

There is a third category of line endings that has been used originally
by MacOS, and that is respected by the default line readers of .NET and
node.js: bare Carriage Returns.

Git cannot handle those, and what is worse: Git's remedy against
CVE-2020-5260 does not catch when credential helpers are used that
interpret bare Carriage Returns as newlines.

Git Credential Manager addressed this as CVE-2024-50338, but other
credential helpers may still be vulnerable. So let's not only disallow
Line Feed characters as part of the values in the credential protocol,
but also disallow Carriage Return characters.

In the unlikely event that a credential helper relies on Carriage
Returns in the protocol, introduce an escape hatch via the
`credential.protectProtocol` config setting.

This addresses CVE-2024-52006.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
7 months agocredential: sanitize the user prompt
Johannes Schindelin [Wed, 30 Oct 2024 12:26:10 +0000 (13:26 +0100)] 
credential: sanitize the user prompt

When asking the user interactively for credentials, we want to avoid
misleading them e.g. via control sequences that pretend that the URL
targets a trusted host when it does not.

While Git learned, over the course of the preceding commits, to disallow
URLs containing URL-encoded control characters by default, credential
helpers are still allowed to specify values very freely (apart from Line
Feed and NUL characters, anything is allowed), and this would allow,
say, a username containing control characters to be specified that would
then be displayed in the interactive terminal prompt asking the user for
the password, potentially sending those control characters directly to
the terminal. This is undesirable because control characters can be used
to mislead users to divulge secret information to untrusted sites.

To prevent such an attack vector, let's add a `git_prompt()` that forces
the displayed text to be sanitized, i.e. displaying question marks
instead of control characters.

Note: While this commit's diff changes a lot of `user@host` strings to
`user%40host`, which may look suspicious on the surface, there is a good
reason for that: this string specifies a user name, not a
<username>@<hostname> combination! In the context of t5541, the actual
combination looks like this: `user%40@127.0.0.1:5541`. Therefore, these
string replacements document a net improvement introduced by this
commit, as `user@host@127.0.0.1` could have left readers wondering where
the user name ends and where the host name begins.

Hinted-at-by: Jeff King <peff@peff.net>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
7 months agocredential_format(): also encode <host>[:<port>]
Johannes Schindelin [Thu, 7 Nov 2024 07:57:52 +0000 (08:57 +0100)] 
credential_format(): also encode <host>[:<port>]

An upcoming change wants to sanitize the credential password prompt
where a URL is displayed that may potentially come from a `.gitmodules`
file. To this end, the `credential_format()` function is employed.

To sanitize the host name (and optional port) part of the URL, we need a
new mode of the `strbuf_add_percentencode()` function because the
current mode is both too strict and too lenient: too strict because it
encodes `:`, `[` and `]` (which should be left unencoded in
`<host>:<port>` and in IPv6 addresses), and too lenient because it does
not encode invalid host name characters `/`, `_` and `~`.

So let's introduce and use a new mode specifically to encode the host
name and optional port part of a URI, leaving alpha-numerical
characters, periods, colons and brackets alone and encoding all others.

This only leads to a change of behavior for URLs that contain invalid
host names.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
7 months agoMerge branch 'backport-github-actions-fixes'
Johannes Schindelin [Wed, 30 Oct 2024 14:03:51 +0000 (15:03 +0100)] 
Merge branch 'backport-github-actions-fixes'

The planet keeps revolving, and CI definitions (even old ones) need to
be kept up to date, even if they worked unchanged before (because now
they don't).

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
7 months agot7300: work around platform-specific behaviour with long paths on MinGW
Patrick Steinhardt [Wed, 9 Oct 2024 13:25:18 +0000 (15:25 +0200)] 
t7300: work around platform-specific behaviour with long paths on MinGW

Windows by default has a restriction in place to only allow paths up to
260 characters. This restriction can nowadays be lifted by setting a
registry key, but is still active by default.

In t7300 we have one test that exercises the behaviour of git-clean(1)
with such long paths. Interestingly enough, this test fails on my system
that uses Windows 10 with mingw-w64 installed via MSYS2: instead of
observing ENAMETOOLONG, we observe ENOENT. This behaviour is consistent
across multiple different environments I have tried.

I cannot say why exactly we observe a different error here, but I would
not be surprised if this was either dependent on the Windows version,
the version of MinGW, the current working directory of Git or any kind
of combination of these.

Work around the issue by handling both errors.

[Backported from 106834e34a2 (t7300: work around platform-specific
behaviour with long paths on MinGW, 2024-10-09).]

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
7 months agocompat/regex: fix argument order to calloc(3)
Junio C Hamano [Sun, 12 May 2024 06:25:04 +0000 (23:25 -0700)] 
compat/regex: fix argument order to calloc(3)

Windows compiler suddenly started complaining that calloc(3) takes
its arguments in <nmemb, size> order.  Indeed, there are many calls
that has their arguments in a _wrong_ order.

Fix them all.

A sample breakage can be seen at

  https://github.com/git/git/actions/runs/9046793153/job/24857988702#step:4:272

[Backported from f01301aabe1 (compat/regex: fix argument order to
calloc(3), 2024-05-11).]

Signed-off-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
7 months agomingw: drop bogus (and unneeded) declaration of `_pgmptr`
Johannes Schindelin [Wed, 19 Jun 2024 06:09:58 +0000 (06:09 +0000)] 
mingw: drop bogus (and unneeded) declaration of `_pgmptr`

In 08809c09aa13 (mingw: add a helper function to attach GDB to the
current process, 2020-02-13), I added a declaration that was not needed.
Back then, that did not matter, but now that the declaration of that
symbol was changed in mingw-w64's headers, it causes the following
compile error:

      CC compat/mingw.o
  compat/mingw.c: In function 'open_in_gdb':
  compat/mingw.c:35:9: error: function declaration isn't a prototype [-Werror=strict-prototypes]
     35 |         extern char *_pgmptr;
        |         ^~~~~~
  In file included from C:/git-sdk-64/usr/src/git/build-installers/mingw64/lib/gcc/x86_64-w64-mingw32/14.1.0/include/mm_malloc.h:27,
                   from C:/git-sdk-64/usr/src/git/build-installers/mingw64/lib/gcc/x86_64-w64-mingw32/14.1.0/include/xmmintrin.h:34,
                   from C:/git-sdk-64/usr/src/git/build-installers/mingw64/lib/gcc/x86_64-w64-mingw32/14.1.0/include/immintrin.h:31,
                   from C:/git-sdk-64/usr/src/git/build-installers/mingw64/lib/gcc/x86_64-w64-mingw32/14.1.0/include/x86intrin.h:32,
                   from C:/git-sdk-64/usr/src/git/build-installers/mingw64/include/winnt.h:1658,
                   from C:/git-sdk-64/usr/src/git/build-installers/mingw64/include/minwindef.h:163,
                   from C:/git-sdk-64/usr/src/git/build-installers/mingw64/include/windef.h:9,
                   from C:/git-sdk-64/usr/src/git/build-installers/mingw64/include/windows.h:69,
                   from C:/git-sdk-64/usr/src/git/build-installers/mingw64/include/winsock2.h:23,
                   from compat/../git-compat-util.h:215,
                   from compat/mingw.c:1:
  compat/mingw.c:35:22: error: '__p__pgmptr' redeclared without dllimport attribute: previous dllimport ignored [-Werror=attributes]
     35 |         extern char *_pgmptr;
        |                      ^~~~~~~

Let's just drop the declaration and get rid of this compile error.

[Backported from 3c295c87c25 (mingw: drop bogus (and unneeded)
declaration of `_pgmptr`, 2024-06-19).]

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
7 months agoci: remove 'Upload failed tests' directories' step from linux32 jobs
Junio C Hamano [Mon, 9 Sep 2024 23:00:20 +0000 (16:00 -0700)] 
ci: remove 'Upload failed tests' directories' step from linux32 jobs

Linux32 jobs seem to be getting:

    Error: This request has been automatically failed because it uses a
    deprecated version of `actions/upload-artifact: v1`. Learn more:
    https://github.blog/changelog/2024-02-13-deprecation-notice-v1-and-v2-of-the-artifact-actions/

before doing anything useful.  For now, disable the step.

Ever since actions/upload-artifact@v1 got disabled, mentioning the
offending version of it seems to stop anything from happening.  At
least this should run the same build and test.

See

    https://github.com/git/git/actions/runs/10780030750/job/29894867249

for example.

[Backported from 90f2c7240cc (ci: remove 'Upload failed tests'
directories' step from linux32 jobs, 2024-09-09).]

Signed-off-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
12 months agoGit 2.44.2 v2.44.2
Junio C Hamano [Fri, 31 May 2024 00:13:43 +0000 (17:13 -0700)] 
Git 2.44.2

Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 months agoMerge branch 'fixes/2.45.1/2.44' into maint-2.44
Junio C Hamano [Fri, 31 May 2024 00:11:02 +0000 (17:11 -0700)] 
Merge branch 'fixes/2.45.1/2.44' into maint-2.44

* fixes/2.45.1/2.44:
  Revert "fsck: warn about symlink pointing inside a gitdir"
  Revert "Add a helper function to compare file contents"
  clone: drop the protections where hooks aren't run
  tests: verify that `clone -c core.hooksPath=/dev/null` works again
  Revert "core.hooksPath: add some protection while cloning"
  init: use the correct path of the templates directory again
  hook: plug a new memory leak
  ci: stop installing "gcc-13" for osx-gcc
  ci: avoid bare "gcc" for osx-gcc job
  ci: drop mention of BREW_INSTALL_PACKAGES variable
  send-email: avoid creating more than one Term::ReadLine object
  send-email: drop FakeTerm hack

12 months agoGit 2.43.5 v2.43.5
Junio C Hamano [Fri, 31 May 2024 00:06:24 +0000 (17:06 -0700)] 
Git 2.43.5

Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 months agoMerge branch 'fixes/2.45.1/2.43' into maint-2.43
Junio C Hamano [Fri, 31 May 2024 00:04:37 +0000 (17:04 -0700)] 
Merge branch 'fixes/2.45.1/2.43' into maint-2.43

* fixes/2.45.1/2.43:
  Revert "fsck: warn about symlink pointing inside a gitdir"
  Revert "Add a helper function to compare file contents"
  clone: drop the protections where hooks aren't run
  tests: verify that `clone -c core.hooksPath=/dev/null` works again
  Revert "core.hooksPath: add some protection while cloning"
  init: use the correct path of the templates directory again
  hook: plug a new memory leak
  ci: stop installing "gcc-13" for osx-gcc
  ci: avoid bare "gcc" for osx-gcc job
  ci: drop mention of BREW_INSTALL_PACKAGES variable
  send-email: avoid creating more than one Term::ReadLine object
  send-email: drop FakeTerm hack

12 months agoGit 2.42.3 v2.42.3
Junio C Hamano [Fri, 31 May 2024 00:03:31 +0000 (17:03 -0700)] 
Git 2.42.3

Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 months agoMerge branch 'fixes/2.45.1/2.42' into maint-2.42
Junio C Hamano [Fri, 31 May 2024 00:00:57 +0000 (17:00 -0700)] 
Merge branch 'fixes/2.45.1/2.42' into maint-2.42

* fixes/2.45.1/2.42:
  Revert "fsck: warn about symlink pointing inside a gitdir"
  Revert "Add a helper function to compare file contents"
  clone: drop the protections where hooks aren't run
  tests: verify that `clone -c core.hooksPath=/dev/null` works again
  Revert "core.hooksPath: add some protection while cloning"
  init: use the correct path of the templates directory again
  hook: plug a new memory leak
  ci: stop installing "gcc-13" for osx-gcc
  ci: avoid bare "gcc" for osx-gcc job
  ci: drop mention of BREW_INSTALL_PACKAGES variable
  send-email: avoid creating more than one Term::ReadLine object
  send-email: drop FakeTerm hack

12 months agoGit 2.41.2 v2.41.2
Junio C Hamano [Fri, 31 May 2024 00:00:29 +0000 (17:00 -0700)] 
Git 2.41.2

Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 months agoMerge branch 'fixes/2.45.1/2.41' into maint-2.41
Junio C Hamano [Thu, 30 May 2024 23:58:12 +0000 (16:58 -0700)] 
Merge branch 'fixes/2.45.1/2.41' into maint-2.41

* fixes/2.45.1/2.41:
  Revert "fsck: warn about symlink pointing inside a gitdir"
  Revert "Add a helper function to compare file contents"
  clone: drop the protections where hooks aren't run
  tests: verify that `clone -c core.hooksPath=/dev/null` works again
  Revert "core.hooksPath: add some protection while cloning"
  init: use the correct path of the templates directory again
  hook: plug a new memory leak
  ci: stop installing "gcc-13" for osx-gcc
  ci: avoid bare "gcc" for osx-gcc job
  ci: drop mention of BREW_INSTALL_PACKAGES variable
  send-email: avoid creating more than one Term::ReadLine object
  send-email: drop FakeTerm hack

12 months agoGit 2.40.3 v2.40.3
Junio C Hamano [Thu, 30 May 2024 23:57:31 +0000 (16:57 -0700)] 
Git 2.40.3

Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 months agoMerge branch 'fixes/2.45.1/2.40' into maint-2.40
Junio C Hamano [Thu, 30 May 2024 23:54:42 +0000 (16:54 -0700)] 
Merge branch 'fixes/2.45.1/2.40' into maint-2.40

* fixes/2.45.1/2.40:
  Revert "fsck: warn about symlink pointing inside a gitdir"
  Revert "Add a helper function to compare file contents"
  clone: drop the protections where hooks aren't run
  tests: verify that `clone -c core.hooksPath=/dev/null` works again
  Revert "core.hooksPath: add some protection while cloning"
  init: use the correct path of the templates directory again
  hook: plug a new memory leak
  ci: stop installing "gcc-13" for osx-gcc
  ci: avoid bare "gcc" for osx-gcc job
  ci: drop mention of BREW_INSTALL_PACKAGES variable
  send-email: avoid creating more than one Term::ReadLine object
  send-email: drop FakeTerm hack

12 months agoGit 2.39.5 v2.39.5
Junio C Hamano [Thu, 30 May 2024 23:52:52 +0000 (16:52 -0700)] 
Git 2.39.5

12 months agoMerge branch 'jc/fix-2.45.1-and-friends-for-2.39' into maint-2.39
Junio C Hamano [Thu, 30 May 2024 23:38:58 +0000 (16:38 -0700)] 
Merge branch 'jc/fix-2.45.1-and-friends-for-2.39' into maint-2.39

* jc/fix-2.45.1-and-friends-for-2.39:
  Revert "fsck: warn about symlink pointing inside a gitdir"
  Revert "Add a helper function to compare file contents"
  clone: drop the protections where hooks aren't run
  tests: verify that `clone -c core.hooksPath=/dev/null` works again
  Revert "core.hooksPath: add some protection while cloning"
  init: use the correct path of the templates directory again
  hook: plug a new memory leak
  ci: stop installing "gcc-13" for osx-gcc
  ci: avoid bare "gcc" for osx-gcc job
  ci: drop mention of BREW_INSTALL_PACKAGES variable
  send-email: avoid creating more than one Term::ReadLine object
  send-email: drop FakeTerm hack

13 months agoMerge branch 'fixes/2.45.1/2.43' into fixes/2.45.1/2.44
Junio C Hamano [Fri, 24 May 2024 23:58:35 +0000 (16:58 -0700)] 
Merge branch 'fixes/2.45.1/2.43' into fixes/2.45.1/2.44

* fixes/2.45.1/2.43:
  Revert "fsck: warn about symlink pointing inside a gitdir"
  Revert "Add a helper function to compare file contents"
  clone: drop the protections where hooks aren't run
  tests: verify that `clone -c core.hooksPath=/dev/null` works again
  Revert "core.hooksPath: add some protection while cloning"
  init: use the correct path of the templates directory again
  hook: plug a new memory leak
  ci: stop installing "gcc-13" for osx-gcc
  ci: avoid bare "gcc" for osx-gcc job
  ci: drop mention of BREW_INSTALL_PACKAGES variable
  send-email: avoid creating more than one Term::ReadLine object
  send-email: drop FakeTerm hack

13 months agoMerge branch 'fixes/2.45.1/2.42' into fixes/2.45.1/2.43
Junio C Hamano [Fri, 24 May 2024 23:58:11 +0000 (16:58 -0700)] 
Merge branch 'fixes/2.45.1/2.42' into fixes/2.45.1/2.43

* fixes/2.45.1/2.42:
  Revert "fsck: warn about symlink pointing inside a gitdir"
  Revert "Add a helper function to compare file contents"
  clone: drop the protections where hooks aren't run
  tests: verify that `clone -c core.hooksPath=/dev/null` works again
  Revert "core.hooksPath: add some protection while cloning"
  init: use the correct path of the templates directory again
  hook: plug a new memory leak
  ci: stop installing "gcc-13" for osx-gcc
  ci: avoid bare "gcc" for osx-gcc job
  ci: drop mention of BREW_INSTALL_PACKAGES variable
  send-email: avoid creating more than one Term::ReadLine object
  send-email: drop FakeTerm hack

13 months agoMerge branch 'fixes/2.45.1/2.41' into fixes/2.45.1/2.42
Junio C Hamano [Fri, 24 May 2024 23:57:43 +0000 (16:57 -0700)] 
Merge branch 'fixes/2.45.1/2.41' into fixes/2.45.1/2.42

* fixes/2.45.1/2.41:
  Revert "fsck: warn about symlink pointing inside a gitdir"
  Revert "Add a helper function to compare file contents"
  clone: drop the protections where hooks aren't run
  tests: verify that `clone -c core.hooksPath=/dev/null` works again
  Revert "core.hooksPath: add some protection while cloning"
  init: use the correct path of the templates directory again
  hook: plug a new memory leak
  ci: stop installing "gcc-13" for osx-gcc
  ci: avoid bare "gcc" for osx-gcc job
  ci: drop mention of BREW_INSTALL_PACKAGES variable
  send-email: avoid creating more than one Term::ReadLine object
  send-email: drop FakeTerm hack

13 months agoMerge branch 'fixes/2.45.1/2.40' into fixes/2.45.1/2.41
Junio C Hamano [Fri, 24 May 2024 23:57:01 +0000 (16:57 -0700)] 
Merge branch 'fixes/2.45.1/2.40' into fixes/2.45.1/2.41

* fixes/2.45.1/2.40:
  Revert "fsck: warn about symlink pointing inside a gitdir"
  Revert "Add a helper function to compare file contents"
  clone: drop the protections where hooks aren't run
  tests: verify that `clone -c core.hooksPath=/dev/null` works again
  Revert "core.hooksPath: add some protection while cloning"
  init: use the correct path of the templates directory again
  hook: plug a new memory leak
  ci: stop installing "gcc-13" for osx-gcc
  ci: avoid bare "gcc" for osx-gcc job
  ci: drop mention of BREW_INSTALL_PACKAGES variable
  send-email: avoid creating more than one Term::ReadLine object
  send-email: drop FakeTerm hack

13 months agoMerge branch 'jc/fix-2.45.1-and-friends-for-2.39' into fixes/2.45.1/2.40
Junio C Hamano [Fri, 24 May 2024 19:29:35 +0000 (12:29 -0700)] 
Merge branch 'jc/fix-2.45.1-and-friends-for-2.39' into fixes/2.45.1/2.40

Revert overly aggressive "layered defence" that went into 2.45.1
and friends, which broke "git-lfs", "git-annex", and other use
cases, so that we can rebuild necessary counterparts in the open.

* jc/fix-2.45.1-and-friends-for-2.39:
  Revert "fsck: warn about symlink pointing inside a gitdir"
  Revert "Add a helper function to compare file contents"
  clone: drop the protections where hooks aren't run
  tests: verify that `clone -c core.hooksPath=/dev/null` works again
  Revert "core.hooksPath: add some protection while cloning"
  init: use the correct path of the templates directory again
  hook: plug a new memory leak
  ci: stop installing "gcc-13" for osx-gcc
  ci: avoid bare "gcc" for osx-gcc job
  ci: drop mention of BREW_INSTALL_PACKAGES variable
  send-email: avoid creating more than one Term::ReadLine object
  send-email: drop FakeTerm hack

13 months agoRevert "fsck: warn about symlink pointing inside a gitdir"
Junio C Hamano [Thu, 23 May 2024 04:55:31 +0000 (21:55 -0700)] 
Revert "fsck: warn about symlink pointing inside a gitdir"

This reverts commit a33fea08 (fsck: warn about symlink pointing
inside a gitdir, 2024-04-10), which warns against symbolic links
commonly created by git-annex.

13 months agoRevert "Add a helper function to compare file contents"
Johannes Schindelin [Mon, 20 May 2024 20:22:05 +0000 (20:22 +0000)] 
Revert "Add a helper function to compare file contents"

Now that during a `git clone`, the hooks' contents are no longer
compared to the templates' files', the caller for which the
`do_files_match()` function was introduced is gone, and therefore this
function can be retired, too.

This reverts commit 584de0b4c23 (Add a helper function to compare file
contents, 2024-03-30).

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
13 months agoclone: drop the protections where hooks aren't run
Johannes Schindelin [Mon, 20 May 2024 20:22:04 +0000 (20:22 +0000)] 
clone: drop the protections where hooks aren't run

As part of the security bug-fix releases v2.39.4, ..., v2.45.1, I
introduced logic to safeguard `git clone` from running hooks that were
installed _during_ the clone operation.

The rationale was that Git's CVE-2024-32002, CVE-2021-21300,
CVE-2019-1354, CVE-2019-1353, CVE-2019-1352, and CVE-2019-1349 should
have been low-severity vulnerabilities but were elevated to
critical/high severity by the attack vector that allows a weakness where
files inside `.git/` can be inadvertently written during a `git clone`
to escalate to a Remote Code Execution attack by virtue of installing a
malicious `post-checkout` hook that Git will then run at the end of the
operation without giving the user a chance to see what code is executed.

Unfortunately, Git LFS uses a similar strategy to install its own
`post-checkout` hook during a `git clone`; In fact, Git LFS is
installing four separate hooks while running the `smudge` filter.

While this pattern is probably in want of being improved by introducing
better support in Git for Git LFS and other tools wishing to register
hooks to be run at various stages of Git's commands, let's undo the
clone protections to unbreak Git LFS-enabled clones.

This reverts commit 8db1e8743c0 (clone: prevent hooks from running
during a clone, 2024-03-28).

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
13 months agotests: verify that `clone -c core.hooksPath=/dev/null` works again
Johannes Schindelin [Mon, 20 May 2024 20:22:03 +0000 (20:22 +0000)] 
tests: verify that `clone -c core.hooksPath=/dev/null` works again

As part of the protections added in Git v2.45.1 and friends,
repository-local `core.hooksPath` settings are no longer allowed, as a
defense-in-depth mechanism to prevent future Git vulnerabilities to
raise to critical level if those vulnerabilities inadvertently allow the
repository-local config to be written.

What the added protection did not anticipate is that such a
repository-local `core.hooksPath` can not only be used to point to
maliciously-placed scripts in the current worktree, but also to
_prevent_ hooks from being called altogether.

We just reverted the `core.hooksPath` protections, based on the Git
maintainer's recommendation in
https://lore.kernel.org/git/xmqq4jaxvm8z.fsf@gitster.g/ to address this
concern as well as related ones. Let's make sure that we won't regress
while trying to protect the clone operation further.

Reported-by: Brooke Kuhlmann <brooke@alchemists.io>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
13 months agoRevert "core.hooksPath: add some protection while cloning"
Johannes Schindelin [Mon, 20 May 2024 20:22:02 +0000 (20:22 +0000)] 
Revert "core.hooksPath: add some protection while cloning"

This defense-in-depth was intended to protect the clone operation
against future escalations where bugs in `git clone` would allow
attackers to write arbitrary files in the `.git/` directory would allow
for Remote Code Execution attacks via maliciously-placed hooks.

However, it turns out that the `core.hooksPath` protection has
unintentional side effects so severe that they do not justify the
benefit of the protections. For example, it has been reported in
https://lore.kernel.org/git/FAFA34CB-9732-4A0A-87FB-BDB272E6AEE8@alchemists.io/
that the following invocation, which is intended to make `git clone`
safer, is itself broken by that protective measure:

git clone --config core.hooksPath=/dev/null <url>

Since it turns out that the benefit does not justify the cost, let's revert
20f3588efc6 (core.hooksPath: add some protection while cloning,
2024-03-30).

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
13 months agoinit: use the correct path of the templates directory again
Johannes Schindelin [Mon, 20 May 2024 20:22:01 +0000 (20:22 +0000)] 
init: use the correct path of the templates directory again

In df93e407f06 (init: refactor the template directory discovery into its
own function, 2024-03-29), I refactored the way the templates directory
is discovered.

The refactoring was faithful, but missed a reference in the `Makefile`
where the `DEFAULT_GIT_TEMPLATE_DIR` constant is defined. As a
consequence, Git v2.45.1 and friends will always use the hard-coded path
`/usr/share/git-core/templates`.

Let's fix that by defining the `DEFAULT_GIT_TEMPLATE_DIR` when building
`setup.o`, where that constant is actually used.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
13 months agohook: plug a new memory leak
Johannes Schindelin [Mon, 20 May 2024 20:22:00 +0000 (20:22 +0000)] 
hook: plug a new memory leak

In 8db1e8743c0 (clone: prevent hooks from running during a clone,
2024-03-28), I introduced an inadvertent memory leak that was
unfortunately not caught before v2.45.1 was released. Here is a fix.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
13 months agoci: stop installing "gcc-13" for osx-gcc
Jeff King [Thu, 9 May 2024 16:25:44 +0000 (12:25 -0400)] 
ci: stop installing "gcc-13" for osx-gcc

Our osx-gcc job explicitly asks to install gcc-13. But since the GitHub
runner image already comes with gcc-13 installed, this is mostly doing
nothing (or in some cases it may install an incremental update over the
runner image). But worse, it recently started causing errors like:

    ==> Fetching gcc@13
    ==> Downloading https://ghcr.io/v2/homebrew/core/gcc/13/blobs/sha256:fb2403d97e2ce67eb441b54557cfb61980830f3ba26d4c5a1fe5ecd0c9730d1a
    ==> Pouring gcc@13--13.2.0.ventura.bottle.tar.gz
    Error: The `brew link` step did not complete successfully
    The formula built, but is not symlinked into /usr/local
    Could not symlink bin/c++-13
    Target /usr/local/bin/c++-13
    is a symlink belonging to gcc. You can unlink it:
      brew unlink gcc

which cause the whole CI job to bail.

I didn't track down the root cause, but I suspect it may be related to
homebrew recently switching the "gcc" default to gcc-14. And it may even
be fixed when a new runner image is released. But if we don't need to
run brew at all, it's one less thing for us to worry about.

[jc: cherry-picked from v2.45.0-3-g7df2405b38]

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
13 months agoci: avoid bare "gcc" for osx-gcc job
Jeff King [Thu, 9 May 2024 16:24:15 +0000 (12:24 -0400)] 
ci: avoid bare "gcc" for osx-gcc job

On macOS, a bare "gcc" (without a version) will invoke a wrapper for
clang, not actual gcc. Even when gcc is installed via homebrew, that
only provides version-specific links in /usr/local/bin (like "gcc-13"),
and never a version-agnostic "gcc" wrapper.

As far as I can tell, this has been the case for a long time, and this
osx-gcc job has largely been doing nothing. We can point it at "gcc-13",
which will pick up the homebrew-installed version.

The fix here is specific to the github workflow file, as the gitlab one
does not have a matching job.

It's a little unfortunate that we cannot just ask for the latest version
of gcc which homebrew provides, but as far as I can tell there is no
easy alias (you'd have to find the highest number gcc-* in
/usr/local/bin yourself).

[jc: cherry-picked from v2.45.0-2-g11c7001e3d]

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
13 months agoci: drop mention of BREW_INSTALL_PACKAGES variable
Jeff King [Thu, 9 May 2024 16:23:05 +0000 (12:23 -0400)] 
ci: drop mention of BREW_INSTALL_PACKAGES variable

The last user of this variable went away in 4a6e4b9602 (CI: remove
Travis CI support, 2021-11-23), so it's doing nothing except making it
more confusing to find out which packages _are_ installed.

[jc: cherry-picked from v2.45.0-1-g9d4453e8d6]

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
13 months agosend-email: avoid creating more than one Term::ReadLine object
Jeff King [Tue, 8 Aug 2023 18:15:31 +0000 (14:15 -0400)] 
send-email: avoid creating more than one Term::ReadLine object

Every time git-send-email calls its ask() function to prompt the user,
we call term(), which instantiates a new Term::ReadLine object. But in
v1.46 of Term::ReadLine::Gnu (which provides the Term::ReadLine
interface on some platforms), its constructor refuses to create a second
instance[1]. So on systems with that version of the module, most
git-send-email instances will fail (as we usually prompt for both "to"
and "in-reply-to" unless the user provided them on the command line).

We can fix this by keeping a single instance variable and returning it
for each call to term(). In perl 5.10 and up, we could do that with a
"state" variable. But since we only require 5.008, we'll do it the
old-fashioned way, with a lexical "my" in its own scope.

Note that the tests in t9001 detect this problem as-is, since the
failure mode is for the program to die. But let's also beef up the
"Prompting works" test to check that it correctly handles multiple
inputs (if we had chosen to keep our FakeTerm hack in the previous
commit, then the failure mode would be incorrectly ignoring prompts
after the first).

[1] For discussion of why multiple instances are forbidden, see:
    https://github.com/hirooih/perl-trg/issues/16

[jc: cherry-picked from v2.42.0-rc2~6^2]

Signed-off-by: Jeff King <peff@peff.net>
Acked-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
13 months agosend-email: drop FakeTerm hack
Jeff King [Tue, 8 Aug 2023 18:14:36 +0000 (14:14 -0400)] 
send-email: drop FakeTerm hack

Back in 280242d1cc (send-email: do not barf when Term::ReadLine does not
like your terminal, 2006-07-02), we added a fallback for when
Term::ReadLine's constructor failed: we'd have a FakeTerm object
instead, which would then die if anybody actually tried to call
readline() on it. Since we instantiated the $term variable at program
startup, we needed this workaround to let the program run in modes when
we did not prompt the user.

But later, in f4dc9432fd (send-email: lazily load modules for a big
speedup, 2021-05-28), we started loading Term::ReadLine lazily only when
ask() is called. So at that point we know we're trying to prompt the
user, and we can just die if ReadLine instantiation fails, rather than
making this fake object to lazily delay showing the error.

This should be OK even if there is no tty (e.g., we're in a cron job),
because Term::ReadLine will return a stub object in that case whose "IN"
and "OUT" functions return undef. And since 5906f54e47 (send-email:
don't attempt to prompt if tty is closed, 2009-03-31), we check for that
case and skip prompting.

And we can be sure that FakeTerm was not kicking in for such a
situation, because it has actually been broken since that commit! It
does not define "IN" or "OUT" methods, so perl would barf with an error.
If FakeTerm was in use, we were neither honoring what 5906f54e47 tried
to do, nor producing the readable message that 280242d1cc intended.

So we're better off just dropping FakeTerm entirely, and letting the
error reported by constructing Term::ReadLine through.

[jc: cherry-picked from v2.42.0-rc2~6^2~1]

Signed-off-by: Jeff King <peff@peff.net>
Acked-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
14 months agoGit 2.44.1 v2.44.1
Johannes Schindelin [Wed, 10 Apr 2024 20:10:07 +0000 (22:10 +0200)] 
Git 2.44.1

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
14 months agoSync with 2.43.4
Johannes Schindelin [Wed, 10 Apr 2024 20:10:06 +0000 (22:10 +0200)] 
Sync with 2.43.4

* maint-2.43: (40 commits)
  Git 2.43.4
  Git 2.42.2
  Git 2.41.1
  Git 2.40.2
  Git 2.39.4
  fsck: warn about symlink pointing inside a gitdir
  core.hooksPath: add some protection while cloning
  init.templateDir: consider this config setting protected
  clone: prevent hooks from running during a clone
  Add a helper function to compare file contents
  init: refactor the template directory discovery into its own function
  find_hook(): refactor the `STRIP_EXTENSION` logic
  clone: when symbolic links collide with directories, keep the latter
  entry: report more colliding paths
  t5510: verify that D/F confusion cannot lead to an RCE
  submodule: require the submodule path to contain directories only
  clone_submodule: avoid using `access()` on directories
  submodules: submodule paths must not contain symlinks
  clone: prevent clashing git dirs when cloning submodule in parallel
  t7423: add tests for symlinked submodule directories
  ...

14 months agoGit 2.43.4 v2.43.4
Johannes Schindelin [Wed, 10 Apr 2024 20:04:50 +0000 (22:04 +0200)] 
Git 2.43.4

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
14 months agoSync with 2.42.2
Johannes Schindelin [Wed, 10 Apr 2024 20:04:48 +0000 (22:04 +0200)] 
Sync with 2.42.2

* maint-2.42: (39 commits)
  Git 2.42.2
  Git 2.41.1
  Git 2.40.2
  Git 2.39.4
  fsck: warn about symlink pointing inside a gitdir
  core.hooksPath: add some protection while cloning
  init.templateDir: consider this config setting protected
  clone: prevent hooks from running during a clone
  Add a helper function to compare file contents
  init: refactor the template directory discovery into its own function
  find_hook(): refactor the `STRIP_EXTENSION` logic
  clone: when symbolic links collide with directories, keep the latter
  entry: report more colliding paths
  t5510: verify that D/F confusion cannot lead to an RCE
  submodule: require the submodule path to contain directories only
  clone_submodule: avoid using `access()` on directories
  submodules: submodule paths must not contain symlinks
  clone: prevent clashing git dirs when cloning submodule in parallel
  t7423: add tests for symlinked submodule directories
  has_dir_name(): do not get confused by characters < '/'
  ...

14 months agoGit 2.42.2 v2.42.2
Johannes Schindelin [Wed, 10 Apr 2024 19:51:47 +0000 (21:51 +0200)] 
Git 2.42.2

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
14 months agoSync with 2.41.1
Johannes Schindelin [Wed, 17 Apr 2024 09:39:09 +0000 (11:39 +0200)] 
Sync with 2.41.1

* maint-2.41: (38 commits)
  Git 2.41.1
  Git 2.40.2
  Git 2.39.4
  fsck: warn about symlink pointing inside a gitdir
  core.hooksPath: add some protection while cloning
  init.templateDir: consider this config setting protected
  clone: prevent hooks from running during a clone
  Add a helper function to compare file contents
  init: refactor the template directory discovery into its own function
  find_hook(): refactor the `STRIP_EXTENSION` logic
  clone: when symbolic links collide with directories, keep the latter
  entry: report more colliding paths
  t5510: verify that D/F confusion cannot lead to an RCE
  submodule: require the submodule path to contain directories only
  clone_submodule: avoid using `access()` on directories
  submodules: submodule paths must not contain symlinks
  clone: prevent clashing git dirs when cloning submodule in parallel
  t7423: add tests for symlinked submodule directories
  has_dir_name(): do not get confused by characters < '/'
  docs: document security issues around untrusted .git dirs
  ...

14 months agoGit 2.41.1 v2.41.1
Johannes Schindelin [Wed, 10 Apr 2024 19:06:57 +0000 (21:06 +0200)] 
Git 2.41.1

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
14 months agoSync with 2.40.2
Johannes Schindelin [Wed, 17 Apr 2024 09:38:18 +0000 (11:38 +0200)] 
Sync with 2.40.2

* maint-2.40: (39 commits)
  Git 2.40.2
  Git 2.39.4
  fsck: warn about symlink pointing inside a gitdir
  core.hooksPath: add some protection while cloning
  init.templateDir: consider this config setting protected
  clone: prevent hooks from running during a clone
  Add a helper function to compare file contents
  init: refactor the template directory discovery into its own function
  find_hook(): refactor the `STRIP_EXTENSION` logic
  clone: when symbolic links collide with directories, keep the latter
  entry: report more colliding paths
  t5510: verify that D/F confusion cannot lead to an RCE
  submodule: require the submodule path to contain directories only
  clone_submodule: avoid using `access()` on directories
  submodules: submodule paths must not contain symlinks
  clone: prevent clashing git dirs when cloning submodule in parallel
  t7423: add tests for symlinked submodule directories
  has_dir_name(): do not get confused by characters < '/'
  docs: document security issues around untrusted .git dirs
  upload-pack: disable lazy-fetching by default
  ...

14 months agoGit 2.40.2 v2.40.2
Johannes Schindelin [Wed, 10 Apr 2024 18:56:02 +0000 (20:56 +0200)] 
Git 2.40.2

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
14 months agoSync with 2.39.4
Johannes Schindelin [Fri, 12 Apr 2024 07:45:28 +0000 (09:45 +0200)] 
Sync with 2.39.4

* maint-2.39: (38 commits)
  Git 2.39.4
  fsck: warn about symlink pointing inside a gitdir
  core.hooksPath: add some protection while cloning
  init.templateDir: consider this config setting protected
  clone: prevent hooks from running during a clone
  Add a helper function to compare file contents
  init: refactor the template directory discovery into its own function
  find_hook(): refactor the `STRIP_EXTENSION` logic
  clone: when symbolic links collide with directories, keep the latter
  entry: report more colliding paths
  t5510: verify that D/F confusion cannot lead to an RCE
  submodule: require the submodule path to contain directories only
  clone_submodule: avoid using `access()` on directories
  submodules: submodule paths must not contain symlinks
  clone: prevent clashing git dirs when cloning submodule in parallel
  t7423: add tests for symlinked submodule directories
  has_dir_name(): do not get confused by characters < '/'
  docs: document security issues around untrusted .git dirs
  upload-pack: disable lazy-fetching by default
  fetch/clone: detect dubious ownership of local repositories
  ...

14 months agoGit 2.39.4 v2.39.4
Johannes Schindelin [Wed, 10 Apr 2024 18:37:40 +0000 (20:37 +0200)] 
Git 2.39.4

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
14 months agoMerge branch 'ownership-checks-in-local-clones'
Johannes Schindelin [Fri, 12 Apr 2024 22:28:19 +0000 (00:28 +0200)] 
Merge branch 'ownership-checks-in-local-clones'

This topic addresses two CVEs:

- CVE-2024-32020:

  Local clones may end up hardlinking files into the target repository's
  object database when source and target repository reside on the same
  disk. If the source repository is owned by a different user, then
  those hardlinked files may be rewritten at any point in time by the
  untrusted user.

- CVE-2024-32021:

  When cloning a local source repository that contains symlinks via the
  filesystem, Git may create hardlinks to arbitrary user-readable files
  on the same filesystem as the target repository in the objects/
  directory.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
14 months agoMerge branch 'defense-in-depth'
Johannes Schindelin [Sat, 30 Mar 2024 23:22:41 +0000 (00:22 +0100)] 
Merge branch 'defense-in-depth'

This topic branch adds a couple of measures designed to make it much
harder to exploit any bugs in Git's recursive clone machinery that might
be found in the future.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
14 months agofsck: warn about symlink pointing inside a gitdir
Johannes Schindelin [Wed, 10 Apr 2024 16:01:13 +0000 (18:01 +0200)] 
fsck: warn about symlink pointing inside a gitdir

In the wake of fixing a vulnerability where `git clone` mistakenly
followed a symbolic link that it had just written while checking out
files, writing into a gitdir, let's add some defense-in-depth by
teaching `git fsck` to report symbolic links stored in its trees that
point inside `.git/`.

Even though the Git project never made any promises about the exact
shape of the `.git/` directory's contents, there are likely repositories
out there containing symbolic links that point inside the gitdir. For
that reason, let's only report these as warnings, not as errors.
Security-conscious users are encouraged to configure
`fsck.symlinkPointsToGitDir = error`.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
14 months agocore.hooksPath: add some protection while cloning
Johannes Schindelin [Sat, 30 Mar 2024 18:12:50 +0000 (19:12 +0100)] 
core.hooksPath: add some protection while cloning

Quite frequently, when vulnerabilities were found in Git's (quite
complex) clone machinery, a relatively common way to escalate the
severity was to trick Git into running a hook which is actually a script
that has just been laid on disk as part of that clone. This constitutes
a Remote Code Execution vulnerability, the highest severity observed in
Git's vulnerabilities so far.

Some previously-fixed vulnerabilities allowed malicious repositories to
be crafted such that Git would check out files not in the worktree, but
in, say, a submodule's `<git>/hooks/` directory.

A vulnerability that "merely" allows to modify the Git config would
allow a related attack vector, to manipulate Git into looking in the
worktree for hooks, e.g. redirecting the location where Git looks for
hooks, via setting `core.hooksPath` (which would be classified as
CWE-427: Uncontrolled Search Path Element and CWE-114: Process Control,
for more details see https://cwe.mitre.org/data/definitions/427.html and
https://cwe.mitre.org/data/definitions/114.html).

To prevent that attack vector, let's error out and complain loudly if an
active `core.hooksPath` configuration is seen in the repository-local
Git config during a `git clone`.

There is one caveat: This changes Git's behavior in a slightly
backwards-incompatible manner. While it is probably a rare scenario (if
it exists at all) to configure `core.hooksPath` via a config in the Git
templates, it _is_ conceivable that some valid setup requires this to
work. In the hopefully very unlikely case that a user runs into this,
there is an escape hatch: set the `GIT_CLONE_PROTECTION_ACTIVE=false`
environment variable. Obviously, this should be done only with utmost
caution.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
14 months agoinit.templateDir: consider this config setting protected
Johannes Schindelin [Fri, 29 Mar 2024 12:15:32 +0000 (13:15 +0100)] 
init.templateDir: consider this config setting protected

The ability to configuring the template directory is a delicate feature:
It allows defining hooks that will be run e.g. during a `git clone`
operation, such as the `post-checkout` hook.

As such, it is of utmost importance that Git would not allow that config
setting to be changed during a `git clone` by mistake, allowing an
attacker a chance for a Remote Code Execution, allowing attackers to run
arbitrary code on unsuspecting users' machines.

As a defense-in-depth measure, to prevent minor vulnerabilities in the
`git clone` code from ballooning into higher-serverity attack vectors,
let's make this a protected setting just like `safe.directory` and
friends, i.e. ignore any `init.templateDir` entries from any local
config.

Note: This does not change the behavior of any recursive clone (modulo
bugs), as the local repository config is not even supposed to be written
while cloning the superproject, except in one scenario: If a config
template is configured that sets the template directory. This might be
done because `git clone --recurse-submodules --template=<directory>`
does not pass that template directory on to the submodules'
initialization.

Another scenario where this commit changes behavior is where
repositories are _not_ cloned recursively, and then some (intentional,
benign) automation configures the template directory to be used before
initializing the submodules.

So the caveat is that this could theoretically break existing processes.

In both scenarios, there is a way out, though: configuring the template
directory via the environment variable `GIT_TEMPLATE_DIR`.

This change in behavior is a trade-off between security and
backwards-compatibility that is struck in favor of security.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
14 months agoclone: prevent hooks from running during a clone
Johannes Schindelin [Thu, 28 Mar 2024 18:21:06 +0000 (19:21 +0100)] 
clone: prevent hooks from running during a clone

Critical security issues typically combine relatively common
vulnerabilities such as case confusion in file paths with other
weaknesses in order to raise the severity of the attack.

One such weakness that has haunted the Git project in many a
submodule-related CVE is that any hooks that are found are executed
during a clone operation. Examples are the `post-checkout` and
`fsmonitor` hooks.

However, Git's design calls for hooks to be disabled by default, as only
disabled example hooks are copied over from the templates in
`<prefix>/share/git-core/templates/`.

As a defense-in-depth measure, let's prevent those hooks from running.

Obviously, administrators can choose to drop enabled hooks into the
template directory, though, _and_ it is also possible to override
`core.hooksPath`, in which case the new check needs to be disabled.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
14 months agoAdd a helper function to compare file contents
Johannes Schindelin [Sat, 30 Mar 2024 14:59:20 +0000 (15:59 +0100)] 
Add a helper function to compare file contents

In the next commit, Git will learn to disallow hooks during `git clone`
operations _except_ when those hooks come from the templates (which are
inherently supposed to be trusted). To that end, we add a function to
compare the contents of two files.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
14 months agoMerge branch 'icasefs-symlink-confusion'
Johannes Schindelin [Sat, 30 Mar 2024 23:22:41 +0000 (00:22 +0100)] 
Merge branch 'icasefs-symlink-confusion'

This topic branch fixes two vulnerabilities:

- Recursive clones on case-insensitive filesystems that support symbolic
  links are susceptible to case confusion that can be exploited to
  execute just-cloned code during the clone operation.

- Repositories can be configured to execute arbitrary code during local
  clones. To address this, the ownership checks introduced in v2.30.3
  are now extended to cover cloning local repositories.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
14 months agoinit: refactor the template directory discovery into its own function
Johannes Schindelin [Fri, 29 Mar 2024 10:45:01 +0000 (11:45 +0100)] 
init: refactor the template directory discovery into its own function

We will need to call this function from `hook.c` to be able to prevent
hooks from running that were written as part of a `clone` but did not
originate from the template directory.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
14 months agofind_hook(): refactor the `STRIP_EXTENSION` logic
Johannes Schindelin [Thu, 28 Mar 2024 18:02:30 +0000 (19:02 +0100)] 
find_hook(): refactor the `STRIP_EXTENSION` logic

When looking for a hook and not finding one, and when `STRIP_EXTENSION`
is available (read: if we're on Windows and `.exe` is the required
extension for executable programs), we want to look also for a hook with
that extension.

Previously, we added that handling into the conditional block that was
meant to handle when no hook was found (possibly providing some advice
for the user's benefit). If the hook with that file extension was found,
we'd return early from that function instead of writing out said advice,
of course.

However, we're about to introduce a safety valve to prevent hooks from
being run during a clone, to reduce the attack surface of bugs that
allow writing files to be written into arbitrary locations.

To prepare for that, refactor the logic to avoid the early return, by
separating the `STRIP_EXTENSION` handling from the conditional block
handling the case when no hook was found.

This commit is best viewed with `--patience`.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
14 months agoclone: when symbolic links collide with directories, keep the latter
Johannes Schindelin [Thu, 28 Mar 2024 09:55:07 +0000 (10:55 +0100)] 
clone: when symbolic links collide with directories, keep the latter

When recursively cloning a repository with submodules, we must ensure
that the submodules paths do not suddenly contain symbolic links that
would let Git write into unintended locations. We just plugged that
vulnerability, but let's add some more defense-in-depth.

Since we can only keep one item on disk if multiple index entries' paths
collide, we may just as well avoid keeping a symbolic link (because that
would allow attack vectors where Git follows those links by mistake).

Technically, we handle more situations than cloning submodules into
paths that were (partially) replaced by symbolic links. This provides
defense-in-depth in case someone finds a case-folding confusion
vulnerability in the future that does not even involve submodules.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
14 months agoentry: report more colliding paths
Johannes Schindelin [Thu, 28 Mar 2024 08:44:28 +0000 (09:44 +0100)] 
entry: report more colliding paths

In b878579ae7 (clone: report duplicate entries on case-insensitive
filesystems, 2018-08-17) code was added to warn about index entries that
resolve to the same file system entity (usually the cause is a
case-insensitive filesystem).

In Git for Windows, where inodes are not trusted (because of a
performance trade-off, inodes are equal to 0 by default), that check
does not compare inode numbers but the verbatim path.

This logic works well when index entries' paths differ only in case.

However, for file/directory conflicts only the file's path was reported,
leaving the user puzzled with what that path collides.

Let's try ot catch colliding paths even if one path is the prefix of the
other. We do this also in setups where the file system is case-sensitive
because the inode check would not be able to catch those collisions.

While not a complete solution (for example, on macOS, Unicode
normalization could also lead to file/directory conflicts but be missed
by this logic), it is at least another defensive layer on top of what
the previous commits added.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
14 months agot5510: verify that D/F confusion cannot lead to an RCE
Johannes Schindelin [Sun, 24 Mar 2024 13:13:41 +0000 (14:13 +0100)] 
t5510: verify that D/F confusion cannot lead to an RCE

The most critical vulnerabilities in Git lead to a Remote Code Execution
("RCE"), i.e. the ability for an attacker to have malicious code being
run as part of a Git operation that is not expected to run said code,
such has hooks delivered as part of a `git clone`.

A couple of parent commits ago, a bug was fixed that let Git be confused
by the presence of a path `a-` to mistakenly assume that a directory
`a/` can safely be created without removing an existing `a` that is a
symbolic link.

This bug did not represent an exploitable vulnerability on its
own; Let's make sure it stays that way.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
14 months agosubmodule: require the submodule path to contain directories only
Johannes Schindelin [Tue, 26 Mar 2024 13:37:25 +0000 (14:37 +0100)] 
submodule: require the submodule path to contain directories only

Submodules are stored in subdirectories of their superproject. When
these subdirectories have been replaced with symlinks by a malicious
actor, all kinds of mayhem can be caused.

This _should_ not be possible, but many CVEs in the past showed that
_when_ possible, it allows attackers to slip in code that gets executed
during, say, a `git clone --recursive` operation.

Let's add some defense-in-depth to disallow submodule paths to have
anything except directories in them.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
14 months agoclone_submodule: avoid using `access()` on directories
Johannes Schindelin [Fri, 12 Apr 2024 19:00:44 +0000 (21:00 +0200)] 
clone_submodule: avoid using `access()` on directories

In 0060fd1511b (clone --recurse-submodules: prevent name squatting on
Windows, 2019-09-12), I introduced code to verify that a git dir either
does not exist, or is at least empty, to fend off attacks where an
inadvertently (and likely maliciously) pre-populated git dir would be
used while cloning submodules recursively.

The logic used `access(<path>, X_OK)` to verify that a directory exists
before calling `is_empty_dir()` on it. That is a curious way to check
for a directory's existence and might well fail for unwanted reasons.
Even the original author (it was I ;-) ) struggles to explain why this
function was used rather than `stat()`.

This code was _almost_ copypastad in the previous commit, but that
`access()` call was caught during review.

Let's use `stat()` instead also in the code that was almost copied
verbatim. Let's not use `lstat()` because in the unlikely event that
somebody snuck a symbolic link in, pointing to a crafted directory, we
want to verify that that directory is empty.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
14 months agosubmodules: submodule paths must not contain symlinks
Johannes Schindelin [Fri, 22 Mar 2024 10:19:22 +0000 (11:19 +0100)] 
submodules: submodule paths must not contain symlinks

When creating a submodule path, we must be careful not to follow
symbolic links. Otherwise we may follow a symbolic link pointing to
a gitdir (which are valid symbolic links!) e.g. while cloning.

On case-insensitive filesystems, however, we blindly replace a directory
that has been created as part of the `clone` operation with a symlink
when the path to the latter differs only in case from the former's path.

Let's simply avoid this situation by expecting not ever having to
overwrite any existing file/directory/symlink upon cloning. That way, we
won't even replace a directory that we just created.

This addresses CVE-2024-32002.

Reported-by: Filip Hejsek <filip.hejsek@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
14 months agoclone: prevent clashing git dirs when cloning submodule in parallel
Filip Hejsek [Sun, 28 Jan 2024 04:09:17 +0000 (05:09 +0100)] 
clone: prevent clashing git dirs when cloning submodule in parallel

While it is expected to have several git dirs within the `.git/modules/`
tree, it is important that they do not interfere with each other. For
example, if one submodule was called "captain" and another submodule
"captain/hooks", their respective git dirs would clash, as they would be
located in `.git/modules/captain/` and `.git/modules/captain/hooks/`,
respectively, i.e. the latter's files could clash with the actual Git
hooks of the former.

To prevent these clashes, and in particular to prevent hooks from being
written and then executed as part of a recursive clone, we introduced
checks as part of the fix for CVE-2019-1387 in a8dee3ca61 (Disallow
dubiously-nested submodule git directories, 2019-10-01).

It is currently possible to bypass the check for clashing submodule
git dirs in two ways:

1. parallel cloning
2. checkout --recurse-submodules

Let's check not only before, but also after parallel cloning (and before
checking out the submodule), that the git dir is not clashing with
another one, otherwise fail. This addresses the parallel cloning issue.

As to the parallel checkout issue: It requires quite a few manual steps
to create clashing git dirs because Git itself would refuse to
initialize the inner one, as demonstrated by the test case.

Nevertheless, let's teach the recursive checkout (namely, the
`submodule_move_head()` function that is used by the recursive checkout)
to be careful to verify that it does not use a clashing git dir, and if
it does, disable it (by deleting the `HEAD` file so that subsequent Git
calls won't recognize it as a git dir anymore).

Note: The parallel cloning test case contains a `cat err` that proved to
be highly useful when analyzing the racy nature of the operation (the
operation can fail with three different error messages, depending on
timing), and was left on purpose to ease future debugging should the
need arise.

Signed-off-by: Filip Hejsek <filip.hejsek@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
14 months agot7423: add tests for symlinked submodule directories
Filip Hejsek [Sun, 28 Jan 2024 03:32:47 +0000 (04:32 +0100)] 
t7423: add tests for symlinked submodule directories

Submodule operations must not follow symlinks in working tree, because
otherwise files might be written to unintended places, leading to
vulnerabilities.

Signed-off-by: Filip Hejsek <filip.hejsek@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
14 months agohas_dir_name(): do not get confused by characters < '/'
Filip Hejsek [Sun, 28 Jan 2024 03:30:25 +0000 (04:30 +0100)] 
has_dir_name(): do not get confused by characters < '/'

There is a bug in directory/file ("D/F") conflict checking optimization:
It assumes that such a conflict cannot happen if a newly added entry's
path is lexicgraphically "greater than" the last already-existing index
entry _and_ contains a directory separator that comes strictly after the
common prefix (`len > len_eq_offset`).

This assumption is incorrect, though: `a-` sorts _between_ `a` and
`a/b`, their common prefix is `a`, the slash comes after the common
prefix, and there is still a file/directory conflict.

Let's re-design this logic, taking these facts into consideration:

- It is impossible for a file to sort after another file with whose
  directory it conflicts because the trailing NUL byte is always smaller
  than any other character.

- Since there are quite a number of ASCII characters that sort before
  the slash (e.g. `-`, `.`, the space character), looking at the last
  already-existing index entry is not enough to determine whether there
  is a D/F conflict when the first character different from the
  existing last index entry's path is a slash.

  If it is not a slash, there cannot be a file/directory conflict.

  And if the existing index entry's first different character is a
  slash, it also cannot be a file/directory conflict because the
  optimization requires the newly-added entry's path to sort _after_ the
  existing entry's, and the conflicting file's path would not.

So let's fall back to the regular binary search whenever the newly-added
item's path differs in a slash character. If it does not, and it sorts
after the last index entry, there is no D/F conflict and the new index
entry can be safely appended.

This fix also nicely simplifies the logic and makes it much easier to
reason about, while the impact on performance should be negligible:
After this fix, the optimization will be skipped only when index
entry's paths differ in a slash and a space, `!`,  `"`,  `#`,  `$`,
`%`, `&`,  `'`,  | (  `)`,  `*`,  `+`,  `,`,  `-`, or  `.`, which should
be a rare situation.

Signed-off-by: Filip Hejsek <filip.hejsek@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
14 months agodocs: document security issues around untrusted .git dirs
Jeff King [Tue, 16 Apr 2024 08:52:13 +0000 (04:52 -0400)] 
docs: document security issues around untrusted .git dirs

For a long time our general philosophy has been that it's unsafe to run
arbitrary Git commands if you don't trust the hooks or config in .git,
but that running upload-pack should be OK. E.g., see 1456b043fc (Remove
post-upload-hook, 2009-12-10), or the design of uploadpack.packObjectsHook.

But we never really documented this (and even the discussions that led
to 1456b043fc were not on the public list!). Let's try to make our
approach more clear, but also be realistic that even upload-pack carries
some risk.

Helped-by: Filip Hejsek <filip.hejsek@gmail.com>
Helped-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
14 months agoupload-pack: disable lazy-fetching by default
Jeff King [Tue, 16 Apr 2024 08:35:33 +0000 (04:35 -0400)] 
upload-pack: disable lazy-fetching by default

The upload-pack command tries to avoid trusting the repository in which
it's run (e.g., by not running any hooks and not using any config that
contains arbitrary commands). But if the server side of a fetch or a
clone is a partial clone, then either upload-pack or its child
pack-objects may run a lazy "git fetch" under the hood. And it is very
easy to convince fetch to run arbitrary commands.

The "server" side can be a local repository owned by someone else, who
would be able to configure commands that are run during a clone with the
current user's permissions. This issue has been designated
CVE-2024-32004.

The fix in this commit's parent helps in this scenario, as well as in
related scenarios using SSH to clone, where the untrusted .git directory
is owned by a different user id. But if you received one as a zip file,
on a USB stick, etc, it may be owned by your user but still untrusted.

This has been designated CVE-2024-32465.

To mitigate the issue more completely, let's disable lazy fetching
entirely during `upload-pack`. While fetching from a partial repository
should be relatively rare, it is certainly not an unreasonable workflow.
And thus we need to provide an escape hatch.

This commit works by respecting a GIT_NO_LAZY_FETCH environment variable
(to skip the lazy-fetch), and setting it in upload-pack, but only when
the user has not already done so (which gives us the escape hatch).

The name of the variable is specifically chosen to match what has
already been added in 'master' via e6d5479e7a (git: extend
--no-lazy-fetch to work across subprocesses, 2024-02-27). Since we're
building this fix as a backport for older versions, we could cherry-pick
that patch and its earlier steps. However, we don't really need the
niceties (like a "--no-lazy-fetch" option) that it offers. By using the
same name, everything should just work when the two are eventually
merged, but here are a few notes:

  - the blocking of the fetch in e6d5479e7a is incomplete! It sets
    fetch_if_missing to 0 when we setup the repository variable, but
    that isn't enough. pack-objects in particular will call
    prefetch_to_pack() even if that variable is 0. This patch by
    contrast checks the environment variable at the lowest level before
    we call the lazy fetch, where we can be sure to catch all code
    paths.

    Possibly the setting of fetch_if_missing from e6d5479e7a can be
    reverted, but it may be useful to have. For example, some code may
    want to use that flag to change behavior before it gets to the point
    of trying to start the fetch. At any rate, that's all outside the
    scope of this patch.

  - there's documentation for GIT_NO_LAZY_FETCH in e6d5479e7a. We can
    live without that here, because for the most part the user shouldn't
    need to set it themselves. The exception is if they do want to
    override upload-pack's default, and that requires a separate
    documentation section (which is added here)

  - it would be nice to use the NO_LAZY_FETCH_ENVIRONMENT macro added by
    e6d5479e7a, but those definitions have moved from cache.h to
    environment.h between 2.39.3 and master. I just used the raw string
    literals, and we can replace them with the macro once this topic is
    merged to master.

At least with respect to CVE-2024-32004, this does render this commit's
parent commit somewhat redundant. However, it is worth retaining that
commit as defense in depth, and because it may help other issues (e.g.,
symlink/hardlink TOCTOU races, where zip files are not really an
interesting attack vector).

The tests in t0411 still pass, but now we have _two_ mechanisms ensuring
that the evil command is not run. Let's beef up the existing ones to
check that they failed for the expected reason, that we refused to run
upload-pack at all with an alternate user id. And add two new ones for
the same-user case that both the restriction and its escape hatch.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
14 months agofetch/clone: detect dubious ownership of local repositories
Johannes Schindelin [Wed, 10 Apr 2024 12:39:37 +0000 (14:39 +0200)] 
fetch/clone: detect dubious ownership of local repositories

When cloning from somebody else's repositories, it is possible that,
say, the `upload-pack` command is overridden in the repository that is
about to be cloned, which would then be run in the user's context who
started the clone.

To remind the user that this is a potentially unsafe operation, let's
extend the ownership checks we have already established for regular
gitdir discovery to extend also to local repositories that are about to
be cloned.

This protection extends also to file:// URLs.

The fixes in this commit address CVE-2024-32004.

Note: This commit does not touch the `fetch`/`clone` code directly, but
instead the function used implicitly by both: `enter_repo()`. This
function is also used by `git receive-pack` (i.e. pushes), by `git
upload-archive`, by `git daemon` and by `git http-backend`. In setups
that want to serve repositories owned by different users than the
account running the service, this will require `safe.*` settings to be
configured accordingly.

Also note: there are tiny time windows where a time-of-check-time-of-use
("TOCTOU") race is possible. The real solution to those would be to work
with `fstat()` and `openat()`. However, the latter function is not
available on Windows (and would have to be emulated with rather
expensive low-level `NtCreateFile()` calls), and the changes would be
quite extensive, for my taste too extensive for the little gain given
that embargoed releases need to pay extra attention to avoid introducing
inadvertent bugs.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
14 months agot0411: add tests for cloning from partial repo
Filip Hejsek [Sun, 28 Jan 2024 03:29:33 +0000 (04:29 +0100)] 
t0411: add tests for cloning from partial repo

Cloning from a partial repository must not fetch missing objects into
the partial repository, because that can lead to arbitrary code
execution.

Add a couple of test cases, pretending to the `upload-pack` command (and
to that command only) that it is working on a repository owned by
someone else.

Helped-by: Jeff King <peff@peff.net>
Signed-off-by: Filip Hejsek <filip.hejsek@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
14 months agobuiltin/clone: refuse local clones of unsafe repositories
Patrick Steinhardt [Mon, 15 Apr 2024 11:30:41 +0000 (13:30 +0200)] 
builtin/clone: refuse local clones of unsafe repositories

When performing a local clone of a repository we end up either copying
or hardlinking the source repository into the target repository. This is
significantly more performant than if we were to use git-upload-pack(1)
and git-fetch-pack(1) to create the new repository and preserves both
disk space and compute time.

Unfortunately though, performing such a local clone of a repository that
is not owned by the current user is inherently unsafe:

  - It is possible that source files get swapped out underneath us while
    we are copying or hardlinking them. While we do perform some checks
    here to assert that we hardlinked the expected file, they cannot
    reliably thwart time-of-check-time-of-use (TOCTOU) style races. It
    is thus possible for an adversary to make us copy or hardlink
    unexpected files into the target directory.

    Ideally, we would address this by starting to use openat(3P),
    fstatat(3P) and friends. Due to platform compatibility with Windows
    we cannot easily do that though. Furthermore, the scope of these
    fixes would likely be quite broad and thus not fit for an embargoed
    security release.

  - Even if we handled TOCTOU-style races perfectly, hardlinking files
    owned by a different user into the target repository is not a good
    idea in general. It is possible for an adversary to rewrite those
    files to contain whatever data they want even after the clone has
    completed.

Address these issues by completely refusing local clones of a repository
that is not owned by the current user. This reuses our existing infra we
have in place via `ensure_valid_ownership()` and thus allows a user to
override the safety guard by adding the source repository path to the
"safe.directory" configuration.

This addresses CVE-2024-32020.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
14 months agosetup.c: introduce `die_upon_dubious_ownership()`
Patrick Steinhardt [Mon, 15 Apr 2024 11:30:36 +0000 (13:30 +0200)] 
setup.c: introduce `die_upon_dubious_ownership()`

Introduce a new function `die_upon_dubious_ownership()` that uses
`ensure_valid_ownership()` to verify whether a repositroy is safe for
use, and causes Git to die in case it is not.

This function will be used in a subsequent commit.

Helped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
14 months agobuiltin/clone: abort when hardlinked source and target file differ
Patrick Steinhardt [Mon, 15 Apr 2024 11:30:31 +0000 (13:30 +0200)] 
builtin/clone: abort when hardlinked source and target file differ

When performing local clones with hardlinks we refuse to copy source
files which are symlinks as a mitigation for CVE-2022-39253. This check
can be raced by an adversary though by changing the file to a symlink
after we have checked it.

Fix the issue by checking whether the hardlinked destination file
matches the source file and abort in case it doesn't.

This addresses CVE-2024-32021.

Reported-by: Apple Product Security <product-security@apple.com>
Suggested-by: Linus Torvalds <torvalds@linuxfoundation.org>
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
14 months agobuiltin/clone: stop resolving symlinks when copying files
Patrick Steinhardt [Mon, 15 Apr 2024 11:30:26 +0000 (13:30 +0200)] 
builtin/clone: stop resolving symlinks when copying files

When a user performs a local clone without `--no-local`, then we end up
copying the source repository into the target repository directly. To
optimize this even further, we try to hardlink files into place instead
of copying data over, which helps both disk usage and speed.

There is an important edge case in this context though, namely when we
try to hardlink symlinks from the source repository into the target
repository. Depending on both platform and filesystem the resulting
behaviour here can be different:

  - On macOS and NetBSD, calling link(3P) with a symlink target creates
    a hardlink to the file pointed to by the symlink.

  - On Linux, calling link(3P) instead creates a hardlink to the symlink
    itself.

To unify this behaviour, 36596fd2df (clone: better handle symlinked
files at .git/objects/, 2019-07-10) introduced logic to resolve symlinks
before we try to link(3P) files. Consequently, the new behaviour was to
always create a hard link to the target of the symlink on all platforms.

Eventually though, we figured out that following symlinks like this can
cause havoc when performing a local clone of a malicious repository,
which resulted in CVE-2022-39253. This issue was fixed via 6f054f9fb3
(builtin/clone.c: disallow `--local` clones with symlinks, 2022-07-28),
by refusing symlinks in the source repository.

But even though we now shouldn't ever link symlinks anymore, the code
that resolves symlinks still exists. In the best case the code does not
end up doing anything because there are no symlinks anymore. In the
worst case though this can be abused by an adversary that rewrites the
source file after it has been checked not to be a symlink such that it
actually is a symlink when we call link(3P). Thus, it is still possible
to recreate CVE-2022-39253 due to this time-of-check-time-of-use bug.

Remove the call to `realpath()`. This doesn't yet address the actual
vulnerability, which will be handled in a subsequent commit.

Reported-by: Apple Product Security <product-security@apple.com>
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
14 months agoMerge branch 'js/github-actions-update'
Johannes Schindelin [Wed, 10 Apr 2024 17:25:03 +0000 (19:25 +0200)] 
Merge branch 'js/github-actions-update'

Update remaining GitHub Actions jobs to avoid warnings against
using deprecated version of Node.js.

* js/github-actions-update:
  ci(linux32): add a note about Actions that must not be updated
  ci: bump remaining outdated Actions versions

With this backport, `maint-2.39`'s CI builds are finally healthy again.

Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
14 months agoMerge branch 'jc/maint-github-actions-update'
Johannes Schindelin [Wed, 10 Apr 2024 17:25:03 +0000 (19:25 +0200)] 
Merge branch 'jc/maint-github-actions-update'

* jc/maint-github-actions-update:
  GitHub Actions: update to github-script@v7
  GitHub Actions: update to checkout@v4

Yet another thing to help `maint-2.39`'s CI builds to become healthy
again.

Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
14 months agoci(linux32): add a note about Actions that must not be updated
Johannes Schindelin [Sun, 11 Feb 2024 12:11:29 +0000 (12:11 +0000)] 
ci(linux32): add a note about Actions that must not be updated

The Docker container used by the `linux32` job comes without Node.js,
and therefore the `actions/checkout` and `actions/upload-artifact`
Actions cannot be upgraded to the latest versions (because they use
Node.js).

One time too many, I accidentally tried to update them, where
`actions/checkout` at least fails immediately, but the
`actions/upload-artifact` step is only used when any test fails, and
therefore the CI run usually passes even though that Action was updated
to a version that is incompatible with the Docker container in which
this job runs.

So let's add a big fat warning, mainly for my own benefit, to avoid
running into the very same issue over and over again.

Backported-from: 20e0ff8835 (ci(linux32): add a note about Actions that must not be updated, 2024-02-11)
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
14 months agoGitHub Actions: update to github-script@v7
Junio C Hamano [Fri, 2 Feb 2024 20:39:35 +0000 (12:39 -0800)] 
GitHub Actions: update to github-script@v7

We seem to be getting "Node.js 16 actions are deprecated." warnings
for jobs that use github-script@v6.  Update to github-script@v7,
which is said to use Node.js 20.

Backported-from: c4ddbe043e (GitHub Actions: update to github-script@v7, 2024-02-02)
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
14 months agoci: bump remaining outdated Actions versions
Johannes Schindelin [Sun, 11 Feb 2024 12:11:28 +0000 (12:11 +0000)] 
ci: bump remaining outdated Actions versions

After activating automatic Dependabot updates in the
git-for-windows/git repository, Dependabot noticed a couple
of yet-unaddressed updates.  They avoid "Node.js 16 Actions"
deprecation messages by bumping the following Actions'
versions:

- actions/upload-artifact from 3 to 4
- actions/download-artifact from 3 to 4
- actions/cache from 3 to 4

Backported-from: 820a340085 (ci: bump remaining outdated Actions versions, 2024-02-11)
Helped-by: Matthias Aßhauer <mha1993@live.de>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
14 months agoGitHub Actions: update to checkout@v4
Junio C Hamano [Fri, 2 Feb 2024 20:39:34 +0000 (12:39 -0800)] 
GitHub Actions: update to checkout@v4

We seem to be getting "Node.js 16 actions are deprecated." warnings
for jobs that use checkout@v3.  Except for the i686 containers job
that is kept at checkout@v1 [*], update to checkout@v4, which is
said to use Node.js 20.

[*] 6cf4d908 (ci(main): upgrade actions/checkout to v3, 2022-12-05)
    refers to https://github.com/actions/runner/issues/2115 and
    explains why container jobs are kept at checkout@v1.  We may
    want to check the current status of the issue and move it to the
    same version as other jobs, but that is outside the scope of
    this step.

Backported-from: e94dec0c1d (GitHub Actions: update to checkout@v4, 2024-02-02)
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
14 months agoMerge branch 'quicker-asan-lsan'
Johannes Schindelin [Fri, 12 Apr 2024 22:05:36 +0000 (00:05 +0200)] 
Merge branch 'quicker-asan-lsan'

This patch speeds up the `asan`/`lsan` jobs that are really slow enough
already.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
14 months agoMerge branch 'jk/test-lsan-denoise-output'
Johannes Schindelin [Mon, 15 Apr 2024 16:04:10 +0000 (18:04 +0200)] 
Merge branch 'jk/test-lsan-denoise-output'

Tests with LSan from time to time seem to emit harmless message
that makes our tests unnecessarily flakey; we work it around by
filtering the uninteresting output.

* jk/test-lsan-denoise-output:
  test-lib: ignore uninteresting LSan output

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
14 months agoMerge branch 'js/ci-use-macos-13'
Johannes Schindelin [Wed, 10 Apr 2024 17:25:02 +0000 (19:25 +0200)] 
Merge branch 'js/ci-use-macos-13'

Replace macos-12 used at GitHub CI with macos-13.

* js/ci-use-macos-13:
  ci: upgrade to using macos-13

This is another backport to `maint-2.39` to allow less CI jobs to break.

Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
14 months agoMerge branch 'backport/jk/libcurl-8.7-regression-workaround' into maint-2.39
Johannes Schindelin [Wed, 10 Apr 2024 17:25:02 +0000 (19:25 +0200)] 
Merge branch 'backport/jk/libcurl-8.7-regression-workaround' into maint-2.39

Fix was added to work around a regression in libcURL 8.7.0 (which has
already been fixed in their tip of the tree).

* jk/libcurl-8.7-regression-workaround:
  remote-curl: add Transfer-Encoding header only for older curl
  INSTALL: bump libcurl version to 7.21.3
  http: reset POSTFIELDSIZE when clearing curl handle

Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>