Skip to content

Commit 2288a71

Browse files
committed
repository: check error codes when reading common link
When checking whether a path is a valid repository path, we try to read the "commondir" link file. In the process, we neither confirm that constructing the file's path succeeded nor do we verify that reading the file succeeded, which might cause us to verify repositories on an empty or bogus path later on. Fix this by checking return values. As the function to verify repos doesn't currently support returning errors, this commit also refactors the function to return an error code, passing validity of the repo via an out parameter instead, and adjusts all existing callers.
1 parent b169cd5 commit 2288a71

File tree

1 file changed

+63
-50
lines changed

1 file changed

+63
-50
lines changed

src/repository.c

Lines changed: 63 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -189,44 +189,52 @@ void git_repository_free(git_repository *repo)
189189
*
190190
* Open a repository object from its path
191191
*/
192-
static bool valid_repository_path(git_buf *repository_path, git_buf *common_path)
192+
static int is_valid_repository_path(bool *out, git_buf *repository_path, git_buf *common_path)
193193
{
194+
int error;
195+
196+
*out = false;
197+
194198
/* Check if we have a separate commondir (e.g. we have a
195199
* worktree) */
196200
if (git_path_contains_file(repository_path, GIT_COMMONDIR_FILE)) {
197201
git_buf common_link = GIT_BUF_INIT;
198-
git_buf_joinpath(&common_link, repository_path->ptr, GIT_COMMONDIR_FILE);
199202

200-
git_futils_readbuffer(&common_link, common_link.ptr);
201-
git_buf_rtrim(&common_link);
203+
if ((error = git_buf_joinpath(&common_link, repository_path->ptr, GIT_COMMONDIR_FILE)) < 0 ||
204+
(error = git_futils_readbuffer(&common_link, common_link.ptr)) < 0)
205+
return error;
202206

207+
git_buf_rtrim(&common_link);
203208
if (git_path_is_relative(common_link.ptr)) {
204-
git_buf_joinpath(common_path, repository_path->ptr, common_link.ptr);
209+
if ((error = git_buf_joinpath(common_path, repository_path->ptr, common_link.ptr)) < 0)
210+
return error;
205211
} else {
206212
git_buf_swap(common_path, &common_link);
207213
}
208214

209215
git_buf_dispose(&common_link);
210216
}
211217
else {
212-
git_buf_set(common_path, repository_path->ptr, repository_path->size);
218+
if ((error = git_buf_set(common_path, repository_path->ptr, repository_path->size)) < 0)
219+
return error;
213220
}
214221

215222
/* Make sure the commondir path always has a trailing * slash */
216223
if (git_buf_rfind(common_path, '/') != (ssize_t)common_path->size - 1)
217-
git_buf_putc(common_path, '/');
224+
if ((error = git_buf_putc(common_path, '/')) < 0)
225+
return error;
218226

219227
/* Ensure HEAD file exists */
220228
if (git_path_contains_file(repository_path, GIT_HEAD_FILE) == false)
221-
return false;
222-
229+
return 0;
223230
/* Check files in common dir */
224231
if (git_path_contains_dir(common_path, GIT_OBJECTS_DIR) == false)
225-
return false;
232+
return 0;
226233
if (git_path_contains_dir(common_path, GIT_REFS_DIR) == false)
227-
return false;
234+
return 0;
228235

229-
return true;
236+
*out = true;
237+
return 0;
230238
}
231239

