From 2b975a449c17268f943403176a7609079b7af084 Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Sat, 4 May 2019 15:32:52 +0200 Subject: Remove compressor internal buffers Pass in an external destination buffer + size and allow for propper bounds checking (especially when unpacking). Signed-off-by: David Oberhollenzer --- include/compress.h | 3 ++- include/meta_reader.h | 1 + include/meta_writer.h | 3 ++- lib/comp/lzma.c | 34 ++++++++++++---------------------- lib/comp/zlib.c | 13 ++++++------- lib/sqfs/frag_reader.c | 7 +++++-- lib/sqfs/meta_reader.c | 8 +++++++- lib/sqfs/meta_writer.c | 10 +++++++--- lib/sqfs/super.c | 4 ++-- mkfs/block.c | 27 ++++++++++++++++++++++----- mkfs/mksquashfs.h | 1 + mkfs/options.c | 3 +-- unpack/extract_file.c | 13 +++++++++---- 13 files changed, 77 insertions(+), 50 deletions(-) diff --git a/include/compress.h b/include/compress.h index d527307..ad193e8 100644 --- a/include/compress.h +++ b/include/compress.h @@ -12,7 +12,8 @@ typedef struct compressor_t compressor_t; struct compressor_t { - ssize_t (*do_block)(compressor_t *cmp, uint8_t *block, size_t outsize); + ssize_t (*do_block)(compressor_t *cmp, const uint8_t *in, size_t size, + uint8_t *out, size_t outsize); void (*destroy)(compressor_t *stream); }; diff --git a/include/meta_reader.h b/include/meta_reader.h index 1fb527a..3085383 100644 --- a/include/meta_reader.h +++ b/include/meta_reader.h @@ -12,6 +12,7 @@ typedef struct { int fd; compressor_t *cmp; uint8_t data[SQFS_META_BLOCK_SIZE]; + uint8_t scratch[SQFS_META_BLOCK_SIZE]; } meta_reader_t; meta_reader_t *meta_reader_create(int fd, compressor_t *cmp); diff --git a/include/meta_writer.h b/include/meta_writer.h index 03f9a2e..7f1be9a 100644 --- a/include/meta_writer.h +++ b/include/meta_writer.h @@ -6,11 +6,12 @@ #include "squashfs.h" typedef struct { - uint8_t data[SQFS_META_BLOCK_SIZE + 2]; size_t offset; size_t block_offset; int outfd; compressor_t *cmp; + uint8_t data[SQFS_META_BLOCK_SIZE + 2]; + uint8_t scratch[SQFS_META_BLOCK_SIZE + 2]; } meta_writer_t; meta_writer_t *meta_writer_create(int fd, compressor_t *cmp); diff --git a/lib/comp/lzma.c b/lib/comp/lzma.c index fd2a6c7..3169c33 100644 --- a/lib/comp/lzma.c +++ b/lib/comp/lzma.c @@ -9,12 +9,11 @@ typedef struct { compressor_t base; - size_t block_size; - uint8_t buffer[]; } lzma_compressor_t; -static ssize_t lzma_comp_block(compressor_t *base, uint8_t *block, size_t size) +static ssize_t lzma_comp_block(compressor_t *base, const uint8_t *in, + size_t size, uint8_t *out, size_t outsize) { lzma_compressor_t *lzma = (lzma_compressor_t *)base; lzma_filter filters[5]; @@ -36,16 +35,10 @@ static ssize_t lzma_comp_block(compressor_t *base, uint8_t *block, size_t size) filters[1].options = NULL; ret = lzma_stream_buffer_encode(filters, LZMA_CHECK_CRC32, NULL, - block, size, lzma->buffer, - &written, lzma->block_size); - - if (ret == LZMA_OK) { - if (written >= size) - return 0; + in, size, out, &written, outsize); - memcpy(block, lzma->buffer, size); - return written; - } + if (ret == LZMA_OK) + return (written >= size) ? 0 : written; if (ret != LZMA_BUF_ERROR) { fputs("lzma block compress failed\n", stderr); @@ -55,24 +48,21 @@ static ssize_t lzma_comp_block(compressor_t *base, uint8_t *block, size_t size) return 0; } -static ssize_t lzma_uncomp_block(compressor_t *base, uint8_t *block, - size_t size) +static ssize_t lzma_uncomp_block(compressor_t *base, const uint8_t *in, + size_t size, uint8_t *out, size_t outsize) { - lzma_compressor_t *lzma = (lzma_compressor_t *)base; uint64_t memlimit = 32 * 1024 * 1024; size_t dest_pos = 0; size_t src_pos = 0; lzma_ret ret; + (void)base; ret = lzma_stream_buffer_decode(&memlimit, 0, NULL, - block, &src_pos, size, - lzma->buffer, &dest_pos, - lzma->block_size); + in, &src_pos, size, + out, &dest_pos, outsize); - if (ret == LZMA_OK && size == src_pos) { - memcpy(block, lzma->buffer, dest_pos); + if (ret == LZMA_OK && size == src_pos) return (ssize_t)dest_pos; - } fputs("lzma block extract failed\n", stderr); return -1; @@ -85,7 +75,7 @@ static void lzma_destroy(compressor_t *base) compressor_t *create_lzma_compressor(bool compress, size_t block_size) { - lzma_compressor_t *lzma = calloc(1, sizeof(*lzma) + block_size); + lzma_compressor_t *lzma = calloc(1, sizeof(*lzma)); compressor_t *base = (compressor_t *)lzma; if (lzma == NULL) { diff --git a/lib/comp/zlib.c b/lib/comp/zlib.c index d3bfe70..f151132 100644 --- a/lib/comp/zlib.c +++ b/lib/comp/zlib.c @@ -14,7 +14,6 @@ typedef struct { bool compress; size_t block_size; - uint8_t buffer[]; } zlib_compressor_t; static void zlib_destroy(compressor_t *base) @@ -30,7 +29,8 @@ static void zlib_destroy(compressor_t *base) free(zlib); } -static ssize_t zlib_do_block(compressor_t *base, uint8_t *block, size_t size) +static ssize_t zlib_do_block(compressor_t *base, const uint8_t *in, + size_t size, uint8_t *out, size_t outsize) { zlib_compressor_t *zlib = (zlib_compressor_t *)base; size_t written; @@ -47,10 +47,10 @@ static ssize_t zlib_do_block(compressor_t *base, uint8_t *block, size_t size) return -1; } - zlib->strm.next_in = (void *)block; + zlib->strm.next_in = (void *)in; zlib->strm.avail_in = size; - zlib->strm.next_out = zlib->buffer; - zlib->strm.avail_out = zlib->block_size; + zlib->strm.next_out = out; + zlib->strm.avail_out = outsize; if (zlib->compress) { ret = deflate(&zlib->strm, Z_FINISH); @@ -64,7 +64,6 @@ static ssize_t zlib_do_block(compressor_t *base, uint8_t *block, size_t size) if (zlib->compress && written >= size) return 0; - memcpy(block, zlib->buffer, written); return (ssize_t)written; } @@ -78,7 +77,7 @@ static ssize_t zlib_do_block(compressor_t *base, uint8_t *block, size_t size) compressor_t *create_zlib_compressor(bool compress, size_t block_size) { - zlib_compressor_t *zlib = calloc(1, sizeof(*zlib) + block_size); + zlib_compressor_t *zlib = calloc(1, sizeof(*zlib)); compressor_t *base = (compressor_t *)zlib; int ret; diff --git a/lib/sqfs/frag_reader.c b/lib/sqfs/frag_reader.c index 1906376..74fd292 100644 --- a/lib/sqfs/frag_reader.c +++ b/lib/sqfs/frag_reader.c @@ -42,12 +42,15 @@ static int precache_block(frag_reader_t *f, size_t i) } if (compressed) { - ret = f->cmp->do_block(f->cmp, f->buffer, size); + ret = f->cmp->do_block(f->cmp, f->buffer, size, + f->buffer + f->block_size, f->block_size); if (ret <= 0) { fputs("extracting fragment failed\n", stderr); return -1; } + + memmove(f->buffer, f->buffer + f->block_size, ret); } f->current_index = i; @@ -73,7 +76,7 @@ frag_reader_t *frag_reader_create(sqfs_super_t *super, int fd, ++blockcount; /* pre allocate all the stuff */ - f = calloc(1, sizeof(*f) + super->block_size); + f = calloc(1, sizeof(*f) + super->block_size * 2); if (f == NULL) goto fail_rd; diff --git a/lib/sqfs/meta_reader.c b/lib/sqfs/meta_reader.c index 8cd7c8f..1a70238 100644 --- a/lib/sqfs/meta_reader.c +++ b/lib/sqfs/meta_reader.c @@ -79,12 +79,18 @@ int meta_reader_seek(meta_reader_t *m, uint64_t block_start, size_t offset) goto fail_trunc; if (compressed) { - ret = m->cmp->do_block(m->cmp, m->data, size); + ret = m->cmp->do_block(m->cmp, m->data, size, + m->scratch, sizeof(m->scratch)); if (ret <= 0) { fputs("error uncompressing meta data block\n", stderr); return -1; } + + memcpy(m->data, m->scratch, ret); + + if ((size_t)ret < sizeof(m->data)) + memset(m->data + ret, 0, sizeof(m->data) - ret); } return 0; diff --git a/lib/sqfs/meta_writer.c b/lib/sqfs/meta_writer.c index 95092d5..77ceeb9 100644 --- a/lib/sqfs/meta_writer.c +++ b/lib/sqfs/meta_writer.c @@ -30,23 +30,27 @@ void meta_writer_destroy(meta_writer_t *m) int meta_writer_flush(meta_writer_t *m) { ssize_t ret, count; + void *ptr; if (m->offset == 0) return 0; - ret = m->cmp->do_block(m->cmp, m->data + 2, m->offset); + ret = m->cmp->do_block(m->cmp, m->data + 2, m->offset, + m->scratch + 2, sizeof(m->scratch) - 2); if (ret < 0) return -1; if (ret > 0) { - ((uint16_t *)m->data)[0] = htole16(ret); + ((uint16_t *)m->scratch)[0] = htole16(ret); count = ret + 2; + ptr = m->scratch; } else { ((uint16_t *)m->data)[0] = htole16(m->offset | 0x8000); count = m->offset + 2; + ptr = m->data; } - ret = write_retry(m->outfd, m->data, count); + ret = write_retry(m->outfd, ptr, count); if (ret < 0) { perror("writing meta data"); diff --git a/lib/sqfs/super.c b/lib/sqfs/super.c index b402496..d3b79c6 100644 --- a/lib/sqfs/super.c +++ b/lib/sqfs/super.c @@ -17,8 +17,8 @@ int sqfs_super_init(sqfs_super_t *super, size_t block_size, uint32_t mtime, return -1; } - if (block_size < 8192 || block_size >= (1 << 24)) { - fputs("Block size must be between 8k and 1M\n", stderr); + if (block_size < 4096 || block_size >= (1 << 24)) { + fputs("Block size must be between 4k and 1M\n", stderr); return -1; } diff --git a/mkfs/block.c b/mkfs/block.c index d68c0c7..3472346 100644 --- a/mkfs/block.c +++ b/mkfs/block.c @@ -6,22 +6,26 @@ static int write_block(file_info_t *fi, sqfs_info_t *info) { size_t idx, bs; ssize_t ret; + void *ptr; idx = info->file_block_count++; bs = info->super.block_size; - ret = info->cmp->do_block(info->cmp, info->block, bs); + ret = info->cmp->do_block(info->cmp, info->block, bs, + info->scratch, bs); if (ret < 0) return -1; if (ret > 0) { + ptr = info->scratch; bs = ret; fi->blocksizes[idx] = bs; } else { + ptr = info->block; fi->blocksizes[idx] = bs | (1 << 24); } - ret = write_retry(info->outfd, info->block, bs); + ret = write_retry(info->outfd, ptr, bs); if (ret < 0) { perror("writing to output file"); return -1; @@ -41,8 +45,8 @@ static int flush_fragments(sqfs_info_t *info) size_t newsz, size; file_info_t *fi; uint64_t offset; + void *new, *ptr; ssize_t ret; - void *new; if (info->num_fragments == info->max_fragments) { newsz = info->max_fragments ? info->max_fragments * 2 : 16; @@ -64,7 +68,8 @@ static int flush_fragments(sqfs_info_t *info) for (fi = info->frag_list; fi != NULL; fi = fi->frag_next) fi->fragment = info->num_fragments; - ret = info->cmp->do_block(info->cmp, info->fragment, size); + ret = info->cmp->do_block(info->cmp, info->fragment, size, + info->scratch, info->super.block_size); if (ret < 0) return -1; @@ -72,16 +77,18 @@ static int flush_fragments(sqfs_info_t *info) info->fragments[info->num_fragments].pad0 = 0; if (ret > 0) { + ptr = info->scratch; size = ret; info->fragments[info->num_fragments].size = htole32(size); } else { + ptr = info->fragment; info->fragments[info->num_fragments].size = htole32(size | (1 << 24)); } info->num_fragments += 1; - ret = write_retry(info->outfd, info->fragment, size); + ret = write_retry(info->outfd, ptr, size); if (ret < 0) { perror("writing to output file"); return -1; @@ -203,12 +210,22 @@ int write_data_to_image(sqfs_info_t *info) return -1; } + info->scratch = malloc(info->super.block_size); + if (info->scratch == NULL) { + perror("allocating scratch buffer"); + free(info->block); + free(info->fragment); + return -1; + } + ret = find_and_process_files(info, info->fs.root); free(info->block); free(info->fragment); + free(info->scratch); info->block = NULL; info->fragment = NULL; + info->scratch = NULL; return ret; } diff --git a/mkfs/mksquashfs.h b/mkfs/mksquashfs.h index f4ab53a..106822c 100644 --- a/mkfs/mksquashfs.h +++ b/mkfs/mksquashfs.h @@ -36,6 +36,7 @@ typedef struct { fstree_t fs; void *block; void *fragment; + void *scratch; sqfs_fragment_t *fragments; size_t num_fragments; diff --git a/mkfs/options.c b/mkfs/options.c index a1077b4..f1fe192 100644 --- a/mkfs/options.c +++ b/mkfs/options.c @@ -248,8 +248,7 @@ void process_command_line(options_t *opt, int argc, char **argv) break; case 'b': opt->blksz = read_number("Block size", optarg, - SQFS_META_BLOCK_SIZE, - 0xFFFFFFFF); + 4096, (1 << 20) - 1); break; case 'B': opt->devblksz = read_number("Device block size", optarg, diff --git a/unpack/extract_file.c b/unpack/extract_file.c index c18ace8..368f6d7 100644 --- a/unpack/extract_file.c +++ b/unpack/extract_file.c @@ -4,18 +4,19 @@ int extract_file(file_info_t *fi, compressor_t *cmp, size_t block_size, frag_reader_t *frag, int sqfsfd, int outfd) { + void *buffer, *scratch, *ptr; size_t i, count, fragsz; bool compressed; - void *buffer; uint32_t bs; ssize_t ret; - buffer = malloc(block_size); + buffer = malloc(block_size * 2); if (buffer == NULL) { perror("allocating scratch buffer"); return -1; } + scratch = (char *)buffer + block_size; count = fi->size / block_size; if (count > 0) { @@ -39,14 +40,18 @@ int extract_file(file_info_t *fi, compressor_t *cmp, size_t block_size, goto fail_trunc; if (compressed) { - ret = cmp->do_block(cmp, buffer, bs); + ret = cmp->do_block(cmp, buffer, bs, + scratch, block_size); if (ret <= 0) goto fail; bs = ret; + ptr = scratch; + } else { + ptr = buffer; } - ret = write_retry(outfd, buffer, bs); + ret = write_retry(outfd, ptr, bs); if (ret < 0) goto fail_wr; -- cgit v1.2.3