@@ -329,7 +329,20 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
329
329
int src_len , dest_len ;
330
330
struct dir_iterator * iter ;
331
331
int iter_status ;
332
- struct strbuf realpath = STRBUF_INIT ;
332
+
333
+ /*
334
+ * Refuse copying directories by default which aren't owned by us. The
335
+ * code that performs either the copying or hardlinking is not prepared
336
+ * to handle various edge cases where an adversary may for example
337
+ * racily swap out files for symlinks. This can cause us to
338
+ * inadvertently use the wrong source file.
339
+ *
340
+ * Furthermore, even if we were prepared to handle such races safely,
341
+ * creating hardlinks across user boundaries is an inherently unsafe
342
+ * operation as the hardlinked files can be rewritten at will by the
343
+ * potentially-untrusted user. We thus refuse to do so by default.
344
+ */
345
+ die_upon_dubious_ownership (NULL , NULL , src_repo );
333
346
334
347
mkdir_if_missing (dest -> buf , 0777 );
335
348
@@ -377,9 +390,27 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
377
390
if (unlink (dest -> buf ) && errno != ENOENT )
378
391
die_errno (_ ("failed to unlink '%s'" ), dest -> buf );
379
392
if (!option_no_hardlinks ) {
380
- strbuf_realpath (& realpath , src -> buf , 1 );
381
- if (!link (realpath .buf , dest -> buf ))
393
+ if (!link (src -> buf , dest -> buf )) {
394
+ struct stat st ;
395
+
396
+ /*
397
+ * Sanity-check whether the created hardlink
398
+ * actually links to the expected file now. This
399
+ * catches time-of-check-time-of-use bugs in
400
+ * case the source file was meanwhile swapped.
401
+ */
402
+ if (lstat (dest -> buf , & st ))
403
+ die (_ ("hardlink cannot be checked at '%s'" ), dest -> buf );
404
+ if (st .st_mode != iter -> st .st_mode ||
405
+ st .st_ino != iter -> st .st_ino ||
406
+ st .st_dev != iter -> st .st_dev ||
407
+ st .st_size != iter -> st .st_size ||
408
+ st .st_uid != iter -> st .st_uid ||
409
+ st .st_gid != iter -> st .st_gid )
410
+ die (_ ("hardlink different from source at '%s'" ), dest -> buf );
411
+
382
412
continue ;
413
+ }
383
414
if (option_local > 0 )
384
415
die_errno (_ ("failed to create link '%s'" ), dest -> buf );
385
416
option_no_hardlinks = 1 ;
@@ -392,8 +423,6 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
392
423
strbuf_setlen (src , src_len );
393
424
die (_ ("failed to iterate over '%s'" ), src -> buf );
394
425
}
395
-
396
- strbuf_release (& realpath );
397
426
}
398
427
399
428
static void clone_local (const char * src_repo , const char * dest_repo )
@@ -936,6 +965,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
936
965
int hash_algo ;
937
966
unsigned int ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN ;
938
967
const int do_not_override_repo_unix_permissions = -1 ;
968
+ const char * template_dir ;
969
+ char * template_dir_dup = NULL ;
939
970
940
971
struct transport_ls_refs_options transport_ls_refs_options =
941
972
TRANSPORT_LS_REFS_OPTIONS_INIT ;
@@ -955,6 +986,13 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
955
986
usage_msg_opt (_ ("You must specify a repository to clone." ),
956
987
builtin_clone_usage , builtin_clone_options );
957
988
989
+ xsetenv ("GIT_CLONE_PROTECTION_ACTIVE" , "true" , 0 /* allow user override */ );
990
+ template_dir = get_template_dir (option_template );
991
+ if (* template_dir && !is_absolute_path (template_dir ))
992
+ template_dir = template_dir_dup =
993
+ absolute_pathdup (template_dir );
994
+ xsetenv ("GIT_CLONE_TEMPLATE_DIR" , template_dir , 1 );
995
+
958
996
if (option_depth || option_since || option_not .nr )
959
997
deepen = 1 ;
960
998
if (option_single_branch == -1 )
@@ -1116,7 +1154,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
1116
1154
* repository, and reference backends may persist that information into
1117
1155
* their on-disk data structures.
1118
1156
*/
1119
- init_db (git_dir , real_git_dir , option_template , GIT_HASH_UNKNOWN ,
1157
+ init_db (git_dir , real_git_dir , template_dir , GIT_HASH_UNKNOWN ,
1120
1158
ref_storage_format , NULL ,
1121
1159
do_not_override_repo_unix_permissions , INIT_DB_QUIET | INIT_DB_SKIP_REFDB );
1122
1160
@@ -1460,6 +1498,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
1460
1498
free (dir );
1461
1499
free (path );
1462
1500
free (repo_to_free );
1501
+ free (template_dir_dup );
1463
1502
junk_mode = JUNK_LEAVE_ALL ;
1464
1503
1465
1504
transport_ls_refs_options_release (& transport_ls_refs_options );
0 commit comments