Commit 9fb755d5 by Edward Thomson

attr: validate workdir paths for attribute files

We should allow attribute files - inside working directories - to have
names longer than MAX_PATH when core.longpaths is set.
`git_attr_path__init` takes a repository to validate the path with.
parent e52c2989
...@@ -67,7 +67,7 @@ int git_attr_get( ...@@ -67,7 +67,7 @@ int git_attr_get(
if (git_repository_is_bare(repo)) if (git_repository_is_bare(repo))
dir_flag = GIT_DIR_FLAG_FALSE; dir_flag = GIT_DIR_FLAG_FALSE;
if (git_attr_path__init(&path, pathname, git_repository_workdir(repo), dir_flag) < 0) if (git_attr_path__init(&path, repo, pathname, git_repository_workdir(repo), dir_flag) < 0)
return -1; return -1;
if ((error = collect_attr_files(repo, NULL, flags, pathname, &files)) < 0) if ((error = collect_attr_files(repo, NULL, flags, pathname, &files)) < 0)
...@@ -133,7 +133,7 @@ int git_attr_get_many_with_session( ...@@ -133,7 +133,7 @@ int git_attr_get_many_with_session(
if (git_repository_is_bare(repo)) if (git_repository_is_bare(repo))
dir_flag = GIT_DIR_FLAG_FALSE; dir_flag = GIT_DIR_FLAG_FALSE;
if (git_attr_path__init(&path, pathname, git_repository_workdir(repo), dir_flag) < 0) if (git_attr_path__init(&path, repo, pathname, git_repository_workdir(repo), dir_flag) < 0)
return -1; return -1;
if ((error = collect_attr_files(repo, attr_session, flags, pathname, &files)) < 0) if ((error = collect_attr_files(repo, attr_session, flags, pathname, &files)) < 0)
...@@ -217,7 +217,7 @@ int git_attr_foreach( ...@@ -217,7 +217,7 @@ int git_attr_foreach(
if (git_repository_is_bare(repo)) if (git_repository_is_bare(repo))
dir_flag = GIT_DIR_FLAG_FALSE; dir_flag = GIT_DIR_FLAG_FALSE;
if (git_attr_path__init(&path, pathname, git_repository_workdir(repo), dir_flag) < 0) if (git_attr_path__init(&path, repo, pathname, git_repository_workdir(repo), dir_flag) < 0)
return -1; return -1;
if ((error = collect_attr_files(repo, NULL, flags, pathname, &files)) < 0 || if ((error = collect_attr_files(repo, NULL, flags, pathname, &files)) < 0 ||
......
...@@ -403,7 +403,7 @@ int git_attr_file__load_standalone(git_attr_file **out, const char *path) ...@@ -403,7 +403,7 @@ int git_attr_file__load_standalone(git_attr_file **out, const char *path)
if ((error = git_attr_file__new(&file, NULL, GIT_ATTR_FILE__FROM_FILE)) < 0 || if ((error = git_attr_file__new(&file, NULL, GIT_ATTR_FILE__FROM_FILE)) < 0 ||
(error = git_attr_file__parse_buffer(NULL, file, content.ptr, true)) < 0 || (error = git_attr_file__parse_buffer(NULL, file, content.ptr, true)) < 0 ||
(error = git_attr_cache__alloc_file_entry(&file->entry, NULL, path, &file->pool)) < 0) (error = git_attr_cache__alloc_file_entry(&file->entry, NULL, NULL, path, &file->pool)) < 0)
goto out; goto out;
*out = file; *out = file;
...@@ -503,14 +503,19 @@ git_attr_assignment *git_attr_rule__lookup_assignment( ...@@ -503,14 +503,19 @@ git_attr_assignment *git_attr_rule__lookup_assignment(
} }
int git_attr_path__init( int git_attr_path__init(
git_attr_path *info, const char *path, const char *base, git_dir_flag dir_flag) git_attr_path *info,
git_repository *repo,
const char *path,
const char *base,
git_dir_flag dir_flag)
{ {
ssize_t root; ssize_t root;
/* build full path as best we can */ /* build full path as best we can */
git_buf_init(&info->full, 0); git_buf_init(&info->full, 0);
if (git_path_join_unrooted(&info->full, path, base, &root) < 0) if (git_path_join_unrooted(&info->full, path, base, &root) < 0 ||
git_path_validate_workdir_buf(repo, &info->full) < 0)
return -1; return -1;
info->path = info->full.ptr + root; info->path = info->full.ptr + root;
......
...@@ -207,8 +207,11 @@ extern git_attr_assignment *git_attr_rule__lookup_assignment( ...@@ -207,8 +207,11 @@ extern git_attr_assignment *git_attr_rule__lookup_assignment(
typedef enum { GIT_DIR_FLAG_TRUE = 1, GIT_DIR_FLAG_FALSE = 0, GIT_DIR_FLAG_UNKNOWN = -1 } git_dir_flag; typedef enum { GIT_DIR_FLAG_TRUE = 1, GIT_DIR_FLAG_FALSE = 0, GIT_DIR_FLAG_UNKNOWN = -1 } git_dir_flag;
extern int git_attr_path__init( extern int git_attr_path__init(
git_attr_path *info, const char *path, const char *base, git_dir_flag is_dir); git_attr_path *out,
git_repository *repo,
const char *path,
const char *base,
git_dir_flag is_dir);
extern void git_attr_path__free(git_attr_path *info); extern void git_attr_path__free(git_attr_path *info);
extern int git_attr_assignment__parse( extern int git_attr_assignment__parse(
......
...@@ -38,6 +38,7 @@ GIT_INLINE(git_attr_file_entry *) attr_cache_lookup_entry( ...@@ -38,6 +38,7 @@ GIT_INLINE(git_attr_file_entry *) attr_cache_lookup_entry(
int git_attr_cache__alloc_file_entry( int git_attr_cache__alloc_file_entry(
git_attr_file_entry **out, git_attr_file_entry **out,
git_repository *repo,
const char *base, const char *base,
const char *path, const char *path,
git_pool *pool) git_pool *pool)
...@@ -65,6 +66,9 @@ int git_attr_cache__alloc_file_entry( ...@@ -65,6 +66,9 @@ int git_attr_cache__alloc_file_entry(
} }
memcpy(&ce->fullpath[baselen], path, pathlen); memcpy(&ce->fullpath[baselen], path, pathlen);
if (git_path_validate_workdir_with_len(repo, ce->fullpath, pathlen + baselen) < 0)
return -1;
ce->path = &ce->fullpath[baselen]; ce->path = &ce->fullpath[baselen];
*out = ce; *out = ce;
...@@ -79,8 +83,8 @@ static int attr_cache_make_entry( ...@@ -79,8 +83,8 @@ static int attr_cache_make_entry(
git_attr_file_entry *entry = NULL; git_attr_file_entry *entry = NULL;
int error; int error;
if ((error = git_attr_cache__alloc_file_entry(&entry, git_repository_workdir(repo), if ((error = git_attr_cache__alloc_file_entry(&entry, repo,
path, &cache->pool)) < 0) git_repository_workdir(repo), path, &cache->pool)) < 0)
return error; return error;
if ((error = git_strmap_set(cache->files, entry->path, entry)) < 0) if ((error = git_strmap_set(cache->files, entry->path, entry)) < 0)
...@@ -169,7 +173,8 @@ static int attr_cache_lookup( ...@@ -169,7 +173,8 @@ static int attr_cache_lookup(
if (base != NULL && git_path_root(filename) < 0) { if (base != NULL && git_path_root(filename) < 0) {
git_buf *p = attr_session ? &attr_session->tmp : &path; git_buf *p = attr_session ? &attr_session->tmp : &path;
if (git_buf_joinpath(p, base, filename) < 0) if (git_buf_joinpath(p, base, filename) < 0 ||
git_path_validate_workdir_buf(repo, p) < 0)
return -1; return -1;
filename = p->ptr; filename = p->ptr;
......
...@@ -44,6 +44,7 @@ extern bool git_attr_cache__is_cached( ...@@ -44,6 +44,7 @@ extern bool git_attr_cache__is_cached(
extern int git_attr_cache__alloc_file_entry( extern int git_attr_cache__alloc_file_entry(
git_attr_file_entry **out, git_attr_file_entry **out,
git_repository *repo,
const char *base, const char *base,
const char *path, const char *path,
git_pool *pool); git_pool *pool);
......
...@@ -453,7 +453,7 @@ int git_ignore__lookup( ...@@ -453,7 +453,7 @@ int git_ignore__lookup(
*out = GIT_IGNORE_NOTFOUND; *out = GIT_IGNORE_NOTFOUND;
if (git_attr_path__init( if (git_attr_path__init(
&path, pathname, git_repository_workdir(ignores->repo), dir_flag) < 0) &path, ignores->repo, pathname, git_repository_workdir(ignores->repo), dir_flag) < 0)
return -1; return -1;
/* first process builtins - success means path was found */ /* first process builtins - success means path was found */
...@@ -537,7 +537,7 @@ int git_ignore_path_is_ignored( ...@@ -537,7 +537,7 @@ int git_ignore_path_is_ignored(
else if (git_repository_is_bare(repo)) else if (git_repository_is_bare(repo))
dir_flag = GIT_DIR_FLAG_FALSE; dir_flag = GIT_DIR_FLAG_FALSE;
if ((error = git_attr_path__init(&path, pathname, workdir, dir_flag)) < 0 || if ((error = git_attr_path__init(&path, repo, pathname, workdir, dir_flag)) < 0 ||
(error = git_ignore__for_path(repo, path.path, &ignores)) < 0) (error = git_ignore__for_path(repo, path.path, &ignores)) < 0)
goto cleanup; goto cleanup;
......
...@@ -13,7 +13,7 @@ void test_attr_lookup__simple(void) ...@@ -13,7 +13,7 @@ void test_attr_lookup__simple(void)
cl_assert_equal_s(cl_fixture("attr/attr0"), file->entry->path); cl_assert_equal_s(cl_fixture("attr/attr0"), file->entry->path);
cl_assert(file->rules.length == 1); cl_assert(file->rules.length == 1);
cl_git_pass(git_attr_path__init(&path, "test", NULL, GIT_DIR_FLAG_UNKNOWN)); cl_git_pass(git_attr_path__init(&path, NULL, "test", NULL, GIT_DIR_FLAG_UNKNOWN));
cl_assert_equal_s("test", path.path); cl_assert_equal_s("test", path.path);
cl_assert_equal_s("test", path.basename); cl_assert_equal_s("test", path.basename);
cl_assert(!path.is_dir); cl_assert(!path.is_dir);
...@@ -36,7 +36,7 @@ static void run_test_cases(git_attr_file *file, struct attr_expected *cases, int ...@@ -36,7 +36,7 @@ static void run_test_cases(git_attr_file *file, struct attr_expected *cases, int
int error; int error;
for (c = cases; c->path != NULL; c++) { for (c = cases; c->path != NULL; c++) {
cl_git_pass(git_attr_path__init(&path, c->path, NULL, GIT_DIR_FLAG_UNKNOWN)); cl_git_pass(git_attr_path__init(&path, NULL, c->path, NULL, GIT_DIR_FLAG_UNKNOWN));
if (force_dir) if (force_dir)
path.is_dir = 1; path.is_dir = 1;
...@@ -133,7 +133,7 @@ void test_attr_lookup__match_variants(void) ...@@ -133,7 +133,7 @@ void test_attr_lookup__match_variants(void)
cl_assert_equal_s(cl_fixture("attr/attr1"), file->entry->path); cl_assert_equal_s(cl_fixture("attr/attr1"), file->entry->path);
cl_assert(file->rules.length == 10); cl_assert(file->rules.length == 10);
cl_git_pass(git_attr_path__init(&path, "/testing/for/pat0", NULL, GIT_DIR_FLAG_UNKNOWN)); cl_git_pass(git_attr_path__init(&path, NULL, "/testing/for/pat0", NULL, GIT_DIR_FLAG_UNKNOWN));
cl_assert_equal_s("pat0", path.basename); cl_assert_equal_s("pat0", path.basename);
run_test_cases(file, cases, 0); run_test_cases(file, cases, 0);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment