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