aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Matuska <mm@FreeBSD.org>2016-12-02 09:26:51 +0000
committerMartin Matuska <mm@FreeBSD.org>2016-12-02 09:26:51 +0000
commit640b179f4e7e86a0b71cd44a4423eabf356cde4c (patch)
treeb59ab039c329407ec9af38a08f5f99b7161455d3
parent181b8217c998bcd403ea399ee7cac80e2a6a1eaa (diff)
downloadsrc-640b179f4e7e86a0b71cd44a4423eabf356cde4c.tar.gz
src-640b179f4e7e86a0b71cd44a4423eabf356cde4c.zip
Update vendor/libarchive to git 53d73345410d69e68171f05facaf4523e38e72bb
Vendor bugfixes: Fix for heap-buffer-overflow in archive_le16dec() Fix for heap-buffer-overflow in uudecode_bidder_bid() Reworked fix for compatibility with archives created by Perl Archive::Tar
Notes
Notes: svn path=/vendor/libarchive/dist/; revision=309403
-rw-r--r--libarchive/archive_read_support_filter_uu.c5
-rw-r--r--libarchive/archive_read_support_format_cab.c5
-rw-r--r--libarchive/archive_read_support_format_tar.c103
3 files changed, 48 insertions, 65 deletions
diff --git a/libarchive/archive_read_support_filter_uu.c b/libarchive/archive_read_support_filter_uu.c
index 787a619f2f3a..f0fc14870123 100644
--- a/libarchive/archive_read_support_filter_uu.c
+++ b/libarchive/archive_read_support_filter_uu.c
@@ -312,6 +312,7 @@ uudecode_bidder_bid(struct archive_read_filter_bidder *self,
avail -= len;
if (l == 6) {
+ /* "begin " */
if (!uuchar[*b])
return (0);
/* Get a length of decoded bytes. */
@@ -352,8 +353,8 @@ uudecode_bidder_bid(struct archive_read_filter_bidder *self,
b += nl;
if (avail && uuchar[*b])
return (firstline+30);
- }
- if (l == 13) {
+ } else if (l == 13) {
+ /* "begin-base64 " */
while (len-nl > 0) {
if (!base64[*b++])
return (0);
diff --git a/libarchive/archive_read_support_format_cab.c b/libarchive/archive_read_support_format_cab.c
index fc70684afa04..099f4a83dcac 100644
--- a/libarchive/archive_read_support_format_cab.c
+++ b/libarchive/archive_read_support_format_cab.c
@@ -645,12 +645,13 @@ cab_read_header(struct archive_read *a)
cab = (struct cab *)(a->format->data);
if (cab->found_header == 0 &&
p[0] == 'M' && p[1] == 'Z') {
- /* This is an executable? Must be self-extracting... */
+ /* This is an executable? Must be self-extracting... */
err = cab_skip_sfx(a);
if (err < ARCHIVE_WARN)
return (err);
- if ((p = __archive_read_ahead(a, sizeof(*p), NULL)) == NULL)
+ /* Re-read header after processing the SFX. */
+ if ((p = __archive_read_ahead(a, 42, NULL)) == NULL)
return (truncated_error(a));
}
diff --git a/libarchive/archive_read_support_format_tar.c b/libarchive/archive_read_support_format_tar.c
index b977cb7400fb..071d766b74b7 100644
--- a/libarchive/archive_read_support_format_tar.c
+++ b/libarchive/archive_read_support_format_tar.c
@@ -297,58 +297,50 @@ archive_read_format_tar_cleanup(struct archive_read *a)
/*
* Validate number field
*
- * Flags:
- * 1 - allow double \0 at field end
+ * This has to be pretty lenient in order to accomodate the enormous
+ * variety of tar writers in the world:
+ * = POSIX ustar requires octal values with leading zeros and
+ * specific termination on fields
+ * = Many writers use different termination (in particular, libarchive
+ * omits terminator bytes to squeeze one or two more digits)
+ * = Many writers pad with space and omit leading zeros
+ * = GNU tar and star write base-256 values if numbers are too
+ * big to be represented in octal
+ *
+ * This should tolerate all variants in use. It will reject a field
+ * where the writer just left garbage after a trailing NUL.
*/
static int
-validate_number_field(const char* p_field, size_t i_size, int flags)
+validate_number_field(const char* p_field, size_t i_size)
{
unsigned char marker = (unsigned char)p_field[0];
- /* octal? */
- if ((marker >= '0' && marker <= '7') || marker == ' ') {
+ if (marker == 128 || marker == 255 || marker == 0) {
+ /* Base-256 marker, there's nothing we can check. */
+ return 1;
+ } else {
+ /* Must be octal */
size_t i = 0;
- int octal_found = 0;
- for (i = 0; i < i_size; ++i) {
- switch (p_field[i])
- {
- case ' ':
- /* skip any leading spaces and trailing space */
- if (octal_found == 0 || i == i_size - 1) {
- continue;
- }
- break;
- case '\0':
- /*
- * null should be allowed only at the end
- *
- * Perl Archive::Tar terminates some fields
- * with two nulls. We must allow this to stay
- * compatible.
- */
- if (i != i_size - 1) {
- if (((flags & 1) == 0)
- || i != i_size - 2)
- return 0;
- }
- break;
- /* rest must be octal digits */
- case '0': case '1': case '2': case '3':
- case '4': case '5': case '6': case '7':
- ++octal_found;
- break;
+ /* Skip any leading spaces */
+ while (i < i_size && p_field[i] == ' ') {
+ ++i;
+ }
+ /* Must be at least one octal digit. */
+ if (i >= i_size || p_field[i] < '0' || p_field[i] > '7') {
+ return 0;
+ }
+ /* Skip remaining octal digits. */
+ while (i < i_size && p_field[i] >= '0' && p_field[i] <= '7') {
+ ++i;
+ }
+ /* Any remaining characters must be space or NUL padding. */
+ while (i < i_size) {
+ if (p_field[i] != ' ' && p_field[i] != 0) {
+ return 0;
}
+ ++i;
}
- return octal_found > 0;
- }
- /* base 256 (i.e. binary number) */
- else if (marker == 128 || marker == 255 || marker == 0) {
- /* nothing to check */
return 1;
}
- /* not a number field */
- else {
- return 0;
- }
}
static int
@@ -404,26 +396,15 @@ archive_read_format_tar_bid(struct archive_read *a, int best_bid)
/*
* Check format of mode/uid/gid/mtime/size/rdevmajor/rdevminor fields.
- * These are usually octal numbers but GNU tar encodes "big" values as
- * base256 and leading zeroes are sometimes replaced by spaces.
- * Even the null terminator is sometimes omitted. Anyway, must be
- * checked to avoid false positives.
- *
- * Perl Archive::Tar does not follow the spec and terminates mode, uid,
- * gid, rdevmajor and rdevminor with a double \0. For compatibility
- * reasons we allow this deviation.
*/
if (bid > 0 && (
- validate_number_field(header->mode, sizeof(header->mode), 1) == 0
- || validate_number_field(header->uid, sizeof(header->uid), 1) == 0
- || validate_number_field(header->gid, sizeof(header->gid), 1) == 0
- || validate_number_field(header->mtime, sizeof(header->mtime),
- 0) == 0
- || validate_number_field(header->size, sizeof(header->size), 0) == 0
- || validate_number_field(header->rdevmajor,
- sizeof(header->rdevmajor), 1) == 0
- || validate_number_field(header->rdevminor,
- sizeof(header->rdevminor), 1) == 0)) {
+ 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)) {
bid = 0;
}