Skip to content

Commit f647bbc

Browse files
committed
tree: fix mode parsing reading out-of-bounds
When parsing a tree entry's mode, we will eagerly parse until we hit a character that is not in the accepted set of octal digits '0' - '7'. If the provided buffer is not a NUL terminated one, we may thus read out-of-bounds. Fix the issue by passing the buffer length to `parse_mode` and paying attention to it. Note that this is not a vulnerability in our usual code paths, as all object data read from the ODB is NUL terminated.
1 parent d4ad658 commit f647bbc

File tree

2 files changed

+16
-3
lines changed

2 files changed

+16
-3
lines changed

src/tree.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -356,15 +356,16 @@ static int tree_error(const char *str, const char *path)
356356
return -1;
357357
}
358358

359-
static int parse_mode(unsigned int *modep, const char *buffer, const char **buffer_out)
359+
static int parse_mode(unsigned int *modep, const char *buffer, size_t buffer_len, const char **buffer_out)
360360
{
361+
const char *buffer_end = buffer + buffer_len;
361362
unsigned char c;
362363
unsigned int mode = 0;
363364

364365
if (*buffer == ' ')
365366
return -1;
366367

367-
while ((c = *buffer++) != ' ') {
368+
while (buffer < buffer_end && (c = *buffer++) != ' ') {
368369
if (c < '0' || c > '7')
369370
return -1;
370371
mode = (mode << 3) + (c - '0');
@@ -394,7 +395,7 @@ int git_tree__parse_raw(void *_tree, const char *data, size_t size)
394395
const char *nul;
395396
unsigned int attr;
396397

397-
if (parse_mode(&attr, buffer, &buffer) < 0 || !buffer)
398+
if (parse_mode(&attr, buffer, buffer_end - buffer, &buffer) < 0 || !buffer)
398399
return tree_error("failed to parse tree: can't parse filemode", NULL);
399400

400401
if ((nul = memchr(buffer, 0, buffer_end - buffer)) == NULL)

tests/object/tree/parse.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,18 @@ void test_object_tree_parse__missing_mode_fails(void)
109109
assert_tree_fails(data, ARRAY_SIZE(data) - 1);
110110
}
111111

112+
void test_object_tree_parse__mode_doesnt_cause_oob_read(void)
113+
{
114+
const char data[] = "100644 bar\x00" OID1_HEX;
115+
assert_tree_fails(data, 2);
116+
/*
117+
* An oob-read would correctly parse the filename and
118+
* later fail to parse the OID with a different error
119+
* message
120+
*/
121+
cl_assert(strstr(giterr_last()->message, "object is corrupted"));
122+
}
123+
112124
void test_object_tree_parse__missing_filename_separator_fails(void)
113125
{
114126
const char data[] = "100644bar\x00" OID1_HEX;

0 commit comments

Comments
 (0)