When unpacking objects from a packfile, the object size is decoded
from a variable-length encoding. On platforms where unsigned long is
32-bit (such as Windows, even in 64-bit builds), the shift operation
overflows when decoding sizes larger than 4GB. The result is a
truncated size value, causing the unpacked object to be corrupted or
rejected.
Fix this by changing the size variable to size_t, which is 64-bit on
64-bit platforms, and ensuring the shift arithmetic occurs in 64-bit
space.
Declare the per-byte continuation variable `c` as size_t as well,
matching the canonical varint decoder unpack_object_header_buffer()
in packfile.c. With c as size_t the expression (c & 0x7f) << shift
is naturally size_t-typed, so the explicit cast that an earlier
iteration carried at the use site is no longer needed.
While at it, add the same overflow guard that
unpack_object_header_buffer() carries: if the cumulative shift would
exceed bitsizeof(size_t) - 7, refuse the input rather than invoking
undefined behavior. Unlike unpack_object_header_buffer(), which
labels this case "bad object header", report it as the platform
limit it actually is: a header may be perfectly well-formed and
still encode a size we cannot represent locally (notably on a
32-bit build consuming a packfile produced on a 64-bit host).
This was originally authored by LordKiRon <https://github.com/LordKiRon>,
who preferred not to reveal their real name and therefore agreed that I
take over authorship.
Helped-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
struct object_entry {
struct pack_idx_entry idx;
- unsigned long size;
+ size_t size;
unsigned char hdr_size;
signed char type;
signed char real_type;
return (type == OBJ_REF_DELTA || type == OBJ_OFS_DELTA);
}
-static void *unpack_entry_data(off_t offset, unsigned long size,
+static void *unpack_entry_data(off_t offset, size_t size,
enum object_type type, struct object_id *oid)
{
static char fixed_buf[8192];
struct object_id *oid)
{
unsigned char *p;
- unsigned long size, c;
+ size_t size, c;
off_t base_offset;
unsigned shift;
void *data;
size = (c & 15);
shift = 4;
while (c & 0x80) {
+ if ((bitsizeof(size_t) - 7) < shift)
+ die(_("object size too large for this platform"));
p = fill(1);
c = *p;
use(1);
{
unsigned shift;
unsigned char *pack;
- unsigned long size, c;
+ size_t size, c;
enum object_type type;
obj_list[nr].offset = consumed_bytes;
size = (c & 15);
shift = 4;
while (c & 0x80) {
+ if ((bitsizeof(size_t) - 7) < shift)
+ die(_("object size too large for this platform"));
pack = fill(1);
c = *pack;
use(1);