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_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_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
150char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
151{
152 file_header_t *file_header = archive_handle->file_header;
153 struct tar_header_t tar;
154 char *cp;
155 int tar_typeflag;
156 int i, sum_u, sum;
157#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
158 int sum_s;
159#endif
160 int parse_names;
161
162
163#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
164# define p_longname (archive_handle->tar__longname)
165# define p_linkname (archive_handle->tar__linkname)
166#else
167# define p_longname 0
168# define p_linkname 0
169#endif
170
171#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS || ENABLE_FEATURE_TAR_SELINUX
172 again:
173#endif
174
175 data_align(archive_handle, 512);
176
177 again_after_align:
178
179#if ENABLE_DESKTOP || ENABLE_FEATURE_TAR_AUTODETECT
180
181 *(aliased_uint32_t*)&tar = 0;
182 i = full_read(archive_handle->src_fd, &tar, 512);
183
184
185
186
187
188
189
190 if (i == 0) {
191
192
193
194
195
196 if (archive_handle->offset == 0)
197 bb_error_msg("short read");
198
199 return EXIT_FAILURE;
200 }
201 if (i != 512) {
202 IF_FEATURE_TAR_AUTODETECT(goto autodetect;)
203 bb_error_msg_and_die("short read");
204 }
205
206#else
207 i = 512;
208 xread(archive_handle->src_fd, &tar, i);
209#endif
210 archive_handle->offset += i;
211
212
213 if (tar.name[0] == 0 && tar.prefix[0] == 0
214
215
216 && !p_longname
217 ) {
218 if (archive_handle->tar__end) {
219
220
221
222 while (full_read(archive_handle->src_fd, &tar, 512) == 512)
223 continue;
224 return EXIT_FAILURE;
225 }
226 archive_handle->tar__end = 1;
227 return EXIT_SUCCESS;
228 }
229 archive_handle->tar__end = 0;
230
231
232
233 if (!is_prefixed_with(tar.magic, "ustar")
234 && (!ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY
235 || memcmp(tar.magic, "\0\0\0\0", 5) != 0)
236 ) {
237#if ENABLE_FEATURE_TAR_AUTODETECT
238 autodetect:
239
240
241
242 if (lseek(archive_handle->src_fd, -i, SEEK_CUR) != 0)
243 goto err;
244 if (setup_unzip_on_fd(archive_handle->src_fd, 0) != 0)
245 err:
246 bb_error_msg_and_die("invalid tar magic");
247 archive_handle->offset = 0;
248 goto again_after_align;
249#endif
250 bb_error_msg_and_die("invalid tar magic");
251 }
252
253
254
255
256
257 sum_u = ' ' * sizeof(tar.chksum);
258#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
259 sum_s = sum_u;
260#endif
261 for (i = 0; i < 148; i++) {
262 sum_u += ((unsigned char*)&tar)[i];
263#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
264 sum_s += ((signed char*)&tar)[i];
265#endif
266 }
267 for (i = 156; i < 512; i++) {
268 sum_u += ((unsigned char*)&tar)[i];
269#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY
270 sum_s += ((signed char*)&tar)[i];
271#endif
272 }
273
274
275
276
277
278
279
280 tar_typeflag = (uint8_t)tar.typeflag;
281 sum = GET_OCTAL(tar.chksum);
282 if (sum_u != sum
283 IF_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum)
284 ) {
285 bb_error_msg_and_die("invalid tar header checksum");
286 }
287
288
289
290 if (tar.devmajor[0]) {
291 char t = tar.prefix[0];
292
293 unsigned minor = GET_OCTAL(tar.devminor);
294 unsigned major = GET_OCTAL(tar.devmajor);
295 file_header->device = makedev(major, minor);
296 tar.prefix[0] = t;
297 }
298
299
300 if (tar_typeflag == '\0') tar_typeflag = '0';
301 parse_names = (tar_typeflag >= '0' && tar_typeflag <= '7');
302
303 file_header->link_target = NULL;
304 if (!p_linkname && parse_names && tar.linkname[0]) {
305 file_header->link_target = xstrndup(tar.linkname, sizeof(tar.linkname));
306
307
308 }
309#if ENABLE_FEATURE_TAR_UNAME_GNAME
310 file_header->tar__uname = tar.uname[0] ? xstrndup(tar.uname, sizeof(tar.uname)) : NULL;
311 file_header->tar__gname = tar.gname[0] ? xstrndup(tar.gname, sizeof(tar.gname)) : NULL;
312#endif
313 file_header->mtime = GET_OCTAL(tar.mtime);
314 file_header->size = GET_OCTAL(tar.size);
315 file_header->gid = GET_OCTAL(tar.gid);
316 file_header->uid = GET_OCTAL(tar.uid);
317
318 file_header->mode = 07777 & GET_OCTAL(tar.mode);
319
320 file_header->name = NULL;
321 if (!p_longname && parse_names) {
322
323
324 tar.mode[0] = '\0';
325 if (tar.prefix[0]) {
326
327
328 tar.padding[0] = '\0';
329 file_header->name = concat_path_file(tar.prefix, tar.name);
330 } else
331 file_header->name = xstrdup(tar.name);
332 }
333
334
335
336 switch (tar_typeflag) {
337 case '1':
338
339 file_header->mode |= S_IFREG;
340
341
342
343
344
345
346
347
348
349
350 goto size0;
351 case '7':
352
353 case '0':
354#if ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY
355 if (last_char_is(file_header->name, '/')) {
356 goto set_dir;
357 }
358#endif
359 file_header->mode |= S_IFREG;
360 break;
361 case '2':
362 file_header->mode |= S_IFLNK;
363
364
365 size0:
366 file_header->size = 0;
367 break;
368 case '3':
369 file_header->mode |= S_IFCHR;
370 goto size0;
371 case '4':
372 file_header->mode |= S_IFBLK;
373 goto size0;
374 case '5':
375 IF_FEATURE_TAR_OLDGNU_COMPATIBILITY(set_dir:)
376 file_header->mode |= S_IFDIR;
377 goto size0;
378 case '6':
379 file_header->mode |= S_IFIFO;
380 goto size0;
381 case 'g':
382 case 'x': {
383 if ((uoff_t)file_header->size > 0xfffff)
384 goto skip_ext_hdr;
385 process_pax_hdr(archive_handle, file_header->size, (tar_typeflag == 'g'));
386 goto again_after_align;
387#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
388
389 case 'L':
390
391 free(p_longname);
392
393 p_longname = xzalloc(file_header->size + 1);
394
395 xread(archive_handle->src_fd, p_longname, file_header->size);
396 archive_handle->offset += file_header->size;
397
398
399
400 goto again;
401 case 'K':
402 free(p_linkname);
403 p_linkname = xzalloc(file_header->size + 1);
404 xread(archive_handle->src_fd, p_linkname, file_header->size);
405 archive_handle->offset += file_header->size;
406
407 goto again;
408
409
410
411
412
413
414
415
416
417
418#endif
419 }
420 skip_ext_hdr:
421 {
422 off_t sz;
423 bb_error_msg("warning: skipping header '%c'", tar_typeflag);
424 sz = (file_header->size + 511) & ~(off_t)511;
425 archive_handle->offset += sz;
426 sz >>= 9;
427 while (sz--)
428 xread(archive_handle->src_fd, &tar, 512);
429
430 goto again_after_align;
431 }
432 default:
433 bb_error_msg_and_die("unknown typeflag: 0x%x", tar_typeflag);
434 }
435
436#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
437 if (p_longname) {
438 file_header->name = p_longname;
439 p_longname = NULL;
440 }
441 if (p_linkname) {
442 file_header->link_target = p_linkname;
443 p_linkname = NULL;
444 }
445#endif
446
447
448 overlapping_strcpy(file_header->name, strip_unsafe_prefix(file_header->name));
449
450
451
452
453 cp = last_char_is(file_header->name, '/');
454
455 if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) {
456 archive_handle->action_header( file_header);
457
458
459 if (cp)
460 *cp = '\0';
461 archive_handle->action_data(archive_handle);
462 if (archive_handle->accept || archive_handle->reject
463 || (archive_handle->ah_flags & ARCHIVE_REMEMBER_NAMES)
464 ) {
465 llist_add_to(&archive_handle->passed, file_header->name);
466 } else
467 free(file_header->name);
468 } else {
469 data_skip(archive_handle);
470 free(file_header->name);
471 }
472 archive_handle->offset += file_header->size;
473
474 free(file_header->link_target);
475
476
477#if ENABLE_FEATURE_TAR_UNAME_GNAME
478 free(file_header->tar__uname);
479 free(file_header->tar__gname);
480#endif
481 return EXIT_SUCCESS;
482}
483