summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--builtin/index-pack.c1
-rw-r--r--cache.h10
-rw-r--r--sha1_file.c15
-rwxr-xr-xt/t5313-pack-bounds-checks.sh2
4 files changed, 27 insertions, 1 deletions
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 723fe8e..98bdbb5 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -1445,6 +1445,7 @@ static void read_v2_anomalous_offsets(struct packed_git *p,
if (!(off & 0x80000000))
continue;
off = off & 0x7fffffff;
+ check_pack_index_ptr(p, &idx2[off * 2]);
if (idx2[off * 2])
continue;
/*
diff --git a/cache.h b/cache.h
index 4427945..6c9aaa1 100644
--- a/cache.h
+++ b/cache.h
@@ -1237,6 +1237,16 @@ extern void clear_delta_base_cache(void);
extern struct packed_git *add_packed_git(const char *, int, int);
/*
+ * Make sure that a pointer access into an mmap'd index file is within bounds,
+ * and can provide at least 8 bytes of data.
+ *
+ * Note that this is only necessary for variable-length segments of the file
+ * (like the 64-bit extended offset table), as we compare the size to the
+ * fixed-length parts when we open the file.
+ */
+extern void check_pack_index_ptr(const struct packed_git *p, const void *ptr);
+
+/*
* Return the SHA-1 of the nth object within the specified packfile.
* Open the index if it is not already open. The return value points
* at the SHA-1 within the mmapped index. Return NULL if there is an
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)));
}
diff --git a/t/t5313-pack-bounds-checks.sh b/t/t5313-pack-bounds-checks.sh
index efc5197..0717746 100755
--- a/t/t5313-pack-bounds-checks.sh
+++ b/t/t5313-pack-bounds-checks.sh
@@ -128,7 +128,7 @@ test_expect_success 'bogus object offset (v2, no msb)' '
test_must_fail git index-pack --verify $pack
'
-test_expect_failure 'bogus offset into v2 extended table' '
+test_expect_success 'bogus offset into v2 extended table' '
do_pack $object --index-version=2 &&
munge $idx $(ofs_table 1) "\377\0\0\0" &&
clear_base &&