blob: 2fd61bb76113846ea0df326ba78b010fcb5107a2 [file] [log] [blame]
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001/*
2** Copyright 1998-2003 University of Illinois Board of Trustees
3** Copyright 1998-2003 Mark D. Roth
4** All rights reserved.
5**
6** block.c - libtar code to handle tar archive header blocks
7**
8** Mark D. Roth <roth@uiuc.edu>
9** Campus Information Technologies and Educational Services
10** University of Illinois at Urbana-Champaign
11*/
12
13#include <internal.h>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050014#include <errno.h>
15
16#ifdef STDC_HEADERS
17# include <string.h>
18# include <stdlib.h>
19#endif
20
21#define BIT_ISSET(bitmask, bit) ((bitmask) & (bit))
22
Vojtech Bocek25fd68d2013-08-27 03:10:10 +020023// Used to identify selinux_context in extended ('x')
24// metadata. From RedHat implementation.
25#define SELINUX_TAG "RHT.security.selinux="
26#define SELINUX_TAG_LEN 21
bigbiff bigbiff9c754052013-01-09 09:09:08 -050027
Ethan Yonker79f88bd2016-12-09 14:52:12 -060028// Used to identify e4crypt_policy in extended ('x')
29#define E4CRYPT_TAG "TWRP.security.e4crypt="
30#define E4CRYPT_TAG_LEN 22
31
bigbiff bigbiff9c754052013-01-09 09:09:08 -050032/* read a header block */
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050033/* FIXME: the return value of this function should match the return value
34 of tar_block_read(), which is a macro which references a prototype
35 that returns a ssize_t. So far, this is safe, since tar_block_read()
36 only ever reads 512 (T_BLOCKSIZE) bytes at a time, so any difference
37 in size of ssize_t and int is of negligible risk. BUT, if
38 T_BLOCKSIZE ever changes, or ever becomes a variable parameter
39 controllable by the user, all the code that calls it,
40 including this function and all code that calls it, should be
41 fixed for security reasons.
42 Thanks to Chris Palmer for the critique.
43*/
bigbiff bigbiff9c754052013-01-09 09:09:08 -050044int
45th_read_internal(TAR *t)
46{
47 int i;
48 int num_zero_blocks = 0;
49
50#ifdef DEBUG
51 printf("==> th_read_internal(TAR=\"%s\")\n", t->pathname);
52#endif
53
54 while ((i = tar_block_read(t, &(t->th_buf))) == T_BLOCKSIZE)
55 {
56 /* two all-zero blocks mark EOF */
57 if (t->th_buf.name[0] == '\0')
58 {
59 num_zero_blocks++;
60 if (!BIT_ISSET(t->options, TAR_IGNORE_EOT)
61 && num_zero_blocks >= 2)
62 return 0; /* EOF */
63 else
64 continue;
65 }
66
67 /* verify magic and version */
68 if (BIT_ISSET(t->options, TAR_CHECK_MAGIC)
69 && strncmp(t->th_buf.magic, TMAGIC, TMAGLEN - 1) != 0)
70 {
71#ifdef DEBUG
72 puts("!!! unknown magic value in tar header");
73#endif
74 return -2;
75 }
76
77 if (BIT_ISSET(t->options, TAR_CHECK_VERSION)
78 && strncmp(t->th_buf.version, TVERSION, TVERSLEN) != 0)
79 {
80#ifdef DEBUG
81 puts("!!! unknown version value in tar header");
82#endif
83 return -2;
84 }
85
86 /* check chksum */
87 if (!BIT_ISSET(t->options, TAR_IGNORE_CRC)
88 && !th_crc_ok(t))
89 {
90#ifdef DEBUG
91 puts("!!! tar header checksum error");
92#endif
93 return -2;
94 }
95
96 break;
97 }
98
99#ifdef DEBUG
100 printf("<== th_read_internal(): returning %d\n", i);
101#endif
102 return i;
103}
104
105
106/* wrapper function for th_read_internal() to handle GNU extensions */
107int
108th_read(TAR *t)
109{
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500110 int i;
111 size_t sz, j, blocks;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500112 char *ptr;
113
114#ifdef DEBUG
115 printf("==> th_read(t=0x%lx)\n", t);
116#endif
117
118 if (t->th_buf.gnu_longname != NULL)
119 free(t->th_buf.gnu_longname);
120 if (t->th_buf.gnu_longlink != NULL)
121 free(t->th_buf.gnu_longlink);
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200122#ifdef HAVE_SELINUX
123 if (t->th_buf.selinux_context != NULL)
124 free(t->th_buf.selinux_context);
125#endif
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600126#ifdef HAVE_EXT4_CRYPT
127 if (t->th_buf.e4crypt_policy != NULL) {
128 free(t->th_buf.e4crypt_policy);
129 }
130#endif
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200131
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500132 memset(&(t->th_buf), 0, sizeof(struct tar_header));
133
134 i = th_read_internal(t);
135 if (i == 0)
136 return 1;
137 else if (i != T_BLOCKSIZE)
138 {
139 if (i != -1)
140 errno = EINVAL;
141 return -1;
142 }
143
144 /* check for GNU long link extention */
145 if (TH_ISLONGLINK(t))
146 {
147 sz = th_get_size(t);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500148 blocks = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0);
149 if (blocks > ((size_t)-1 / T_BLOCKSIZE))
150 {
151 errno = E2BIG;
152 return -1;
153 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500154#ifdef DEBUG
155 printf(" th_read(): GNU long linkname detected "
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500156 "(%ld bytes, %d blocks)\n", sz, blocks);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500157#endif
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500158 t->th_buf.gnu_longlink = (char *)malloc(blocks * T_BLOCKSIZE);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500159 if (t->th_buf.gnu_longlink == NULL)
160 return -1;
161
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500162 for (j = 0, ptr = t->th_buf.gnu_longlink; j < blocks;
163 j++, ptr += T_BLOCKSIZE)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500164 {
165#ifdef DEBUG
166 printf(" th_read(): reading long linkname "
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500167 "(%d blocks left, ptr == %ld)\n", blocks-j, ptr);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500168#endif
169 i = tar_block_read(t, ptr);
170 if (i != T_BLOCKSIZE)
171 {
172 if (i != -1)
173 errno = EINVAL;
174 return -1;
175 }
176#ifdef DEBUG
177 printf(" th_read(): read block == \"%s\"\n", ptr);
178#endif
179 }
180#ifdef DEBUG
181 printf(" th_read(): t->th_buf.gnu_longlink == \"%s\"\n",
182 t->th_buf.gnu_longlink);
183#endif
184
185 i = th_read_internal(t);
186 if (i != T_BLOCKSIZE)
187 {
188 if (i != -1)
189 errno = EINVAL;
190 return -1;
191 }
192 }
193
194 /* check for GNU long name extention */
195 if (TH_ISLONGNAME(t))
196 {
197 sz = th_get_size(t);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500198 blocks = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0);
199 if (blocks > ((size_t)-1 / T_BLOCKSIZE))
200 {
201 errno = E2BIG;
202 return -1;
203 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500204#ifdef DEBUG
205 printf(" th_read(): GNU long filename detected "
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500206 "(%ld bytes, %d blocks)\n", sz, blocks);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500207#endif
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500208 t->th_buf.gnu_longname = (char *)malloc(blocks * T_BLOCKSIZE);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500209 if (t->th_buf.gnu_longname == NULL)
210 return -1;
211
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500212 for (j = 0, ptr = t->th_buf.gnu_longname; j < blocks;
213 j++, ptr += T_BLOCKSIZE)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500214 {
215#ifdef DEBUG
216 printf(" th_read(): reading long filename "
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500217 "(%d blocks left, ptr == %ld)\n", blocks-j, ptr);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500218#endif
219 i = tar_block_read(t, ptr);
220 if (i != T_BLOCKSIZE)
221 {
222 if (i != -1)
223 errno = EINVAL;
224 return -1;
225 }
226#ifdef DEBUG
227 printf(" th_read(): read block == \"%s\"\n", ptr);
228#endif
229 }
230#ifdef DEBUG
231 printf(" th_read(): t->th_buf.gnu_longname == \"%s\"\n",
232 t->th_buf.gnu_longname);
233#endif
234
235 i = th_read_internal(t);
236 if (i != T_BLOCKSIZE)
237 {
238 if (i != -1)
239 errno = EINVAL;
240 return -1;
241 }
242 }
243
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200244#ifdef HAVE_SELINUX
245 if(TH_ISEXTHEADER(t))
246 {
247 sz = th_get_size(t);
248
249 if(sz >= T_BLOCKSIZE) // Not supported
250 {
251#ifdef DEBUG
252 printf(" th_read(): Extended header is too long!\n");
253#endif
254 }
255 else
256 {
257 char buf[T_BLOCKSIZE];
258 i = tar_block_read(t, buf);
259 if (i != T_BLOCKSIZE)
260 {
261 if (i != -1)
262 errno = EINVAL;
263 return -1;
264 }
265
266 // To be sure
267 buf[T_BLOCKSIZE-1] = 0;
268
269 int len = strlen(buf);
270 char *start = strstr(buf, SELINUX_TAG);
271 if(start && start+SELINUX_TAG_LEN < buf+len)
272 {
273 start += SELINUX_TAG_LEN;
274 char *end = strchr(start, '\n');
275 if(end)
276 {
277 t->th_buf.selinux_context = strndup(start, end-start);
278#ifdef DEBUG
279 printf(" th_read(): SELinux context xattr detected: %s\n", t->th_buf.selinux_context);
280#endif
281 }
282 }
283 }
284
285 i = th_read_internal(t);
286 if (i != T_BLOCKSIZE)
287 {
288 if (i != -1)
289 errno = EINVAL;
290 return -1;
291 }
292 }
293#endif
294
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600295#ifdef HAVE_EXT4_CRYPT
296 if(TH_ISPOLHEADER(t))
297 {
298 sz = th_get_size(t);
299
300 if(sz >= T_BLOCKSIZE) // Not supported
301 {
302#ifdef DEBUG
303 printf(" th_read(): Policy header is too long!\n");
304#endif
305 }
306 else
307 {
308 char buf[T_BLOCKSIZE];
309 i = tar_block_read(t, buf);
310 if (i != T_BLOCKSIZE)
311 {
312 if (i != -1)
313 errno = EINVAL;
314 return -1;
315 }
316
317 // To be sure
318 buf[T_BLOCKSIZE-1] = 0;
319
320 int len = strlen(buf);
321 char *start = strstr(buf, E4CRYPT_TAG);
322 if(start && start+E4CRYPT_TAG_LEN < buf+len)
323 {
324 start += E4CRYPT_TAG_LEN;
325 char *end = strchr(start, '\n');
326 if(end)
327 {
328 t->th_buf.e4crypt_policy = strndup(start, end-start);
329#ifdef DEBUG
330 printf(" th_read(): E4Crypt policy detected: %s\n", t->th_buf.e4crypt_policy);
331#endif
332 }
333 }
334 }
335
336 i = th_read_internal(t);
337 if (i != T_BLOCKSIZE)
338 {
339 if (i != -1)
340 errno = EINVAL;
341 return -1;
342 }
343 }
344#endif
345
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500346 return 0;
347}
348
349
350/* write a header block */
351int
352th_write(TAR *t)
353{
354 int i, j;
355 char type2;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500356 uint64_t sz, sz2;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500357 char *ptr;
358 char buf[T_BLOCKSIZE];
359
360#ifdef DEBUG
361 printf("==> th_write(TAR=\"%s\")\n", t->pathname);
362 th_print(t);
363#endif
364
365 if ((t->options & TAR_GNU) && t->th_buf.gnu_longlink != NULL)
366 {
367#ifdef DEBUG
368 printf("th_write(): using gnu_longlink (\"%s\")\n",
369 t->th_buf.gnu_longlink);
370#endif
371 /* save old size and type */
372 type2 = t->th_buf.typeflag;
373 sz2 = th_get_size(t);
374
375 /* write out initial header block with fake size and type */
376 t->th_buf.typeflag = GNU_LONGLINK_TYPE;
377 sz = strlen(t->th_buf.gnu_longlink);
378 th_set_size(t, sz);
379 th_finish(t);
380 i = tar_block_write(t, &(t->th_buf));
381 if (i != T_BLOCKSIZE)
382 {
383 if (i != -1)
384 errno = EINVAL;
385 return -1;
386 }
387
388 /* write out extra blocks containing long name */
389 for (j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0),
390 ptr = t->th_buf.gnu_longlink; j > 1;
391 j--, ptr += T_BLOCKSIZE)
392 {
393 i = tar_block_write(t, ptr);
394 if (i != T_BLOCKSIZE)
395 {
396 if (i != -1)
397 errno = EINVAL;
398 return -1;
399 }
400 }
401 memset(buf, 0, T_BLOCKSIZE);
402 strncpy(buf, ptr, T_BLOCKSIZE);
403 i = tar_block_write(t, &buf);
404 if (i != T_BLOCKSIZE)
405 {
406 if (i != -1)
407 errno = EINVAL;
408 return -1;
409 }
410
411 /* reset type and size to original values */
412 t->th_buf.typeflag = type2;
413 th_set_size(t, sz2);
414 }
415
416 if ((t->options & TAR_GNU) && t->th_buf.gnu_longname != NULL)
417 {
418#ifdef DEBUG
419 printf("th_write(): using gnu_longname (\"%s\")\n",
420 t->th_buf.gnu_longname);
421#endif
422 /* save old size and type */
423 type2 = t->th_buf.typeflag;
424 sz2 = th_get_size(t);
425
426 /* write out initial header block with fake size and type */
427 t->th_buf.typeflag = GNU_LONGNAME_TYPE;
428 sz = strlen(t->th_buf.gnu_longname);
429 th_set_size(t, sz);
430 th_finish(t);
431 i = tar_block_write(t, &(t->th_buf));
432 if (i != T_BLOCKSIZE)
433 {
434 if (i != -1)
435 errno = EINVAL;
436 return -1;
437 }
438
439 /* write out extra blocks containing long name */
440 for (j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0),
441 ptr = t->th_buf.gnu_longname; j > 1;
442 j--, ptr += T_BLOCKSIZE)
443 {
444 i = tar_block_write(t, ptr);
445 if (i != T_BLOCKSIZE)
446 {
447 if (i != -1)
448 errno = EINVAL;
449 return -1;
450 }
451 }
452 memset(buf, 0, T_BLOCKSIZE);
453 strncpy(buf, ptr, T_BLOCKSIZE);
454 i = tar_block_write(t, &buf);
455 if (i != T_BLOCKSIZE)
456 {
457 if (i != -1)
458 errno = EINVAL;
459 return -1;
460 }
461
462 /* reset type and size to original values */
463 t->th_buf.typeflag = type2;
464 th_set_size(t, sz2);
465 }
466
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200467#ifdef HAVE_SELINUX
468 if((t->options & TAR_STORE_SELINUX) && t->th_buf.selinux_context != NULL)
469 {
470#ifdef DEBUG
471 printf("th_write(): using selinux_context (\"%s\")\n",
472 t->th_buf.selinux_context);
473#endif
474 /* save old size and type */
475 type2 = t->th_buf.typeflag;
476 sz2 = th_get_size(t);
477
478 /* write out initial header block with fake size and type */
479 t->th_buf.typeflag = TH_EXT_TYPE;
480
481 /* setup size - EXT header has format "*size of this whole tag as ascii numbers* *space* *content* *newline* */
482 // size newline
483 sz = SELINUX_TAG_LEN + strlen(t->th_buf.selinux_context) + 3 + 1;
484
485 if(sz >= 100) // another ascci digit for size
486 ++sz;
487
488 if(sz >= T_BLOCKSIZE) // impossible
489 {
490 errno = EINVAL;
491 return -1;
492 }
493
494 th_set_size(t, sz);
495 th_finish(t);
496 i = tar_block_write(t, &(t->th_buf));
497 if (i != T_BLOCKSIZE)
498 {
499 if (i != -1)
500 errno = EINVAL;
501 return -1;
502 }
503
504 memset(buf, 0, T_BLOCKSIZE);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500505 snprintf(buf, T_BLOCKSIZE, "%d "SELINUX_TAG"%s\n", (int)sz, t->th_buf.selinux_context);
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200506 i = tar_block_write(t, &buf);
507 if (i != T_BLOCKSIZE)
508 {
509 if (i != -1)
510 errno = EINVAL;
511 return -1;
512 }
513
514 /* reset type and size to original values */
515 t->th_buf.typeflag = type2;
516 th_set_size(t, sz2);
517 }
518#endif
519
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600520#ifdef HAVE_EXT4_CRYPT
521 if((t->options & TAR_STORE_EXT4_POL) && t->th_buf.e4crypt_policy != NULL)
522 {
523#ifdef DEBUG
524 printf("th_write(): using e4crypt_policy %s\n",
525 t->th_buf.e4crypt_policy);
526#endif
527 /* save old size and type */
528 type2 = t->th_buf.typeflag;
529 sz2 = th_get_size(t);
530
531 /* write out initial header block with fake size and type */
532 t->th_buf.typeflag = TH_POL_TYPE;
533
534 /* setup size - EXT header has format "*size of this whole tag as ascii numbers* *space* *content* *newline* */
535 // size newline
536 sz = E4CRYPT_TAG_LEN + EXT4_KEY_DESCRIPTOR_HEX + 3 + 1;
537
538 if(sz >= 100) // another ascci digit for size
539 ++sz;
540
541 if(sz >= T_BLOCKSIZE) // impossible
542 {
543 errno = EINVAL;
544 return -1;
545 }
546
547 th_set_size(t, sz);
548 th_finish(t);
549 i = tar_block_write(t, &(t->th_buf));
550 if (i != T_BLOCKSIZE)
551 {
552 if (i != -1)
553 errno = EINVAL;
554 return -1;
555 }
556
557 memset(buf, 0, T_BLOCKSIZE);
558 snprintf(buf, T_BLOCKSIZE, "%d "E4CRYPT_TAG"%s\n", (int)sz, t->th_buf.e4crypt_policy);
559 i = tar_block_write(t, &buf);
560 if (i != T_BLOCKSIZE)
561 {
562 if (i != -1)
563 errno = EINVAL;
564 return -1;
565 }
566
567 /* reset type and size to original values */
568 t->th_buf.typeflag = type2;
569 th_set_size(t, sz2);
570 }
571#endif
572
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500573 th_finish(t);
574
575#ifdef DEBUG
576 /* print tar header */
577 th_print(t);
578#endif
579
580 i = tar_block_write(t, &(t->th_buf));
581 if (i != T_BLOCKSIZE)
582 {
583 if (i != -1)
584 errno = EINVAL;
585 return -1;
586 }
587
588#ifdef DEBUG
589 puts("th_write(): returning 0");
590#endif
591 return 0;
592}
593
594