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;
        }
 
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to