Skip to content

Commit aa9136a

Browse files
committed
Merge branch 'nd/pack-ofs-4gb-limit' into maint
"git pack-objects" and "git index-pack" mostly operate with off_t when talking about the offset of objects in a packfile, but there were a handful of places that used "unsigned long" to hold that value, leading to an unintended truncation. * nd/pack-ofs-4gb-limit: fsck: use streaming interface for large blobs in pack pack-objects: do not truncate result in-pack object size on 32-bit systems index-pack: correct "offset" type in unpack_entry_data() index-pack: report correct bad object offsets even if they are large index-pack: correct "len" type in unpack_data() sha1_file.c: use type off_t* for object_info->disk_sizep pack-objects: pass length to check_pack_crc() without truncation
2 parents 743fba8 + ec9d224 commit aa9136a

File tree

9 files changed

+54
-29
lines changed

9 files changed

+54
-29
lines changed

builtin/cat-file.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ struct expand_data {
131131
unsigned char sha1[20];
132132
enum object_type type;
133133
unsigned long size;
134-
unsigned long disk_size;
134+
off_t disk_size;
135135
const char *rest;
136136
unsigned char delta_base_sha1[20];
137137

@@ -191,7 +191,7 @@ static void expand_atom(struct strbuf *sb, const char *atom, int len,
191191
if (data->mark_query)
192192
data->info.disk_sizep = &data->disk_size;
193193
else
194-
strbuf_addf(sb, "%lu", data->disk_size);
194+
strbuf_addf(sb, "%"PRIuMAX, (uintmax_t)data->disk_size);
195195
} else if (is_atom("rest", atom, len)) {
196196
if (data->mark_query)
197197
data->split_on_whitespace = 1;

builtin/fsck.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,10 @@ static int fsck_sha1(const unsigned char *sha1)
356356
static int fsck_obj_buffer(const unsigned char *sha1, enum object_type type,
357357
unsigned long size, void *buffer, int *eaten)
358358
{
359+
/*
360+
* Note, buffer may be NULL if type is OBJ_BLOB. See
361+
* verify_packfile(), data_valid variable for details.
362+
*/
359363
struct object *obj;
360364
obj = parse_object_buffer(sha1, type, size, buffer, eaten);
361365
if (!obj) {

builtin/index-pack.c

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -338,18 +338,19 @@ static void parse_pack_header(void)
338338
use(sizeof(struct pack_header));
339339
}
340340

341-
static NORETURN void bad_object(unsigned long offset, const char *format,
341+
static NORETURN void bad_object(off_t offset, const char *format,
342342
...) __attribute__((format (printf, 2, 3)));
343343

344-
static NORETURN void bad_object(unsigned long offset, const char *format, ...)
344+
static NORETURN void bad_object(off_t offset, const char *format, ...)
345345
{
346346
va_list params;
347347
char buf[1024];
348348

349349
va_start(params, format);
350350
vsnprintf(buf, sizeof(buf), format, params);
351351
va_end(params);
352-
die(_("pack has bad object at offset %lu: %s"), offset, buf);
352+
die(_("pack has bad object at offset %"PRIuMAX": %s"),
353+
(uintmax_t)offset, buf);
353354
}
354355

355356
static inline struct thread_local *get_thread_data(void)
@@ -429,7 +430,7 @@ static int is_delta_type(enum object_type type)
429430
return (type == OBJ_REF_DELTA || type == OBJ_OFS_DELTA);
430431
}
431432

432-
static void *unpack_entry_data(unsigned long offset, unsigned long size,
433+
static void *unpack_entry_data(off_t offset, unsigned long size,
433434
enum object_type type, unsigned char *sha1)
434435
{
435436
static char fixed_buf[8192];
@@ -549,29 +550,29 @@ static void *unpack_data(struct object_entry *obj,
549550
void *cb_data)
550551
{
551552
off_t from = obj[0].idx.offset + obj[0].hdr_size;
552-
unsigned long len = obj[1].idx.offset - from;
553+
off_t len = obj[1].idx.offset - from;
553554
unsigned char *data, *inbuf;
554555
git_zstream stream;
555556
int status;
556557

557558
data = xmallocz(consume ? 64*1024 : obj->size);
558-
inbuf = xmalloc((len < 64*1024) ? len : 64*1024);
559+
inbuf = xmalloc((len < 64*1024) ? (int)len : 64*1024);
559560

560561
memset(&stream, 0, sizeof(stream));
561562
git_inflate_init(&stream);
562563
stream.next_out = data;
563564
stream.avail_out = consume ? 64*1024 : obj->size;
564565

565566
do {
566-
ssize_t n = (len < 64*1024) ? len : 64*1024;
567+
ssize_t n = (len < 64*1024) ? (ssize_t)len : 64*1024;
567568
n = xpread(get_thread_data()->pack_fd, inbuf, n, from);
568569
if (n < 0)
569570
die_errno(_("cannot pread pack file"));
570571
if (!n)
571-
die(Q_("premature end of pack file, %lu byte missing",
572-
"premature end of pack file, %lu bytes missing",
573-
len),
574-
len);
572+
die(Q_("premature end of pack file, %"PRIuMAX" byte missing",
573+
"premature end of pack file, %"PRIuMAX" bytes missing",
574+
(unsigned int)len),
575+
(uintmax_t)len);
575576
from += n;
576577
len -= n;
577578
stream.next_in = inbuf;

builtin/pack-objects.c

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -341,15 +341,15 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent
341341
}
342342

343343
/* Return 0 if we will bust the pack-size limit */
344-
static unsigned long write_reuse_object(struct sha1file *f, struct object_entry *entry,
345-
unsigned long limit, int usable_delta)
344+
static off_t write_reuse_object(struct sha1file *f, struct object_entry *entry,
345+
unsigned long limit, int usable_delta)
346346
{
347347
struct packed_git *p = entry->in_pack;
348348
struct pack_window *w_curs = NULL;
349349
struct revindex_entry *revidx;
350350
off_t offset;
351351
enum object_type type = entry->type;
352-
unsigned long datalen;
352+
off_t datalen;
353353
unsigned char header[10], dheader[10];
354354
unsigned hdrlen;
355355

@@ -415,11 +415,12 @@ static unsigned long write_reuse_object(struct sha1file *f, struct object_entry
415415
}
416416

417417
/* Return 0 if we will bust the pack-size limit */
418-
static unsigned long write_object(struct sha1file *f,
419-
struct object_entry *entry,
420-
off_t write_offset)
418+
static off_t write_object(struct sha1file *f,
419+
struct object_entry *entry,
420+
off_t write_offset)
421421
{
422-
unsigned long limit, len;
422+
unsigned long limit;
423+
off_t len;
423424
int usable_delta, to_reuse;
424425

425426
if (!pack_to_stdout)
@@ -491,7 +492,7 @@ static enum write_one_status write_one(struct sha1file *f,
491492
struct object_entry *e,
492493
off_t *offset)
493494
{
494-
unsigned long size;
495+
off_t size;
495496
int recursing;
496497

497498
/*

cache.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1508,7 +1508,7 @@ struct object_info {
15081508
/* Request */
15091509
enum object_type *typep;
15101510
unsigned long *sizep;
1511-
unsigned long *disk_sizep;
1511+
off_t *disk_sizep;
15121512
unsigned char *delta_base_sha1;
15131513
struct strbuf *typename;
15141514

pack-check.c

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ static int verify_packfile(struct packed_git *p,
105105
void *data;
106106
enum object_type type;
107107
unsigned long size;
108+
off_t curpos;
109+
int data_valid;
108110

109111
if (p->index_version > 1) {
110112
off_t offset = entries[i].offset;
@@ -116,8 +118,25 @@ static int verify_packfile(struct packed_git *p,
116118
sha1_to_hex(entries[i].sha1),
117119
p->pack_name, (uintmax_t)offset);
118120
}
119-
data = unpack_entry(p, entries[i].offset, &type, &size);
120-
if (!data)
121+
122+
curpos = entries[i].offset;
123+
type = unpack_object_header(p, w_curs, &curpos, &size);
124+
unuse_pack(w_curs);
125+
126+
if (type == OBJ_BLOB && big_file_threshold <= size) {
127+
/*
128+
* Let check_sha1_signature() check it with
129+
* the streaming interface; no point slurping
130+
* the data in-core only to discard.
131+
*/
132+
data = NULL;
133+
data_valid = 0;
134+
} else {
135+
data = unpack_entry(p, entries[i].offset, &type, &size);
136+
data_valid = 1;
137+
}
138+
139+
if (data_valid && !data)
121140
err = error("cannot unpack %s from %s at offset %"PRIuMAX"",
122141
sha1_to_hex(entries[i].sha1), p->pack_name,
123142
(uintmax_t)entries[i].offset);

pack.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ struct pack_idx_entry {
7474

7575

7676
struct progress;
77+
/* Note, the data argument could be NULL if object type is blob */
7778
typedef int (*verify_fn)(const unsigned char*, enum object_type, unsigned long, void*, int*);
7879

7980
extern const char *write_idx_file(const char *index_name, struct pack_idx_entry **objects, int nr_objects, const struct pack_idx_option *, const unsigned char *sha1);

sha1_file.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2281,7 +2281,7 @@ void *unpack_entry(struct packed_git *p, off_t obj_offset,
22812281

22822282
if (do_check_packed_object_crc && p->index_version > 1) {
22832283
struct revindex_entry *revidx = find_pack_revindex(p, obj_offset);
2284-
unsigned long len = revidx[1].offset - obj_offset;
2284+
off_t len = revidx[1].offset - obj_offset;
22852285
if (check_pack_crc(p, &w_curs, obj_offset, len, revidx->nr)) {
22862286
const unsigned char *sha1 =
22872287
nth_packed_object_sha1(p, revidx->nr);

t/t1050-large.sh

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -177,10 +177,9 @@ test_expect_success 'zip achiving, deflate' '
177177
git archive --format=zip HEAD >/dev/null
178178
'
179179

180-
test_expect_success 'fsck' '
181-
test_must_fail git fsck 2>err &&
182-
n=$(grep "error: attempting to allocate .* over limit" err | wc -l) &&
183-
test "$n" -gt 1
180+
test_expect_success 'fsck large blobs' '
181+
git fsck 2>err &&
182+
test_must_be_empty err
184183
'
185184

186185
test_done

0 commit comments

Comments
 (0)