Changeset 3232 in MondoRescue for branches/3.2/mindi-busybox/archival/libarchive/get_header_tar.c
- Timestamp:
- Jan 1, 2014, 12:47:38 AM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/3.2/mindi-busybox/archival/libarchive/get_header_tar.c
r2725 r3232 13 13 14 14 #include "libbb.h" 15 #include " archive.h"15 #include "bb_archive.h" 16 16 17 17 typedef uint32_t aliased_uint32_t FIX_ALIASING; 18 18 typedef off_t aliased_off_t FIX_ALIASING; 19 19 20 21 const 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 } 20 49 21 50 /* NB: _DESTROYS_ str[len] character! */ … … 51 80 * NB: tarballs with NEGATIVE unix times encoded that way were seen! 52 81 */ 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 */ 57 86 while (--len != 0) 58 v = (v << 8) + (u nsigned char) *str++;87 v = (v << 8) + (uint8_t) *++str; 59 88 } 60 89 return v; … … 62 91 #define GET_OCTAL(a) getOctal((a), sizeof(a)) 63 92 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 */ 94 static void process_pax_hdr(archive_handle_t *archive_handle, unsigned sz, int global) 70 95 { 71 96 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 75 104 /* prevent bb_strtou from running off the buffer */ 76 105 buf[sz] = '\0'; 77 xread(archive_handle->src_fd, buf, sz); 78 archive_handle->offset += sz; 79 80 result = NULL; 106 81 107 while (sz != 0) { 82 108 char *end, *value; … … 105 131 */ 106 132 p[-1] = '\0'; 107 /* Is it selinux security context? */108 133 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" 109 149 if (strncmp(value, SELINUX_CONTEXT_KEYWORD"=", sizeof(SELINUX_CONTEXT_KEYWORD"=") - 1) == 0) { 110 150 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 114 156 } 115 157 116 158 free(buf); 117 return result;118 159 } 119 #endif120 160 121 161 char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) … … 196 236 ) { 197 237 #if ENABLE_FEATURE_TAR_AUTODETECT 198 char FAST_FUNC (*get_header_ptr)(archive_handle_t *);199 uint16_t magic2;200 201 238 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) works207 * on any fd... */208 # if ENABLE_FEATURE_SEAMLESS_GZ209 if (magic2 == GZIP_MAGIC) {210 get_header_ptr = get_header_tar_gz;211 } else212 # endif213 # if ENABLE_FEATURE_SEAMLESS_BZ2214 if (magic2 == BZIP2_MAGIC215 && tar.name[2] == 'h' && isdigit(tar.name[3])216 ) { /* bzip2 */217 get_header_ptr = get_header_tar_bz2;218 } else219 # endif220 # if ENABLE_FEATURE_SEAMLESS_XZ221 //TODO: if (magic2 == XZ_MAGIC1)...222 //else223 # endif224 goto err;225 239 /* Two different causes for lseek() != 0: 226 240 * unseekable fd (would like to support that too, but...), … … 228 242 if (lseek(archive_handle->src_fd, -i, SEEK_CUR) != 0) 229 243 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) 233 245 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 235 250 bb_error_msg_and_die("invalid tar magic"); 236 251 } … … 320 335 /* (typeflag was not trashed because chksum does not use getOctal) */ 321 336 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 */ 324 339 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; 326 351 case '7': 327 352 /* case 0: */ … … 380 405 case 'V': /* Volume header */ 381 406 #endif 382 #if !ENABLE_FEATURE_TAR_SELINUX383 407 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 } 386 414 skip_ext_hdr: 387 #endif388 415 { 389 416 off_t sz; … … 397 424 goto again_after_align; 398 425 } 399 #if ENABLE_FEATURE_TAR_SELINUX400 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 #endif411 426 default: 412 427 bb_error_msg_and_die("unknown typeflag: 0x%x", tar.typeflag); … … 423 438 } 424 439 #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)); 431 443 432 444 /* Strip trailing '/' in directories */ … … 441 453 *cp = '\0'; 442 454 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 ) { 444 458 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 */ 446 460 free(file_header->name); 447 461 } else {
Note:
See TracChangeset
for help on using the changeset viewer.