Skip to content

Commit 9fb755d

Browse files
committed
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.
1 parent e52c298 commit 9fb755d

File tree

7 files changed

+30
-16
lines changed

7 files changed

+30
-16
lines changed

src/attr.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ int git_attr_get(
6767
if (git_repository_is_bare(repo))
6868
dir_flag = GIT_DIR_FLAG_FALSE;
6969

70-
if (git_attr_path__init(&path, pathname, git_repository_workdir(repo), dir_flag) < 0)
70+
if (git_attr_path__init(&path, repo, pathname, git_repository_workdir(repo), dir_flag) < 0)
7171
return -1;
7272

7373
if ((error = collect_attr_files(repo, NULL, flags, pathname, &files)) < 0)
@@ -133,7 +133,7 @@ int git_attr_get_many_with_session(
133133
if (git_repository_is_bare(repo))
134134
dir_flag = GIT_DIR_FLAG_FALSE;
135135

136-
if (git_attr_path__init(&path, pathname, git_repository_workdir(repo), dir_flag) < 0)
136+
if (git_attr_path__init(&path, repo, pathname, git_repository_workdir(repo), dir_flag) < 0)
137137
return -1;
138138

139139
if ((error = collect_attr_files(repo, attr_session, flags, pathname, &files)) < 0)
@@ -217,7 +217,7 @@ int git_attr_foreach(
217217
if (git_repository_is_bare(repo))
218218
dir_flag = GIT_DIR_FLAG_FALSE;
219219

220-
if (git_attr_path__init(&path, pathname, git_repository_workdir(repo), dir_flag) < 0)
220+
if (git_attr_path__init(&path, repo, pathname, git_repository_workdir(repo), dir_flag) < 0)
221221
return -1;
222222

223223
if ((error = collect_attr_files(repo, NULL, flags, pathname, &files)) < 0 ||

src/attr_file.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ int git_attr_file__load_standalone(git_attr_file **out, const char *path)
403403

404404
if ((error = git_attr_file__new(&file, NULL, GIT_ATTR_FILE__FROM_FILE)) < 0 ||
405405
(error = git_attr_file__parse_buffer(NULL, file, content.ptr, true)) < 0 ||
406-
(error = git_attr_cache__alloc_file_entry(&file->entry, NULL, path, &file->pool)) < 0)
406+
(error = git_attr_cache__alloc_file_entry(&file->entry, NULL, NULL, path, &file->pool)) < 0)
407407
goto out;
408408

409409
*out = file;
@@ -503,14 +503,19 @@ git_attr_assignment *git_attr_rule__lookup_assignment(
503503
}
504504

505505
int git_attr_path__init(
506-
git_attr_path *info, const char *path, const char *base, git_dir_flag dir_flag)
506+
git_attr_path *info,
507+
git_repository *repo,
508+
const char *path,
509+
const char *base,
510+
git_dir_flag dir_flag)
507511
{
508512
ssize_t root;
509513

510514
/* build full path as best we can */
511515
git_buf_init(&info->full, 0);
512516

513-
if (git_path_join_unrooted(&info->full, path, base, &root) < 0)
517+
if (git_path_join_unrooted(&info->full, path, base, &root) < 0 ||
518+
git_path_validate_workdir_buf(repo, &info->full) < 0)
514519
return -1;
515520

516521
info->path = info->full.ptr + root;

src/attr_file.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,8 +207,11 @@ extern git_attr_assignment *git_attr_rule__lookup_assignment(
207207
typedef enum { GIT_DIR_FLAG_TRUE = 1, GIT_DIR_FLAG_FALSE = 0, GIT_DIR_FLAG_UNKNOWN = -1 } git_dir_flag;
208208

209209
extern int git_attr_path__init(
210-
git_attr_path *info, const char *path, const char *base, git_dir_flag is_dir);
211-
210+
git_attr_path *out,
211+
git_repository *repo,
212+
const char *path,
213+
const char *base,
214+
git_dir_flag is_dir);
212215
extern void git_attr_path__free(git_attr_path *info);
213216

214217
extern int git_attr_assignment__parse(

src/attrcache.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ GIT_INLINE(git_attr_file_entry *) attr_cache_lookup_entry(
3838

3939
int git_attr_cache__alloc_file_entry(
4040
git_attr_file_entry **out,
41+
git_repository *repo,
4142
const char *base,
4243
const char *path,
4344
git_pool *pool)
@@ -65,6 +66,9 @@ int git_attr_cache__alloc_file_entry(
6566
}
6667
memcpy(&ce->fullpath[baselen], path, pathlen);
6768

69+
if (git_path_validate_workdir_with_len(repo, ce->fullpath, pathlen + baselen) < 0)
70+
return -1;
71+
6872
ce->path = &ce->fullpath[baselen];
6973
*out = ce;
7074

@@ -79,8 +83,8 @@ static int attr_cache_make_entry(
7983
git_attr_file_entry *entry = NULL;
8084
int error;
8185

82-
if ((error = git_attr_cache__alloc_file_entry(&entry, git_repository_workdir(repo),
83-
path, &cache->pool)) < 0)
86+
if ((error = git_attr_cache__alloc_file_entry(&entry, repo,
87+
git_repository_workdir(repo), path, &cache->pool)) < 0)
8488
return error;
8589

8690
if ((error = git_strmap_set(cache->files, entry->path, entry)) < 0)
@@ -169,7 +173,8 @@ static int attr_cache_lookup(
169173
if (base != NULL && git_path_root(filename) < 0) {
170174
git_buf *p = attr_session ? &attr_session->tmp : &path;
171175

172-
if (git_buf_joinpath(p, base, filename) < 0)
176+
if (git_buf_joinpath(p, base, filename) < 0 ||
177+
git_path_validate_workdir_buf(repo, p) < 0)
173178
return -1;
174179

175180
filename = p->ptr;

src/attrcache.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ extern bool git_attr_cache__is_cached(
4444

4545
extern int git_attr_cache__alloc_file_entry(
4646
git_attr_file_entry **out,
47+
git_repository *repo,
4748
const char *base,
4849
const char *path,
4950
git_pool *pool);

src/ignore.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,7 @@ int git_ignore__lookup(
453453
*out = GIT_IGNORE_NOTFOUND;
454454

455455
if (git_attr_path__init(
456-
&path, pathname, git_repository_workdir(ignores->repo), dir_flag) < 0)
456+
&path, ignores->repo, pathname, git_repository_workdir(ignores->repo), dir_flag) < 0)
457457
return -1;
458458

459459
/* first process builtins - success means path was found */
@@ -537,7 +537,7 @@ int git_ignore_path_is_ignored(
537537
else if (git_repository_is_bare(repo))
538538
dir_flag = GIT_DIR_FLAG_FALSE;
539539

540-
if ((error = git_attr_path__init(&path, pathname, workdir, dir_flag)) < 0 ||
540+
if ((error = git_attr_path__init(&path, repo, pathname, workdir, dir_flag)) < 0 ||
541541
(error = git_ignore__for_path(repo, path.path, &ignores)) < 0)
542542
goto cleanup;
543543

tests/attr/lookup.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ void test_attr_lookup__simple(void)
1313
cl_assert_equal_s(cl_fixture("attr/attr0"), file->entry->path);
1414
cl_assert(file->rules.length == 1);
1515

16-
cl_git_pass(git_attr_path__init(&path, "test", NULL, GIT_DIR_FLAG_UNKNOWN));
16+
cl_git_pass(git_attr_path__init(&path, NULL, "test", NULL, GIT_DIR_FLAG_UNKNOWN));
1717
cl_assert_equal_s("test", path.path);
1818
cl_assert_equal_s("test", path.basename);
1919
cl_assert(!path.is_dir);
@@ -36,7 +36,7 @@ static void run_test_cases(git_attr_file *file, struct attr_expected *cases, int
3636
int error;
3737

3838
for (c = cases; c->path != NULL; c++) {
39-
cl_git_pass(git_attr_path__init(&path, c->path, NULL, GIT_DIR_FLAG_UNKNOWN));
39+
cl_git_pass(git_attr_path__init(&path, NULL, c->path, NULL, GIT_DIR_FLAG_UNKNOWN));
4040

4141
if (force_dir)
4242
path.is_dir = 1;
@@ -133,7 +133,7 @@ void test_attr_lookup__match_variants(void)
133133
cl_assert_equal_s(cl_fixture("attr/attr1"), file->entry->path);
134134
cl_assert(file->rules.length == 10);
135135

136-
cl_git_pass(git_attr_path__init(&path, "/testing/for/pat0", NULL, GIT_DIR_FLAG_UNKNOWN));
136+
cl_git_pass(git_attr_path__init(&path, NULL, "/testing/for/pat0", NULL, GIT_DIR_FLAG_UNKNOWN));
137137
cl_assert_equal_s("pat0", path.basename);
138138

139139
run_test_cases(file, cases, 0);

0 commit comments

Comments
 (0)