@@ -488,60 +488,110 @@ static int read_gitfile(git_str *path_out, const char *file_path)
488488typedef struct {
489489 const char * repo_path ;
490490 git_str tmp ;
491- bool is_safe ;
491+ bool * is_safe ;
492492} validate_ownership_data ;
493493
494494static int validate_ownership_cb (const git_config_entry * entry , void * payload )
495495{
496496 validate_ownership_data * data = payload ;
497497
498498 if (strcmp (entry -> value , "" ) == 0 )
499- data -> is_safe = false;
499+ * data -> is_safe = false;
500500
501501 if (git_fs_path_prettify_dir (& data -> tmp , entry -> value , NULL ) == 0 &&
502502 strcmp (data -> tmp .ptr , data -> repo_path ) == 0 )
503- data -> is_safe = true;
503+ * data -> is_safe = true;
504504
505505 return 0 ;
506506}
507507
508- static int validate_ownership ( const char * repo_path )
508+ static int validate_ownership_config ( bool * is_safe , const char * path )
509509{
510- git_config * config = NULL ;
511- validate_ownership_data data = { repo_path , GIT_STR_INIT , false };
512- git_fs_path_owner_t owner_level =
513- GIT_FS_PATH_OWNER_CURRENT_USER |
514- GIT_FS_PATH_USER_IS_ADMINISTRATOR ;
515- bool is_safe ;
510+ validate_ownership_data ownership_data = {
511+ path , GIT_STR_INIT , is_safe
512+ };
513+ git_config * config ;
516514 int error ;
517515
518- if ((error = git_fs_path_owner_is (& is_safe , repo_path , owner_level )) < 0 ) {
519- if (error == GIT_ENOTFOUND )
520- error = 0 ;
516+ if (load_global_config (& config ) != 0 )
517+ return 0 ;
521518
522- goto done ;
523- }
519+ error = git_config_get_multivar_foreach (config ,
520+ "safe.directory" , NULL ,
521+ validate_ownership_cb ,
522+ & ownership_data );
523+
524+ git_config_free (config );
525+ git_str_dispose (& ownership_data .tmp );
524526
525- if (is_safe ) {
527+ return error ;
528+ }
529+
530+ static int validate_ownership_path (bool * is_safe , const char * path )
531+ {
532+ git_fs_path_owner_t owner_level =
533+ GIT_FS_PATH_OWNER_CURRENT_USER |
534+ GIT_FS_PATH_USER_IS_ADMINISTRATOR |
535+ GIT_FS_PATH_OWNER_RUNNING_SUDO ;
536+ int error = 0 ;
537+
538+ if (path )
539+ error = git_fs_path_owner_is (is_safe , path , owner_level );
540+
541+ if (error == GIT_ENOTFOUND ) {
542+ * is_safe = true;
526543 error = 0 ;
527- goto done ;
528544 }
529545
530- if (load_global_config (& config ) == 0 ) {
531- error = git_config_get_multivar_foreach (config , "safe.directory" , NULL , validate_ownership_cb , & data );
546+ return error ;
547+ }
548+
549+ static int validate_ownership (git_repository * repo )
550+ {
551+ const char * validation_paths [3 ] = { NULL }, * path ;
552+ size_t validation_len = 0 , i ;
553+ bool is_safe = false;
554+ int error = 0 ;
555+
556+ /*
557+ * If there's a worktree, validate the permissions to it *and*
558+ * the git directory, and use the worktree as the configuration
559+ * key for allowlisting the directory. In a bare setup, only
560+ * look at the gitdir and use that as the allowlist. So we
561+ * examine all `validation_paths` but use only the first as
562+ * the configuration lookup.
563+ */
564+
565+ if (repo -> workdir )
566+ validation_paths [validation_len ++ ] = repo -> workdir ;
532567
533- if (!error && data .is_safe )
568+ if (repo -> gitlink )
569+ validation_paths [validation_len ++ ] = repo -> gitlink ;
570+
571+ validation_paths [validation_len ++ ] = repo -> gitdir ;
572+
573+ for (i = 0 ; i < validation_len ; i ++ ) {
574+ path = validation_paths [i ];
575+
576+ if ((error = validate_ownership_path (& is_safe , path )) < 0 )
534577 goto done ;
578+
579+ if (!is_safe )
580+ break ;
535581 }
536582
537- git_error_set (GIT_ERROR_CONFIG ,
538- "repository path '%s' is not owned by current user" ,
539- repo_path );
540- error = GIT_EOWNER ;
583+ if (is_safe ||
584+ (error = validate_ownership_config (& is_safe , validation_paths [0 ])) < 0 )
585+ goto done ;
586+
587+ if (!is_safe ) {
588+ git_error_set (GIT_ERROR_CONFIG ,
589+ "repository path '%s' is not owned by current user" ,
590+ path );
591+ error = GIT_EOWNER ;
592+ }
541593
542594done :
543- git_config_free (config );
544- git_str_dispose (& data .tmp );
545595 return error ;
546596}
547597
@@ -918,7 +968,6 @@ int git_repository_open_ext(
918968 gitlink = GIT_STR_INIT , commondir = GIT_STR_INIT ;
919969 git_repository * repo = NULL ;
920970 git_config * config = NULL ;
921- const char * validation_path ;
922971 int version = 0 ;
923972
924973 if (flags & GIT_REPOSITORY_OPEN_FROM_ENV )
@@ -977,12 +1026,11 @@ int git_repository_open_ext(
9771026 }
9781027
9791028 /*
980- * Ensure that the git directory is owned by the current user.
1029+ * Ensure that the git directory and worktree are
1030+ * owned by the current user.
9811031 */
982- validation_path = repo -> is_bare ? repo -> gitdir : repo -> workdir ;
983-
9841032 if (git_repository__validate_ownership &&
985- (error = validate_ownership (validation_path )) < 0 )
1033+ (error = validate_ownership (repo )) < 0 )
9861034 goto cleanup ;
9871035
9881036cleanup :
0 commit comments