summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@edwardthomson.com>2018-03-12 10:09:49 +0100
committerGitHub <noreply@github.com>2018-03-12 10:09:49 +0100
commit7b66bfe2c9a0a73caf6fc771ba624f3fd7165b43 (patch)
treeb7ef8719612d70a86dc19b345961df6b5738807d
parent358cc2e2ea2e0fffc0672870e4a99160c068ebde (diff)
parent3db1af1f370295ad5355b8f64b865a2a357bcac0 (diff)
downloadlibgit2-7b66bfe2c9a0a73caf6fc771ba624f3fd7165b43.tar.gz
Merge pull request #4575 from pks-t/pks/index-secfixes-master
Index parsing fixes
-rw-r--r--src/index.c45
1 files changed, 27 insertions, 18 deletions
diff --git a/src/index.c b/src/index.c
index d98872adf..a867547fb 100644
--- a/src/index.c
+++ b/src/index.c
@@ -2299,8 +2299,9 @@ static size_t index_entry_size(size_t path_len, size_t varint_len, uint32_t flag
}
}
-static size_t read_entry(
+static int read_entry(
git_index_entry **out,
+ size_t *out_size,
git_index *index,
const void *buffer,
size_t buffer_size,
@@ -2314,7 +2315,7 @@ static size_t read_entry(
char *tmp_path = NULL;
if (INDEX_FOOTER_SIZE + minimal_entry_size > buffer_size)
- return 0;
+ return -1;
/* buffer is not guaranteed to be aligned */
memcpy(&source, buffer, sizeof(struct entry_short));
@@ -2356,7 +2357,7 @@ static size_t read_entry(
path_end = memchr(path_ptr, '\0', buffer_size);
if (path_end == NULL)
- return 0;
+ return -1;
path_length = path_end - path_ptr;
}
@@ -2364,19 +2365,24 @@ static size_t read_entry(
entry_size = index_entry_size(path_length, 0, entry.flags);
entry.path = (char *)path_ptr;
} else {
- size_t varint_len;
- size_t strip_len = git_decode_varint((const unsigned char *)path_ptr,
- &varint_len);
- size_t last_len = strlen(last);
- size_t prefix_len = last_len - strip_len;
- size_t suffix_len = strlen(path_ptr + varint_len);
- size_t path_len;
-
- if (varint_len == 0)
+ size_t varint_len, last_len, prefix_len, suffix_len, path_len;
+ uintmax_t strip_len;
+
+ strip_len = git_decode_varint((const unsigned char *)path_ptr, &varint_len);
+ last_len = strlen(last);
+
+ if (varint_len == 0 || last_len < strip_len)
return index_error_invalid("incorrect prefix length");
+ prefix_len = last_len - strip_len;
+ suffix_len = strlen(path_ptr + varint_len);
+
GITERR_CHECK_ALLOC_ADD(&path_len, prefix_len, suffix_len);
GITERR_CHECK_ALLOC_ADD(&path_len, path_len, 1);
+
+ if (path_len > GIT_PATH_MAX)
+ return index_error_invalid("unreasonable path length");
+
tmp_path = git__malloc(path_len);
GITERR_CHECK_ALLOC(tmp_path);
@@ -2386,16 +2392,20 @@ static size_t read_entry(
entry.path = tmp_path;
}
+ if (entry_size == 0)
+ return -1;
+
if (INDEX_FOOTER_SIZE + entry_size > buffer_size)
- return 0;
+ return -1;
if (index_entry_dup(out, index, &entry) < 0) {
git__free(tmp_path);
- return 0;
+ return -1;
}
git__free(tmp_path);
- return entry_size;
+ *out_size = entry_size;
+ return 0;
}
static int read_header(struct index_header *dest, const void *buffer)
@@ -2499,10 +2509,9 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size)
/* Parse all the entries */
for (i = 0; i < header.entry_count && buffer_size > INDEX_FOOTER_SIZE; ++i) {
git_index_entry *entry = NULL;
- size_t entry_size = read_entry(&entry, index, buffer, buffer_size, last);
+ size_t entry_size;
- /* 0 bytes read means an object corruption */
- if (entry_size == 0) {
+ if ((error = read_entry(&entry, &entry_size, index, buffer, buffer_size, last)) < 0) {
error = index_error_invalid("invalid entry");
goto done;
}