Skip to content

Commit 8f5d6b4

Browse files
author
Junio C Hamano
committed
Merge branch 'jc/pack'
* jc/pack: more lightweight revalidation while reusing deflated stream in packing pack-objects: fix thinko in revalidate code pack-objects: re-validate data we copy from elsewhere.
2 parents f685d07 + 72518e9 commit 8f5d6b4

File tree

4 files changed

+100
-16
lines changed

4 files changed

+100
-16
lines changed

builtin-pack-objects.c

Lines changed: 87 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ static unsigned char pack_file_sha1[20];
6565
static int progress = 1;
6666
static volatile sig_atomic_t progress_update;
6767
static int window = 10;
68+
static int pack_to_stdout;
6869

6970
/*
7071
* The object names in objects array are hashed with this hashtable,
@@ -242,6 +243,82 @@ static int encode_header(enum object_type type, unsigned long size, unsigned cha
242243
return n;
243244
}
244245

246+
static int check_inflate(unsigned char *data, unsigned long len, unsigned long expect)
247+
{
248+
z_stream stream;
249+
unsigned char fakebuf[4096];
250+
int st;
251+
252+
memset(&stream, 0, sizeof(stream));
253+
stream.next_in = data;
254+
stream.avail_in = len;
255+
stream.next_out = fakebuf;
256+
stream.avail_out = sizeof(fakebuf);
257+
inflateInit(&stream);
258+
259+
while (1) {
260+
st = inflate(&stream, Z_FINISH);
261+
if (st == Z_STREAM_END || st == Z_OK) {
262+
st = (stream.total_out == expect &&
263+
stream.total_in == len) ? 0 : -1;
264+
break;
265+
}
266+
if (st != Z_BUF_ERROR) {
267+
st = -1;
268+
break;
269+
}
270+
stream.next_out = fakebuf;
271+
stream.avail_out = sizeof(fakebuf);
272+
}
273+
inflateEnd(&stream);
274+
return st;
275+
}
276+
277+
/*
278+
* we are going to reuse the existing pack entry data. make
279+
* sure it is not corrupt.
280+
*/
281+
static int revalidate_pack_entry(struct object_entry *entry, unsigned char *data, unsigned long len)
282+
{
283+
enum object_type type;
284+
unsigned long size, used;
285+
286+
if (pack_to_stdout)
287+
return 0;
288+
289+
/* the caller has already called use_packed_git() for us,
290+
* so it is safe to access the pack data from mmapped location.
291+
* make sure the entry inflates correctly.
292+
*/
293+
used = unpack_object_header_gently(data, len, &type, &size);
294+
if (!used)
295+
return -1;
296+
if (type == OBJ_DELTA)
297+
used += 20; /* skip base object name */
298+
data += used;
299+
len -= used;
300+
return check_inflate(data, len, entry->size);
301+
}
302+
303+
static int revalidate_loose_object(struct object_entry *entry,
304+
unsigned char *map,
305+
unsigned long mapsize)
306+
{
307+
/* we already know this is a loose object with new type header. */
308+
enum object_type type;
309+
unsigned long size, used;
310+
311+
if (pack_to_stdout)
312+
return 0;
313+
314+
used = unpack_object_header_gently(map, mapsize, &type, &size);
315+
if (!used)
316+
return -1;
317+
map += used;
318+
mapsize -= used;
319+
return check_inflate(map, mapsize, size);
320+
}
321+
245322
static unsigned long write_object(struct sha1file *f,
246323
struct object_entry *entry)
247324
{
@@ -276,6 +353,9 @@ static unsigned long write_object(struct sha1file *f,
276353
map = map_sha1_file(entry->sha1, &mapsize);
277354
if (map && !legacy_loose_object(map)) {
278355
/* We can copy straight into the pack file */
356+
if (revalidate_loose_object(entry, map, mapsize))
357+
die("corrupt loose object %s",
358+
sha1_to_hex(entry->sha1));
279359
sha1write(f, map, mapsize);
280360
munmap(map, mapsize);
281361
written++;
@@ -286,7 +366,7 @@ static unsigned long write_object(struct sha1file *f,
286366
munmap(map, mapsize);
287367
}
288368

289-
if (! to_reuse) {
369+
if (!to_reuse) {
290370
buf = read_sha1_file(entry->sha1, type, &size);
291371
if (!buf)
292372
die("unable to read %s", sha1_to_hex(entry->sha1));
@@ -319,6 +399,9 @@ static unsigned long write_object(struct sha1file *f,
319399

320400
datalen = find_packed_object_size(p, entry->in_pack_offset);
321401
buf = (char *) p->pack_base + entry->in_pack_offset;
402+
403+
if (revalidate_pack_entry(entry, buf, datalen))
404+
die("corrupt delta in pack %s", sha1_to_hex(entry->sha1));
322405
sha1write(f, buf, datalen);
323406
unuse_packed_git(p);
324407
hdrlen = 0; /* not really */
@@ -1163,7 +1246,7 @@ static void prepare_pack(int window, int depth)
11631246
find_deltas(sorted_by_type, window+1, depth);
11641247
}
11651248

1166-
static int reuse_cached_pack(unsigned char *sha1, int pack_to_stdout)
1249+
static int reuse_cached_pack(unsigned char *sha1)
11671250
{
11681251
static const char cache[] = "pack-cache/pack-%s.%s";
11691252
char *cached_pack, *cached_idx;
@@ -1247,7 +1330,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
12471330
{
12481331
SHA_CTX ctx;
12491332
char line[40 + 1 + PATH_MAX + 2];
1250-
int depth = 10, pack_to_stdout = 0;
1333+
int depth = 10;
12511334
struct object_entry **list;
12521335
int num_preferred_base = 0;
12531336
int i;
@@ -1367,7 +1450,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
13671450
if (progress && (nr_objects != nr_result))
13681451
fprintf(stderr, "Result has %d objects.\n", nr_result);
13691452

1370-
if (reuse_cached_pack(object_list_sha1, pack_to_stdout))
1453+
if (reuse_cached_pack(object_list_sha1))
13711454
;
13721455
else {
13731456
if (nr_result)

cache.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,17 @@ extern int legacy_loose_object(unsigned char *);
267267
extern int has_pack_file(const unsigned char *sha1);
268268
extern int has_pack_index(const unsigned char *sha1);
269269

270+
enum object_type {
271+
OBJ_NONE = 0,
272+
OBJ_COMMIT = 1,
273+
OBJ_TREE = 2,
274+
OBJ_BLOB = 3,
275+
OBJ_TAG = 4,
276+
/* 5/6 for future expansion */
277+
OBJ_DELTA = 7,
278+
OBJ_BAD,
279+
};
280+
270281
/* Convert to/from hex/sha1 representation */
271282
#define MINIMUM_ABBREV 4
272283
#define DEFAULT_ABBREV 7
@@ -374,6 +385,7 @@ extern int num_packed_objects(const struct packed_git *p);
374385
extern int nth_packed_object_sha1(const struct packed_git *, int, unsigned char*);
375386
extern int find_pack_entry_one(const unsigned char *, struct pack_entry *, struct packed_git *);
376387
extern void *unpack_entry_gently(struct pack_entry *, char *, unsigned long *);
388+
extern unsigned long unpack_object_header_gently(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep);
377389
extern void packed_object_info_detail(struct pack_entry *, char *, unsigned long *, unsigned long *, unsigned int *, unsigned char *);
378390

379391
/* Dumb servers support */

object.h

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,6 @@ struct object_array {
2727
/*
2828
* The object type is stored in 3 bits.
2929
*/
30-
enum object_type {
31-
OBJ_NONE = 0,
32-
OBJ_COMMIT = 1,
33-
OBJ_TREE = 2,
34-
OBJ_BLOB = 3,
35-
OBJ_TAG = 4,
36-
/* 5/6 for future expansion */
37-
OBJ_DELTA = 7,
38-
OBJ_BAD,
39-
};
40-
4130
struct object {
4231
unsigned parsed : 1;
4332
unsigned used : 1;

sha1_file.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -711,7 +711,7 @@ int legacy_loose_object(unsigned char *map)
711711
return 0;
712712
}
713713

714-
static unsigned long unpack_object_header_gently(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep)
714+
unsigned long unpack_object_header_gently(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep)
715715
{
716716
unsigned shift;
717717
unsigned char c;

0 commit comments

Comments
 (0)