Merge branch 'pr/7265'

This commit is contained in:
Edward Thomson
2026-06-01 23:40:56 +01:00
2 changed files with 87 additions and 3 deletions

View File

@@ -582,16 +582,27 @@ static int validate_ownership_cb(const git_config_entry *entry, void *payload)
} else if (strcmp(entry->value, "*") == 0) { } else if (strcmp(entry->value, "*") == 0) {
*data->is_safe = true; *data->is_safe = true;
} else { } else {
bool is_prefix = false, match;
if (git_str_sets(&data->tmp, entry->value) < 0) if (git_str_sets(&data->tmp, entry->value) < 0)
return -1; return -1;
/*
* A value ending with slash* is treated as a prefix match.
* Strip only the '*', leaving the trailing slash in place.
*/
if (git__suffixcmp(data->tmp.ptr, "/*") == 0) {
is_prefix = true;
git_str_shorten(&data->tmp, 1);
}
if (!git_fs_path_is_root(data->tmp.ptr)) { if (!git_fs_path_is_root(data->tmp.ptr)) {
/* Input must not have trailing backslash. */ /* Input must not have trailing backslash. */
if (!data->tmp.size || if (!data->tmp.size ||
data->tmp.ptr[data->tmp.size - 1] == '/') (!is_prefix && data->tmp.ptr[data->tmp.size - 1] == '/'))
return 0; return 0;
if (git_fs_path_to_dir(&data->tmp) < 0) if (!is_prefix && git_fs_path_to_dir(&data->tmp) < 0)
return -1; return -1;
} }
@@ -623,7 +634,11 @@ static int validate_ownership_cb(const git_config_entry *entry, void *payload)
if (strncmp(test_path, "%(prefix)//", strlen("%(prefix)//")) == 0) if (strncmp(test_path, "%(prefix)//", strlen("%(prefix)//")) == 0)
test_path += strlen("%(prefix)/"); test_path += strlen("%(prefix)/");
if (strcmp(test_path, data->repo_path) == 0) match = is_prefix ?
(git__prefixcmp(data->repo_path, test_path) == 0) :
(strcmp(test_path, data->repo_path) == 0);
if (match)
*data->is_safe = true; *data->is_safe = true;
} }

View File

@@ -659,6 +659,26 @@ void test_repo_open__can_wildcard_allowlist_with_problematic_ownership(void)
cl_git_pass(test_safe_path("*")); cl_git_pass(test_safe_path("*"));
} }
void test_repo_open__can_allowlist_dirs_wildcard(void)
{
git_str path = GIT_STR_INIT;
cl_git_pass(git_str_printf(
&path, "%s/*", clar_sandbox_path()));
cl_git_pass(test_safe_path(path.ptr));
git_str_dispose(&path);
}
void test_repo_open__allowlist_dirs_cannot_have_wildcard_suffix(void)
{
git_str path = GIT_STR_INIT;
cl_git_pass(git_str_printf(
&path, "%s/%s*", clar_sandbox_path(), "empty_standard_repo"));
cl_git_fail_with(GIT_EOWNER, test_safe_path(path.ptr));
git_str_dispose(&path);
}
void test_repo_open__can_allowlist_bare_gitdir(void) void test_repo_open__can_allowlist_bare_gitdir(void)
{ {
git_str path = GIT_STR_INIT; git_str path = GIT_STR_INIT;
@@ -669,6 +689,38 @@ void test_repo_open__can_allowlist_bare_gitdir(void)
git_str_dispose(&path); git_str_dispose(&path);
} }
void test_repo_open__can_allowlist_bare_wildcard_gitdir(void)
{
git_str path = GIT_STR_INIT;
cl_git_pass(git_str_printf(
&path, "%s/*", clar_sandbox_path()));
cl_git_pass(test_bare_safe_path(path.ptr));
git_str_dispose(&path);
}
void test_repo_open__allowlist_bare_dirs_cannot_have_wildcard_suffix(void)
{
git_str path = GIT_STR_INIT;
cl_git_pass(git_str_printf(
&path, "%s/%s*", clar_sandbox_path(), "testrepo.git"));
cl_git_fail_with(GIT_EOWNER, test_bare_safe_path(path.ptr));
git_str_dispose(&path);
}
void test_repo_open__allowlist_relative_bare_dirs_cannot_have_wildcard_suffix(void)
{
git_str path = GIT_STR_INIT;
cl_git_pass(git_str_printf(&path, "%s*", clar_sandbox_path()));
cl_git_fail_with(GIT_EOWNER, test_bare_safe_path(path.ptr));
git_str_dispose(&path);
}
void test_repo_open__can_wildcard_allowlist_bare_gitdir(void) void test_repo_open__can_wildcard_allowlist_bare_gitdir(void)
{ {
cl_git_pass(test_bare_safe_path("*")); cl_git_pass(test_bare_safe_path("*"));
@@ -691,6 +743,23 @@ void test_repo_open__can_handle_prefixed_safe_paths(void)
#endif #endif
} }
void test_repo_open__can_handle_prefixed_wildcard_safe_paths(void)
{
#ifndef GIT_WIN32
git_str path = GIT_STR_INIT;
/*
* Using "%(prefix)/" becomes "%(prefix)//tmp/foo" - so
* "%(prefix)/" is stripped and means the literal path
* follows.
*/
cl_git_pass(git_str_printf(&path, "%%(prefix)/%s/*",
clar_sandbox_path()));
cl_git_pass(test_safe_path(path.ptr));
git_str_dispose(&path);
#endif
}
void test_repo_open__prefixed_safe_paths_must_have_two_slashes(void) void test_repo_open__prefixed_safe_paths_must_have_two_slashes(void)
{ {
git_str path = GIT_STR_INIT; git_str path = GIT_STR_INIT;