diff options
| author | Johannes Schindelin <johannes.schindelin@gmx.de> | 2019-10-02 13:08:45 +0200 |
|---|---|---|
| committer | Johannes Schindelin <johannes.schindelin@gmx.de> | 2019-12-05 15:37:08 +0100 |
| commit | 76a681ce9c20e2827ebc02ca8c29fa6a3e946190 (patch) | |
| tree | 3055874d4666b3364d15cc205dc36e9680f294d9 /submodule.c | |
| parent | dd53ea7220606f9ed36db5a0ef910143fdac2903 (diff) | |
| parent | a8dee3ca610f5a1d403634492136c887f83b59d2 (diff) | |
| download | git-76a681ce9c20e2827ebc02ca8c29fa6a3e946190.tar.xz | |
Merge branch 'dubiously-nested-submodules'
Recursive clones are currently affected by a vulnerability that is
caused by too-lax validation of submodule names.
This topic branch fixes that.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Diffstat (limited to 'submodule.c')
| -rw-r--r-- | submodule.c | 49 |
1 files changed, 47 insertions, 2 deletions
diff --git a/submodule.c b/submodule.c index 36f45f5a5a..9abc90d9cd 100644 --- a/submodule.c +++ b/submodule.c @@ -1842,6 +1842,47 @@ int parallel_submodules(void) return parallel_jobs; } +int validate_submodule_git_dir(char *git_dir, const char *submodule_name) +{ + size_t len = strlen(git_dir), suffix_len = strlen(submodule_name); + char *p; + int ret = 0; + + if (len <= suffix_len || (p = git_dir + len - suffix_len)[-1] != '/' || + strcmp(p, submodule_name)) + BUG("submodule name '%s' not a suffix of git dir '%s'", + submodule_name, git_dir); + + /* + * We prevent the contents of sibling submodules' git directories to + * clash. + * + * Example: having a submodule named `hippo` and another one named + * `hippo/hooks` would result in the git directories + * `.git/modules/hippo/` and `.git/modules/hippo/hooks/`, respectively, + * but the latter directory is already designated to contain the hooks + * of the former. + */ + for (; *p; p++) { + if (is_dir_sep(*p)) { + char c = *p; + + *p = '\0'; + if (is_git_directory(git_dir)) + ret = -1; + *p = c; + + if (ret < 0) + return error(_("submodule git dir '%s' is " + "inside git dir '%.*s'"), + git_dir, + (int)(p - git_dir), git_dir); + } + } + + return 0; +} + /* * Embeds a single submodules git directory into the superprojects git dir, * non recursively. @@ -1850,7 +1891,7 @@ static void relocate_single_git_dir_into_superproject(const char *prefix, const char *path) { char *old_git_dir = NULL, *real_old_git_dir = NULL, *real_new_git_dir = NULL; - const char *new_git_dir; + char *new_git_dir; const struct submodule *sub; if (submodule_uses_worktrees(path)) @@ -1868,10 +1909,14 @@ static void relocate_single_git_dir_into_superproject(const char *prefix, if (!sub) die(_("could not lookup name for submodule '%s'"), path); - new_git_dir = git_path("modules/%s", sub->name); + new_git_dir = git_pathdup("modules/%s", sub->name); + if (validate_submodule_git_dir(new_git_dir, sub->name) < 0) + die(_("refusing to move '%s' into an existing git dir"), + real_old_git_dir); if (safe_create_leading_directories_const(new_git_dir) < 0) die(_("could not create directory '%s'"), new_git_dir); real_new_git_dir = real_pathdup(new_git_dir, 1); + free(new_git_dir); fprintf(stderr, _("Migrating git directory of '%s%s' from\n'%s' to\n'%s'\n"), get_super_prefix_or_empty(), path, |
