@@ -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 )
@@ -938,6 +967,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
938
967
int hash_algo ;
939
968
unsigned int ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN ;
940
969
const int do_not_override_repo_unix_permissions = -1 ;
970
+ const char * template_dir ;
971
+ char * template_dir_dup = NULL ;
941
972
942
973
struct transport_ls_refs_options transport_ls_refs_options =
943
974
TRANSPORT_LS_REFS_OPTIONS_INIT ;
@@ -957,6 +988,13 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
957
988
usage_msg_opt (_ ("You must specify a repository to clone." ),
958
989
builtin_clone_usage , builtin_clone_options );
959
990
991
+ xsetenv ("GIT_CLONE_PROTECTION_ACTIVE" , "true" , 0 /* allow user override */ );
992
+ template_dir = get_template_dir (option_template );
993
+ if (* template_dir && !is_absolute_path (template_dir ))
994
+ template_dir = template_dir_dup =
995
+ absolute_pathdup (template_dir );
996
+ xsetenv ("GIT_CLONE_TEMPLATE_DIR" , template_dir , 1 );
997
+
960
998
if (option_depth || option_since || option_not .nr )
961
999
deepen = 1 ;
962
1000
if (option_single_branch == -1 )
@@ -1118,7 +1156,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
1118
1156
* repository, and reference backends may persist that information into
1119
1157
* their on-disk data structures.
1120
1158
*/
1121
- init_db (git_dir , real_git_dir , option_template , GIT_HASH_UNKNOWN ,
1159
+ init_db (git_dir , real_git_dir , template_dir , GIT_HASH_UNKNOWN ,
1122
1160
ref_storage_format , NULL ,
1123
1161
do_not_override_repo_unix_permissions , INIT_DB_QUIET | INIT_DB_SKIP_REFDB );
1124
1162
@@ -1507,6 +1545,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
1507
1545
free (dir );
1508
1546
free (path );
1509
1547
free (repo_to_free );
1548
+ free (template_dir_dup );
1510
1549
junk_mode = JUNK_LEAVE_ALL ;
1511
1550
1512
1551
transport_ls_refs_options_release (& transport_ls_refs_options );
0 commit comments