From owner-svn-src-all@freebsd.org Fri Dec 2 09:30:14 2016 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id ECCECC5F70A; Fri, 2 Dec 2016 09:30:14 +0000 (UTC) (envelope-from mm@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id C79971A7C; Fri, 2 Dec 2016 09:30:14 +0000 (UTC) (envelope-from mm@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id uB29UD7H031067; Fri, 2 Dec 2016 09:30:13 GMT (envelope-from mm@FreeBSD.org) Received: (from mm@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id uB29UDQR031063; Fri, 2 Dec 2016 09:30:13 GMT (envelope-from mm@FreeBSD.org) Message-Id: <201612020930.uB29UDQR031063@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: mm set sender to mm@FreeBSD.org using -f From: Martin Matuska Date: Fri, 2 Dec 2016 09:30:13 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r309405 - head/contrib/libarchive/libarchive X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 02 Dec 2016 09:30:15 -0000 Author: mm Date: Fri Dec 2 09:30:13 2016 New Revision: 309405 URL: https://svnweb.freebsd.org/changeset/base/309405 Log: MFV r309403: Sync libarchive with vendor. 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 MFC after: 1 week Modified: head/contrib/libarchive/libarchive/archive_read_support_filter_uu.c head/contrib/libarchive/libarchive/archive_read_support_format_cab.c head/contrib/libarchive/libarchive/archive_read_support_format_tar.c Directory Properties: head/contrib/libarchive/ (props changed) Modified: head/contrib/libarchive/libarchive/archive_read_support_filter_uu.c ============================================================================== --- head/contrib/libarchive/libarchive/archive_read_support_filter_uu.c Fri Dec 2 09:29:22 2016 (r309404) +++ head/contrib/libarchive/libarchive/archive_read_support_filter_uu.c Fri Dec 2 09:30:13 2016 (r309405) @@ -312,6 +312,7 @@ uudecode_bidder_bid(struct archive_read_ 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_ 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); Modified: head/contrib/libarchive/libarchive/archive_read_support_format_cab.c ============================================================================== --- head/contrib/libarchive/libarchive/archive_read_support_format_cab.c Fri Dec 2 09:29:22 2016 (r309404) +++ head/contrib/libarchive/libarchive/archive_read_support_format_cab.c Fri Dec 2 09:30:13 2016 (r309405) @@ -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)); } Modified: head/contrib/libarchive/libarchive/archive_read_support_format_tar.c ============================================================================== --- head/contrib/libarchive/libarchive/archive_read_support_format_tar.c Fri Dec 2 09:29:22 2016 (r309404) +++ head/contrib/libarchive/libarchive/archive_read_support_format_tar.c Fri Dec 2 09:30:13 2016 (r309405) @@ -297,58 +297,50 @@ archive_read_format_tar_cleanup(struct 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 archi /* * 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; }