diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libarchive/archive_read.c | 18 | ||||
-rw-r--r-- | lib/libarchive/archive_read_support_compression_uu.c | 12 | ||||
-rw-r--r-- | lib/libarchive/archive_read_support_format_iso9660.c | 49 | ||||
-rw-r--r-- | lib/libarchive/archive_read_support_format_mtree.c | 11 | ||||
-rw-r--r-- | lib/libarchive/archive_write_set_compression_xz.c | 4 | ||||
-rw-r--r-- | lib/libarchive/archive_write_set_format_zip.c | 3 | ||||
-rw-r--r-- | lib/libarchive/test/Makefile | 1 | ||||
-rw-r--r-- | lib/libarchive/test/test_open_failure.c | 198 | ||||
-rw-r--r-- | lib/libarchive/test/test_read_format_mtree.c | 43 | ||||
-rw-r--r-- | lib/libarchive/test/test_write_compress_lzma.c | 7 | ||||
-rw-r--r-- | lib/libarchive/test/test_write_compress_xz.c | 6 |
11 files changed, 317 insertions, 35 deletions
diff --git a/lib/libarchive/archive_read.c b/lib/libarchive/archive_read.c index 027ed60..7873d45 100644 --- a/lib/libarchive/archive_read.c +++ b/lib/libarchive/archive_read.c @@ -377,6 +377,12 @@ build_stream(struct archive_read *a) /* If no bidder, we're done. */ if (best_bidder == NULL) { + /* Verify the final pipelin by asking it for some data. */ + __archive_read_filter_ahead(a->filter, 1, &avail); + if (avail < 0) { + cleanup_filters(a); + return (ARCHIVE_FATAL); + } a->archive.compression_name = a->filter->name; a->archive.compression_code = a->filter->code; return (ARCHIVE_OK); @@ -389,17 +395,11 @@ build_stream(struct archive_read *a) filter->bidder = best_bidder; filter->archive = a; filter->upstream = a->filter; - r = (best_bidder->init)(filter); - if (r != ARCHIVE_OK) { - free(filter); - return (r); - } a->filter = filter; - /* Verify the filter by asking it for some data. */ - __archive_read_filter_ahead(filter, 1, &avail); - if (avail < 0) { + r = (best_bidder->init)(a->filter); + if (r != ARCHIVE_OK) { cleanup_filters(a); - return (ARCHIVE_FATAL); + return (r); } } } diff --git a/lib/libarchive/archive_read_support_compression_uu.c b/lib/libarchive/archive_read_support_compression_uu.c index c3c37d6..cb1dae5 100644 --- a/lib/libarchive/archive_read_support_compression_uu.c +++ b/lib/libarchive/archive_read_support_compression_uu.c @@ -381,7 +381,17 @@ ensure_in_buff_size(struct archive_read_filter *self, unsigned char *ptr; size_t newsize; - newsize = uudecode->in_allocated << 1; + /* + * Calculate a new buffer size for in_buff. + * Increase its value until it has enough size we need. + */ + newsize = uudecode->in_allocated; + do { + if (newsize < IN_BUFF_SIZE*32) + newsize <<= 1; + else + newsize += IN_BUFF_SIZE; + } while (size > newsize); ptr = malloc(newsize); if (ptr == NULL || newsize < uudecode->in_allocated) { diff --git a/lib/libarchive/archive_read_support_format_iso9660.c b/lib/libarchive/archive_read_support_format_iso9660.c index 1f64003..2cca410 100644 --- a/lib/libarchive/archive_read_support_format_iso9660.c +++ b/lib/libarchive/archive_read_support_format_iso9660.c @@ -709,16 +709,18 @@ isSVD(struct iso9660 *iso9660, const unsigned char *h) /* Location of Occurrence of Type L Path Table must be * available location, - * > SYSTEM_AREA_BLOCK(16) + 2 and < Volume Space Size. */ + * >= SYSTEM_AREA_BLOCK(16) + 2 and < Volume Space Size. */ location = archive_le32dec(h+SVD_type_L_path_table_offset); - if (location <= SYSTEM_AREA_BLOCK+2 || location >= volume_block) + if (location < SYSTEM_AREA_BLOCK+2 || location >= volume_block) return (0); - /* Location of Occurrence of Type M Path Table must be - * available location, - * > SYSTEM_AREA_BLOCK(16) + 2 and < Volume Space Size. */ + /* The Type M Path Table must be at a valid location (WinISO + * and probably other programs omit this, so we allow zero) + * + * >= SYSTEM_AREA_BLOCK(16) + 2 and < Volume Space Size. */ location = archive_be32dec(h+SVD_type_M_path_table_offset); - if (location <= SYSTEM_AREA_BLOCK+2 || location >= volume_block) + if ((location > 0 && location < SYSTEM_AREA_BLOCK+2) + || location >= volume_block) return (0); /* Read Root Directory Record in Volume Descriptor. */ @@ -781,16 +783,17 @@ isEVD(struct iso9660 *iso9660, const unsigned char *h) /* Location of Occurrence of Type L Path Table must be * available location, - * > SYSTEM_AREA_BLOCK(16) + 2 and < Volume Space Size. */ + * >= SYSTEM_AREA_BLOCK(16) + 2 and < Volume Space Size. */ location = archive_le32dec(h+PVD_type_1_path_table_offset); - if (location <= SYSTEM_AREA_BLOCK+2 || location >= volume_block) + if (location < SYSTEM_AREA_BLOCK+2 || location >= volume_block) return (0); /* Location of Occurrence of Type M Path Table must be * available location, - * > SYSTEM_AREA_BLOCK(16) + 2 and < Volume Space Size. */ + * >= SYSTEM_AREA_BLOCK(16) + 2 and < Volume Space Size. */ location = archive_be32dec(h+PVD_type_m_path_table_offset); - if (location <= SYSTEM_AREA_BLOCK+2 || location >= volume_block) + if ((location > 0 && location < SYSTEM_AREA_BLOCK+2) + || location >= volume_block) return (0); /* Reserved field must be 0. */ @@ -862,19 +865,24 @@ isPVD(struct iso9660 *iso9660, const unsigned char *h) * available location, * > SYSTEM_AREA_BLOCK(16) + 2 and < Volume Space Size. */ location = archive_le32dec(h+PVD_type_1_path_table_offset); - if (location <= SYSTEM_AREA_BLOCK+2 || location >= volume_block) + if (location < SYSTEM_AREA_BLOCK+2 || location >= volume_block) return (0); - /* Location of Occurrence of Type M Path Table must be - * available location, - * > SYSTEM_AREA_BLOCK(16) + 2 and < Volume Space Size. */ + /* The Type M Path Table must also be at a valid location + * (although ECMA 119 requires a Type M Path Table, WinISO and + * probably other programs omit it, so we permit a zero here) + * + * >= SYSTEM_AREA_BLOCK(16) + 2 and < Volume Space Size. */ location = archive_be32dec(h+PVD_type_m_path_table_offset); - if (location <= SYSTEM_AREA_BLOCK+2 || location >= volume_block) + if ((location > 0 && location < SYSTEM_AREA_BLOCK+2) + || location >= volume_block) return (0); /* Reserved field must be 0. */ + /* FreeBSD: makefs erroneously created images with 0x20 */ for (i = 0; i < PVD_reserved4_size; ++i) - if (h[PVD_reserved4_offset + i] != 0) + if (h[PVD_reserved4_offset + i] != 0 && + h[PVD_reserved4_offset + i] != 32) return (0); /* Reserved field must be 0. */ @@ -1677,6 +1685,7 @@ parse_file_info(struct archive_read *a, struct file_info *parent, const unsigned char *rr_start, *rr_end; const unsigned char *p; size_t dr_len; + uint64_t fsize; int32_t location; int flags; @@ -1685,6 +1694,7 @@ parse_file_info(struct archive_read *a, struct file_info *parent, dr_len = (size_t)isodirrec[DR_length_offset]; name_len = (size_t)isodirrec[DR_name_len_offset]; location = archive_le32dec(isodirrec + DR_extent_offset); + fsize = toi(isodirrec + DR_size_offset, DR_size_size); /* Sanity check that dr_len needs at least 34. */ if (dr_len < 34) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, @@ -1703,7 +1713,10 @@ parse_file_info(struct archive_read *a, struct file_info *parent, * link or file size is zero. As far as I know latest mkisofs * do that. */ - if (location >= iso9660->volume_block) { + if (location > 0 && + (location + ((fsize + iso9660->logical_block_size -1) + / iso9660->logical_block_size)) > + (unsigned int)iso9660->volume_block) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Invalid location of extent of file"); return (NULL); @@ -1719,7 +1732,7 @@ parse_file_info(struct archive_read *a, struct file_info *parent, memset(file, 0, sizeof(*file)); file->parent = parent; file->offset = iso9660->logical_block_size * (uint64_t)location; - file->size = toi(isodirrec + DR_size_offset, DR_size_size); + file->size = fsize; file->mtime = isodate7(isodirrec + DR_date_offset); file->ctime = file->atime = file->mtime; diff --git a/lib/libarchive/archive_read_support_format_mtree.c b/lib/libarchive/archive_read_support_format_mtree.c index bb231fa..7ae0b02 100644 --- a/lib/libarchive/archive_read_support_format_mtree.c +++ b/lib/libarchive/archive_read_support_format_mtree.c @@ -525,6 +525,7 @@ parse_file(struct archive_read *a, struct archive_entry *entry, /* Initialize reasonable defaults. */ mtree->filetype = AE_IFREG; archive_entry_set_size(entry, 0); + archive_string_empty(&mtree->contents_name); /* Parse options from this line. */ parsed_kws = 0; @@ -613,9 +614,8 @@ parse_file(struct archive_read *a, struct archive_entry *entry, } /* - * If there is a contents file on disk, use that size; - * otherwise leave it as-is (it might have been set from - * the mtree size= keyword). + * Check for a mismatch between the type in the specification and + * the type of the contents object on disk. */ if (st != NULL) { mismatched_type = 0; @@ -660,6 +660,11 @@ parse_file(struct archive_read *a, struct archive_entry *entry, } } + /* + * If there is a contents file on disk, pick some of the metadata + * from that file. For most of these, we only set it from the contents + * if it wasn't already parsed from the specification. + */ if (st != NULL) { if ((parsed_kws & MTREE_HAS_DEVICE) == 0 && (archive_entry_filetype(entry) == AE_IFCHR || diff --git a/lib/libarchive/archive_write_set_compression_xz.c b/lib/libarchive/archive_write_set_compression_xz.c index 8173317..d97bca7 100644 --- a/lib/libarchive/archive_write_set_compression_xz.c +++ b/lib/libarchive/archive_write_set_compression_xz.c @@ -421,8 +421,8 @@ drive_compressor(struct archive_write *a, struct private_data *state, int finish archive_set_error(&a->archive, ENOMEM, "lzma compression error: " "%ju MiB would have been needed", - (lzma_memusage(&(state->stream)) + 1024 * 1024 -1) - / (1024 * 1024)); + (uintmax_t)((lzma_memusage(&(state->stream)) + 1024 * 1024 -1) + / (1024 * 1024))); return (ARCHIVE_FATAL); default: /* Any other return value indicates an error. */ diff --git a/lib/libarchive/archive_write_set_format_zip.c b/lib/libarchive/archive_write_set_format_zip.c index d4d4f87..1bbbb6a 100644 --- a/lib/libarchive/archive_write_set_format_zip.c +++ b/lib/libarchive/archive_write_set_format_zip.c @@ -502,6 +502,9 @@ archive_write_zip_finish(struct archive_write *a) int entries; int ret; + if (a->compressor.write == NULL) + return (ARCHIVE_OK); + zip = a->format_data; l = zip->central_directory; diff --git a/lib/libarchive/test/Makefile b/lib/libarchive/test/Makefile index 3f747b6..ba72db7 100644 --- a/lib/libarchive/test/Makefile +++ b/lib/libarchive/test/Makefile @@ -25,6 +25,7 @@ TESTS= \ test_fuzz.c \ test_link_resolver.c \ test_open_fd.c \ + test_open_failure.c \ test_open_file.c \ test_open_filename.c \ test_pax_filename_encoding.c \ diff --git a/lib/libarchive/test/test_open_failure.c b/lib/libarchive/test/test_open_failure.c new file mode 100644 index 0000000..0a7632a --- /dev/null +++ b/lib/libarchive/test/test_open_failure.c @@ -0,0 +1,198 @@ +/*- + * Copyright (c) 2003-2010 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "test.h" +__FBSDID("$FreeBSD$"); + +#define MAGIC 123456789 +struct my_data { + int magic; + int read_return; + int read_called; + int write_return; + int write_called; + int open_return; + int open_called; + int close_return; + int close_called; +}; + +static ssize_t +my_read(struct archive *a, void *_private, const void **buff) +{ + struct my_data *private = (struct my_data *)_private; + assertEqualInt(MAGIC, private->magic); + ++private->read_called; + return (private->read_return); +} + +static ssize_t +my_write(struct archive *a, void *_private, const void *buff, size_t s) +{ + struct my_data *private = (struct my_data *)_private; + assertEqualInt(MAGIC, private->magic); + ++private->write_called; + return (private->write_return); +} + +static int +my_open(struct archive *a, void *_private) +{ + struct my_data *private = (struct my_data *)_private; + assertEqualInt(MAGIC, private->magic); + ++private->open_called; + return (private->open_return); +} + +static int +my_close(struct archive *a, void *_private) +{ + struct my_data *private = (struct my_data *)_private; + assertEqualInt(MAGIC, private->magic); + ++private->close_called; + return (private->close_return); +} + + +DEFINE_TEST(test_open_failure) +{ + struct archive *a; + struct my_data private; + + memset(&private, 0, sizeof(private)); + private.magic = MAGIC; + private.open_return = ARCHIVE_FATAL; + a = archive_read_new(); + assert(a != NULL); + assertEqualInt(ARCHIVE_FATAL, + archive_read_open(a, &private, my_open, my_read, my_close)); + assertEqualInt(1, private.open_called); + assertEqualInt(0, private.read_called); + assertEqualInt(1, private.close_called); + assertEqualInt(ARCHIVE_OK, archive_read_finish(a)); + assertEqualInt(1, private.open_called); + assertEqualInt(0, private.read_called); + assertEqualInt(1, private.close_called); + + memset(&private, 0, sizeof(private)); + private.magic = MAGIC; + private.open_return = ARCHIVE_FAILED; + a = archive_read_new(); + assert(a != NULL); + assertEqualInt(ARCHIVE_FAILED, + archive_read_open(a, &private, my_open, my_read, my_close)); + assertEqualInt(1, private.open_called); + assertEqualInt(0, private.read_called); + assertEqualInt(1, private.close_called); + assertEqualInt(ARCHIVE_OK, archive_read_finish(a)); + assertEqualInt(1, private.open_called); + assertEqualInt(0, private.read_called); + assertEqualInt(1, private.close_called); + + memset(&private, 0, sizeof(private)); + private.magic = MAGIC; + private.open_return = ARCHIVE_WARN; + a = archive_read_new(); + assert(a != NULL); + assertEqualInt(ARCHIVE_WARN, + archive_read_open(a, &private, my_open, my_read, my_close)); + assertEqualInt(1, private.open_called); + assertEqualInt(0, private.read_called); + assertEqualInt(1, private.close_called); + assertEqualInt(ARCHIVE_OK, archive_read_finish(a)); + assertEqualInt(1, private.open_called); + assertEqualInt(0, private.read_called); + assertEqualInt(1, private.close_called); + + memset(&private, 0, sizeof(private)); + private.magic = MAGIC; + private.open_return = ARCHIVE_OK; + private.read_return = ARCHIVE_FATAL; + a = archive_read_new(); + assert(a != NULL); + assertEqualInt(ARCHIVE_OK, + archive_read_support_compression_compress(a)); + assertEqualInt(ARCHIVE_OK, archive_read_support_format_tar(a)); + assertEqualInt(ARCHIVE_FATAL, + archive_read_open(a, &private, my_open, my_read, my_close)); + assertEqualInt(1, private.open_called); + assertEqualInt(1, private.read_called); + assertEqualInt(1, private.close_called); + assertEqualInt(ARCHIVE_OK, archive_read_finish(a)); + assertEqualInt(1, private.open_called); + assertEqualInt(1, private.read_called); + assertEqualInt(1, private.close_called); + + memset(&private, 0, sizeof(private)); + private.magic = MAGIC; + private.open_return = ARCHIVE_FATAL; + a = archive_write_new(); + assert(a != NULL); + assertEqualInt(ARCHIVE_FATAL, + archive_write_open(a, &private, my_open, my_write, my_close)); + assertEqualInt(1, private.open_called); + assertEqualInt(0, private.write_called); + // Broken in 2.8, fixed in 3.0 + //assertEqualInt(1, private.close_called); + assertEqualInt(ARCHIVE_OK, archive_write_finish(a)); + assertEqualInt(1, private.open_called); + assertEqualInt(0, private.write_called); + assertEqualInt(1, private.close_called); + + memset(&private, 0, sizeof(private)); + private.magic = MAGIC; + private.open_return = ARCHIVE_FATAL; + a = archive_write_new(); + assert(a != NULL); + archive_write_set_compression_compress(a); + archive_write_set_format_zip(a); + assertEqualInt(ARCHIVE_FATAL, + archive_write_open(a, &private, my_open, my_write, my_close)); + assertEqualInt(1, private.open_called); + assertEqualInt(0, private.write_called); + // Broken in 2.8, fixed in 3.0 + //assertEqualInt(1, private.close_called); + assertEqualInt(ARCHIVE_OK, archive_write_finish(a)); + assertEqualInt(1, private.open_called); + assertEqualInt(0, private.write_called); + assertEqualInt(1, private.close_called); + + memset(&private, 0, sizeof(private)); + private.magic = MAGIC; + private.open_return = ARCHIVE_FATAL; + a = archive_write_new(); + assert(a != NULL); + archive_write_set_compression_gzip(a); + assertEqualInt(ARCHIVE_FATAL, + archive_write_open(a, &private, my_open, my_write, my_close)); + assertEqualInt(1, private.open_called); + assertEqualInt(0, private.write_called); + // Broken in 2.8, fixed in 3.0 + //assertEqualInt(1, private.close_called); + assertEqualInt(ARCHIVE_OK, archive_write_finish(a)); + assertEqualInt(1, private.open_called); + assertEqualInt(0, private.write_called); + assertEqualInt(1, private.close_called); + +} diff --git a/lib/libarchive/test/test_read_format_mtree.c b/lib/libarchive/test/test_read_format_mtree.c index 5001e4d..93e658f 100644 --- a/lib/libarchive/test/test_read_format_mtree.c +++ b/lib/libarchive/test/test_read_format_mtree.c @@ -134,10 +134,53 @@ test_read_format_mtree2(void) assertEqualInt(ARCHIVE_OK, archive_read_finish(a)); } +/* + * Reported to libarchive.googlecode.com as Issue 121. + */ +static void +test_read_format_mtree3(void) +{ + static char archive[] = + "#mtree\n" + "a type=file contents=file\n" + "b type=link link=a\n" + "c type=file contents=file\n"; + struct archive_entry *ae; + struct archive *a; + + assertMakeDir("mtree3", 0777); + assertChdir("mtree3"); + assertMakeFile("file", 0644, "file contents"); + + assert((a = archive_read_new()) != NULL); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_support_compression_all(a)); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_support_format_all(a)); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_open_memory(a, archive, sizeof(archive))); + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualString(archive_entry_pathname(ae), "a"); + assertEqualInt(archive_entry_filetype(ae), AE_IFREG); + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualString(archive_entry_pathname(ae), "b"); + assertEqualInt(archive_entry_filetype(ae), AE_IFLNK); + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualString(archive_entry_pathname(ae), "c"); + assertEqualInt(archive_entry_filetype(ae), AE_IFREG); + + assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); + assertEqualInt(ARCHIVE_OK, archive_read_close(a)); + assertEqualInt(ARCHIVE_OK, archive_read_finish(a)); + + assertChdir(".."); +} + DEFINE_TEST(test_read_format_mtree) { test_read_format_mtree1(); test_read_format_mtree2(); + test_read_format_mtree3(); } diff --git a/lib/libarchive/test/test_write_compress_lzma.c b/lib/libarchive/test/test_write_compress_lzma.c index 639e58f..88b9d63 100644 --- a/lib/libarchive/test/test_write_compress_lzma.c +++ b/lib/libarchive/test/test_write_compress_lzma.c @@ -185,10 +185,15 @@ DEFINE_TEST(test_write_compress_lzma) archive_write_close(a); assert(0 == archive_write_finish(a)); - /* Level 0 really does result in larger data. */ + /* It would be nice to assert that compression-level=0 produced + * consistently larger/smaller results than the default compression, + * but the results here vary a lot depending on the version of liblzma + * being used. */ + /* failure("Compression-level=0 wrote %d bytes; default wrote %d bytes", (int)used2, (int)used1); assert(used2 > used1); + */ assert((a = archive_read_new()) != NULL); assertA(0 == archive_read_support_format_all(a)); diff --git a/lib/libarchive/test/test_write_compress_xz.c b/lib/libarchive/test/test_write_compress_xz.c index 988fb6e..554d163 100644 --- a/lib/libarchive/test/test_write_compress_xz.c +++ b/lib/libarchive/test/test_write_compress_xz.c @@ -193,10 +193,14 @@ DEFINE_TEST(test_write_compress_xz) archive_write_close(a); assert(0 == archive_write_finish(a)); - /* Level 0 really does result in larger data. */ + /* I would like to assert that compression-level=0 results in + * larger data than the default compression, but that's not true + * for all versions of liblzma. */ + /* failure("Compression-level=0 wrote %d bytes; default wrote %d bytes", (int)used2, (int)used1); assert(used2 > used1); + */ assert((a = archive_read_new()) != NULL); assertA(0 == archive_read_support_format_all(a)); |