Commit 3207ddb0103543da8ad2139ec6539f590f9900c1

Patrick Steinhardt 2018-03-08T12:00:27

index: fix out-of-bounds read with invalid index entry prefix length The index format in version 4 has prefix-compressed entries, where every index entry can compress its path by using a path prefix of the previous entry. Since implmenting support for this index format version in commit 5625d86b9 (index: support index v4, 2016-05-17), though, we do not correctly verify that the prefix length that we want to reuse is actually smaller or equal to the amount of characters than the length of the previous index entry's path. This can lead to a an integer underflow and subsequently to an out-of-bounds read. Fix this by verifying that the prefix is actually smaller than the previous entry's path length. Reported-by: Krishna Ram Prakash R <krp@gtux.in> Reported-by: Vivek Parikh <viv0411.parikh@gmail.com>

diff --git a/src/index.c b/src/index.c
index 3ef892b..20586f5 100644
--- a/src/index.c
+++ b/src/index.c
@@ -2365,17 +2365,18 @@ static int 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);
 		tmp_path = git__malloc(path_len);