232240
static git_repository *repository_alloc(void)
@@ -441,15 +449,15 @@ static int find_repo(
441449
uint32_t flags,
442450
const char *ceiling_dirs)
443451
{
444-
int error;
445452
git_buf path = GIT_BUF_INIT;
446453
git_buf repo_link = GIT_BUF_INIT;
447454
git_buf common_link = GIT_BUF_INIT;
448455
struct stat st;
449456
dev_t initial_device = 0;
450457
int min_iterations;
451-
bool in_dot_git;
458+
bool in_dot_git, is_valid;
452459
size_t ceiling_offset = 0;
460+
int error;
453461

454462
git_buf_clear(gitdir_path);
455463

@@ -475,9 +483,8 @@ static int find_repo(
475483
for (;;) {
476484
if (!(flags & GIT_REPOSITORY_OPEN_NO_DOTGIT)) {
477485
if (!in_dot_git) {
478-
error = git_buf_joinpath(&path, path.ptr, DOT_GIT);
479-
if (error < 0)
480-
break;
486+
if ((error = git_buf_joinpath(&path, path.ptr, DOT_GIT)) < 0)
487+
goto out;
481488
}
482489
in_dot_git = !in_dot_git;
483490
}
@@ -491,28 +498,33 @@ static int find_repo(
491498
break;
492499

493500
if (S_ISDIR(st.st_mode)) {
494-
if (valid_repository_path(&path, &common_link)) {
495-
git_path_to_dir(&path);
496-
git_buf_set(gitdir_path, path.ptr, path.size);
501+
if ((error = is_valid_repository_path(&is_valid, &path, &common_link)) < 0)
502+
goto out;
503+
504+
if (is_valid) {
505+
if ((error = git_path_to_dir(&path)) < 0 ||
506+
(error = git_buf_set(gitdir_path, path.ptr, path.size)) < 0)
507+
goto out;
497508

498509
if (gitlink_path)
499-
git_buf_attach(gitlink_path,
500-
git_worktree__read_link(path.ptr, GIT_GITDIR_FILE), 0);
510+
if ((error = git_buf_attach(gitlink_path, git_worktree__read_link(path.ptr, GIT_GITDIR_FILE), 0)) < 0)
511+
goto out;
501512
if (commondir_path)
502513
git_buf_swap(&common_link, commondir_path);
503514

504515
break;
505516
}
506-
}
507-
else if (S_ISREG(st.st_mode) && git__suffixcmp(path.ptr, "/" DOT_GIT) == 0) {
508-
error = read_gitfile(&repo_link, path.ptr);
509-
if (error < 0)
510-
break;
511-
if (valid_repository_path(&repo_link, &common_link)) {
517+
} else if (S_ISREG(st.st_mode) && git__suffixcmp(path.ptr, "/" DOT_GIT) == 0) {
518+
if ((error = read_gitfile(&repo_link, path.ptr)) < 0 ||
519+
(error = is_valid_repository_path(&is_valid, &repo_link, &common_link)) < 0)
520+
goto out;
521+
522+
if (is_valid) {
512523
git_buf_swap(gitdir_path, &repo_link);
513524

514525
if (gitlink_path)
515-
error = git_buf_put(gitlink_path, path.ptr, path.size);
526+
if ((error = git_buf_put(gitlink_path, path.ptr, path.size)) < 0)
527+
goto out;
516528
if (commondir_path)
517529
git_buf_swap(&common_link, commondir_path);
518530
}
@@ -523,42 +535,37 @@ static int find_repo(
523535
/* Move up one directory. If we're in_dot_git, we'll search the
524536
* parent itself next. If we're !in_dot_git, we'll search .git
525537
* in the parent directory next (added at the top of the loop). */
526-
if (git_path_dirname_r(&path, path.ptr) < 0) {
527-
error = -1;
528-
break;
529-
}
538+
if ((error = git_path_dirname_r(&path, path.ptr)) < 0)
539+
goto out;
530540

531541
/* Once we've checked the directory (and .git if applicable),
532542
* find the ceiling for a search. */
533543
if (min_iterations && (--min_iterations == 0))
534544
ceiling_offset = find_ceiling_dir_offset(path.ptr, ceiling_dirs);
535545

536546
/* Check if we should stop searching here. */
537-
if (min_iterations == 0
538-
&& (path.ptr[ceiling_offset] == 0
539-
|| (flags & GIT_REPOSITORY_OPEN_NO_SEARCH)))
547+
if (min_iterations == 0 &&
548+
(path.ptr[ceiling_offset] == 0 || (flags & GIT_REPOSITORY_OPEN_NO_SEARCH)))
540549
break;
541550
}
542551

543-
if (!error && workdir_path && !(flags & GIT_REPOSITORY_OPEN_BARE)) {
552+
if (workdir_path && !(flags & GIT_REPOSITORY_OPEN_BARE)) {
544553
if (!git_buf_len(gitdir_path))
545554
git_buf_clear(workdir_path);
546-
else {
547-
git_path_dirname_r(workdir_path, path.ptr);
548-
git_path_to_dir(workdir_path);
549-
}
550-
if (git_buf_oom(workdir_path))
551-
return -1;
555+
else if ((error = git_path_dirname_r(workdir_path, path.ptr)) < 0 ||
556+
(error = git_path_to_dir(workdir_path)) < 0)
557+
goto out;
552558
}
553559

554560
/* If we didn't find the repository, and we don't have any other error
555561
* to report, report that. */
556-
if (!git_buf_len(gitdir_path) && !error) {
557-
git_error_set(GIT_ERROR_REPOSITORY,
558-
"could not find repository from '%s'", start_path);
562+
if (!git_buf_len(gitdir_path)) {
563+
git_error_set(GIT_ERROR_REPOSITORY, "could not find repository from '%s'", start_path);
559564
error = GIT_ENOTFOUND;
565+
goto out;
560566
}
561567

568+
out:
562569
git_buf_dispose(&path);
563570
git_buf_dispose(&repo_link);
564571
git_buf_dispose(&common_link);
@@ -569,14 +576,16 @@ int git_repository_open_bare(
569576
git_repository **repo_ptr,
570577
const char *bare_path)
571578
{
572-
int error;
573579
git_buf path = GIT_BUF_INIT, common_path = GIT_BUF_INIT;
574580
git_repository *repo = NULL;
581+
bool is_valid;
582+
int error;
575583

576-
if ((error = git_path_prettify_dir(&path, bare_path, NULL)) < 0)
584+
if ((error = git_path_prettify_dir(&path, bare_path, NULL)) < 0 ||
585+
(error = is_valid_repository_path(&is_valid, &path, &common_path)) < 0)
577586
return error;
578587

579-
if (!valid_repository_path(&path, &common_path)) {
588+
if (!is_valid) {
580589
git_buf_dispose(&path);
581590
git_buf_dispose(&common_path);
582591
git_error_set(GIT_ERROR_REPOSITORY, "path is not a repository: %s", bare_path);
@@ -2055,6 +2064,7 @@ int git_repository_init_ext(
20552064
git_buf repo_path = GIT_BUF_INIT, wd_path = GIT_BUF_INIT,
20562065
common_path = GIT_BUF_INIT, head_path = GIT_BUF_INIT;
20572066
const char *wd;
2067+
bool is_valid;
20582068
int error;
20592069

20602070
assert(out && given_repo && opts);
@@ -2066,7 +2076,10 @@ int git_repository_init_ext(
20662076

20672077
wd = (opts->flags & GIT_REPOSITORY_INIT_BARE) ? NULL : git_buf_cstr(&wd_path);
20682078

2069-
if (valid_repository_path(&repo_path, &common_path)) {
2079+
if ((error = is_valid_repository_path(&is_valid, &repo_path, &common_path)) < 0)
2080+
goto out;
2081+
2082+
if (is_valid) {
20702083
if ((opts->flags & GIT_REPOSITORY_INIT_NO_REINIT) != 0) {
20712084
git_error_set(GIT_ERROR_REPOSITORY,
20722085
"attempt to reinitialize '%s'", given_repo);

0 commit comments

Comments
 (0)