commit 5e6be23258e2648c6ad1bf3b1d5617e827ac3ab6 from: Stefan Sperling date: Fri Nov 08 21:55:41 2019 UTC fix reading pack files larger than 2GB; ok tb@; problem found by mpi@ commit - 70015d7a0e09198dfe1d24d340818d8769ff6ab8 commit + 5e6be23258e2648c6ad1bf3b1d5617e827ac3ab6 blob - 7e7c69769bca88c55404098a3ff10d7603f937df blob + 654dfa86d4de464fcdc3b68b5b8469f50f476a4c --- lib/got_lib_pack.h +++ lib/got_lib_pack.h @@ -89,6 +89,7 @@ struct got_packidx { int fd; uint8_t *map; size_t len; + size_t nlargeobj; struct got_packidx_v2_hdr hdr; /* convenient pointers into map */ }; blob - b6f49c5941537ece4825344a137f3cbe7ac37e24 blob + f4d09931a07992b989e1780e9a1409217e137e08 --- lib/pack.c +++ lib/pack.c @@ -75,6 +75,7 @@ got_packidx_init_hdr(struct got_packidx *p, int verify uint8_t sha1[SHA1_DIGEST_LENGTH]; size_t nobj, len_fanout, len_ids, offset, remain; ssize_t n; + int i; SHA1Init(&ctx); @@ -255,35 +256,41 @@ got_packidx_init_hdr(struct got_packidx *p, int verify offset += nobj * sizeof(*h->offsets); /* Large file offsets are contained only in files > 2GB. */ - if (p->len <= 0x80000000) + for (i = 0; i < nobj; i++) { + uint32_t o = betoh32(h->offsets[i]); + if (o & GOT_PACKIDX_OFFSET_VAL_IS_LARGE_IDX) + p->nlargeobj++; + } + if (p->nlargeobj == 0) goto checksum; - if (remain < nobj * sizeof(*h->large_offsets)) { + if (remain < p->nlargeobj * sizeof(*h->large_offsets)) { err = got_error(GOT_ERR_BAD_PACKIDX); goto done; } if (p->map) h->large_offsets = (uint64_t *)((uint8_t*)(p->map + offset)); else { - h->large_offsets = malloc(nobj * sizeof(*h->large_offsets)); + h->large_offsets = malloc(p->nlargeobj * + sizeof(*h->large_offsets)); if (h->large_offsets == NULL) { err = got_error_from_errno("malloc"); goto done; } n = read(p->fd, h->large_offsets, - nobj * sizeof(*h->large_offsets)); + p->nlargeobj * sizeof(*h->large_offsets)); if (n < 0) err = got_error_from_errno("read"); - else if (n != nobj * sizeof(*h->large_offsets)) { + else if (n != p->nlargeobj * sizeof(*h->large_offsets)) { err = got_error(GOT_ERR_BAD_PACKIDX); goto done; } } if (verify) SHA1Update(&ctx, (uint8_t*)h->large_offsets, - nobj * sizeof(*h->large_offsets)); - remain -= nobj * sizeof(*h->large_offsets); - offset += nobj * sizeof(*h->large_offsets); + p->nlargeobj * sizeof(*h->large_offsets)); + remain -= p->nlargeobj * sizeof(*h->large_offsets); + offset += p->nlargeobj * sizeof(*h->large_offsets); checksum: if (remain < sizeof(*h->trailer)) { @@ -408,12 +415,11 @@ got_packidx_close(struct got_packidx *packidx) static off_t get_object_offset(struct got_packidx *packidx, int idx) { - uint32_t totobj = betoh32(packidx->hdr.fanout_table[0xff]); uint32_t offset = betoh32(packidx->hdr.offsets[idx]); if (offset & GOT_PACKIDX_OFFSET_VAL_IS_LARGE_IDX) { uint64_t loffset; idx = offset & GOT_PACKIDX_OFFSET_VAL_MASK; - if (idx < 0 || idx > totobj || + if (idx < 0 || idx >= packidx->nlargeobj || packidx->hdr.large_offsets == NULL) return -1; loffset = betoh64(packidx->hdr.large_offsets[idx]);