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
  ...
This commit is contained in:
Johannes Schindelin
2024-04-10 22:10:06 +02:00
45 changed files with 1281 additions and 87 deletions

View File

@ -329,7 +329,20 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
int src_len, dest_len;
struct dir_iterator *iter;
int iter_status;
struct strbuf realpath = STRBUF_INIT;
/*
* Refuse copying directories by default which aren't owned by us. The
* code that performs either the copying or hardlinking is not prepared
* to handle various edge cases where an adversary may for example
* racily swap out files for symlinks. This can cause us to
* inadvertently use the wrong source file.
*
* Furthermore, even if we were prepared to handle such races safely,
* creating hardlinks across user boundaries is an inherently unsafe
* operation as the hardlinked files can be rewritten at will by the
* potentially-untrusted user. We thus refuse to do so by default.
*/
die_upon_dubious_ownership(NULL, NULL, src_repo);
mkdir_if_missing(dest->buf, 0777);
@ -377,9 +390,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) {
strbuf_realpath(&realpath, src->buf, 1);
if (!link(realpath.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;
@ -392,8 +423,6 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
strbuf_setlen(src, src_len);
die(_("failed to iterate over '%s'"), src->buf);
}
strbuf_release(&realpath);
}
static void clone_local(const char *src_repo, const char *dest_repo)
@ -936,6 +965,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
int hash_algo;
unsigned int ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN;
const int do_not_override_repo_unix_permissions = -1;
const char *template_dir;
char *template_dir_dup = NULL;
struct transport_ls_refs_options transport_ls_refs_options =
TRANSPORT_LS_REFS_OPTIONS_INIT;
@ -955,6 +986,13 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
usage_msg_opt(_("You must specify a repository to clone."),
builtin_clone_usage, builtin_clone_options);
xsetenv("GIT_CLONE_PROTECTION_ACTIVE", "true", 0 /* allow user override */);
template_dir = get_template_dir(option_template);
if (*template_dir && !is_absolute_path(template_dir))
template_dir = template_dir_dup =
absolute_pathdup(template_dir);
xsetenv("GIT_CLONE_TEMPLATE_DIR", template_dir, 1);
if (option_depth || option_since || option_not.nr)
deepen = 1;
if (option_single_branch == -1)
@ -1116,7 +1154,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
* repository, and reference backends may persist that information into
* their on-disk data structures.
*/
init_db(git_dir, real_git_dir, option_template, GIT_HASH_UNKNOWN,
init_db(git_dir, real_git_dir, template_dir, GIT_HASH_UNKNOWN,
ref_storage_format, NULL,
do_not_override_repo_unix_permissions, INIT_DB_QUIET | INIT_DB_SKIP_REFDB);
@ -1460,6 +1498,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
free(dir);
free(path);
free(repo_to_free);
free(template_dir_dup);
junk_mode = JUNK_LEAVE_ALL;
transport_ls_refs_options_release(&transport_ls_refs_options);