1
2
3
4
5
6
7
8
9
10
11
12
13
14#include "libbb.h"
15#include "bb_archive.h"
16
17typedef uint32_t aliased_uint32_t FIX_ALIASING;
18typedef off_t aliased_off_t FIX_ALIASING;
19
20
21static unsigned long long getOctal(char *str, int len)
22{
23 unsigned long long v;
24 char *end;
25
26
27
28 str[len] = '\0';
29 v = strtoull(str, &end, 8);
30
31
32 if (*end != '\0' && *end != ' ') {
33 int8_t first = str[0];
34 if (!(first & 0x80))
35 bb_simple_error_msg_and_die("corrupted octal value in tar header");
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53 first <<= 1;
54 first >>= 1;
55 v = first;
56 while (--len != 0)
57 v = (v << 8) + (uint8_t) *++str;
58 }
59 return v;
60}
61#define GET_OCTAL(a) getOctal((a), sizeof(a))
62
63#define TAR_EXTD (ENABLE_FEATURE_TAR_GNU_EXTENSIONS || ENABLE_FEATURE_TAR_SELINUX)
64#if !TAR_EXTD
65#define process_pax_hdr(archive_handle, sz, global) \
66 process_pax_hdr(archive_handle, sz)
67#endif
68
69static void process_pax_hdr(archive_handle_t *archive_handle, unsigned sz, int global)
70{
71#if !TAR_EXTD
72 unsigned blk_sz = (sz + 511) & (~511);
73 seek_by_read(archive_handle->src_fd, blk_sz);
74#else
75 unsigned blk_sz = (sz + 511) & (~511);
76 char *buf, *p;
77
78 p = buf = xmalloc(blk_sz + 1);
79 xread(archive_handle->src_fd, buf, blk_sz);
80 archive_handle->offset += blk_sz;
81
82
83 buf[sz] = '\0';
84
85 while (sz != 0) {
86 char *end, *value;
87 unsigned len;
88
89
90 len = bb_strtou(p, &end, 10);
91
92
93
94 p += len;
95 sz -= len;
96 if (
97
98 (int)(sz|len) < 0
99 || len == 0
100 || errno != EINVAL
101 || *end != ' '
102 ) {
103 bb_simple_error_msg("malformed extended header, skipped");
104
105
106
107 break;
108 }
109
110
111
112 p[-1] = '\0';
113 value = end + 1;
114
115# if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
116 if (!global) {
117 if (is_prefixed_with(value, "path=")) {
118 value += sizeof("path=") - 1;
119 free(archive_handle->tar__longname);
120 archive_handle->tar__longname = xstrdup(value);
121 continue;
122 }
123 if (is_prefixed_with(value, "linkpath=")) {
124 value += sizeof("linkpath=") - 1;
125 free(archive_handle->tar__linkname);
126 archive_handle->tar__linkname = xstrdup(value);
127 continue;
128 }
129 }
130# endif
131
132# if ENABLE_FEATURE_TAR_SELINUX
133
134
135
136# define SELINUX_CONTEXT_KEYWORD "RHT.security.selinux"
137 if (is_prefixed_with(value, SELINUX_CONTEXT_KEYWORD"=")) {
138 value += sizeof(SELINUX_CONTEXT_KEYWORD"=") - 1;
139 free(archive_handle->tar__sctx[global]);
140 archive_handle->tar__sctx[global] = xstrdup(value);
141 continue;
142 }
143# endif
144 }
145
146 free(buf);
147#endif
148}
149
150#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
151static void die_if_bad_fnamesize(off_t sz)
152{
153 if ((uoff_t)sz > 0xfff)
154 bb_simple_error_msg_and_die("bad archive");
155}
156#endif
157
158char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
159{
160 file_header_t *file_header = archive_handle->file_header;
161 struct tar_header_t tar;
162 char *cp;
163 int tar_typeflag;
164 int i, sum_u, sum;
165#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
166 int sum_s;
167#endif
168 int parse_names;
169
170
171#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
172# define p_longname (archive_handle->tar__longname)
173# define p_linkname (archive_handle->tar__linkname)
174#else
175# define p_longname 0
176# define p_linkname 0
177#endif
178
179#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS || ENABLE_FEATURE_TAR_SELINUX
180 again:
181#endif
182
183 data_align(archive_handle, 512);
184
185 again_after_align:
186
187#if ENABLE_DESKTOP || ENABLE_FEATURE_TAR_AUTODETECT
188
189 *(aliased_uint32_t*)&tar = 0;
190 i = full_read(archive_handle->src_fd, &tar, 512);
191
192
193
194
195
196
197
198 if (i == 0) {
199
200
201
202
203
204 if (archive_handle->offset == 0)
205 bb_simple_error_msg("short read");
206
207 return EXIT_FAILURE;
208 }
209 if (i != 512) {
210 IF_FEATURE_TAR_AUTODETECT(goto autodetect;)
211 bb_simple_error_msg_and_die("short read");
212 }
213
214#else
215 i = 512;
216 xread(archive_handle->src_fd, &tar, i);
217#endif
218 archive_handle->offset += i;
219
220
221 if (tar.name[0] == 0 && tar.prefix[0] == 0
222
223
224 && !p_longname
225 ) {
226 if (archive_handle->tar__end) {
227
228
229
230 while (full_read(archive_handle->src_fd, &tar, 512) == 512)
231 continue;
232 return EXIT_FAILURE;
233 }
234 archive_handle->tar__end = 1;
235 return EXIT_SUCCESS;
236 }
237 archive_handle->tar__end = 0;
238
239
240
241 if (!is_prefixed_with(tar.magic, "ustar")
242 && (!ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY
243 || memcmp(tar.magic, "\0\0\0\0", 5) != 0)
244 ) {
245#if ENABLE_FEATURE_TAR_AUTODETECT
246 autodetect:
247
248
249
250 if (lseek(archive_handle->src_fd, -i, SEEK_CUR) != 0)
251 goto err;
252 if (setup_unzip_on_fd(archive_handle->src_fd, 0) != 0)
253 err:
254 bb_simple_error_msg_and_die("invalid tar magic");
255 archive_handle->offset = 0;
256 goto again_after_align;
257#endif
258 bb_simple_error_msg_and_die("invalid tar magic");
259 }
260
261
262
263
264
265 sum_u = ' ' * sizeof(tar.chksum);
266#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
267 sum_s = sum_u;
268#endif
269 for (i = 0; i < 148; i++) {
270 sum_u += ((unsigned char*)&tar)[i];
271#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
272 sum_s += ((signed char*)&tar)[i];
273#endif
274 }
275 for (i = 156; i < 512; i++) {
276 sum_u += ((unsigned char*)&tar)[i];
277#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
278 sum_s += ((signed char*)&tar)[i];
279#endif
280 }
281
282
283
284
285
286
287
288 tar_typeflag = (uint8_t)tar.typeflag;
289 sum = GET_OCTAL(tar.chksum);
290 if (sum_u != sum
291 IF_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum)
292 ) {
293 bb_simple_error_msg_and_die("invalid tar header checksum");
294 }
295
296
297
298 if (tar.devmajor[0]) {
299 char t = tar.prefix[0];
300
301 unsigned minor = GET_OCTAL(tar.devminor);
302 unsigned major = GET_OCTAL(tar.devmajor);
303 file_header->device = makedev(major, minor);
304 tar.prefix[0] = t;
305 }
306
307
308 if (tar_typeflag == '\0') tar_typeflag = '0';
309 parse_names = (tar_typeflag >= '0' && tar_typeflag <= '7');
310
311 file_header->link_target = NULL;
312 if (!p_linkname && parse_names && tar.linkname[0]) {
313 file_header->link_target = xstrndup(tar.linkname, sizeof(tar.linkname));
314
315
316 }
317#if ENABLE_FEATURE_TAR_UNAME_GNAME
318 file_header->tar__uname = tar.uname[0] ? xstrndup(tar.uname, sizeof(tar.uname)) : NULL;
319 file_header->tar__gname = tar.gname[0] ? xstrndup(tar.gname, sizeof(tar.gname)) : NULL;
320#endif
321 file_header->mtime = GET_OCTAL(tar.mtime);
322 file_header->size = GET_OCTAL(tar.size);
323 file_header->gid = GET_OCTAL(tar.gid);
324 file_header->uid = GET_OCTAL(tar.uid);
325
326 file_header->mode = 07777 & GET_OCTAL(tar.mode);
327
328 file_header->name = NULL;
329 if (!p_longname && parse_names) {
330
331
332 tar.mode[0] = '\0';
333 if (tar.prefix[0]) {
334
335
336 tar.padding[0] = '\0';
337 file_header->name = concat_path_file(tar.prefix, tar.name);
338 } else
339 file_header->name = xstrdup(tar.name);
340 }
341
342 switch (tar_typeflag) {
343 case '1':
344
345 file_header->mode |= S_IFREG;
346
347
348
349
350
351
352
353
354
355
356 goto size0;
357 case '7':
358
359 case '0':
360#if ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY
361 if (file_header->name && last_char_is(file_header->name, '/')) {
362 goto set_dir;
363 }
364#endif
365 file_header->mode |= S_IFREG;
366 break;
367 case '2':
368 file_header->mode |= S_IFLNK;
369
370
371 size0:
372 file_header->size = 0;
373 break;
374 case '3':
375 file_header->mode |= S_IFCHR;
376 goto size0;
377 case '4':
378 file_header->mode |= S_IFBLK;
379 goto size0;
380 case '5':
381 IF_FEATURE_TAR_OLDGNU_COMPATIBILITY(set_dir:)
382 file_header->mode |= S_IFDIR;
383 goto size0;
384 case '6':
385 file_header->mode |= S_IFIFO;
386 goto size0;
387 case 'g':
388 case 'x': {
389 if ((uoff_t)file_header->size > 0xfffff)
390 goto skip_ext_hdr;
391 process_pax_hdr(archive_handle, file_header->size, (tar_typeflag == 'g'));
392 goto again_after_align;
393#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
394
395 case 'L':
396
397 free(p_longname);
398
399 die_if_bad_fnamesize(file_header->size);
400 p_longname = xzalloc(file_header->size + 1);
401
402 xread(archive_handle->src_fd, p_longname, file_header->size);
403 archive_handle->offset += file_header->size;
404
405
406
407 goto again;
408 case 'K':
409 free(p_linkname);
410 die_if_bad_fnamesize(file_header->size);
411 p_linkname = xzalloc(file_header->size + 1);
412 xread(archive_handle->src_fd, p_linkname, file_header->size);
413 archive_handle->offset += file_header->size;
414
415 goto again;
416
417
418
419
420
421
422
423
424
425 case 'V':
426 ;
427#endif
428 }
429 skip_ext_hdr:
430 {
431 off_t sz;
432 bb_error_msg("warning: skipping header '%c'", tar_typeflag);
433 sz = (file_header->size + 511) & ~(off_t)511;
434 archive_handle->offset += sz;
435 sz >>= 9;
436 while (sz--)
437 xread(archive_handle->src_fd, &tar, 512);
438
439 goto again_after_align;
440 }
441 default:
442 bb_error_msg_and_die("unknown typeflag: 0x%x", tar_typeflag);
443 }
444
445#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
446 if (p_longname) {
447 file_header->name = p_longname;
448 p_longname = NULL;
449 }
450 if (p_linkname) {
451 file_header->link_target = p_linkname;
452 p_linkname = NULL;
453 }
454#endif
455
456
457 overlapping_strcpy(file_header->name, strip_unsafe_prefix(file_header->name));
458
459
460
461
462 cp = last_char_is(file_header->name, '/');
463
464 if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) {
465 archive_handle->action_header( file_header);
466
467
468 if (cp)
469 *cp = '\0';
470 archive_handle->action_data(archive_handle);
471 if (archive_handle->accept || archive_handle->reject
472 || (archive_handle->ah_flags & ARCHIVE_REMEMBER_NAMES)
473 ) {
474 llist_add_to(&archive_handle->passed, file_header->name);
475 } else
476 free(file_header->name);
477 } else {
478 data_skip(archive_handle);
479 free(file_header->name);
480 }
481 archive_handle->offset += file_header->size;
482
483 free(file_header->link_target);
484
485
486#if ENABLE_FEATURE_TAR_UNAME_GNAME
487 free(file_header->tar__uname);
488 free(file_header->tar__gname);
489#endif
490 return EXIT_SUCCESS;
491}
492