Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 335c9e2

Browse files
committed
Prevent segfault when parsing a reflog with oid parse error
Using calloc instead of malloc because the parse error will lead to an immediate free of committer (and its properties, which can segfault on free if undefined - test_refs_reflog_reflog__reading_a_reflog_with_invalid_format_returns_error segfaulted before the fix). libgit2#3458
1 parent 821131f commit 335c9e2

File tree

2 files changed

+44
-1
lines changed

2 files changed

+44
-1
lines changed

src/refdb_fs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1463,7 +1463,7 @@ static int reflog_parse(git_reflog *log, const char *buf, size_t buf_size)
14631463
entry = git__calloc(1, sizeof(git_reflog_entry));
14641464
GITERR_CHECK_ALLOC(entry);
14651465

1466-
entry->committer = git__malloc(sizeof(git_signature));
1466+
entry->committer = git__calloc(1, sizeof(git_signature));
14671467
GITERR_CHECK_ALLOC(entry->committer);
14681468

14691469
if (git_oid_fromstrn(&entry->oid_old, buf, GIT_OID_HEXSZ) < 0)

tests/refs/reflog/reflog.c

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,49 @@ void test_refs_reflog_reflog__reading_the_reflog_from_a_reference_with_no_log_re
154154
git_buf_free(&subtrees_log_path);
155155
}
156156

157+
void test_refs_reflog_reflog__reading_a_reflog_with_invalid_format_returns_error(void)
158+
{
159+
git_reflog *reflog;
160+
const git_error *error;
161+
const char *refname = "refs/heads/newline";
162+
const char *refmessage =
163+
"Reflog*message with a newline and enough content after it to pass the GIT_REFLOG_SIZE_MIN check inside reflog_parse.";
164+
git_reference *ref;
165+
git_oid id;
166+
git_buf logpath = GIT_BUF_INIT, logcontents = GIT_BUF_INIT;
167+
char *star;
168+
169+
git_oid_fromstr(&id, current_master_tip);
170+
171+
/* create a new branch */
172+
cl_git_pass(git_reference_create(&ref, g_repo, refname, &id, 1, refmessage));
173+
174+
/* corrupt the branch reflog by introducing a newline inside the reflog message (we replace '*' with '\n') */
175+
git_buf_join_n(&logpath, '/', 3, git_repository_path(g_repo), GIT_REFLOG_DIR, refname);
176+
cl_git_pass(git_futils_readbuffer(&logcontents, git_buf_cstr(&logpath)));
177+
cl_assert((star = strchr(git_buf_cstr(&logcontents), '*')) != NULL);
178+
*star = '\n';
179+
cl_git_rewritefile(git_buf_cstr(&logpath), git_buf_cstr(&logcontents));
180+
181+
/* confirm that the file was rewritten successfully and now contains a '\n' in the expected location */
182+
cl_git_pass(git_futils_readbuffer(&logcontents, git_buf_cstr(&logpath)));
183+
cl_assert(strstr(git_buf_cstr(&logcontents), "Reflog\nmessage") != NULL);
184+
185+
/* clear the error state so we can capture the error generated by git_reflog_read */
186+
giterr_clear();
187+
188+
cl_git_fail(git_reflog_read(&reflog, g_repo, refname));
189+
190+
error = giterr_last();
191+
192+
cl_assert(error != NULL);
193+
cl_assert_equal_s("Unable to parse OID - contains invalid characters", error->message);
194+
195+
git_reference_free(ref);
196+
git_buf_free(&logpath);
197+
git_buf_free(&logcontents);
198+
}
199+
157200
void test_refs_reflog_reflog__cannot_write_a_moved_reflog(void)
158201
{
159202
git_reference *master, *new_master;

0 commit comments

Comments
 (0)