add overflow tests on pack offset variables
authorNicolas Pitre <nico@cam.org>
Mon, 9 Apr 2007 05:06:30 +0000 (01:06 -0400)
committerJunio C Hamano <junkio@cox.net>
Tue, 10 Apr 2007 19:48:14 +0000 (12:48 -0700)
Change a few size and offset variables to more appropriate type, then
add overflow tests on those offsets.  This prevents any bad data to be
generated/processed if off_t happens to not be large enough to handle
some big packs.

Better be safe than sorry.

Signed-off-by: Nicolas Pitre <nico@cam.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
builtin-pack-objects.c
builtin-unpack-objects.c
index-pack.c

index ee607a0d2c086d93d9d9f56453a4e79e397b4a20..d0be879443c16fe7b2fec319a9965ae13af28a9b 100644 (file)
@@ -369,7 +369,7 @@ static int revalidate_loose_object(struct object_entry *entry,
        return check_loose_inflate(map, mapsize, size);
 }
 
-static off_t write_object(struct sha1file *f,
+static unsigned long write_object(struct sha1file *f,
                                  struct object_entry *entry)
 {
        unsigned long size;
@@ -503,16 +503,23 @@ static off_t write_one(struct sha1file *f,
                               struct object_entry *e,
                               off_t offset)
 {
+       unsigned long size;
+
+       /* offset is non zero if object is written already. */
        if (e->offset || e->preferred_base)
-               /* offset starts from header size and cannot be zero
-                * if it is written already.
-                */
                return offset;
-       /* if we are deltified, write out its base object first. */
+
+       /* if we are deltified, write out base object first. */
        if (e->delta)
                offset = write_one(f, e->delta, offset);
+
        e->offset = offset;
-       return offset + write_object(f, e);
+       size = write_object(f, e);
+
+       /* make sure off_t is sufficiently large not to wrap */
+       if (offset > offset + size)
+               die("pack too large for current definition of off_t");
+       return offset + size;
 }
 
 static void write_pack_file(void)
index 63f7db6831f7d5408ddf67d0f7f882c4a7b236cd..f8219064602775346bb0d8a323339b3d077da31c 100644 (file)
@@ -13,7 +13,8 @@ static const char unpack_usage[] = "git-unpack-objects [-n] [-q] [-r] < pack-fil
 
 /* We always read in 4kB chunks. */
 static unsigned char buffer[4096];
-static unsigned long offset, len, consumed_bytes;
+static unsigned int offset, len;
+static off_t consumed_bytes;
 static SHA_CTX ctx;
 
 /*
@@ -49,6 +50,10 @@ static void use(int bytes)
                die("used more bytes than were available");
        len -= bytes;
        offset += bytes;
+
+       /* make sure off_t is sufficiently large not to wrap */
+       if (consumed_bytes > consumed_bytes + bytes)
+               die("pack too large for current definition of off_t");
        consumed_bytes += bytes;
 }
 
@@ -88,17 +93,17 @@ static void *get_data(unsigned long size)
 
 struct delta_info {
        unsigned char base_sha1[20];
-       unsigned long base_offset;
+       unsigned nr;
+       off_t base_offset;
        unsigned long size;
        void *delta;
-       unsigned nr;
        struct delta_info *next;
 };
 
 static struct delta_info *delta_list;
 
 static void add_delta_to_list(unsigned nr, unsigned const char *base_sha1,
-                             unsigned long base_offset,
+                             off_t base_offset,
                              void *delta, unsigned long size)
 {
        struct delta_info *info = xmalloc(sizeof(*info));
@@ -113,7 +118,7 @@ static void add_delta_to_list(unsigned nr, unsigned const char *base_sha1,
 }
 
 struct obj_info {
-       unsigned long offset;
+       off_t offset;
        unsigned char sha1[20];
 };
 
@@ -200,7 +205,7 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
        } else {
                unsigned base_found = 0;
                unsigned char *pack, c;
-               unsigned long base_offset;
+               off_t base_offset;
                unsigned lo, mid, hi;
 
                pack = fill(1);
index 0e54aa68448bab2497f16e57f34537f7ac884f37..66fb0bcedf17a6205ec21aef2ad67c51f791bca7 100644 (file)
@@ -12,7 +12,7 @@ static const char index_pack_usage[] =
 
 struct object_entry
 {
-       unsigned long offset;
+       off_t offset;
        unsigned long size;
        unsigned int hdr_size;
        enum object_type type;
@@ -22,7 +22,7 @@ struct object_entry
 
 union delta_base {
        unsigned char sha1[20];
-       unsigned long offset;
+       off_t offset;
 };
 
 /*
@@ -83,7 +83,8 @@ static unsigned display_progress(unsigned n, unsigned total, unsigned last_pc)
 
 /* We always read in 4kB chunks. */
 static unsigned char input_buffer[4096];
-static unsigned long input_offset, input_len, consumed_bytes;
+static unsigned int input_offset, input_len;
+static off_t consumed_bytes;
 static SHA_CTX input_ctx;
 static int input_fd, output_fd, pack_fd;
 
@@ -129,6 +130,10 @@ static void use(int bytes)
                die("used more bytes than were available");
        input_len -= bytes;
        input_offset += bytes;
+
+       /* make sure off_t is sufficiently large not to wrap */
+       if (consumed_bytes > consumed_bytes + bytes)
+               die("pack too large for current definition of off_t");
        consumed_bytes += bytes;
 }
 
@@ -216,7 +221,8 @@ static void *unpack_entry_data(unsigned long offset, unsigned long size)
 static void *unpack_raw_entry(struct object_entry *obj, union delta_base *delta_base)
 {
        unsigned char *p, c;
-       unsigned long size, base_offset;
+       unsigned long size;
+       off_t base_offset;
        unsigned shift;
 
        obj->offset = consumed_bytes;