Skip to content

Commit ee11d47

Browse files
committed
tag: fix out of bounds read when searching for tag message
When parsing tags, we skip all unknown fields that appear before the tag message. This skipping is done by using a plain `strstr(buffer, "\n\n")` to search for the two newlines that separate tag fields from tag message. As it is not possible to supply a buffer length to `strstr`, this call may skip over the buffer's end and thus result in an out of bounds read. As `strstr` may return a pointer that is out of bounds, the following computation of `buffer_end - buffer` will overflow and result in an allocation of an invalid length. Fix the issue by using `git__memmem` instead. Add a test that verifies parsing the tag fails not due to the allocation failure but due to the tag having no message.
1 parent 4c738e5 commit ee11d47

File tree

2 files changed

+23
-5
lines changed

2 files changed

+23
-5
lines changed

src/tag.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,9 @@ static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end)
7070
static const char *tag_types[] = {
7171
NULL, "commit\n", "tree\n", "blob\n", "tag\n"
7272
};
73-
74-
unsigned int i;
7573
size_t text_len, alloc_len;
76-
char *search;
74+
const char *search;
75+
unsigned int i;
7776

7877
if (git_oid__parse(&tag->target, &buffer, buffer_end, "object ") < 0)
7978
return tag_error("object field invalid");
@@ -138,8 +137,9 @@ static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end)
138137
tag->message = NULL;
139138
if (buffer < buffer_end) {
140139
/* If we're not at the end of the header, search for it */
141-
if( *buffer != '\n' ) {
142-
search = strstr(buffer, "\n\n");
140+
if(*buffer != '\n') {
141+
search = git__memmem(buffer, buffer_end - buffer,
142+
"\n\n", 2);
143143
if (search)
144144
buffer = search + 1;
145145
else

tests/object/tag/parse.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,3 +198,21 @@ void test_object_tag_parse__missing_message_fails(void)
198198
"tagger taggy@taggart.com>\n";
199199
assert_tag_fails(tag, 0);
200200
}
201+
202+
void test_object_tag_parse__no_oob_read_when_searching_message(void)
203+
{
204+
const char *tag =
205+
"object a8d447f68076d1520f69649bb52629941be7031f\n"
206+
"type tag\n"
207+
"tag \n"
208+
"tagger <>\n"
209+
" \n\n"
210+
"Message";
211+
/*
212+
* The OOB read previously resulted in an OOM error. We
213+
* thus want to make sure that the resulting error is the
214+
* expected one.
215+
*/
216+
assert_tag_fails(tag, strlen(tag) - strlen("\n\nMessage"));
217+
cl_assert(strstr(giterr_last()->message, "tag contains no message"));
218+
}

0 commit comments

Comments
 (0)