diff options
Diffstat (limited to 'contrib/libarchive/libarchive/archive_read_support_format_tar.c')
-rw-r--r-- | contrib/libarchive/libarchive/archive_read_support_format_tar.c | 43 |
1 files changed, 33 insertions, 10 deletions
diff --git a/contrib/libarchive/libarchive/archive_read_support_format_tar.c b/contrib/libarchive/libarchive/archive_read_support_format_tar.c index ce2e4095f6d9..db36b9e07767 100644 --- a/contrib/libarchive/libarchive/archive_read_support_format_tar.c +++ b/contrib/libarchive/libarchive/archive_read_support_format_tar.c @@ -26,7 +26,6 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD$"); #ifdef HAVE_ERRNO_H #include <errno.h> @@ -407,14 +406,13 @@ archive_read_format_tar_bid(struct archive_read *a, int best_bid) /* * Check format of mode/uid/gid/mtime/size/rdevmajor/rdevminor fields. */ - if (bid > 0 && ( - validate_number_field(header->mode, sizeof(header->mode)) == 0 + if (validate_number_field(header->mode, sizeof(header->mode)) == 0 || validate_number_field(header->uid, sizeof(header->uid)) == 0 || validate_number_field(header->gid, sizeof(header->gid)) == 0 || validate_number_field(header->mtime, sizeof(header->mtime)) == 0 || validate_number_field(header->size, sizeof(header->size)) == 0 || validate_number_field(header->rdevmajor, sizeof(header->rdevmajor)) == 0 - || validate_number_field(header->rdevminor, sizeof(header->rdevminor)) == 0)) { + || validate_number_field(header->rdevminor, sizeof(header->rdevminor)) == 0) { bid = 0; } @@ -573,11 +571,15 @@ archive_read_format_tar_read_header(struct archive_read *a, l = wcslen(wp); if (l > 0 && wp[l - 1] == L'/') { archive_entry_set_filetype(entry, AE_IFDIR); + tar->entry_bytes_remaining = 0; + tar->entry_padding = 0; } } else if ((p = archive_entry_pathname(entry)) != NULL) { l = strlen(p); if (l > 0 && p[l - 1] == '/') { archive_entry_set_filetype(entry, AE_IFDIR); + tar->entry_bytes_remaining = 0; + tar->entry_padding = 0; } } } @@ -1396,6 +1398,7 @@ read_mac_metadata_blob(struct archive_read *a, struct tar *tar, struct archive_entry *entry, const void *h, size_t *unconsumed) { int64_t size; + size_t msize; const void *data; const char *p, *name; const wchar_t *wp, *wname; @@ -1434,6 +1437,11 @@ read_mac_metadata_blob(struct archive_read *a, struct tar *tar, /* Read the body as a Mac OS metadata blob. */ size = archive_entry_size(entry); + msize = (size_t)size; + if (size < 0 || (uintmax_t)msize != (uintmax_t)size) { + *unconsumed = 0; + return (ARCHIVE_FATAL); + } /* * TODO: Look beyond the body here to peek at the next header. @@ -1447,13 +1455,13 @@ read_mac_metadata_blob(struct archive_read *a, struct tar *tar, * Q: Is the above idea really possible? Even * when there are GNU or pax extension entries? */ - data = __archive_read_ahead(a, (size_t)size, NULL); + data = __archive_read_ahead(a, msize, NULL); if (data == NULL) { *unconsumed = 0; return (ARCHIVE_FATAL); } - archive_entry_copy_mac_metadata(entry, data, (size_t)size); - *unconsumed = (size_t)((size + 511) & ~ 511); + archive_entry_copy_mac_metadata(entry, data, msize); + *unconsumed = (msize + 511) & ~ 511; tar_flush_unconsumed(a, unconsumed); return (tar_read_header(a, tar, entry, unconsumed)); } @@ -1908,7 +1916,7 @@ pax_attribute(struct archive_read *a, struct tar *tar, } if (strcmp(key, "GNU.sparse.numbytes") == 0) { tar->sparse_numbytes = tar_atol10(value, strlen(value)); - if (tar->sparse_numbytes != -1) { + if (tar->sparse_offset != -1) { if (gnu_add_sparse_entry(a, tar, tar->sparse_offset, tar->sparse_numbytes) != ARCHIVE_OK) @@ -2100,6 +2108,21 @@ pax_attribute(struct archive_read *a, struct tar *tar, /* "size" is the size of the data in the entry. */ tar->entry_bytes_remaining = tar_atol10(value, strlen(value)); + if (tar->entry_bytes_remaining < 0) { + tar->entry_bytes_remaining = 0; + archive_set_error(&a->archive, + ARCHIVE_ERRNO_MISC, + "Tar size attribute is negative"); + return (ARCHIVE_FATAL); + } + if (tar->entry_bytes_remaining == INT64_MAX) { + /* Note: tar_atol returns INT64_MAX on overflow */ + tar->entry_bytes_remaining = 0; + archive_set_error(&a->archive, + ARCHIVE_ERRNO_MISC, + "Tar size attribute overflow"); + return (ARCHIVE_FATAL); + } /* * The "size" pax header keyword always overrides the * "size" field in the tar header. @@ -2645,14 +2668,14 @@ tar_atol_base_n(const char *p, size_t char_cnt, int base) maxval = INT64_MIN; limit = -(INT64_MIN / base); - last_digit_limit = INT64_MIN % base; + last_digit_limit = -(INT64_MIN % base); } l = 0; if (char_cnt != 0) { digit = *p - '0'; while (digit >= 0 && digit < base && char_cnt != 0) { - if (l>limit || (l == limit && digit > last_digit_limit)) { + if (l>limit || (l == limit && digit >= last_digit_limit)) { return maxval; /* Truncate on overflow. */ } l = (l * base) + digit; |