From: Omar Polo Subject: check for size_t overflow when mapping memory To: gameoftrees@openbsd.org Date: Mon, 24 Oct 2022 21:57:38 +0200 diff below ensures that every time we call mmap(2) the size argument effectively less than SIZE_MAX. In some cases this is a no-op since filesize is currently size_t and so we've potentially already truncated the value. In a follow-up commit i'd like to turn the `filesize' field in the structs got_pack and packidx from size_t to off_t, so these checks will start to work. diff 933f287a77cf1c9dced8ed3afbf3850f5c0c1bb3 90ac69281429b4caf05f7b3617e0acabdc062028 commit - 933f287a77cf1c9dced8ed3afbf3850f5c0c1bb3 commit + 90ac69281429b4caf05f7b3617e0acabdc062028 blob - f8e685448165384cfc578c0f089b4aa6fb6219c8 blob + 7f2a014edb74884a7f92a43fb66ec78eb24e3228 --- lib/object.c +++ lib/object.c @@ -926,7 +926,10 @@ got_object_raw_alloc(struct got_raw_object **obj, uint size_t hdrlen, off_t size) { const struct got_error *err = NULL; + off_t tot; + tot = hdrlen + size; + *obj = calloc(1, sizeof(**obj)); if (*obj == NULL) { err = got_error_from_errno("calloc"); @@ -944,13 +947,15 @@ got_object_raw_alloc(struct got_raw_object **obj, uint goto done; } - if (sb.st_size != hdrlen + size) { + if (sb.st_size != tot) { err = got_error(GOT_ERR_PRIVSEP_LEN); goto done; } #ifndef GOT_PACK_NO_MMAP - if (hdrlen + size > 0) { - (*obj)->data = mmap(NULL, hdrlen + size, PROT_READ, + (*obj)->fd = *outfd; + *outfd = -1; + if (tot > 0 && tot < SIZE_MAX) { + (*obj)->data = mmap(NULL, tot, PROT_READ, MAP_PRIVATE, *outfd, 0); if ((*obj)->data == MAP_FAILED) { if (errno != ENOMEM) { @@ -958,9 +963,6 @@ got_object_raw_alloc(struct got_raw_object **obj, uint goto done; } (*obj)->data = NULL; - } else { - (*obj)->fd = *outfd; - *outfd = -1; } } #endif blob - becc8ffd68217466f0bad6d811196c0d7137e4df blob + 0b79146e747f73787b2ee568b7fb74c517ce1d9e --- lib/pack.c +++ lib/pack.c @@ -392,13 +392,15 @@ got_packidx_open(struct got_packidx **packidx, } #ifndef GOT_PACK_NO_MMAP - p->map = mmap(NULL, p->len, PROT_READ, MAP_PRIVATE, p->fd, 0); - if (p->map == MAP_FAILED) { - if (errno != ENOMEM) { - err = got_error_from_errno("mmap"); - goto done; + if (p->len < SIZE_MAX) { + p->map = mmap(NULL, p->len, PROT_READ, MAP_PRIVATE, p->fd, 0); + if (p->map == MAP_FAILED) { + if (errno != ENOMEM) { + err = got_error_from_errno("mmap"); + goto done; + } + p->map = NULL; /* fall back to read(2) */ } - p->map = NULL; /* fall back to read(2) */ } #endif @@ -1036,7 +1038,6 @@ resolve_offset_delta(struct got_delta_chain *deltas, resolve_offset_delta(struct got_delta_chain *deltas, struct got_packidx *packidx, struct got_pack *pack, off_t delta_offset, size_t tslen, int delta_type, size_t delta_size, unsigned int recursion) - { const struct got_error *err; off_t base_offset; blob - b07bf0c9c711997031a7d3afa3388a27527ef2db blob + 7372c43fc3a9bd8d47fb3d868c90311eb3c51451 --- lib/repository.c +++ lib/repository.c @@ -1427,15 +1427,18 @@ got_repo_cache_pack(struct got_pack **packp, struct go if (err) goto done; + pack->map = NULL; #ifndef GOT_PACK_NO_MMAP - pack->map = mmap(NULL, pack->filesize, PROT_READ, MAP_PRIVATE, - pack->fd, 0); - if (pack->map == MAP_FAILED) { - if (errno != ENOMEM) { - err = got_error_from_errno("mmap"); - goto done; + if (pack->filesize < SIZE_MAX) { + pack->map = mmap(NULL, pack->filesize, PROT_READ, MAP_PRIVATE, + pack->fd, 0); + if (pack->map == MAP_FAILED) { + if (errno != ENOMEM) { + err = got_error_from_errno("mmap"); + goto done; + } + pack->map = NULL; /* fall back to read(2) */ } - pack->map = NULL; /* fall back to read(2) */ } #endif done: blob - 8a38382357c6aeb5b642965a26a50d9a6621d34e blob + e914ae79dd30bfd6591ea94dfadb6d91ddd80c65 --- libexec/got-index-pack/got-index-pack.c +++ libexec/got-index-pack/got-index-pack.c @@ -183,10 +183,12 @@ main(int argc, char **argv) } #ifndef GOT_PACK_NO_MMAP - pack.map = mmap(NULL, pack.filesize, PROT_READ, MAP_PRIVATE, - pack.fd, 0); - if (pack.map == MAP_FAILED) - pack.map = NULL; /* fall back to read(2) */ + if (pack.filesize < SIZE_MAX) { + pack.map = mmap(NULL, pack.filesize, PROT_READ, MAP_PRIVATE, + pack.fd, 0); + if (pack.map == MAP_FAILED) + pack.map = NULL; /* fall back to read(2) */ + } #endif err = got_pack_index(&pack, idxfd, tmpfiles[0], tmpfiles[1], tmpfiles[2], pack_hash, send_index_pack_progress, &ibuf, &rl); blob - 268ab18c5371e622b7f9c3a62c9a894a7050de85 blob + fd77f35cfff0c52c0cf09457929ce3c48d8470c8 --- libexec/got-read-pack/got-read-pack.c +++ libexec/got-read-pack/got-read-pack.c @@ -1146,9 +1146,11 @@ receive_packidx(struct got_packidx **packidx, struct i } #ifndef GOT_PACK_NO_MMAP - p->map = mmap(NULL, p->len, PROT_READ, MAP_PRIVATE, p->fd, 0); - if (p->map == MAP_FAILED) - p->map = NULL; /* fall back to read(2) */ + if (p->len < SIZE_MAX) { + p->map = mmap(NULL, p->len, PROT_READ, MAP_PRIVATE, p->fd, 0); + if (p->map == MAP_FAILED) + p->map = NULL; /* fall back to read(2) */ + } #endif err = got_packidx_init_hdr(p, 1, ipackidx.packfile_size); done: @@ -1874,10 +1876,12 @@ receive_pack(struct got_pack **packp, struct imsgbuf * goto done; #ifndef GOT_PACK_NO_MMAP - pack->map = mmap(NULL, pack->filesize, PROT_READ, MAP_PRIVATE, - pack->fd, 0); - if (pack->map == MAP_FAILED) - pack->map = NULL; /* fall back to read(2) */ + if (pack->filesize < SIZE_MAX) { + pack->map = mmap(NULL, pack->filesize, PROT_READ, MAP_PRIVATE, + pack->fd, 0); + if (pack->map == MAP_FAILED) + pack->map = NULL; /* fall back to read(2) */ + } #endif done: if (err) {