@@ -1055,14 +1055,32 @@ static int safe_directory_cb(const char *key, const char *value, void *d)
1055
1055
return 0 ;
1056
1056
}
1057
1057
1058
- static int ensure_valid_ownership (const char * path )
1058
+ /*
1059
+ * Check if a repository is safe, by verifying the ownership of the
1060
+ * worktree (if any), the git directory, and the gitfile (if any).
1061
+ *
1062
+ * Exemptions for known-safe repositories can be added via `safe.directory`
1063
+ * config settings; for non-bare repositories, their worktree needs to be
1064
+ * added, for bare ones their git directory.
1065
+ */
1066
+ static int ensure_valid_ownership (const char * gitfile ,
1067
+ const char * worktree , const char * gitdir )
1059
1068
{
1060
- struct safe_directory_data data = { .path = path };
1069
+ struct safe_directory_data data = {
1070
+ .path = worktree ? worktree : gitdir
1071
+ };
1061
1072
1062
1073
if (!git_env_bool ("GIT_TEST_ASSUME_DIFFERENT_OWNER" , 0 ) &&
1063
- is_path_owned_by_current_user (path ))
1074
+ (!gitfile || is_path_owned_by_current_user (gitfile )) &&
1075
+ (!worktree || is_path_owned_by_current_user (worktree )) &&
1076
+ (!gitdir || is_path_owned_by_current_user (gitdir )))
1064
1077
return 1 ;
1065
1078
1079
+ /*
1080
+ * data.path is the "path" that identifies the repository and it is
1081
+ * constant regardless of what failed above. data.is_safe should be
1082
+ * initialized to false, and might be changed by the callback.
1083
+ */
1066
1084
read_very_early_config (safe_directory_cb , & data );
1067
1085
1068
1086
return data .is_safe ;
@@ -1150,6 +1168,8 @@ static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir,
1150
1168
current_device = get_device_or_die (dir -> buf , NULL , 0 );
1151
1169
for (;;) {
1152
1170
int offset = dir -> len , error_code = 0 ;
1171
+ char * gitdir_path = NULL ;
1172
+ char * gitfile = NULL ;
1153
1173
1154
1174
if (offset > min_offset )
1155
1175
strbuf_addch (dir , '/' );
@@ -1160,21 +1180,50 @@ static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir,
1160
1180
if (die_on_error ||
1161
1181
error_code == READ_GITFILE_ERR_NOT_A_FILE ) {
1162
1182
/* NEEDSWORK: fail if .git is not file nor dir */
1163
- if (is_git_directory (dir -> buf ))
1183
+ if (is_git_directory (dir -> buf )) {
1164
1184
gitdirenv = DEFAULT_GIT_DIR_ENVIRONMENT ;
1185
+ gitdir_path = xstrdup (dir -> buf );
1186
+ }
1165
1187
} else if (error_code != READ_GITFILE_ERR_STAT_FAILED )
1166
1188
return GIT_DIR_INVALID_GITFILE ;
1167
- }
1189
+ } else
1190
+ gitfile = xstrdup (dir -> buf );
1191
+ /*
1192
+ * Earlier, we tentatively added DEFAULT_GIT_DIR_ENVIRONMENT
1193
+ * to check that directory for a repository.
1194
+ * Now trim that tentative addition away, because we want to
1195
+ * focus on the real directory we are in.
1196
+ */
1168
1197
strbuf_setlen (dir , offset );
1169
1198
if (gitdirenv ) {
1170
- if (!ensure_valid_ownership (dir -> buf ))
1171
- return GIT_DIR_INVALID_OWNERSHIP ;
1172
- strbuf_addstr (gitdir , gitdirenv );
1173
- return GIT_DIR_DISCOVERED ;
1199
+ enum discovery_result ret ;
1200
+
1201
+ if (ensure_valid_ownership (gitfile ,
1202
+ dir -> buf ,
1203
+ (gitdir_path ? gitdir_path : gitdirenv ))) {
1204
+ strbuf_addstr (gitdir , gitdirenv );
1205
+ ret = GIT_DIR_DISCOVERED ;
1206
+ } else
1207
+ ret = GIT_DIR_INVALID_OWNERSHIP ;
1208
+
1209
+ /*
1210
+ * Earlier, during discovery, we might have allocated
1211
+ * string copies for gitdir_path or gitfile so make
1212
+ * sure we don't leak by freeing them now, before
1213
+ * leaving the loop and function.
1214
+ *
1215
+ * Note: gitdirenv will be non-NULL whenever these are
1216
+ * allocated, therefore we need not take care of releasing
1217
+ * them outside of this conditional block.
1218
+ */
1219
+ free (gitdir_path );
1220
+ free (gitfile );
1221
+
1222
+ return ret ;
1174
1223
}
1175
1224
1176
1225
if (is_git_directory (dir -> buf )) {
1177
- if (!ensure_valid_ownership (dir -> buf ))
1226
+ if (!ensure_valid_ownership (NULL , NULL , dir -> buf ))
1178
1227
return GIT_DIR_INVALID_OWNERSHIP ;
1179
1228
strbuf_addstr (gitdir , "." );
1180
1229
return GIT_DIR_BARE ;
@@ -1312,7 +1361,7 @@ const char *setup_git_directory_gently(int *nongit_ok)
1312
1361
struct strbuf quoted = STRBUF_INIT ;
1313
1362
1314
1363
sq_quote_buf_pretty (& quoted , dir .buf );
1315
- die (_ ("unsafe repository ( '%s' is owned by someone else) \n"
1364
+ die (_ ("detected dubious ownership in repository at '%s'\n"
1316
1365
"To add an exception for this directory, call:\n"
1317
1366
"\n"
1318
1367
"\tgit config --global --add safe.directory %s" ),
0 commit comments