Ignore:
Timestamp:
Jan 1, 2014, 12:47:38 AM (7 years ago)
Author:
Bruno Cornec
Message:
  • Update mindi-busybox to 1.21.1
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/3.2/mindi-busybox/archival/libarchive/get_header_tar.c

    r2725 r3232  
    1313
    1414#include "libbb.h"
    15 #include "archive.h"
     15#include "bb_archive.h"
    1616
    1717typedef uint32_t aliased_uint32_t FIX_ALIASING;
    1818typedef off_t    aliased_off_t    FIX_ALIASING;
    1919
     20
     21const char* FAST_FUNC strip_unsafe_prefix(const char *str)
     22{
     23    const char *cp = str;
     24    while (1) {
     25        char *cp2;
     26        if (*cp == '/') {
     27            cp++;
     28            continue;
     29        }
     30        if (strncmp(cp, "/../"+1, 3) == 0) {
     31            cp += 3;
     32            continue;
     33        }
     34        cp2 = strstr(cp, "/../");
     35        if (!cp2)
     36            break;
     37        cp = cp2 + 4;
     38    }
     39    if (cp != str) {
     40        static smallint warned = 0;
     41        if (!warned) {
     42            warned = 1;
     43            bb_error_msg("removing leading '%.*s' from member names",
     44                (int)(cp - str), str);
     45        }
     46    }
     47    return cp;
     48}
    2049
    2150/* NB: _DESTROYS_ str[len] character! */
     
    5180         * NB: tarballs with NEGATIVE unix times encoded that way were seen!
    5281         */
    53         v = first;
    54         /* Sign-extend using 6th bit: */
    55         v <<= sizeof(unsigned long long)*8 - 7;
    56         v = (long long)v >> (sizeof(unsigned long long)*8 - 7);
     82        /* Sign-extend 7bit 'first' to 64bit 'v' (that is, using 6th bit as sign): */
     83        first <<= 1;
     84        first >>= 1; /* now 7th bit = 6th bit */
     85        v = first;   /* sign-extend 8 bits to 64 */
    5786        while (--len != 0)
    58             v = (v << 8) + (unsigned char) *str++;
     87            v = (v << 8) + (uint8_t) *++str;
    5988    }
    6089    return v;
     
    6291#define GET_OCTAL(a) getOctal((a), sizeof(a))
    6392
    64 #if ENABLE_FEATURE_TAR_SELINUX
    65 /* Scan a PAX header for SELinux contexts, via "RHT.security.selinux" keyword.
    66  * This is what Red Hat's patched version of tar uses.
    67  */
    68 # define SELINUX_CONTEXT_KEYWORD "RHT.security.selinux"
    69 static char *get_selinux_sctx_from_pax_hdr(archive_handle_t *archive_handle, unsigned sz)
     93/* "global" is 0 or 1 */
     94static void process_pax_hdr(archive_handle_t *archive_handle, unsigned sz, int global)
    7095{
    7196    char *buf, *p;
    72     char *result;
    73 
    74     p = buf = xmalloc(sz + 1);
     97    unsigned blk_sz;
     98
     99    blk_sz = (sz + 511) & (~511);
     100    p = buf = xmalloc(blk_sz + 1);
     101    xread(archive_handle->src_fd, buf, blk_sz);
     102    archive_handle->offset += blk_sz;
     103
    75104    /* prevent bb_strtou from running off the buffer */
    76105    buf[sz] = '\0';
    77     xread(archive_handle->src_fd, buf, sz);
    78     archive_handle->offset += sz;
    79 
    80     result = NULL;
     106
    81107    while (sz != 0) {
    82108        char *end, *value;
     
    105131         */
    106132        p[-1] = '\0';
    107         /* Is it selinux security context? */
    108133        value = end + 1;
     134
     135#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
     136        if (!global && strncmp(value, "path=", sizeof("path=") - 1) == 0) {
     137            value += sizeof("path=") - 1;
     138            free(archive_handle->tar__longname);
     139            archive_handle->tar__longname = xstrdup(value);
     140            continue;
     141        }
     142#endif
     143
     144#if ENABLE_FEATURE_TAR_SELINUX
     145        /* Scan for SELinux contexts, via "RHT.security.selinux" keyword.
     146         * This is what Red Hat's patched version of tar uses.
     147         */
     148# define SELINUX_CONTEXT_KEYWORD "RHT.security.selinux"
    109149        if (strncmp(value, SELINUX_CONTEXT_KEYWORD"=", sizeof(SELINUX_CONTEXT_KEYWORD"=") - 1) == 0) {
    110150            value += sizeof(SELINUX_CONTEXT_KEYWORD"=") - 1;
    111             result = xstrdup(value);
    112             break;
    113         }
     151            free(archive_handle->tar__sctx[global]);
     152            archive_handle->tar__sctx[global] = xstrdup(value);
     153            continue;
     154        }
     155#endif
    114156    }
    115157
    116158    free(buf);
    117     return result;
    118159}
    119 #endif
    120160
    121161char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
     
    196236    ) {
    197237#if ENABLE_FEATURE_TAR_AUTODETECT
    198         char FAST_FUNC (*get_header_ptr)(archive_handle_t *);
    199         uint16_t magic2;
    200 
    201238 autodetect:
    202         magic2 = *(uint16_t*)tar.name;
    203         /* tar gz/bz autodetect: check for gz/bz2 magic.
    204          * If we see the magic, and it is the very first block,
    205          * we can switch to get_header_tar_gz/bz2/lzma().
    206          * Needs seekable fd. I wish recv(MSG_PEEK) works
    207          * on any fd... */
    208 # if ENABLE_FEATURE_SEAMLESS_GZ
    209         if (magic2 == GZIP_MAGIC) {
    210             get_header_ptr = get_header_tar_gz;
    211         } else
    212 # endif
    213 # if ENABLE_FEATURE_SEAMLESS_BZ2
    214         if (magic2 == BZIP2_MAGIC
    215          && tar.name[2] == 'h' && isdigit(tar.name[3])
    216         ) { /* bzip2 */
    217             get_header_ptr = get_header_tar_bz2;
    218         } else
    219 # endif
    220 # if ENABLE_FEATURE_SEAMLESS_XZ
    221         //TODO: if (magic2 == XZ_MAGIC1)...
    222         //else
    223 # endif
    224             goto err;
    225239        /* Two different causes for lseek() != 0:
    226240         * unseekable fd (would like to support that too, but...),
     
    228242        if (lseek(archive_handle->src_fd, -i, SEEK_CUR) != 0)
    229243            goto err;
    230         while (get_header_ptr(archive_handle) == EXIT_SUCCESS)
    231             continue;
    232         return EXIT_FAILURE;
     244        if (setup_unzip_on_fd(archive_handle->src_fd, /*fail_if_not_detected:*/ 0) != 0)
    233245 err:
    234 #endif /* FEATURE_TAR_AUTODETECT */
     246            bb_error_msg_and_die("invalid tar magic");
     247        archive_handle->offset = 0;
     248        goto again_after_align;
     249#endif
    235250        bb_error_msg_and_die("invalid tar magic");
    236251    }
     
    320335    /* (typeflag was not trashed because chksum does not use getOctal) */
    321336    switch (tar.typeflag) {
    322     /* busybox identifies hard links as being regular files with 0 size and a link name */
    323     case '1':
     337    case '1': /* hardlink */
     338        /* we mark hardlinks as regular files with zero size and a link name */
    324339        file_header->mode |= S_IFREG;
    325         break;
     340        /* on size of link fields from star(4)
     341         * ... For tar archives written by pre POSIX.1-1988
     342         * implementations, the size field usually contains the size of
     343         * the file and needs to be ignored as no data may follow this
     344         * header type.  For POSIX.1- 1988 compliant archives, the size
     345         * field needs to be 0.  For POSIX.1-2001 compliant archives,
     346         * the size field may be non zero, indicating that file data is
     347         * included in the archive.
     348         * i.e; always assume this is zero for safety.
     349         */
     350        goto size0;
    326351    case '7':
    327352    /* case 0: */
     
    380405    case 'V':   /* Volume header */
    381406#endif
    382 #if !ENABLE_FEATURE_TAR_SELINUX
    383407    case 'g':   /* pax global header */
    384     case 'x':   /* pax extended header */
    385 #else
     408    case 'x': { /* pax extended header */
     409        if ((uoff_t)file_header->size > 0xfffff) /* paranoia */
     410            goto skip_ext_hdr;
     411        process_pax_hdr(archive_handle, file_header->size, (tar.typeflag == 'g'));
     412        goto again_after_align;
     413    }
    386414 skip_ext_hdr:
    387 #endif
    388415    {
    389416        off_t sz;
     
    397424        goto again_after_align;
    398425    }
    399 #if ENABLE_FEATURE_TAR_SELINUX
    400     case 'g':   /* pax global header */
    401     case 'x': { /* pax extended header */
    402         char **pp;
    403         if ((uoff_t)file_header->size > 0xfffff) /* paranoia */
    404             goto skip_ext_hdr;
    405         pp = (tar.typeflag == 'g') ? &archive_handle->tar__global_sctx : &archive_handle->tar__next_file_sctx;
    406         free(*pp);
    407         *pp = get_selinux_sctx_from_pax_hdr(archive_handle, file_header->size);
    408         goto again;
    409     }
    410 #endif
    411426    default:
    412427        bb_error_msg_and_die("unknown typeflag: 0x%x", tar.typeflag);
     
    423438    }
    424439#endif
    425     if (strncmp(file_header->name, "/../"+1, 3) == 0
    426      || strstr(file_header->name, "/../")
    427     ) {
    428         bb_error_msg_and_die("name with '..' encountered: '%s'",
    429                 file_header->name);
    430     }
     440
     441    /* Everything up to and including last ".." component is stripped */
     442    overlapping_strcpy(file_header->name, strip_unsafe_prefix(file_header->name));
    431443
    432444    /* Strip trailing '/' in directories */
     
    441453            *cp = '\0';
    442454        archive_handle->action_data(archive_handle);
    443         if (archive_handle->accept || archive_handle->reject)
     455        if (archive_handle->accept || archive_handle->reject
     456         || (archive_handle->ah_flags & ARCHIVE_REMEMBER_NAMES)
     457        ) {
    444458            llist_add_to(&archive_handle->passed, file_header->name);
    445         else /* Caller isn't interested in list of unpacked files */
     459        } else /* Caller isn't interested in list of unpacked files */
    446460            free(file_header->name);
    447461    } else {
Note: See TracChangeset for help on using the changeset viewer.