3939# include "win32/w32_util.h"
4040#endif
4141
42+ bool git_repository__validate_ownership = true;
4243bool git_repository__fsync_gitdir = false;
4344
4445static const struct {
@@ -65,6 +66,7 @@ static const struct {
6566
6667static int check_repositoryformatversion (int * version , git_config * config );
6768static int check_extensions (git_config * config , int version );
69+ static int load_global_config (git_config * * config );
6870
6971#define GIT_COMMONDIR_FILE "commondir"
7072#define GIT_GITDIR_FILE "gitdir"
@@ -483,6 +485,63 @@ static int read_gitfile(git_str *path_out, const char *file_path)
483485 return error ;
484486}
485487
488+ typedef struct {
489+ const char * repo_path ;
490+ git_str tmp ;
491+ bool is_safe ;
492+ } validate_ownership_data ;
493+
494+ static int validate_ownership_cb (const git_config_entry * entry , void * payload )
495+ {
496+ validate_ownership_data * data = payload ;
497+
498+ if (strcmp (entry -> value , "" ) == 0 )
499+ data -> is_safe = false;
500+
501+ if (git_fs_path_prettify_dir (& data -> tmp , entry -> value , NULL ) == 0 &&
502+ strcmp (data -> tmp .ptr , data -> repo_path ) == 0 )
503+ data -> is_safe = true;
504+
505+ return 0 ;
506+ }
507+
508+ static int validate_ownership (const char * repo_path )
509+ {
510+ git_config * config = NULL ;
511+ validate_ownership_data data = { repo_path , GIT_STR_INIT , false };
512+ bool is_safe ;
513+ int error ;
514+
515+ if ((error = git_fs_path_owner_is_current_user (& is_safe , repo_path )) < 0 ) {
516+ if (error == GIT_ENOTFOUND )
517+ error = 0 ;
518+
519+ goto done ;
520+ }
521+
522+ if (is_safe ) {
523+ error = 0 ;
524+ goto done ;
525+ }
526+
527+ if (load_global_config (& config ) == 0 ) {
528+ error = git_config_get_multivar_foreach (config , "safe.directory" , NULL , validate_ownership_cb , & data );
529+
530+ if (!error && data .is_safe )
531+ goto done ;
532+ }
533+
534+ git_error_set (GIT_ERROR_CONFIG ,
535+ "repository path '%s' is not owned by current user" ,
536+ repo_path );
537+ error = GIT_EOWNER ;
538+
539+ done :
540+ git_config_free (config );
541+ git_str_dispose (& data .tmp );
542+ return error ;
543+ }
544+
486545static int find_repo (
487546 git_str * gitdir_path ,
488547 git_str * workdir_path ,
@@ -856,6 +915,7 @@ int git_repository_open_ext(
856915 gitlink = GIT_STR_INIT , commondir = GIT_STR_INIT ;
857916 git_repository * repo = NULL ;
858917 git_config * config = NULL ;
918+ const char * validation_path ;
859919 int version = 0 ;
860920
861921 if (flags & GIT_REPOSITORY_OPEN_FROM_ENV )
@@ -904,16 +964,24 @@ int git_repository_open_ext(
904964 if ((error = check_extensions (config , version )) < 0 )
905965 goto cleanup ;
906966
907- if ((flags & GIT_REPOSITORY_OPEN_BARE ) != 0 )
967+ if ((flags & GIT_REPOSITORY_OPEN_BARE ) != 0 ) {
908968 repo -> is_bare = 1 ;
909- else {
910-
969+ } else {
911970 if (config &&
912971 ((error = load_config_data (repo , config )) < 0 ||
913972 (error = load_workdir (repo , config , & workdir )) < 0 ))
914973 goto cleanup ;
915974 }
916975
976+ /*
977+ * Ensure that the git directory is owned by the current user.
978+ */
979+ validation_path = repo -> is_bare ? repo -> gitdir : repo -> workdir ;
980+
981+ if (git_repository__validate_ownership &&
982+ (error = validate_ownership (validation_path )) < 0 )
983+ goto cleanup ;
984+
917985cleanup :
918986 git_str_dispose (& gitdir );
919987 git_str_dispose (& workdir );
@@ -1607,13 +1675,40 @@ static bool is_filesystem_case_insensitive(const char *gitdir_path)
16071675 return is_insensitive ;
16081676}
16091677
1610- static bool are_symlinks_supported (const char * wd_path )
1678+ /*
1679+ * Return a configuration object with only the global and system
1680+ * configurations; no repository-level configuration.
1681+ */
1682+ static int load_global_config (git_config * * config )
16111683{
1612- git_config * config = NULL ;
16131684 git_str global_buf = GIT_STR_INIT ;
16141685 git_str xdg_buf = GIT_STR_INIT ;
16151686 git_str system_buf = GIT_STR_INIT ;
16161687 git_str programdata_buf = GIT_STR_INIT ;
1688+ int error ;
1689+
1690+ git_config__find_global (& global_buf );
1691+ git_config__find_xdg (& xdg_buf );
1692+ git_config__find_system (& system_buf );
1693+ git_config__find_programdata (& programdata_buf );
1694+
1695+ error = load_config (config , NULL ,
1696+ path_unless_empty (& global_buf ),
1697+ path_unless_empty (& xdg_buf ),
1698+ path_unless_empty (& system_buf ),
1699+ path_unless_empty (& programdata_buf ));
1700+
1701+ git_str_dispose (& global_buf );
1702+ git_str_dispose (& xdg_buf );
1703+ git_str_dispose (& system_buf );
1704+ git_str_dispose (& programdata_buf );
1705+
1706+ return error ;
1707+ }
1708+
1709+ static bool are_symlinks_supported (const char * wd_path )
1710+ {
1711+ git_config * config = NULL ;
16171712 int symlinks = 0 ;
16181713
16191714 /*
@@ -1624,30 +1719,16 @@ static bool are_symlinks_supported(const char *wd_path)
16241719 * _not_ set, then we do not test or enable symlink support.
16251720 */
16261721#ifdef GIT_WIN32
1627- git_config__find_global (& global_buf );
1628- git_config__find_xdg (& xdg_buf );
1629- git_config__find_system (& system_buf );
1630- git_config__find_programdata (& programdata_buf );
1631-
1632- if (load_config (& config , NULL ,
1633- path_unless_empty (& global_buf ),
1634- path_unless_empty (& xdg_buf ),
1635- path_unless_empty (& system_buf ),
1636- path_unless_empty (& programdata_buf )) < 0 )
1637- goto done ;
1638-
1639- if (git_config_get_bool (& symlinks , config , "core.symlinks" ) < 0 || !symlinks )
1722+ if (load_global_config (& config ) < 0 ||
1723+ git_config_get_bool (& symlinks , config , "core.symlinks" ) < 0 ||
1724+ !symlinks )
16401725 goto done ;
16411726#endif
16421727
16431728 if (!(symlinks = git_fs_path_supports_symlinks (wd_path )))
16441729 goto done ;
16451730
16461731done :
1647- git_str_dispose (& global_buf );
1648- git_str_dispose (& xdg_buf );
1649- git_str_dispose (& system_buf );
1650- git_str_dispose (& programdata_buf );
16511732 git_config_free (config );
16521733 return symlinks != 0 ;
16531734}
0 commit comments