aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2018-01-27 19:04:08 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2018-02-14 17:38:29 +0100
commit20f02c3c871cf0c8d9d2f2dad11d96c0ea41e0df (patch)
treeb1ea7f4a3e333910b2edc575e99ca1ddecbc1ff3
parent277636670c583720580c452e90b73cc2a5b0357e (diff)
downloadbusybox-w32-20f02c3c871cf0c8d9d2f2dad11d96c0ea41e0df.tar.gz
busybox-w32-20f02c3c871cf0c8d9d2f2dad11d96c0ea41e0df.tar.bz2
busybox-w32-20f02c3c871cf0c8d9d2f2dad11d96c0ea41e0df.zip
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>
-rw-r--r--archival/libarchive/get_header_tar.c49
1 files changed, 25 insertions, 24 deletions
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)
152 file_header_t *file_header = archive_handle->file_header; 152 file_header_t *file_header = archive_handle->file_header;
153 struct tar_header_t tar; 153 struct tar_header_t tar;
154 char *cp; 154 char *cp;
155 int tar_typeflag; /* can be "char", "int" seems give smaller code */
155 int i, sum_u, sum; 156 int i, sum_u, sum;
156#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY 157#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
157 int sum_s; 158 int sum_s;
@@ -253,10 +254,10 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
253 * POSIX says that checksum is done on unsigned bytes, but 254 * POSIX says that checksum is done on unsigned bytes, but
254 * Sun and HP-UX gets it wrong... more details in 255 * Sun and HP-UX gets it wrong... more details in
255 * GNU tar source. */ 256 * GNU tar source. */
257 sum_u = ' ' * sizeof(tar.chksum);
256#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY 258#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
257 sum_s = ' ' * sizeof(tar.chksum); 259 sum_s = sum_u;
258#endif 260#endif
259 sum_u = ' ' * sizeof(tar.chksum);
260 for (i = 0; i < 148; i++) { 261 for (i = 0; i < 148; i++) {
261 sum_u += ((unsigned char*)&tar)[i]; 262 sum_u += ((unsigned char*)&tar)[i];
262#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY 263#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
@@ -269,27 +270,22 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
269 sum_s += ((signed char*)&tar)[i]; 270 sum_s += ((signed char*)&tar)[i];
270#endif 271#endif
271 } 272 }
272 /* This field does not need special treatment (getOctal) */ 273 /* Most tarfiles have tar.chksum NUL or space terminated, but
273 { 274 * github.com decided to be "special" and have unterminated field:
274 char *endp; /* gcc likes temp var for &endp */ 275 * 0090: 30343300 30303031 33323731 30000000 |043.000132710...|
275 sum = strtoul(tar.chksum, &endp, 8); 276 * ^^^^^^^^|
276 if ((*endp != '\0' && *endp != ' ') 277 * Need to use GET_OCTAL. This overwrites tar.typeflag ---+
277 || (sum_u != sum IF_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum)) 278 * (the '0' char immediately after chksum in example above) with NUL.
278 ) { 279 */
279 bb_error_msg_and_die("invalid tar header checksum"); 280 tar_typeflag = (uint8_t)tar.typeflag; /* save it */
280 } 281 sum = GET_OCTAL(tar.chksum);
281 } 282 if (sum_u != sum
282 /* don't use xstrtoul, tar.chksum may have leading spaces */ 283 IF_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum)
283 sum = strtoul(tar.chksum, NULL, 8); 284 ) {
284 if (sum_u != sum IF_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum)) {
285 bb_error_msg_and_die("invalid tar header checksum"); 285 bb_error_msg_and_die("invalid tar header checksum");
286 } 286 }
287 287
288 /* 0 is reserved for high perf file, treat as normal file */ 288 /* GET_OCTAL trashes subsequent field, therefore we call it
289 if (!tar.typeflag) tar.typeflag = '0';
290 parse_names = (tar.typeflag >= '0' && tar.typeflag <= '7');
291
292 /* getOctal trashes subsequent field, therefore we call it
293 * on fields in reverse order */ 289 * on fields in reverse order */
294 if (tar.devmajor[0]) { 290 if (tar.devmajor[0]) {
295 char t = tar.prefix[0]; 291 char t = tar.prefix[0];
@@ -299,6 +295,11 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
299 file_header->device = makedev(major, minor); 295 file_header->device = makedev(major, minor);
300 tar.prefix[0] = t; 296 tar.prefix[0] = t;
301 } 297 }
298
299 /* 0 is reserved for high perf file, treat as normal file */
300 if (tar_typeflag == '\0') tar_typeflag = '0';
301 parse_names = (tar_typeflag >= '0' && tar_typeflag <= '7');
302
302 file_header->link_target = NULL; 303 file_header->link_target = NULL;
303 if (!p_linkname && parse_names && tar.linkname[0]) { 304 if (!p_linkname && parse_names && tar.linkname[0]) {
304 file_header->link_target = xstrndup(tar.linkname, sizeof(tar.linkname)); 305 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)
332 333
333 /* Set bits 12-15 of the files mode */ 334 /* Set bits 12-15 of the files mode */
334 /* (typeflag was not trashed because chksum does not use getOctal) */ 335 /* (typeflag was not trashed because chksum does not use getOctal) */
335 switch (tar.typeflag) { 336 switch (tar_typeflag) {
336 case '1': /* hardlink */ 337 case '1': /* hardlink */
337 /* we mark hardlinks as regular files with zero size and a link name */ 338 /* we mark hardlinks as regular files with zero size and a link name */
338 file_header->mode |= S_IFREG; 339 file_header->mode |= S_IFREG;
@@ -381,7 +382,7 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
381 case 'x': { /* pax extended header */ 382 case 'x': { /* pax extended header */
382 if ((uoff_t)file_header->size > 0xfffff) /* paranoia */ 383 if ((uoff_t)file_header->size > 0xfffff) /* paranoia */
383 goto skip_ext_hdr; 384 goto skip_ext_hdr;
384 process_pax_hdr(archive_handle, file_header->size, (tar.typeflag == 'g')); 385 process_pax_hdr(archive_handle, file_header->size, (tar_typeflag == 'g'));
385 goto again_after_align; 386 goto again_after_align;
386#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS 387#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
387/* See http://www.gnu.org/software/tar/manual/html_node/Extensions.html */ 388/* 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)
419 skip_ext_hdr: 420 skip_ext_hdr:
420 { 421 {
421 off_t sz; 422 off_t sz;
422 bb_error_msg("warning: skipping header '%c'", tar.typeflag); 423 bb_error_msg("warning: skipping header '%c'", tar_typeflag);
423 sz = (file_header->size + 511) & ~(off_t)511; 424 sz = (file_header->size + 511) & ~(off_t)511;
424 archive_handle->offset += sz; 425 archive_handle->offset += sz;
425 sz >>= 9; /* sz /= 512 but w/o contortions for signed div */ 426 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)
429 goto again_after_align; 430 goto again_after_align;
430 } 431 }
431 default: 432 default:
432 bb_error_msg_and_die("unknown typeflag: 0x%x", tar.typeflag); 433 bb_error_msg_and_die("unknown typeflag: 0x%x", tar_typeflag);
433 } 434 }
434 435
435#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS 436#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS