From: Denys Vlasenko Date: Sat, 27 Jan 2018 18:04:08 +0000 (+0100) Subject: tar: accomodate non-terminated tar.chksum fields as seen from github.com X-Git-Tag: 1_28_1~6 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=20f02c3c871cf0c8d9d2f2dad11d96c0ea41e0df;p=oweals%2Fbusybox.git tar: accomodate non-terminated tar.chksum fields as seen from github.com function old new delta get_header_tar 1783 1696 -87 Signed-off-by: Denys Vlasenko --- diff --git a/archival/libarchive/get_header_tar.c b/archival/libarchive/get_header_tar.c index aeb54190f..5c495e14e 100644 --- a/archival/libarchive/get_header_tar.c +++ b/archival/libarchive/get_header_tar.c @@ -152,6 +152,7 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) file_header_t *file_header = archive_handle->file_header; struct tar_header_t tar; char *cp; + int tar_typeflag; /* can be "char", "int" seems give smaller code */ int i, sum_u, sum; #if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY int sum_s; @@ -253,10 +254,10 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) * POSIX says that checksum is done on unsigned bytes, but * Sun and HP-UX gets it wrong... more details in * GNU tar source. */ + sum_u = ' ' * sizeof(tar.chksum); #if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY - sum_s = ' ' * sizeof(tar.chksum); + sum_s = sum_u; #endif - sum_u = ' ' * sizeof(tar.chksum); for (i = 0; i < 148; i++) { sum_u += ((unsigned char*)&tar)[i]; #if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY @@ -269,27 +270,22 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) sum_s += ((signed char*)&tar)[i]; #endif } - /* This field does not need special treatment (getOctal) */ - { - char *endp; /* gcc likes temp var for &endp */ - sum = strtoul(tar.chksum, &endp, 8); - if ((*endp != '\0' && *endp != ' ') - || (sum_u != sum IF_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum)) - ) { - bb_error_msg_and_die("invalid tar header checksum"); - } - } - /* don't use xstrtoul, tar.chksum may have leading spaces */ - sum = strtoul(tar.chksum, NULL, 8); - if (sum_u != sum IF_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum)) { + /* Most tarfiles have tar.chksum NUL or space terminated, but + * github.com decided to be "special" and have unterminated field: + * 0090: 30343300 30303031 33323731 30000000 |043.000132710...| + * ^^^^^^^^| + * Need to use GET_OCTAL. This overwrites tar.typeflag ---+ + * (the '0' char immediately after chksum in example above) with NUL. + */ + tar_typeflag = (uint8_t)tar.typeflag; /* save it */ + sum = GET_OCTAL(tar.chksum); + if (sum_u != sum + IF_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum) + ) { bb_error_msg_and_die("invalid tar header checksum"); } - /* 0 is reserved for high perf file, treat as normal file */ - if (!tar.typeflag) tar.typeflag = '0'; - parse_names = (tar.typeflag >= '0' && tar.typeflag <= '7'); - - /* getOctal trashes subsequent field, therefore we call it + /* GET_OCTAL trashes subsequent field, therefore we call it * on fields in reverse order */ if (tar.devmajor[0]) { char t = tar.prefix[0]; @@ -299,6 +295,11 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) file_header->device = makedev(major, minor); tar.prefix[0] = t; } + + /* 0 is reserved for high perf file, treat as normal file */ + if (tar_typeflag == '\0') tar_typeflag = '0'; + parse_names = (tar_typeflag >= '0' && tar_typeflag <= '7'); + file_header->link_target = NULL; if (!p_linkname && parse_names && tar.linkname[0]) { file_header->link_target = xstrndup(tar.linkname, sizeof(tar.linkname)); @@ -332,7 +333,7 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) /* Set bits 12-15 of the files mode */ /* (typeflag was not trashed because chksum does not use getOctal) */ - switch (tar.typeflag) { + switch (tar_typeflag) { case '1': /* hardlink */ /* we mark hardlinks as regular files with zero size and a link name */ file_header->mode |= S_IFREG; @@ -381,7 +382,7 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) case 'x': { /* pax extended header */ if ((uoff_t)file_header->size > 0xfffff) /* paranoia */ goto skip_ext_hdr; - process_pax_hdr(archive_handle, file_header->size, (tar.typeflag == 'g')); + process_pax_hdr(archive_handle, file_header->size, (tar_typeflag == 'g')); goto again_after_align; #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS /* See http://www.gnu.org/software/tar/manual/html_node/Extensions.html */ @@ -419,7 +420,7 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) skip_ext_hdr: { off_t sz; - bb_error_msg("warning: skipping header '%c'", tar.typeflag); + bb_error_msg("warning: skipping header '%c'", tar_typeflag); sz = (file_header->size + 511) & ~(off_t)511; archive_handle->offset += sz; sz >>= 9; /* sz /= 512 but w/o contortions for signed div */ @@ -429,7 +430,7 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) goto again_after_align; } default: - bb_error_msg_and_die("unknown typeflag: 0x%x", tar.typeflag); + bb_error_msg_and_die("unknown typeflag: 0x%x", tar_typeflag); } #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS