@@ -1129,14 +1129,32 @@ static int safe_directory_cb(const char *key, const char *value, void *d)
1129
1129
return 0 ;
1130
1130
}
1131
1131
1132
- static int ensure_valid_ownership (const char * path )
1132
+ /*
1133
+ * Check if a repository is safe, by verifying the ownership of the
1134
+ * worktree (if any), the git directory, and the gitfile (if any).
1135
+ *
1136
+ * Exemptions for known-safe repositories can be added via `safe.directory`
1137
+ * config settings; for non-bare repositories, their worktree needs to be
1138
+ * added, for bare ones their git directory.
1139
+ */
1140
+ static int ensure_valid_ownership (const char * gitfile ,
1141
+ const char * worktree , const char * gitdir )
1133
1142
{
1134
- struct safe_directory_data data = { .path = path };
1143
+ struct safe_directory_data data = {
1144
+ .path = worktree ? worktree : gitdir
1145
+ };
1135
1146
1136
1147
if (!git_env_bool ("GIT_TEST_ASSUME_DIFFERENT_OWNER" , 0 ) &&
1137
- is_path_owned_by_current_user (path ))
1148
+ (!gitfile || is_path_owned_by_current_user (gitfile )) &&
1149
+ (!worktree || is_path_owned_by_current_user (worktree )) &&
1150
+ (!gitdir || is_path_owned_by_current_user (gitdir )))
1138
1151
return 1 ;
1139
1152
1153
+ /*
1154
+ * data.path is the "path" that identifies the repository and it is
1155
+ * constant regardless of what failed above. data.is_safe should be
1156
+ * initialized to false, and might be changed by the callback.
1157
+ */
1140
1158
read_very_early_config (safe_directory_cb , & data );
1141
1159
1142
1160
return data .is_safe ;
@@ -1224,6 +1242,8 @@ static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir,
1224
1242
current_device = get_device_or_die (dir -> buf , NULL , 0 );
1225
1243
for (;;) {
1226
1244
int offset = dir -> len , error_code = 0 ;
1245
+ char * gitdir_path = NULL ;
1246
+ char * gitfile = NULL ;
1227
1247
1228
1248
if (offset > min_offset )
1229
1249
strbuf_addch (dir , '/' );
@@ -1234,21 +1254,50 @@ static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir,
1234
1254
if (die_on_error ||
1235
1255
error_code == READ_GITFILE_ERR_NOT_A_FILE ) {
1236
1256
/* NEEDSWORK: fail if .git is not file nor dir */
1237
- if (is_git_directory (dir -> buf ))
1257
+ if (is_git_directory (dir -> buf )) {
1238
1258
gitdirenv = DEFAULT_GIT_DIR_ENVIRONMENT ;
1259
+ gitdir_path = xstrdup (dir -> buf );
1260
+ }
1239
1261
} else if (error_code != READ_GITFILE_ERR_STAT_FAILED )
1240
1262
return GIT_DIR_INVALID_GITFILE ;
1241
- }
1263
+ } else
1264
+ gitfile = xstrdup (dir -> buf );
1265
+ /*
1266
+ * Earlier, we tentatively added DEFAULT_GIT_DIR_ENVIRONMENT
1267
+ * to check that directory for a repository.
1268
+ * Now trim that tentative addition away, because we want to
1269
+ * focus on the real directory we are in.
1270
+ */
1242
1271
strbuf_setlen (dir , offset );
1243
1272
if (gitdirenv ) {
1244
- if (!ensure_valid_ownership (dir -> buf ))
1245
- return GIT_DIR_INVALID_OWNERSHIP ;
1246
- strbuf_addstr (gitdir , gitdirenv );
1247
- return GIT_DIR_DISCOVERED ;
1273
+ enum discovery_result ret ;
1274
+
1275
+ if (ensure_valid_ownership (gitfile ,
1276
+ dir -> buf ,
1277
+ (gitdir_path ? gitdir_path : gitdirenv ))) {
1278
+ strbuf_addstr (gitdir , gitdirenv );
1279
+ ret = GIT_DIR_DISCOVERED ;
1280
+ } else
1281
+ ret = GIT_DIR_INVALID_OWNERSHIP ;
1282
+
1283
+ /*
1284
+ * Earlier, during discovery, we might have allocated
1285
+ * string copies for gitdir_path or gitfile so make
1286
+ * sure we don't leak by freeing them now, before
1287
+ * leaving the loop and function.
1288
+ *
1289
+ * Note: gitdirenv will be non-NULL whenever these are
1290
+ * allocated, therefore we need not take care of releasing
1291
+ * them outside of this conditional block.
1292
+ */
1293
+ free (gitdir_path );
1294
+ free (gitfile );
1295
+
1296
+ return ret ;
1248
1297
}
1249
1298
1250
1299
if (is_git_directory (dir -> buf )) {
1251
- if (!ensure_valid_ownership (dir -> buf ))
1300
+ if (!ensure_valid_ownership (NULL , NULL , dir -> buf ))
1252
1301
return GIT_DIR_INVALID_OWNERSHIP ;
1253
1302
strbuf_addstr (gitdir , "." );
1254
1303
return GIT_DIR_BARE ;
@@ -1386,7 +1435,7 @@ const char *setup_git_directory_gently(int *nongit_ok)
1386
1435
struct strbuf quoted = STRBUF_INIT ;
1387
1436
1388
1437
sq_quote_buf_pretty (& quoted , dir .buf );
1389
- die (_ ("unsafe repository ( '%s' is owned by someone else) \n"
1438
+ die (_ ("detected dubious ownership in repository at '%s'\n"
1390
1439
"To add an exception for this directory, call:\n"
1391
1440
"\n"
1392
1441
"\tgit config --global --add safe.directory %s" ),
0 commit comments