summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/submodule.c28
-rw-r--r--src/submodule.h13
-rw-r--r--tests/submodule/escape.c29
3 files changed, 55 insertions, 15 deletions
diff --git a/src/submodule.c b/src/submodule.c
index b7b28acd5..a7f76d3c5 100644
--- a/src/submodule.c
+++ b/src/submodule.c
@@ -214,7 +214,7 @@ static void free_submodule_names(git_strmap *names)
* TODO: for some use-cases, this might need case-folding on a
* case-insensitive filesystem
*/
-static int load_submodule_names(git_strmap *out, git_config *cfg)
+static int load_submodule_names(git_strmap *out, git_repository *repo, git_config *cfg)
{
const char *key = "submodule\\..*\\.path";
git_config_iterator *iter;
@@ -232,6 +232,9 @@ static int load_submodule_names(git_strmap *out, git_config *cfg)
ldot = strrchr(entry->name, '.');
git_buf_put(&buf, fdot + 1, ldot - fdot - 1);
+ if (!git_submodule_name_is_valid(repo, buf.ptr, 0))
+ continue;
+
git_strmap_insert(out, entry->value, git_buf_detach(&buf), &rval);
if (rval < 0) {
giterr_set(GITERR_NOMEMORY, "error inserting submodule into hash table");
@@ -359,6 +362,15 @@ int git_submodule_lookup(
return 0;
}
+int git_submodule_name_is_valid(const git_repository *repo, const char *name, int flags)
+{
+ if (flags == 0)
+ flags = GIT_PATH_REJECT_FILESYSTEM_DEFAULTS;
+
+ /* FIXME: Un-consting it to reduce the amount of diff */
+ return git_path_isvalid((git_repository *)repo, name, flags);
+}
+
static void submodule_free_dup(void *sm)
{
git_submodule_free(sm);
@@ -404,7 +416,7 @@ static int submodules_from_index(git_strmap *map, git_index *idx, git_config *cf
git_strmap *names = 0;
git_strmap_alloc(&names);
- if ((error = load_submodule_names(names, cfg)))
+ if ((error = load_submodule_names(names, git_index_owner(idx), cfg)))
goto done;
if ((error = git_iterator_for_index(&i, git_index_owner(idx), idx, NULL)) < 0)
@@ -456,7 +468,7 @@ static int submodules_from_head(git_strmap *map, git_tree *head, git_config *cfg
const git_index_entry *entry;
git_strmap *names = 0;
git_strmap_alloc(&names);
- if ((error = load_submodule_names(names, cfg)))
+ if ((error = load_submodule_names(names, git_tree_owner(head), cfg)))
goto done;
if ((error = git_iterator_for_tree(&i, head, NULL)) < 0)
@@ -1566,6 +1578,11 @@ int git_submodule_reload(git_submodule *sm, int force)
assert(sm);
+ if (!git_submodule_name_is_valid(sm->repo, sm->name, 0)) {
+ /* This should come with a warning, but we've no API for that */
+ return 0;
+ }
+
if (!git_repository_is_bare(sm->repo)) {
/* refresh config data */
if ((error = gitmodules_snapshot(&mods, sm->repo)) < 0 && error != GIT_ENOTFOUND)
@@ -1923,6 +1940,11 @@ static int submodule_load_each(const git_config_entry *entry, void *payload)
if ((error = git_buf_set(&name, namestart, property - namestart -1)) < 0)
return error;
+ if (!git_path_isvalid(data->repo, name.ptr, GIT_PATH_REJECT_TRAVERSAL)) {
+ error = 0;
+ goto done;
+ }
+
/*
* Now that we have the submodule's name, we can use that to
* figure out whether it's in the map. If it's not, we create
diff --git a/src/submodule.h b/src/submodule.h
index 72867a322..e188dbb3c 100644
--- a/src/submodule.h
+++ b/src/submodule.h
@@ -148,4 +148,17 @@ extern int git_submodule_parse_update(
extern int git_submodule__map(
git_repository *repo,
git_strmap *map);
+
+/**
+ * Check whether a submodule's name is valid.
+ *
+ * Check the path against the path validity rules, either the filesystem
+ * defaults (like checkout does) or whichever you want to compare against.
+ *
+ * @param repo the repository which contains the submodule
+ * @param name the name to check
+ * @param flags the `GIT_PATH` flags to use for the check (0 to use filesystem defaults)
+ */
+extern int git_submodule_name_is_valid(const git_repository *repo, const char *name, int flags);
+
#endif
diff --git a/tests/submodule/escape.c b/tests/submodule/escape.c
index 18d238f24..576d7884b 100644
--- a/tests/submodule/escape.c
+++ b/tests/submodule/escape.c
@@ -32,29 +32,34 @@ void test_submodule_escape__from_gitdir(void)
git_config *cfg;
git_submodule *sm;
git_buf buf = GIT_BUF_INIT;
+ unsigned int sm_location;
g_repo = setup_fixture_submodule_simple();
cl_git_pass(git_buf_joinpath(&buf, git_repository_workdir(g_repo), ".gitmodules"));
- cl_git_pass(git_config_open_ondisk(&cfg, git_buf_cstr(&buf)));
-
- /* We don't have a function to rename a subsection so we do it manually */
- cl_git_pass(git_submodule_lookup(&sm, g_repo, "testrepo"));
- cl_git_pass(git_config_set_string(cfg, "submodule." EVIL_SM_NAME ".path", git_submodule_path(sm)));
- cl_git_pass(git_config_set_string(cfg, "submodule." EVIL_SM_NAME ".url", git_submodule_url(sm)));
- cl_git_pass(git_config_delete_entry(cfg, "submodule.testrepo.path"));
- cl_git_pass(git_config_delete_entry(cfg, "submodule.testrepo.url"));
- git_config_free(cfg);
+ cl_git_rewritefile(buf.ptr,
+ "[submodule \"" EVIL_SM_NAME "\"]\n"
+ " path = testrepo\n"
+ " url = ../testrepo.git\n");
/* We also need to update the value in the config */
cl_git_pass(git_repository_config__weakptr(&cfg, g_repo));
- cl_git_pass(git_config_set_string(cfg, "submodule." EVIL_SM_NAME ".url", git_submodule_url(sm)));
cfg = NULL;
/* Find it all the different ways we know about it */
- cl_git_fail_with(GIT_ENOTFOUND, git_submodule_lookup(&sm, g_repo, EVIL_SM_NAME));
- cl_git_fail_with(GIT_ENOTFOUND, git_submodule_lookup(&sm, g_repo, "testrepo"));
foundit = 0;
cl_git_pass(git_submodule_foreach(g_repo, find_evil, &foundit));
cl_assert_equal_i(0, foundit);
+ cl_git_fail_with(GIT_ENOTFOUND, git_submodule_lookup(&sm, g_repo, EVIL_SM_NAME));
+ /*
+ * We do know about this as it's in the index and HEAD, but the data is
+ * incomplete as there is no configured data for it (we pretend it
+ * doesn't exist). This leaves us with an odd situation but it's
+ * consistent with what we would do if we did add a submodule with no
+ * configuration.
+ */
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "testrepo"));
+ cl_git_pass(git_submodule_location(&sm_location, sm));
+ cl_assert_equal_i(GIT_SUBMODULE_STATUS_IN_INDEX | GIT_SUBMODULE_STATUS_IN_HEAD, sm_location);
+ git_submodule_free(sm);
}