Commit graph

73319 commits

Author SHA1 Message Date
Junio C Hamano
ae3196a5ea Git 2.45-rc0
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-04-19 09:13:47 -07:00
Junio C Hamano
6c69d3a91f Merge branch 'la/mailmap-entry'
Update contact address for Linus Arver.

* la/mailmap-entry:
  mailmap: change primary address for Linus Arver
2024-04-19 09:13:47 -07:00
Junio C Hamano
18dd9301a2 Merge branch 'pf/commitish-committish'
Spellfix.

* pf/commitish-committish:
  typo: replace 'commitish' with 'committish'
2024-04-19 09:13:47 -07:00
Dragan Simic
cadcf58085 format-patch: ensure that --rfc and -k are mutually exclusive
Fix a bug that allows the "--rfc" and "-k" options to be specified together
when "git format-patch" is executed, which was introduced in the commit
e0d7db7423 ("format-patch: --rfc honors what --subject-prefix sets").

Add a couple of additional tests to t4014, to cover additional cases of
the mutual exclusivity between different "git format-patch" options.

Signed-off-by: Dragan Simic <dsimic@manjaro.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-04-19 08:40:57 -07:00
Johannes Schindelin
10dc9846b8 Git 2.44.1
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2024-04-19 12:38:56 +02:00
Johannes Schindelin
e5e6663e69 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
  ...
2024-04-19 12:38:54 +02:00
Johannes Schindelin
1f2e64e22d Git 2.43.4
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2024-04-19 12:38:52 +02:00
Johannes Schindelin
8e97ec3662 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 < '/'
  ...
2024-04-19 12:38:50 +02:00
Johannes Schindelin
babb4e5d71 Git 2.42.2
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2024-04-19 12:38:48 +02:00
Johannes Schindelin
be348e9815 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
  ...
2024-04-19 12:38:46 +02:00
Johannes Schindelin
0f15832059 Git 2.41.1
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2024-04-19 12:38:43 +02:00
Johannes Schindelin
f5b2af06f5 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
  ...
2024-04-19 12:38:42 +02:00
Johannes Schindelin
b9b439e0e3 Git 2.40.2
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2024-04-19 12:38:38 +02:00
Johannes Schindelin
93a88f42db 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
  ...
2024-04-19 12:38:37 +02:00
Johannes Schindelin
47b6d90e91 Git 2.39.4
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2024-04-19 12:38:33 +02:00
Johannes Schindelin
9e65df5eab 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>
2024-04-19 12:38:32 +02:00
Johannes Schindelin
2b3d38a6b1 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>
2024-04-19 12:38:29 +02:00
Johannes Schindelin
a33fea0886 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>
2024-04-19 12:38:25 +02:00
Johannes Schindelin
20f3588efc 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>
2024-04-19 12:38:24 +02:00
Johannes Schindelin
4412a04fe6 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>
2024-04-19 12:38:24 +02:00
Johannes Schindelin
8db1e8743c 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>
2024-04-19 12:38:23 +02:00
Johannes Schindelin
584de0b4c2 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>
2024-04-19 12:38:19 +02:00
Linus Arver
61e124bb2d SubmittingPatches: demonstrate using git-contacts with git-send-email
Signed-off-by: Linus Arver <linusa@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-04-18 14:55:11 -07:00
Linus Arver
bf96614541 SubmittingPatches: add heading for format-patch and send-email
Signed-off-by: Linus Arver <linusa@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-04-18 14:55:11 -07:00
Linus Arver
01ea2b2836 SubmittingPatches: dedupe discussion of security patches
Signed-off-by: Linus Arver <linusa@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-04-18 14:55:11 -07:00
Linus Arver
e2663c4597 SubmittingPatches: discuss reviewers first
No matter how well someone configures their email tooling, understanding
who to send the patches to is something that must always be considered.
So discuss it first instead of at the end.

In the following commit we will clean up the (now redundant) discussion
about sending security patches to the Git Security mailing list.

