submodule: require the submodule path to contain directories only
Submodules are stored in subdirectories of their superproject. When these subdirectories have been replaced with symlinks by a malicious actor, all kinds of mayhem can be caused. This _should_ not be possible, but many CVEs in the past showed that _when_ possible, it allows attackers to slip in code that gets executed during, say, a `git clone --recursive` operation. Let's add some defense-in-depth to disallow submodule paths to have anything except directories in them. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This commit is contained in:
@ -294,6 +294,9 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,
|
||||
struct child_process cp = CHILD_PROCESS_INIT;
|
||||
char *displaypath;
|
||||
|
||||
if (validate_submodule_path(path) < 0)
|
||||
exit(128);
|
||||
|
||||
displaypath = get_submodule_displaypath(path, info->prefix);
|
||||
|
||||
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,
|
||||
.free_removed_argv_elements = 1,
|
||||
};
|
||||
|
||||
if (validate_submodule_path(path) < 0)
|
||||
exit(128);
|
||||
|
||||
if (!submodule_from_path(the_repository, null_oid(), path))
|
||||
die(_("no submodule mapping found in .gitmodules for path '%s'"),
|
||||
path);
|
||||
@ -1220,6 +1226,9 @@ static void sync_submodule(const char *path, const char *prefix,
|
||||
if (!is_submodule_active(the_repository, path))
|
||||
return;
|
||||
|
||||
if (validate_submodule_path(path) < 0)
|
||||
exit(128);
|
||||
|
||||
sub = submodule_from_path(the_repository, null_oid(), path);
|
||||
|
||||
if (sub && sub->url) {
|
||||
@ -1360,6 +1369,9 @@ static void deinit_submodule(const char *path, const char *prefix,
|
||||
struct strbuf sb_config = STRBUF_INIT;
|
||||
char *sub_git_dir = xstrfmt("%s/.git", path);
|
||||
|
||||
if (validate_submodule_path(path) < 0)
|
||||
exit(128);
|
||||
|
||||
sub = submodule_from_path(the_repository, null_oid(), path);
|
||||
|
||||
if (!sub || !sub->name)
|
||||
@ -1674,6 +1686,9 @@ static int clone_submodule(const struct module_clone_data *clone_data,
|
||||
const char *clone_data_path = clone_data->path;
|
||||
char *to_free = NULL;
|
||||
|
||||
if (validate_submodule_path(clone_data_path) < 0)
|
||||
exit(128);
|
||||
|
||||
if (!is_absolute_path(clone_data->path))
|
||||
clone_data_path = to_free = xstrfmt("%s/%s", get_git_work_tree(),
|
||||
clone_data->path);
|
||||
@ -2542,6 +2557,9 @@ static int update_submodule(struct update_data *update_data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (validate_submodule_path(update_data->sm_path) < 0)
|
||||
return -1;
|
||||
|
||||
ret = determine_submodule_update_strategy(the_repository,
|
||||
update_data->just_cloned,
|
||||
update_data->sm_path,
|
||||
@ -2649,12 +2667,21 @@ static int update_submodules(struct update_data *update_data)
|
||||
|
||||
for (i = 0; i < suc.update_clone_nr; i++) {
|
||||
struct update_clone_data ucd = suc.update_clone[i];
|
||||
int code;
|
||||
int code = 128;
|
||||
|
||||
oidcpy(&update_data->oid, &ucd.oid);
|
||||
update_data->just_cloned = ucd.just_cloned;
|
||||
update_data->sm_path = ucd.sub->path;
|
||||
|
||||
/*
|
||||
* Verify that the submodule path does not contain any
|
||||
* symlinks; if it does, it might have been tampered with.
|
||||
* TODO: allow exempting it via
|
||||
* `safe.submodule.path` or something
|
||||
*/
|
||||
if (validate_submodule_path(update_data->sm_path) < 0)
|
||||
goto fail;
|
||||
|
||||
code = ensure_core_worktree(update_data->sm_path);
|
||||
if (code)
|
||||
goto fail;
|
||||
@ -3361,6 +3388,9 @@ static int module_add(int argc, const char **argv, const char *prefix)
|
||||
normalize_path_copy(add_data.sm_path, add_data.sm_path);
|
||||
strip_dir_trailing_slashes(add_data.sm_path);
|
||||
|
||||
if (validate_submodule_path(add_data.sm_path) < 0)
|
||||
exit(128);
|
||||
|
||||
die_on_index_match(add_data.sm_path, force);
|
||||
die_on_repo_without_commits(add_data.sm_path);
|
||||
|
||||
|
Reference in New Issue
Block a user