@@ -294,6 +294,9 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,
294
294
struct child_process cp = CHILD_PROCESS_INIT ;
295
295
char * displaypath ;
296
296
297
+ if (validate_submodule_path (path ) < 0 )
298
+ exit (128 );
299
+
297
300
displaypath = get_submodule_displaypath (path , info -> prefix );
298
301
299
302
sub = submodule_from_path (the_repository , null_oid (), path );
@@ -620,6 +623,9 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,
620
623
.free_removed_argv_elements = 1 ,
621
624
};
622
625
626
+ if (validate_submodule_path (path ) < 0 )
627
+ exit (128 );
628
+
623
629
if (!submodule_from_path (the_repository , null_oid (), path ))
624
630
die (_ ("no submodule mapping found in .gitmodules for path '%s'" ),
625
631
path );
@@ -1220,6 +1226,9 @@ static void sync_submodule(const char *path, const char *prefix,
1220
1226
if (!is_submodule_active (the_repository , path ))
1221
1227
return ;
1222
1228
1229
+ if (validate_submodule_path (path ) < 0 )
1230
+ exit (128 );
1231
+
1223
1232
sub = submodule_from_path (the_repository , null_oid (), path );
1224
1233
1225
1234
if (sub && sub -> url ) {
@@ -1360,6 +1369,9 @@ static void deinit_submodule(const char *path, const char *prefix,
1360
1369
struct strbuf sb_config = STRBUF_INIT ;
1361
1370
char * sub_git_dir = xstrfmt ("%s/.git" , path );
1362
1371
1372
+ if (validate_submodule_path (path ) < 0 )
1373
+ exit (128 );
1374
+
1363
1375
sub = submodule_from_path (the_repository , null_oid (), path );
1364
1376
1365
1377
if (!sub || !sub -> name )
@@ -1641,16 +1653,42 @@ static char *clone_submodule_sm_gitdir(const char *name)
1641
1653
return sm_gitdir ;
1642
1654
}
1643
1655
1656
+ static int dir_contains_only_dotgit (const char * path )
1657
+ {
1658
+ DIR * dir = opendir (path );
1659
+ struct dirent * e ;
1660
+ int ret = 1 ;
1661
+
1662
+ if (!dir )
1663
+ return 0 ;
1664
+
1665
+ e = readdir_skip_dot_and_dotdot (dir );
1666
+ if (!e )
1667
+ ret = 0 ;
1668
+ else if (strcmp (DEFAULT_GIT_DIR_ENVIRONMENT , e -> d_name ) ||
1669
+ (e = readdir_skip_dot_and_dotdot (dir ))) {
1670
+ error ("unexpected item '%s' in '%s'" , e -> d_name , path );
1671
+ ret = 0 ;
1672
+ }
1673
+
1674
+ closedir (dir );
1675
+ return ret ;
1676
+ }
1677
+
1644
1678
static int clone_submodule (const struct module_clone_data * clone_data ,
1645
1679
struct string_list * reference )
1646
1680
{
1647
1681
char * p ;
1648
1682
char * sm_gitdir = clone_submodule_sm_gitdir (clone_data -> name );
1649
1683
char * sm_alternate = NULL , * error_strategy = NULL ;
1684
+ struct stat st ;
1650
1685
struct child_process cp = CHILD_PROCESS_INIT ;
1651
1686
const char * clone_data_path = clone_data -> path ;
1652
1687
char * to_free = NULL ;
1653
1688
1689
+ if (validate_submodule_path (clone_data_path ) < 0 )
1690
+ exit (128 );
1691
+
1654
1692
if (!is_absolute_path (clone_data -> path ))
1655
1693
clone_data_path = to_free = xstrfmt ("%s/%s" , get_git_work_tree (),
1656
1694
clone_data -> path );
@@ -1660,6 +1698,10 @@ static int clone_submodule(const struct module_clone_data *clone_data,
1660
1698
"git dir" ), sm_gitdir );
1661
1699
1662
1700
if (!file_exists (sm_gitdir )) {
1701
+ if (clone_data -> require_init && !stat (clone_data_path , & st ) &&
1702
+ !is_empty_dir (clone_data_path ))
1703
+ die (_ ("directory not empty: '%s'" ), clone_data_path );
1704
+
1663
1705
if (safe_create_leading_directories_const (sm_gitdir ) < 0 )
1664
1706
die (_ ("could not create directory '%s'" ), sm_gitdir );
1665
1707
@@ -1704,10 +1746,18 @@ static int clone_submodule(const struct module_clone_data *clone_data,
1704
1746
if (run_command (& cp ))
1705
1747
die (_ ("clone of '%s' into submodule path '%s' failed" ),
1706
1748
clone_data -> url , clone_data_path );
1749
+
1750
+ if (clone_data -> require_init && !stat (clone_data_path , & st ) &&
1751
+ !dir_contains_only_dotgit (clone_data_path )) {
1752
+ char * dot_git = xstrfmt ("%s/.git" , clone_data_path );
1753
+ unlink (dot_git );
1754
+ free (dot_git );
1755
+ die (_ ("directory not empty: '%s'" ), clone_data_path );
1756
+ }
1707
1757
} else {
1708
1758
char * path ;
1709
1759
1710
- if (clone_data -> require_init && !access (clone_data_path , X_OK ) &&
1760
+ if (clone_data -> require_init && !stat (clone_data_path , & st ) &&
1711
1761
!is_empty_dir (clone_data_path ))
1712
1762
die (_ ("directory not empty: '%s'" ), clone_data_path );
1713
1763
if (safe_create_leading_directories_const (clone_data_path ) < 0 )
@@ -1717,6 +1767,23 @@ static int clone_submodule(const struct module_clone_data *clone_data,
1717
1767
free (path );
1718
1768
}
1719
1769
1770
+ /*
1771
+ * We already performed this check at the beginning of this function,
1772
+ * before cloning the objects. This tries to detect racy behavior e.g.
1773
+ * in parallel clones, where another process could easily have made the
1774
+ * gitdir nested _after_ it was created.
1775
+ *
1776
+ * To prevent further harm coming from this unintentionally-nested
1777
+ * gitdir, let's disable it by deleting the `HEAD` file.
1778
+ */
1779
+ if (validate_submodule_git_dir (sm_gitdir , clone_data -> name ) < 0 ) {
1780
+ char * head = xstrfmt ("%s/HEAD" , sm_gitdir );
1781
+ unlink (head );
1782
+ free (head );
1783
+ die (_ ("refusing to create/use '%s' in another submodule's "
1784
+ "git dir" ), sm_gitdir );
1785
+ }
1786
+
1720
1787
connect_work_tree_and_git_dir (clone_data_path , sm_gitdir , 0 );
1721
1788
1722
1789
p = git_pathdup_submodule (clone_data_path , "config" );
@@ -2490,6 +2557,9 @@ static int update_submodule(struct update_data *update_data)
2490
2557
{
2491
2558
int ret ;
2492
2559
2560
+ if (validate_submodule_path (update_data -> sm_path ) < 0 )
2561
+ return -1 ;
2562
+
2493
2563
ret = determine_submodule_update_strategy (the_repository ,
2494
2564
update_data -> just_cloned ,
2495
2565
update_data -> sm_path ,
@@ -2597,12 +2667,21 @@ static int update_submodules(struct update_data *update_data)
2597
2667
2598
2668
for (i = 0 ; i < suc .update_clone_nr ; i ++ ) {
2599
2669
struct update_clone_data ucd = suc .update_clone [i ];
2600
- int code ;
2670
+ int code = 128 ;
2601
2671
2602
2672
oidcpy (& update_data -> oid , & ucd .oid );
2603
2673
update_data -> just_cloned = ucd .just_cloned ;
2604
2674
update_data -> sm_path = ucd .sub -> path ;
2605
2675
2676
+ /*
2677
+ * Verify that the submodule path does not contain any
2678
+ * symlinks; if it does, it might have been tampered with.
2679
+ * TODO: allow exempting it via
2680
+ * `safe.submodule.path` or something
2681
+ */
2682
+ if (validate_submodule_path (update_data -> sm_path ) < 0 )
2683
+ goto fail ;
2684
+
2606
2685
code = ensure_core_worktree (update_data -> sm_path );
2607
2686
if (code )
2608
2687
goto fail ;
@@ -3309,6 +3388,9 @@ static int module_add(int argc, const char **argv, const char *prefix)
3309
3388
normalize_path_copy (add_data .sm_path , add_data .sm_path );
3310
3389
strip_dir_trailing_slashes (add_data .sm_path );
3311
3390
3391
+ if (validate_submodule_path (add_data .sm_path ) < 0 )
3392
+ exit (128 );
3393
+
3312
3394
die_on_index_match (add_data .sm_path , force );
3313
3395
die_on_repo_without_commits (add_data .sm_path );
3314
3396
0 commit comments