diff options
author | simon <simon@FreeBSD.org> | 2006-11-08 14:03:50 +0000 |
---|---|---|
committer | simon <simon@FreeBSD.org> | 2006-11-08 14:03:50 +0000 |
commit | bee45f8f124b459f4eeb41c3506e0f32fceef3e0 (patch) | |
tree | 66cb1c6cf64a65495b96718e8e2755f99bc8f4b1 | |
parent | d893a05647b4aa69965d30bd6a1d5f360400bfbc (diff) | |
download | FreeBSD-src-bee45f8f124b459f4eeb41c3506e0f32fceef3e0.zip FreeBSD-src-bee45f8f124b459f4eeb41c3506e0f32fceef3e0.tar.gz |
Fix infinite loop in corrupt archives handling in libarchive(3).
Reported by: rink
Submitted by: kientzle
Security: FreeBSD-SA-06:24.libarchive
-rw-r--r-- | lib/libarchive/archive_read_support_compression_none.c | 20 |
1 files changed, 16 insertions, 4 deletions
diff --git a/lib/libarchive/archive_read_support_compression_none.c b/lib/libarchive/archive_read_support_compression_none.c index 0ec68df..26e9d07 100644 --- a/lib/libarchive/archive_read_support_compression_none.c +++ b/lib/libarchive/archive_read_support_compression_none.c @@ -257,7 +257,9 @@ archive_decompressor_none_read_consume(struct archive *a, size_t request) } /* - * Skip at most request bytes. Skipped data is marked as consumed. + * Skip forward by exactly the requested bytes or else return + * ARCHIVE_FATAL. Note that this differs from the contract for + * read_ahead, which does not gaurantee a minimum count. */ static ssize_t archive_decompressor_none_skip(struct archive *a, size_t request) @@ -287,9 +289,7 @@ archive_decompressor_none_skip(struct archive *a, size_t request) if (request == 0) return (total_bytes_skipped); /* - * If no client_skipper is provided, just read the old way. It is very - * likely that after skipping, the request has not yet been fully - * satisfied (and is still > 0). In that case, read as well. + * If a client_skipper was provided, try that first. */ if (a->client_skipper != NULL) { bytes_skipped = (a->client_skipper)(a, a->client_data, @@ -307,6 +307,12 @@ archive_decompressor_none_skip(struct archive *a, size_t request) a->raw_position += bytes_skipped; state->client_avail = state->client_total = 0; } + /* + * Note that client_skipper will usually not satisfy the + * full request (due to low-level blocking concerns), + * so even if client_skipper is provided, we may still + * have to use ordinary reads to finish out the request. + */ while (request > 0) { const void* dummy_buffer; ssize_t bytes_read; @@ -314,6 +320,12 @@ archive_decompressor_none_skip(struct archive *a, size_t request) &dummy_buffer, request); if (bytes_read < 0) return (bytes_read); + if (bytes_read == 0) { + /* We hit EOF before we satisfied the skip request. */ + archive_set_error(a, ARCHIVE_ERRNO_MISC, + "Truncated input file (need to skip %d bytes)", (int)request); + return (ARCHIVE_FATAL); + } assert(bytes_read >= 0); /* precondition for cast below */ min = minimum((size_t)bytes_read, request); bytes_read = archive_decompressor_none_read_consume(a, min); |