File CVE-2024-32020.patch of Package git.34829

commit 9e65df5eab274bf74c7b570107aacd1303a1e703
Merge: 2b3d38a6b1 1204e1a824
Author: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Date:   Sat Apr 13 00:28:19 2024 +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>

diff --combined builtin/clone.c
index 35a73ed0a7,9ec500d427..e7721f5c22
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@@ -320,7 -320,20 +320,20 @@@ static void copy_or_link_directory(stru
  	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);
  
@@@ -358,9 -371,27 +371,27 @@@
  		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;
@@@ -373,8 -404,6 +404,6 @@@
  		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)
@@@ -908,8 -937,6 +937,8 @@@ int cmd_clone(int argc, const char **ar
  	int err = 0, complete_refs_before_fetch = 1;
  	int submodule_progress;
  	int filter_submodules = 0;
 +	const char *template_dir;
 +	char *template_dir_dup = NULL;
  
  	struct transport_ls_refs_options transport_ls_refs_options =
  		TRANSPORT_LS_REFS_OPTIONS_INIT;
@@@ -929,13 -956,6 +958,13 @@@
  		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)
@@@ -1083,7 -1103,7 +1112,7 @@@
  		}
  	}
  
 -	init_db(git_dir, real_git_dir, option_template, GIT_HASH_UNKNOWN, NULL,
 +	init_db(git_dir, real_git_dir, template_dir, GIT_HASH_UNKNOWN, NULL,
  		INIT_DB_QUIET);
  
  	if (real_git_dir) {
@@@ -1401,7 -1421,6 +1430,7 @@@
  	free(unborn_head);
  	free(dir);
  	free(path);
 +	free(template_dir_dup);
  	UNLEAK(repo);
  	junk_mode = JUNK_LEAVE_ALL;
  
openSUSE Build Service is sponsored by