1 /* vi: set sw=4 ts=4: */
2 /* Licensed under GPLv2 or later, see file LICENSE in this source tree.
5 * In privileged mode if uname and gname map to a uid and gid then use the
6 * mapped value instead of the uid/gid values in tar header
9 * GNU tar and star man pages,
10 * Opengroup's ustar interchange format,
11 * http://www.opengroup.org/onlinepubs/007904975/utilities/pax.html
15 #include "bb_archive.h"
17 typedef uint32_t aliased_uint32_t FIX_ALIASING
;
18 typedef off_t aliased_off_t FIX_ALIASING
;
21 const char* FAST_FUNC
strip_unsafe_prefix(const char *str
)
30 if (strncmp(cp
, "/../"+1, 3) == 0) {
34 cp2
= strstr(cp
, "/../");
40 static smallint warned
= 0;
43 bb_error_msg("removing leading '%.*s' from member names",
44 (int)(cp
- str
), str
);
50 /* NB: _DESTROYS_ str[len] character! */
51 static unsigned long long getOctal(char *str
, int len
)
55 /* NB: leading spaces are allowed. Using strtoull to handle that.
56 * The downside is that we accept e.g. "-123" too :(
59 v
= strtoull(str
, &end
, 8);
60 /* std: "Each numeric field is terminated by one or more
61 * <space> or NUL characters". We must support ' '! */
62 if (*end
!= '\0' && *end
!= ' ') {
63 int8_t first
= str
[0];
65 bb_error_msg_and_die("corrupted octal value in tar header");
67 * GNU tar uses "base-256 encoding" for very large numbers.
68 * Encoding is binary, with highest bit always set as a marker
69 * and sign in next-highest bit:
71 * bf ff .. ff - largest positive number
72 * ff ff .. ff - minus 1
73 * c0 00 .. 00 - smallest negative number
75 * Example of tar file with 8914993153 (0x213600001) byte file.
76 * Field starts at offset 7c:
77 * 00070 30 30 30 00 30 30 30 30 30 30 30 00 80 00 00 00 |000.0000000.....|
78 * 00080 00 00 00 02 13 60 00 01 31 31 31 32 30 33 33 36 |.....`..11120336|
80 * NB: tarballs with NEGATIVE unix times encoded that way were seen!
82 /* Sign-extend 7bit 'first' to 64bit 'v' (that is, using 6th bit as sign): */
84 first
>>= 1; /* now 7th bit = 6th bit */
85 v
= first
; /* sign-extend 8 bits to 64 */
87 v
= (v
<< 8) + (uint8_t) *++str
;
91 #define GET_OCTAL(a) getOctal((a), sizeof(a))
93 /* "global" is 0 or 1 */
94 static void process_pax_hdr(archive_handle_t
*archive_handle
, unsigned sz
, int global
)
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
;
104 /* prevent bb_strtou from running off the buffer */
111 /* Every record has this format: "LEN NAME=VALUE\n" */
112 len
= bb_strtou(p
, &end
, 10);
113 /* expect errno to be EINVAL, because the character
114 * following the digits should be a space
119 /** (int)sz < 0 - not good enough for huge malicious VALUE of 2^32-1 */
120 (int)(sz
|len
) < 0 /* this works */
125 bb_error_msg("malformed extended header, skipped");
126 // More verbose version:
127 //bb_error_msg("malformed extended header at %"OFF_FMT"d, skipped",
128 // archive_handle->offset - (sz + len));
131 /* overwrite the terminating newline with NUL
132 * (we do not bother to check that it *was* a newline)
137 #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
138 if (!global
&& strncmp(value
, "path=", sizeof("path=") - 1) == 0) {
139 value
+= sizeof("path=") - 1;
140 free(archive_handle
->tar__longname
);
141 archive_handle
->tar__longname
= xstrdup(value
);
146 #if ENABLE_FEATURE_TAR_SELINUX
147 /* Scan for SELinux contexts, via "RHT.security.selinux" keyword.
148 * This is what Red Hat's patched version of tar uses.
150 # define SELINUX_CONTEXT_KEYWORD "RHT.security.selinux"
151 if (strncmp(value
, SELINUX_CONTEXT_KEYWORD
"=", sizeof(SELINUX_CONTEXT_KEYWORD
"=") - 1) == 0) {
152 value
+= sizeof(SELINUX_CONTEXT_KEYWORD
"=") - 1;
153 free(archive_handle
->tar__sctx
[global
]);
154 archive_handle
->tar__sctx
[global
] = xstrdup(value
);
163 char FAST_FUNC
get_header_tar(archive_handle_t
*archive_handle
)
165 file_header_t
*file_header
= archive_handle
->file_header
;
166 struct tar_header_t tar
;
169 #if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
174 /* Our "private data" */
175 #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
176 # define p_longname (archive_handle->tar__longname)
177 # define p_linkname (archive_handle->tar__linkname)
179 # define p_longname 0
180 # define p_linkname 0
183 #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS || ENABLE_FEATURE_TAR_SELINUX
187 data_align(archive_handle
, 512);
191 #if ENABLE_DESKTOP || ENABLE_FEATURE_TAR_AUTODETECT
192 /* to prevent misdetection of bz2 sig */
193 *(aliased_uint32_t
*)&tar
= 0;
194 i
= full_read(archive_handle
->src_fd
, &tar
, 512);
195 /* If GNU tar sees EOF in above read, it says:
196 * "tar: A lone zero block at N", where N = kilobyte
197 * where EOF was met (not EOF block, actual EOF!),
198 * and exits with EXIT_SUCCESS.
199 * We will mimic exit(EXIT_SUCCESS), although we will not mimic
200 * the message and we don't check whether we indeed
201 * saw zero block directly before this. */
203 bb_error_msg("short read");
204 /* this merely signals end of archive, not exit(1): */
208 IF_FEATURE_TAR_AUTODETECT(goto autodetect
;)
209 bb_error_msg_and_die("short read");
214 xread(archive_handle
->src_fd
, &tar
, i
);
216 archive_handle
->offset
+= i
;
218 /* If there is no filename its an empty header */
219 if (tar
.name
[0] == 0 && tar
.prefix
[0] == 0) {
220 if (archive_handle
->tar__end
) {
221 /* Second consecutive empty header - end of archive.
222 * Read until the end to empty the pipe from gz or bz2
224 while (full_read(archive_handle
->src_fd
, &tar
, 512) == 512)
226 return EXIT_FAILURE
; /* "end of archive" */
228 archive_handle
->tar__end
= 1;
229 return EXIT_SUCCESS
; /* "decoded one header" */
231 archive_handle
->tar__end
= 0;
233 /* Check header has valid magic, "ustar" is for the proper tar,
234 * five NULs are for the old tar format */
235 if (strncmp(tar
.magic
, "ustar", 5) != 0
236 && (!ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY
237 || memcmp(tar
.magic
, "\0\0\0\0", 5) != 0)
239 #if ENABLE_FEATURE_TAR_AUTODETECT
241 /* Two different causes for lseek() != 0:
242 * unseekable fd (would like to support that too, but...),
243 * or not first block (false positive, it's not .gz/.bz2!) */
244 if (lseek(archive_handle
->src_fd
, -i
, SEEK_CUR
) != 0)
246 if (setup_unzip_on_fd(archive_handle
->src_fd
, /*fail_if_not_compressed:*/ 0) != 0)
248 bb_error_msg_and_die("invalid tar magic");
249 archive_handle
->offset
= 0;
250 goto again_after_align
;
252 bb_error_msg_and_die("invalid tar magic");
255 /* Do checksum on headers.
256 * POSIX says that checksum is done on unsigned bytes, but
257 * Sun and HP-UX gets it wrong... more details in
259 #if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
260 sum_s
= ' ' * sizeof(tar
.chksum
);
262 sum_u
= ' ' * sizeof(tar
.chksum
);
263 for (i
= 0; i
< 148; i
++) {
264 sum_u
+= ((unsigned char*)&tar
)[i
];
265 #if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
266 sum_s
+= ((signed char*)&tar
)[i
];
269 for (i
= 156; i
< 512; i
++) {
270 sum_u
+= ((unsigned char*)&tar
)[i
];
271 #if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
272 sum_s
+= ((signed char*)&tar
)[i
];
275 /* This field does not need special treatment (getOctal) */
277 char *endp
; /* gcc likes temp var for &endp */
278 sum
= strtoul(tar
.chksum
, &endp
, 8);
279 if ((*endp
!= '\0' && *endp
!= ' ')
280 || (sum_u
!= sum
IF_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s
!= sum
))
282 bb_error_msg_and_die("invalid tar header checksum");
285 /* don't use xstrtoul, tar.chksum may have leading spaces */
286 sum
= strtoul(tar
.chksum
, NULL
, 8);
287 if (sum_u
!= sum
IF_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s
!= sum
)) {
288 bb_error_msg_and_die("invalid tar header checksum");
291 /* 0 is reserved for high perf file, treat as normal file */
292 if (!tar
.typeflag
) tar
.typeflag
= '0';
293 parse_names
= (tar
.typeflag
>= '0' && tar
.typeflag
<= '7');
295 /* getOctal trashes subsequent field, therefore we call it
296 * on fields in reverse order */
297 if (tar
.devmajor
[0]) {
298 char t
= tar
.prefix
[0];
299 /* we trash prefix[0] here, but we DO need it later! */
300 unsigned minor
= GET_OCTAL(tar
.devminor
);
301 unsigned major
= GET_OCTAL(tar
.devmajor
);
302 file_header
->device
= makedev(major
, minor
);
305 file_header
->link_target
= NULL
;
306 if (!p_linkname
&& parse_names
&& tar
.linkname
[0]) {
307 file_header
->link_target
= xstrndup(tar
.linkname
, sizeof(tar
.linkname
));
308 /* FIXME: what if we have non-link object with link_target? */
309 /* Will link_target be free()ed? */
311 #if ENABLE_FEATURE_TAR_UNAME_GNAME
312 file_header
->tar__uname
= tar
.uname
[0] ? xstrndup(tar
.uname
, sizeof(tar
.uname
)) : NULL
;
313 file_header
->tar__gname
= tar
.gname
[0] ? xstrndup(tar
.gname
, sizeof(tar
.gname
)) : NULL
;
315 file_header
->mtime
= GET_OCTAL(tar
.mtime
);
316 file_header
->size
= GET_OCTAL(tar
.size
);
317 file_header
->gid
= GET_OCTAL(tar
.gid
);
318 file_header
->uid
= GET_OCTAL(tar
.uid
);
319 /* Set bits 0-11 of the files mode */
320 file_header
->mode
= 07777 & GET_OCTAL(tar
.mode
);
322 file_header
->name
= NULL
;
323 if (!p_longname
&& parse_names
) {
324 /* we trash mode[0] here, it's ok */
325 //tar.name[sizeof(tar.name)] = '\0'; - gcc 4.3.0 would complain
329 //tar.prefix[sizeof(tar.prefix)] = '\0'; - gcc 4.3.0 would complain
330 tar
.padding
[0] = '\0';
331 file_header
->name
= concat_path_file(tar
.prefix
, tar
.name
);
333 file_header
->name
= xstrdup(tar
.name
);
336 /* Set bits 12-15 of the files mode */
337 /* (typeflag was not trashed because chksum does not use getOctal) */
338 switch (tar
.typeflag
) {
339 case '1': /* hardlink */
340 /* we mark hardlinks as regular files with zero size and a link name */
341 file_header
->mode
|= S_IFREG
;
342 /* on size of link fields from star(4)
343 * ... For tar archives written by pre POSIX.1-1988
344 * implementations, the size field usually contains the size of
345 * the file and needs to be ignored as no data may follow this
346 * header type. For POSIX.1- 1988 compliant archives, the size
347 * field needs to be 0. For POSIX.1-2001 compliant archives,
348 * the size field may be non zero, indicating that file data is
349 * included in the archive.
350 * i.e; always assume this is zero for safety.
356 #if ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY
357 if (last_char_is(file_header
->name
, '/')) {
361 file_header
->mode
|= S_IFREG
;
364 file_header
->mode
|= S_IFLNK
;
365 /* have seen tarballs with size field containing
366 * the size of the link target's name */
368 file_header
->size
= 0;
371 file_header
->mode
|= S_IFCHR
;
372 goto size0
; /* paranoia */
374 file_header
->mode
|= S_IFBLK
;
377 IF_FEATURE_TAR_OLDGNU_COMPATIBILITY(set_dir
:)
378 file_header
->mode
|= S_IFDIR
;
381 file_header
->mode
|= S_IFIFO
;
383 #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
385 /* free: paranoia: tar with several consecutive longnames */
387 /* For paranoia reasons we allocate extra NUL char */
388 p_longname
= xzalloc(file_header
->size
+ 1);
389 /* We read ASCIZ string, including NUL */
390 xread(archive_handle
->src_fd
, p_longname
, file_header
->size
);
391 archive_handle
->offset
+= file_header
->size
;
392 /* return get_header_tar(archive_handle); */
393 /* gcc 4.1.1 didn't optimize it into jump */
394 /* so we will do it ourself, this also saves stack */
398 p_linkname
= xzalloc(file_header
->size
+ 1);
399 xread(archive_handle
->src_fd
, p_linkname
, file_header
->size
);
400 archive_handle
->offset
+= file_header
->size
;
401 /* return get_header_tar(archive_handle); */
403 case 'D': /* GNU dump dir */
404 case 'M': /* Continuation of multi volume archive */
405 case 'N': /* Old GNU for names > 100 characters */
406 case 'S': /* Sparse file */
407 case 'V': /* Volume header */
409 case 'g': /* pax global header */
410 case 'x': { /* pax extended header */
411 if ((uoff_t
)file_header
->size
> 0xfffff) /* paranoia */
413 process_pax_hdr(archive_handle
, file_header
->size
, (tar
.typeflag
== 'g'));
414 goto again_after_align
;
419 bb_error_msg("warning: skipping header '%c'", tar
.typeflag
);
420 sz
= (file_header
->size
+ 511) & ~(off_t
)511;
421 archive_handle
->offset
+= sz
;
422 sz
>>= 9; /* sz /= 512 but w/o contortions for signed div */
424 xread(archive_handle
->src_fd
, &tar
, 512);
425 /* return get_header_tar(archive_handle); */
426 goto again_after_align
;
429 bb_error_msg_and_die("unknown typeflag: 0x%x", tar
.typeflag
);
432 #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
434 file_header
->name
= p_longname
;
438 file_header
->link_target
= p_linkname
;
443 /* Everything up to and including last ".." component is stripped */
444 overlapping_strcpy(file_header
->name
, strip_unsafe_prefix(file_header
->name
));
446 /* Strip trailing '/' in directories */
447 /* Must be done after mode is set as '/' is used to check if it's a directory */
448 cp
= last_char_is(file_header
->name
, '/');
450 if (archive_handle
->filter(archive_handle
) == EXIT_SUCCESS
) {
451 archive_handle
->action_header(/*archive_handle->*/ file_header
);
452 /* Note that we kill the '/' only after action_header() */
453 /* (like GNU tar 1.15.1: verbose mode outputs "dir/dir/") */
456 archive_handle
->action_data(archive_handle
);
457 if (archive_handle
->accept
|| archive_handle
->reject
458 || (archive_handle
->ah_flags
& ARCHIVE_REMEMBER_NAMES
)
460 llist_add_to(&archive_handle
->passed
, file_header
->name
);
461 } else /* Caller isn't interested in list of unpacked files */
462 free(file_header
->name
);
464 data_skip(archive_handle
);
465 free(file_header
->name
);
467 archive_handle
->offset
+= file_header
->size
;
469 free(file_header
->link_target
);
470 /* Do not free(file_header->name)!
471 * It might be inserted in archive_handle->passed - see above */
472 #if ENABLE_FEATURE_TAR_UNAME_GNAME
473 free(file_header
->tar__uname
);
474 free(file_header
->tar__gname
);
476 return EXIT_SUCCESS
; /* "decoded one header" */