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
This commit is contained in:
Martin Matuska 2016-12-02 09:30:13 +00:00
commit c4247af46a
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=309405
3 changed files with 51 additions and 68 deletions

View File

@ -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);

View File

@ -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));
}

View File

@ -297,57 +297,49 @@ 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 == ' ') {
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;
}
}
return octal_found > 0;
}
/* base 256 (i.e. binary number) */
else if (marker == 128 || marker == 255 || marker == 0) {
/* nothing to check */
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;
/* 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 1;
}
/* not a number field */
else {
return 0;
}
}
@ -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;
}