summaryrefslogtreecommitdiff
path: root/sha1_file.c
diff options
context:
space:
mode:
authorJeff King <peff@peff.net>2016-02-25 14:22:52 (GMT)
committerJunio C Hamano <gitster@pobox.com>2016-02-25 19:32:43 (GMT)
commit47fe3f6ef0f5a336db90d816c5fb4330ffa23668 (patch)
tree86425f817d2e2116956355c387cafd78b50e9877 /sha1_file.c
parenta1283866bab1cd12da57b3e427664180f5dee333 (diff)
downloadgit-47fe3f6ef0f5a336db90d816c5fb4330ffa23668.zip
git-47fe3f6ef0f5a336db90d816c5fb4330ffa23668.tar.gz
git-47fe3f6ef0f5a336db90d816c5fb4330ffa23668.tar.bz2
nth_packed_object_offset: bounds-check extended offset
If a pack .idx file has a corrupted offset for an object, we may try to access an offset in the .idx or .pack file that is larger than the file's size. For the .pack case, we have use_pack() to protect us, which realizes the access is out of bounds. But if the corrupted value asks us to look in the .idx file's secondary 64-bit offset table, we blindly add it to the mmap'd index data and access arbitrary memory. We can fix this with a simple bounds-check compared to the size we found when we opened the .idx file. Note that there's similar code in index-pack that is triggered only during "index-pack --verify". To support both, we pull the bounds-check into a separate function, which dies when it sees a corrupted file. It would be nice if we could return an error, so that the pack code could try to find a good copy of the object elsewhere. Currently nth_packed_object_offset doesn't have any way to return an error, but it could probably use "0" as a sentinel value (since no object can start there). This is the minimal fix, and we can improve the resilience later on top. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'sha1_file.c')
-rw-r--r--sha1_file.c15
1 files changed, 15 insertions, 0 deletions
diff --git a/sha1_file.c b/sha1_file.c
index 99155c0..bd0f8f7 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -2359,6 +2359,20 @@ const unsigned char *nth_packed_object_sha1(struct packed_git *p,
}
}
+void check_pack_index_ptr(const struct packed_git *p, const void *vptr)
+{
+ const unsigned char *ptr = vptr;
+ const unsigned char *start = p->index_data;
+ const unsigned char *end = start + p->index_size;
+ if (ptr < start)
+ die("offset before start of pack index for %s (corrupt index?)",
+ p->pack_name);
+ /* No need to check for underflow; .idx files must be at least 8 bytes */
+ if (ptr >= end - 8)
+ die("offset beyond end of pack index for %s (truncated index?)",
+ p->pack_name);
+}
+
off_t nth_packed_object_offset(const struct packed_git *p, uint32_t n)
{
const unsigned char *index = p->index_data;
@@ -2372,6 +2386,7 @@ off_t nth_packed_object_offset(const struct packed_git *p, uint32_t n)
if (!(off & 0x80000000))
return off;
index += p->num_objects * 4 + (off & 0x7fffffff) * 8;
+ check_pack_index_ptr(p, index);
return (((uint64_t)ntohl(*((uint32_t *)(index + 0)))) << 32) |
ntohl(*((uint32_t *)(index + 4)));
}