Signed-off-by: Linus Arver <linusa@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-04-18 14:55:10 -07:00
Linus Arver
c8d6a54a07 SubmittingPatches: quote commands
Signed-off-by: Linus Arver <linusa@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-04-18 14:55:10 -07:00
Linus Arver
84b91fc465 SubmittingPatches: mention GitGitGadget
Signed-off-by: Linus Arver <linusa@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-04-18 14:55:10 -07:00
Linus Arver
824503ce88 SubmittingPatches: clarify 'git-contacts' location
Use a dash ("git-contacts", not "git contacts") because the script is
not installed as part of "git" toolset. This also puts the script on
one line, which should make it easier to grep for with a loose search
query, such as

    $ git grep git.contacts Documentation

Also add a footnote to describe where the script is located, to help
readers who may not be familiar with such "contrib" scripts (and how
they are not accessible with the usual "git <subcommand>" syntax).

Signed-off-by: Linus Arver <linusa@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-04-18 14:55:10 -07:00
Linus Arver
7e50b3f5df MyFirstContribution: mention contrib/contacts/git-contacts
Although we've had this script since 4d06402b1b (contrib: add
git-contacts helper, 2013-07-21), we don't mention it in our
introductory docs. Do so now.

Helped-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Linus Arver <linusa@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-04-18 14:55:09 -07:00
Phillip Wood
a6c2654f83 rebase -m: fix --signoff with conflicts
When rebasing with "--signoff" the commit created by "rebase --continue"
after resolving conflicts or editing a commit fails to add the
"Signed-off-by:" trailer. This happens because the message from the
original commit is reused instead of the one that would have been used
if the sequencer had not stopped for the user interaction. The correct
message is stored in ctx->message and so with a couple of exceptions
this is written to rebase_path_message() when stopping for user
interaction instead. The exceptions are (i) "fixup" and "squash"
commands where the file is written by error_failed_squash() and (ii)
"edit" commands that are fast-forwarded where the original message is
still reused. The latter is safe because "--signoff" will never
fast-forward.

Note this introduces a change in behavior as the message file now
contains conflict comments. This is safe because commit_staged_changes()
passes an explicit cleanup flag when not editing the message and when
the message is being edited it will be cleaned up automatically. This
means user now sees the same message comments in editor with "rebase
--continue" as they would if they ran "git commit" themselves before
continuing the rebase. It also matches the behavior of "git
cherry-pick", "git merge" etc. which all list the files with merge
conflicts.

The tests are extended to check that all commits made after continuing a
rebase have a "Signed-off-by:" trailer. Sadly there are a couple of
leaks in apply.c which I've not been able to track down that mean this
test file is no-longer leak free when testing "git rebase --apply
--signoff" with conflicts.

Reported-by: David Bimmler <david.bimmler@isovalent.com>
Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-04-18 13:33:41 -07:00
Phillip Wood
53f6746615 sequencer: store commit message in private context
Add an strbuf to "struct replay_ctx" to hold the current commit
message. This does not change the behavior but it will allow us to fix a
bug with "git rebase --signoff" in the next commit. A future patch
series will use the changes here to avoid writing the commit message to
disc unless there are conflicts or the commit is being reworded.

The changes in do_pick_commit() are a mechanical replacement of "msgbuf"
with "ctx->message". In do_merge() the code to write commit message to
disc is factored out of the conditional now that both branches store the
message in the same buffer.

Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-04-18 13:33:41 -07:00
Phillip Wood
497a01a2d3 sequencer: move current fixups to private context
The list of current fixups is an implementation detail of the sequencer
and so it should not be stored in the public options struct.

Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-04-18 13:33:41 -07:00
Phillip Wood
a3152edc97 sequencer: start removing private fields from public API
"struct replay_opts" has a number of fields that are for internal
use. While they are marked as private having them in a public struct is
a distraction for callers and means that every time the internal details
are changed we have to recompile all the files that include sequencer.h
even though the public API is unchanged. This commit starts the process
of removing the private fields by adding an opaque pointer to a "struct
replay_ctx" to "struct replay_opts" and moving the "reflog_message"
member to the new private struct.

The sequencer currently updates the state files on disc each time it
processes a command in the todo list. This is an artifact of the
scripted implementation and makes the code hard to reason about as it is
not possible to get a complete view of the state in memory. In the
future we will add new members to "struct replay_ctx" to remedy this and
avoid writing state to disc unless the sequencer stops for user
interaction.

Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-04-18 13:33:41 -07:00
Phillip Wood
42aae6a49a sequencer: always free "struct replay_opts"
sequencer_post_commit_cleanup() initializes an instance of "struct
replay_opts" but does not call replay_opts_release(). Currently this
does not leak memory because the code paths called don't allocate any of
the struct members. That will change in the next commit so add call to
replay_opts_release() to prevent a memory leak in "git commit" that
breaks all of the leak free tests.

Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-04-18 13:33:41 -07:00
Junio C Hamano
2a60cb766e Merge branch 'pw/t3428-cleanup' into pw/rebase-m-signoff-fix
* pw/t3428-cleanup:
  t3428: restore coverage for "apply" backend
  t3428: use test_commit_message
  t3428: modernize test setup
2024-04-18 13:33:37 -07:00
Patrick Steinhardt
0c47355790 repository: drop initialize_the_repository()
Now that we have dropped `the_index`, `initialize_the_repository()`
doesn't really do a lot anymore except for setting up the pointer for
`the_repository` and then calling `initialize_repository()`. The former
can be replaced by statically initializing the pointer though, which
basically makes this function moot.

Convert callers to instead call `initialize_repository(the_repository)`
and drop `initialize_thee_repository()`.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-04-18 12:30:43 -07:00
Patrick Steinhardt
19fa8cd48c repository: drop the_index variable
All users of `the_index` have been converted to use either a custom
`struct index_state *` or the index provided by `the_repository`. We can
thus drop the globally-accessible declaration of this variable. In fact,
we can go further than that and drop `the_index` completely now and have
it be allocated dynamically in `initialize_repository()` as all the
other data structures in it are.

This concludes the quest to make Git `the_index` free, which has started
with 4aab5b46f4 (Make read-cache.c "the_index" free., 2007-04-01).

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-04-18 12:30:42 -07:00
Patrick Steinhardt
9ee6d63bab builtin/clone: stop using the_index
Convert git-clone(1) to use `the_repository->index` instead of
`the_index`.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-04-18 12:30:42 -07:00
Patrick Steinhardt
66bce9d00b repository: initialize index in repo_init()
When Git starts, one of the first things it will do is to call
`initialize_the_repository()`. This function sets up both the global
`the_repository` and `the_index` variables as required. Part of that
setup is also to set `the_repository.index = &the_index` so that the
index can be accessed via the repository.

When calling `repo_init()` on a repository though we set the complete
struct to all-zeroes, which will also cause us to unset the `index`
pointer. And as we don't re-initialize the index in that function, we
will end up with a `NULL` pointer here.

This has been fine until now becaues this function is only used to
create a new repository. git-init(1) does not access the index at all
after initializing the repository, whereas git-checkout(1) only uses
`the_index` directly. We are about to remove `the_index` though, which
will uncover this partially-initialized repository structure.

Refactor the code and create a common `initialize_repository()` function
that gets called from `repo_init()` and `initialize_the_repository()`.
This function sets up both the repository and the index as required.
Like this, we can easily special-case when `repo_init()` gets called
with `the_repository`.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-04-18 12:30:42 -07:00
Patrick Steinhardt
f59aa5e0a9 builtin: stop using the_index
Convert builtins to use `the_repository->index` instead of `the_index`.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-04-18 12:30:42 -07:00
Patrick Steinhardt
319ba14407 t/helper: stop using the_index
Convert test-helper tools to use `the_repository->index` instead of
`the_index`.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-04-18 12:30:41 -07:00
Johannes Schindelin
86cb6a3f05 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>
2024-04-17 22:30:24 +02:00
Johannes Schindelin
df93e407f0 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>
2024-04-17 22:30:10 +02:00
Johannes Schindelin
48c171d927 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>
2024-04-17 22:30:09 +02:00
Johannes Schindelin
31572dc420 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>
2024-04-17 22:30:08 +02:00
Johannes Schindelin
850c3a220e 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>
2024-04-17 22:30:07 +02:00
Johannes Schindelin
e4930e86c0 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>
2024-04-17 22:30:06 +02:00
Johannes Schindelin
e8d0608944 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>
2024-04-17 22:30:04 +02:00
Johannes Schindelin
eafffd9ad4 clone_submodule: avoid using access() on directories
In 0060fd1511 (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>
2024-04-17 22:30:03 +02:00