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 <vda.linux@googlemail.com>
This commit is contained in:
parent
01f7b9e182
commit
bb373dbc32
@ -152,6 +152,7 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
|
|||||||
file_header_t *file_header = archive_handle->file_header;
|
file_header_t *file_header = archive_handle->file_header;
|
||||||
struct tar_header_t tar;
|
struct tar_header_t tar;
|
||||||
char *cp;
|
char *cp;
|
||||||
|
int tar_typeflag; /* can be "char", "int" seems give smaller code */
|
||||||
int i, sum_u, sum;
|
int i, sum_u, sum;
|
||||||
#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
|
#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
|
||||||
int sum_s;
|
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
|
* POSIX says that checksum is done on unsigned bytes, but
|
||||||
* Sun and HP-UX gets it wrong... more details in
|
* Sun and HP-UX gets it wrong... more details in
|
||||||
* GNU tar source. */
|
* GNU tar source. */
|
||||||
#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
|
|
||||||
sum_s = ' ' * sizeof(tar.chksum);
|
|
||||||
#endif
|
|
||||||
sum_u = ' ' * sizeof(tar.chksum);
|
sum_u = ' ' * sizeof(tar.chksum);
|
||||||
|
#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
|
||||||
|
sum_s = sum_u;
|
||||||
|
#endif
|
||||||
for (i = 0; i < 148; i++) {
|
for (i = 0; i < 148; i++) {
|
||||||
sum_u += ((unsigned char*)&tar)[i];
|
sum_u += ((unsigned char*)&tar)[i];
|
||||||
#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
|
#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];
|
sum_s += ((signed char*)&tar)[i];
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
/* This field does not need special treatment (getOctal) */
|
/* Most tarfiles have tar.chksum NUL or space terminated, but
|
||||||
{
|
* github.com decided to be "special" and have unterminated field:
|
||||||
char *endp; /* gcc likes temp var for &endp */
|
* 0090: 30343300 30303031 33323731 30000000 |043.000132710...|
|
||||||
sum = strtoul(tar.chksum, &endp, 8);
|
* ^^^^^^^^|
|
||||||
if ((*endp != '\0' && *endp != ' ')
|
* Need to use GET_OCTAL. This overwrites tar.typeflag ---+
|
||||||
|| (sum_u != sum IF_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum))
|
* (the '0' char immediately after chksum in example above) with NUL.
|
||||||
) {
|
*/
|
||||||
bb_error_msg_and_die("invalid tar header checksum");
|
tar_typeflag = (uint8_t)tar.typeflag; /* save it */
|
||||||
}
|
sum = GET_OCTAL(tar.chksum);
|
||||||
}
|
if (sum_u != sum
|
||||||
/* don't use xstrtoul, tar.chksum may have leading spaces */
|
IF_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum)
|
||||||
sum = strtoul(tar.chksum, NULL, 8);
|
) {
|
||||||
if (sum_u != sum IF_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum)) {
|
|
||||||
bb_error_msg_and_die("invalid tar header checksum");
|
bb_error_msg_and_die("invalid tar header checksum");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 0 is reserved for high perf file, treat as normal file */
|
/* GET_OCTAL trashes subsequent field, therefore we call it
|
||||||
if (!tar.typeflag) tar.typeflag = '0';
|
|
||||||
parse_names = (tar.typeflag >= '0' && tar.typeflag <= '7');
|
|
||||||
|
|
||||||
/* getOctal trashes subsequent field, therefore we call it
|
|
||||||
* on fields in reverse order */
|
* on fields in reverse order */
|
||||||
if (tar.devmajor[0]) {
|
if (tar.devmajor[0]) {
|
||||||
char t = tar.prefix[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);
|
file_header->device = makedev(major, minor);
|
||||||
tar.prefix[0] = t;
|
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;
|
file_header->link_target = NULL;
|
||||||
if (!p_linkname && parse_names && tar.linkname[0]) {
|
if (!p_linkname && parse_names && tar.linkname[0]) {
|
||||||
file_header->link_target = xstrndup(tar.linkname, sizeof(tar.linkname));
|
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 */
|
/* Set bits 12-15 of the files mode */
|
||||||
/* (typeflag was not trashed because chksum does not use getOctal) */
|
/* (typeflag was not trashed because chksum does not use getOctal) */
|
||||||
switch (tar.typeflag) {
|
switch (tar_typeflag) {
|
||||||
case '1': /* hardlink */
|
case '1': /* hardlink */
|
||||||
/* we mark hardlinks as regular files with zero size and a link name */
|
/* we mark hardlinks as regular files with zero size and a link name */
|
||||||
file_header->mode |= S_IFREG;
|
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 */
|
case 'x': { /* pax extended header */
|
||||||
if ((uoff_t)file_header->size > 0xfffff) /* paranoia */
|
if ((uoff_t)file_header->size > 0xfffff) /* paranoia */
|
||||||
goto skip_ext_hdr;
|
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;
|
goto again_after_align;
|
||||||
#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
|
#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
|
||||||
/* See http://www.gnu.org/software/tar/manual/html_node/Extensions.html */
|
/* 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:
|
skip_ext_hdr:
|
||||||
{
|
{
|
||||||
off_t sz;
|
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;
|
sz = (file_header->size + 511) & ~(off_t)511;
|
||||||
archive_handle->offset += sz;
|
archive_handle->offset += sz;
|
||||||
sz >>= 9; /* sz /= 512 but w/o contortions for signed div */
|
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;
|
goto again_after_align;
|
||||||
}
|
}
|
||||||
default:
|
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
|
#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
|
||||||
|
Loading…
x
Reference in New Issue
Block a user