aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick Steinhardt <ps@pks.im>2024-04-15 13:30:31 +0200
committerJohannes Schindelin <johannes.schindelin@gmx.de>2024-04-17 00:01:25 +0200
commitd1bb66a546b4bb46005d17ba711caaad26f26c1e (patch)
treecfa3c90be2598a17fbbe09fd3caadb9aee6aacbd
parentbuiltin/clone: stop resolving symlinks when copying files (diff)
downloadgit-d1bb66a546b4bb46005d17ba711caaad26f26c1e.tar.gz
git-d1bb66a546b4bb46005d17ba711caaad26f26c1e.zip
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>
-rw-r--r--builtin/clone.c21
1 files changed, 20 insertions, 1 deletions
diff --git a/builtin/clone.c b/builtin/clone.c
index 073e6323d7..4b80fa0870 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -357,8 +357,27 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
if (unlink(dest->buf) && errno != ENOENT)
die_errno(_("failed to unlink '%s'"), dest->buf);
if (!option_no_hardlinks) {
- if (!link(src->buf, dest->buf))
+ if (!link(src->buf, dest->buf)) {
+ struct stat st;
+
+ /*
+ * Sanity-check whether the created hardlink
+ * actually links to the expected file now. This
+ * catches time-of-check-time-of-use bugs in
+ * case the source file was meanwhile swapped.
+ */
+ if (lstat(dest->buf, &st))
+ die(_("hardlink cannot be checked at '%s'"), dest->buf);
+ if (st.st_mode != iter->st.st_mode ||
+ st.st_ino != iter->st.st_ino ||
+ st.st_dev != iter->st.st_dev ||
+ st.st_size != iter->st.st_size ||
+ st.st_uid != iter->st.st_uid ||
+ st.st_gid != iter->st.st_gid)
+ die(_("hardlink different from source at '%s'"), dest->buf);
+
continue;
+ }
if (option_local > 0)
die_errno(_("failed to create link '%s'"), dest->buf);
option_no_hardlinks = 1;