blob: db972220ac1e97c0a1b57eab0860cbbdd24a8ee9 [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
DarthJabba9247c68b2020-10-11 16:47:56 +010021#ifdef TW_LIBTAR_DEBUG
22#define DEBUG 1
23#endif
24
bigbiff7ba75002020-04-11 20:47:09 -040025#ifdef USE_FSCRYPT
26#include "fscrypt_policy.h"
Ethan Yonkerfefe5912017-09-30 22:22:13 -050027#endif
28
bigbiff bigbiff9c754052013-01-09 09:09:08 -050029#define BIT_ISSET(bitmask, bit) ((bitmask) & (bit))
30
Vojtech Bocek25fd68d2013-08-27 03:10:10 +020031// Used to identify selinux_context in extended ('x')
32// metadata. From RedHat implementation.
33#define SELINUX_TAG "RHT.security.selinux="
Ethan Yonker8d039f72017-02-03 14:26:15 -060034#define SELINUX_TAG_LEN strlen(SELINUX_TAG)
bigbiff bigbiff9c754052013-01-09 09:09:08 -050035
bigbiff7ba75002020-04-11 20:47:09 -040036// Used to identify fscrypt_policy in extended ('x')
37#define FSCRYPT_TAG "TWRP.security.fscrypt="
38#define FSCRYPT_TAG_LEN strlen(FSCRYPT_TAG)
39
Ethan Yonker71187742017-01-13 13:30:10 -060040// Used to identify Posix capabilities in extended ('x')
41#define CAPABILITIES_TAG "SCHILY.xattr.security.capability="
Ethan Yonker8d039f72017-02-03 14:26:15 -060042#define CAPABILITIES_TAG_LEN strlen(CAPABILITIES_TAG)
43
44// Used to identify Android user.default xattr in extended ('x')
45#define ANDROID_USER_DEFAULT_TAG "ANDROID.user.default"
46#define ANDROID_USER_DEFAULT_TAG_LEN strlen(ANDROID_USER_DEFAULT_TAG)
47
48// Used to identify Android user.inode_cache xattr in extended ('x')
49#define ANDROID_USER_CACHE_TAG "ANDROID.user.inode_cache"
50#define ANDROID_USER_CACHE_TAG_LEN strlen(ANDROID_USER_CACHE_TAG)
51
52// Used to identify Android user.inode_code_cache xattr in extended ('x')
53#define ANDROID_USER_CODE_CACHE_TAG "ANDROID.user.inode_code_cache"
54#define ANDROID_USER_CODE_CACHE_TAG_LEN strlen(ANDROID_USER_CODE_CACHE_TAG)
Ethan Yonker71187742017-01-13 13:30:10 -060055
bigbiff bigbiff9c754052013-01-09 09:09:08 -050056/* read a header block */
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050057/* FIXME: the return value of this function should match the return value
58 of tar_block_read(), which is a macro which references a prototype
59 that returns a ssize_t. So far, this is safe, since tar_block_read()
60 only ever reads 512 (T_BLOCKSIZE) bytes at a time, so any difference
61 in size of ssize_t and int is of negligible risk. BUT, if
62 T_BLOCKSIZE ever changes, or ever becomes a variable parameter
63 controllable by the user, all the code that calls it,
64 including this function and all code that calls it, should be
65 fixed for security reasons.
66 Thanks to Chris Palmer for the critique.
67*/
bigbiff bigbiff9c754052013-01-09 09:09:08 -050068int
69th_read_internal(TAR *t)
70{
71 int i;
72 int num_zero_blocks = 0;
73
74#ifdef DEBUG
75 printf("==> th_read_internal(TAR=\"%s\")\n", t->pathname);
76#endif
77
78 while ((i = tar_block_read(t, &(t->th_buf))) == T_BLOCKSIZE)
79 {
80 /* two all-zero blocks mark EOF */
81 if (t->th_buf.name[0] == '\0')
82 {
83 num_zero_blocks++;
84 if (!BIT_ISSET(t->options, TAR_IGNORE_EOT)
85 && num_zero_blocks >= 2)
86 return 0; /* EOF */
87 else
88 continue;
89 }
90
91 /* verify magic and version */
92 if (BIT_ISSET(t->options, TAR_CHECK_MAGIC)
93 && strncmp(t->th_buf.magic, TMAGIC, TMAGLEN - 1) != 0)
94 {
95#ifdef DEBUG
96 puts("!!! unknown magic value in tar header");
97#endif
98 return -2;
99 }
100
101 if (BIT_ISSET(t->options, TAR_CHECK_VERSION)
102 && strncmp(t->th_buf.version, TVERSION, TVERSLEN) != 0)
103 {
104#ifdef DEBUG
105 puts("!!! unknown version value in tar header");
106#endif
107 return -2;
108 }
109
110 /* check chksum */
111 if (!BIT_ISSET(t->options, TAR_IGNORE_CRC)
112 && !th_crc_ok(t))
113 {
114#ifdef DEBUG
115 puts("!!! tar header checksum error");
116#endif
117 return -2;
118 }
119
120 break;
121 }
122
123#ifdef DEBUG
124 printf("<== th_read_internal(): returning %d\n", i);
125#endif
126 return i;
127}
128
129
130/* wrapper function for th_read_internal() to handle GNU extensions */
131int
132th_read(TAR *t)
133{
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500134 int i;
135 size_t sz, j, blocks;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500136 char *ptr;
137
138#ifdef DEBUG
bigbiff7ba75002020-04-11 20:47:09 -0400139 printf("==> th_read(t=0x%p)\n", (void *)t);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500140#endif
141
142 if (t->th_buf.gnu_longname != NULL)
143 free(t->th_buf.gnu_longname);
144 if (t->th_buf.gnu_longlink != NULL)
145 free(t->th_buf.gnu_longlink);
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200146 if (t->th_buf.selinux_context != NULL)
147 free(t->th_buf.selinux_context);
bigbiff7ba75002020-04-11 20:47:09 -0400148
149#ifdef USE_FSCRYPT
150 if (t->th_buf.fep != NULL)
151 free(t->th_buf.fep);
152#endif
153
Ethan Yonker71187742017-01-13 13:30:10 -0600154 if (t->th_buf.has_cap_data)
155 {
156 memset(&t->th_buf.cap_data, 0, sizeof(struct vfs_cap_data));
157 t->th_buf.has_cap_data = 0;
158 }
Ethan Yonker8d039f72017-02-03 14:26:15 -0600159 t->th_buf.has_user_default = 0;
160 t->th_buf.has_user_cache = 0;
161 t->th_buf.has_user_code_cache = 0;
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200162
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500163 memset(&(t->th_buf), 0, sizeof(struct tar_header));
164
165 i = th_read_internal(t);
166 if (i == 0)
167 return 1;
168 else if (i != T_BLOCKSIZE)
169 {
170 if (i != -1)
171 errno = EINVAL;
172 return -1;
173 }
174
175 /* check for GNU long link extention */
176 if (TH_ISLONGLINK(t))
177 {
178 sz = th_get_size(t);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500179 blocks = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0);
180 if (blocks > ((size_t)-1 / T_BLOCKSIZE))
181 {
182 errno = E2BIG;
183 return -1;
184 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500185#ifdef DEBUG
186 printf(" th_read(): GNU long linkname detected "
bigbiff7ba75002020-04-11 20:47:09 -0400187 "(%zu bytes, %zu blocks)\n", sz, blocks);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500188#endif
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500189 t->th_buf.gnu_longlink = (char *)malloc(blocks * T_BLOCKSIZE);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500190 if (t->th_buf.gnu_longlink == NULL)
191 return -1;
192
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500193 for (j = 0, ptr = t->th_buf.gnu_longlink; j < blocks;
194 j++, ptr += T_BLOCKSIZE)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500195 {
196#ifdef DEBUG
197 printf(" th_read(): reading long linkname "
bigbiff7ba75002020-04-11 20:47:09 -0400198 "(%zu blocks left, ptr == %p)\n", blocks-j, (void *) ptr);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500199#endif
200 i = tar_block_read(t, ptr);
201 if (i != T_BLOCKSIZE)
202 {
203 if (i != -1)
204 errno = EINVAL;
205 return -1;
206 }
207#ifdef DEBUG
208 printf(" th_read(): read block == \"%s\"\n", ptr);
209#endif
210 }
211#ifdef DEBUG
212 printf(" th_read(): t->th_buf.gnu_longlink == \"%s\"\n",
213 t->th_buf.gnu_longlink);
214#endif
215
216 i = th_read_internal(t);
217 if (i != T_BLOCKSIZE)
218 {
219 if (i != -1)
220 errno = EINVAL;
221 return -1;
222 }
223 }
224
225 /* check for GNU long name extention */
226 if (TH_ISLONGNAME(t))
227 {
228 sz = th_get_size(t);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500229 blocks = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0);
230 if (blocks > ((size_t)-1 / T_BLOCKSIZE))
231 {
232 errno = E2BIG;
233 return -1;
234 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500235#ifdef DEBUG
236 printf(" th_read(): GNU long filename detected "
bigbiff7ba75002020-04-11 20:47:09 -0400237 "(%zu bytes, %zu blocks)\n", sz, blocks);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500238#endif
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500239 t->th_buf.gnu_longname = (char *)malloc(blocks * T_BLOCKSIZE);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500240 if (t->th_buf.gnu_longname == NULL)
241 return -1;
242
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500243 for (j = 0, ptr = t->th_buf.gnu_longname; j < blocks;
244 j++, ptr += T_BLOCKSIZE)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500245 {
246#ifdef DEBUG
247 printf(" th_read(): reading long filename "
bigbiff7ba75002020-04-11 20:47:09 -0400248 "(%zu blocks left, ptr == %p)\n", blocks-j, (void *) ptr);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500249#endif
250 i = tar_block_read(t, ptr);
251 if (i != T_BLOCKSIZE)
252 {
253 if (i != -1)
254 errno = EINVAL;
255 return -1;
256 }
257#ifdef DEBUG
258 printf(" th_read(): read block == \"%s\"\n", ptr);
259#endif
260 }
261#ifdef DEBUG
262 printf(" th_read(): t->th_buf.gnu_longname == \"%s\"\n",
263 t->th_buf.gnu_longname);
264#endif
265
266 i = th_read_internal(t);
267 if (i != T_BLOCKSIZE)
268 {
269 if (i != -1)
270 errno = EINVAL;
271 return -1;
272 }
273 }
274
bigbiff7ba75002020-04-11 20:47:09 -0400275 // Extended headers (selinux contexts, posix file capabilities and encryption policies)
Ethan Yonker71187742017-01-13 13:30:10 -0600276 while(TH_ISEXTHEADER(t) || TH_ISPOLHEADER(t))
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200277 {
278 sz = th_get_size(t);
279
280 if(sz >= T_BLOCKSIZE) // Not supported
281 {
282#ifdef DEBUG
283 printf(" th_read(): Extended header is too long!\n");
284#endif
285 }
286 else
287 {
288 char buf[T_BLOCKSIZE];
289 i = tar_block_read(t, buf);
290 if (i != T_BLOCKSIZE)
291 {
292 if (i != -1)
293 errno = EINVAL;
294 return -1;
295 }
296
297 // To be sure
298 buf[T_BLOCKSIZE-1] = 0;
299
300 int len = strlen(buf);
Ethan Yonker71187742017-01-13 13:30:10 -0600301 // posix capabilities
302 char *start = strstr(buf, CAPABILITIES_TAG);
Ethan Yonker8d039f72017-02-03 14:26:15 -0600303 if (start && start+CAPABILITIES_TAG_LEN < buf+len)
Ethan Yonker71187742017-01-13 13:30:10 -0600304 {
305 start += CAPABILITIES_TAG_LEN;
306 memcpy(&t->th_buf.cap_data, start, sizeof(struct vfs_cap_data));
307 t->th_buf.has_cap_data = 1;
308#ifdef DEBUG
309 printf(" th_read(): Posix capabilities detected\n");
310#endif
311 } // end posix capabilities
Matt Mower87413642017-01-17 21:14:46 -0600312 // selinux contexts
Ethan Yonker71187742017-01-13 13:30:10 -0600313 start = strstr(buf, SELINUX_TAG);
Ethan Yonker8d039f72017-02-03 14:26:15 -0600314 if (start && start+SELINUX_TAG_LEN < buf+len)
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200315 {
316 start += SELINUX_TAG_LEN;
317 char *end = strchr(start, '\n');
318 if(end)
319 {
320 t->th_buf.selinux_context = strndup(start, end-start);
321#ifdef DEBUG
322 printf(" th_read(): SELinux context xattr detected: %s\n", t->th_buf.selinux_context);
323#endif
324 }
Matt Mower87413642017-01-17 21:14:46 -0600325 } // end selinux contexts
Ethan Yonker8d039f72017-02-03 14:26:15 -0600326 // android user.default xattr
327 start = strstr(buf, ANDROID_USER_DEFAULT_TAG);
328 if (start)
329 {
330 t->th_buf.has_user_default = 1;
331#ifdef DEBUG
332 printf(" th_read(): android user.default xattr detected\n");
333#endif
334 } // end android user.default xattr
335 // android user.inode_cache xattr
336 start = strstr(buf, ANDROID_USER_CACHE_TAG);
337 if (start)
338 {
339 t->th_buf.has_user_cache = 1;
340#ifdef DEBUG
341 printf(" th_read(): android user.inode_cache xattr detected\n");
342#endif
343 } // end android user.inode_cache xattr
344 // android user.inode_code_cache xattr
345 start = strstr(buf, ANDROID_USER_CODE_CACHE_TAG);
346 if (start)
347 {
348 t->th_buf.has_user_code_cache = 1;
349#ifdef DEBUG
350 printf(" th_read(): android user.inode_code_cache xattr detected\n");
351#endif
352 } // end android user.inode_code_cache xattr
bigbiff7ba75002020-04-11 20:47:09 -0400353
354#ifdef USE_FSCRYPT
355 start = strstr(buf, FSCRYPT_TAG);
356 if (start && start+FSCRYPT_TAG_LEN < buf+len) {
bigbiffa957f072021-03-07 18:20:29 -0500357#ifdef USE_FSCRYPT_POLICY_V1
358 t->th_buf.fep = (struct fscrypt_policy_v1*)malloc(sizeof(struct fscrypt_policy_v1));
359#else
360 t->th_buf.fep = (struct fscrypt_policy_v2*)malloc(sizeof(struct fscrypt_policy_v2));
361#endif
bigbiff7ba75002020-04-11 20:47:09 -0400362 if (!t->th_buf.fep) {
bigbiffa957f072021-03-07 18:20:29 -0500363 printf("malloc failed for fscrypt policy\n");
bigbiff7ba75002020-04-11 20:47:09 -0400364 return -1;
365 }
366 start += FSCRYPT_TAG_LEN;
367 if (*start == '0') {
368 start++;
bigbiffa957f072021-03-07 18:20:29 -0500369#ifdef USE_FSCRYPT_POLICY_V1
370 char *newline_check = start + sizeof(struct fscrypt_policy_v1);
371#else
372 char *newline_check = start + sizeof(struct fscrypt_policy_v2);
373#endif
bigbiff7ba75002020-04-11 20:47:09 -0400374 if (*newline_check != '\n')
375 printf("did not find newline char in expected location, continuing anyway...\n");
bigbiffa957f072021-03-07 18:20:29 -0500376#ifdef USE_FSCRYPT_POLICY_V1
377 memcpy(t->th_buf.fep, start, sizeof(struct fscrypt_policy_v1));
378#else
379 memcpy(t->th_buf.fep, start, sizeof(struct fscrypt_policy_v2));
380#endif
bigbiff7ba75002020-04-11 20:47:09 -0400381#ifdef DEBUG
bigbiffa957f072021-03-07 18:20:29 -0500382 printf(" th_read(): FSCrypt policy detected: %i %i %i %i %s\n",
bigbiff7ba75002020-04-11 20:47:09 -0400383 (int)t->th_buf.fep->version,
384 (int)t->th_buf.fep->contents_encryption_mode,
385 (int)t->th_buf.fep->filenames_encryption_mode,
386 (int)t->th_buf.fep->flags,
bigbiffa957f072021-03-07 18:20:29 -0500387 t->th_buf.fep->master_key_identifier);
bigbiff7ba75002020-04-11 20:47:09 -0400388#endif
389 }
390 else {
391 printf(" invalid fscrypt header found\n");
392 }
393 }
394#endif // USE_FSCRYPT
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600395 }
396
397 i = th_read_internal(t);
398 if (i != T_BLOCKSIZE)
399 {
400 if (i != -1)
401 errno = EINVAL;
402 return -1;
403 }
404 }
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600405
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500406 return 0;
407}
408
Ethan Yonker71187742017-01-13 13:30:10 -0600409/* write an extended block */
410static int
411th_write_extended(TAR *t, char* buf, uint64_t sz)
412{
413 char type2;
414 uint64_t sz2;
415 int i;
416
417 /* save old size and type */
418 type2 = t->th_buf.typeflag;
419 sz2 = th_get_size(t);
420
421 /* write out initial header block with fake size and type */
422 t->th_buf.typeflag = TH_EXT_TYPE;
423
424 if(sz >= T_BLOCKSIZE) // impossible
425 {
426 errno = EINVAL;
427 return -1;
428 }
429
430 th_set_size(t, sz);
431 th_finish(t);
432 i = tar_block_write(t, &(t->th_buf));
433 if (i != T_BLOCKSIZE)
434 {
435 if (i != -1)
436 errno = EINVAL;
437 return -1;
438 }
439
440 i = tar_block_write(t, buf);
441 if (i != T_BLOCKSIZE)
442 {
443 if (i != -1)
444 errno = EINVAL;
445 return -1;
446 }
447
448 /* reset type and size to original values */
449 t->th_buf.typeflag = type2;
450 th_set_size(t, sz2);
451 memset(buf, 0, T_BLOCKSIZE);
452 return 0;
453}
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500454
455/* write a header block */
456int
457th_write(TAR *t)
458{
459 int i, j;
460 char type2;
Ethan Yonker71187742017-01-13 13:30:10 -0600461 uint64_t sz, sz2, total_sz = 0;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500462 char *ptr;
463 char buf[T_BLOCKSIZE];
464
465#ifdef DEBUG
466 printf("==> th_write(TAR=\"%s\")\n", t->pathname);
467 th_print(t);
468#endif
469
470 if ((t->options & TAR_GNU) && t->th_buf.gnu_longlink != NULL)
471 {
472#ifdef DEBUG
473 printf("th_write(): using gnu_longlink (\"%s\")\n",
474 t->th_buf.gnu_longlink);
475#endif
476 /* save old size and type */
477 type2 = t->th_buf.typeflag;
478 sz2 = th_get_size(t);
479
480 /* write out initial header block with fake size and type */
481 t->th_buf.typeflag = GNU_LONGLINK_TYPE;
482 sz = strlen(t->th_buf.gnu_longlink);
483 th_set_size(t, sz);
484 th_finish(t);
485 i = tar_block_write(t, &(t->th_buf));
486 if (i != T_BLOCKSIZE)
487 {
488 if (i != -1)
489 errno = EINVAL;
490 return -1;
491 }
492
493 /* write out extra blocks containing long name */
494 for (j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0),
495 ptr = t->th_buf.gnu_longlink; j > 1;
496 j--, ptr += T_BLOCKSIZE)
497 {
498 i = tar_block_write(t, ptr);
499 if (i != T_BLOCKSIZE)
500 {
501 if (i != -1)
502 errno = EINVAL;
503 return -1;
504 }
505 }
506 memset(buf, 0, T_BLOCKSIZE);
507 strncpy(buf, ptr, T_BLOCKSIZE);
508 i = tar_block_write(t, &buf);
509 if (i != T_BLOCKSIZE)
510 {
511 if (i != -1)
512 errno = EINVAL;
513 return -1;
514 }
515
516 /* reset type and size to original values */
517 t->th_buf.typeflag = type2;
518 th_set_size(t, sz2);
519 }
520
521 if ((t->options & TAR_GNU) && t->th_buf.gnu_longname != NULL)
522 {
523#ifdef DEBUG
524 printf("th_write(): using gnu_longname (\"%s\")\n",
525 t->th_buf.gnu_longname);
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 = GNU_LONGNAME_TYPE;
533 sz = strlen(t->th_buf.gnu_longname);
534 th_set_size(t, sz);
535 th_finish(t);
536 i = tar_block_write(t, &(t->th_buf));
537 if (i != T_BLOCKSIZE)
538 {
539 if (i != -1)
540 errno = EINVAL;
541 return -1;
542 }
543
544 /* write out extra blocks containing long name */
545 for (j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0),
546 ptr = t->th_buf.gnu_longname; j > 1;
547 j--, ptr += T_BLOCKSIZE)
548 {
549 i = tar_block_write(t, ptr);
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 strncpy(buf, ptr, T_BLOCKSIZE);
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
Ethan Yonker71187742017-01-13 13:30:10 -0600572 memset(buf, 0, T_BLOCKSIZE);
573 ptr = buf;
Matt Mower87413642017-01-17 21:14:46 -0600574
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200575 if((t->options & TAR_STORE_SELINUX) && t->th_buf.selinux_context != NULL)
576 {
577#ifdef DEBUG
578 printf("th_write(): using selinux_context (\"%s\")\n",
579 t->th_buf.selinux_context);
580#endif
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200581 /* setup size - EXT header has format "*size of this whole tag as ascii numbers* *space* *content* *newline* */
582 // size newline
583 sz = SELINUX_TAG_LEN + strlen(t->th_buf.selinux_context) + 3 + 1;
584
585 if(sz >= 100) // another ascci digit for size
586 ++sz;
587
Ethan Yonker71187742017-01-13 13:30:10 -0600588 total_sz += sz;
589 snprintf(ptr, T_BLOCKSIZE, "%d "SELINUX_TAG"%s\n", (int)sz, t->th_buf.selinux_context);
590 ptr += sz;
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200591 }
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200592
bigbiff7ba75002020-04-11 20:47:09 -0400593#ifdef USE_FSCRYPT
594 if((t->options & TAR_STORE_FSCRYPT_POL) && t->th_buf.fep != NULL)
595 {
596#ifdef DEBUG
597 printf("th_write(): using fscrypt_policy %s\n",
bigbiffa957f072021-03-07 18:20:29 -0500598 t->th_buf.fep->master_key_identifier);
bigbiff7ba75002020-04-11 20:47:09 -0400599#endif
600 /* setup size - EXT header has format "*size of this whole tag as ascii numbers* *space* *version code* *content* *newline* */
601 // size newline
bigbiffa957f072021-03-07 18:20:29 -0500602#ifdef USE_FSCRYPT_POLICY_V1
603 sz = FSCRYPT_TAG_LEN + sizeof(struct fscrypt_policy_v1) + 1 + 3 + 1;
604#else
605 sz = FSCRYPT_TAG_LEN + sizeof(struct fscrypt_policy_v2) + 1 + 3 + 1;
606#endif
bigbiff7ba75002020-04-11 20:47:09 -0400607
608 if(sz >= 100) // another ascci digit for size
609 ++sz;
610
611 if (total_sz + sz >= T_BLOCKSIZE)
612 {
613 if (th_write_extended(t, &buf[0], total_sz))
614 return -1;
615 ptr = buf;
616 total_sz = sz;
617 }
618 else
619 total_sz += sz;
620
621 snprintf(ptr, T_BLOCKSIZE, "%d "FSCRYPT_TAG"0", (int)sz);
bigbiffa957f072021-03-07 18:20:29 -0500622#ifdef USE_FSCRYPT_POLICY_V1
623 memcpy(ptr + sz - sizeof(struct fscrypt_policy_v1) - 1, t->th_buf.fep, sizeof(struct fscrypt_policy_v1));
624#else
625 memcpy(ptr + sz - sizeof(struct fscrypt_policy_v2) - 1, t->th_buf.fep, sizeof(struct fscrypt_policy_v2));
626#endif
bigbiff7ba75002020-04-11 20:47:09 -0400627 char *nlptr = ptr + sz - 1;
628 *nlptr = '\n';
629 ptr += sz;
630 }
631#endif
632
Ethan Yonker71187742017-01-13 13:30:10 -0600633 if((t->options & TAR_STORE_POSIX_CAP) && t->th_buf.has_cap_data)
634 {
635#ifdef DEBUG
636 printf("th_write(): has a posix capability\n");
637#endif
638 sz = CAPABILITIES_TAG_LEN + sizeof(struct vfs_cap_data) + 3 + 1;
639
640 if(sz >= 100) // another ascci digit for size
641 ++sz;
642
643 if (total_sz + sz >= T_BLOCKSIZE)
644 {
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500645 if (th_write_extended(t, &buf[0], total_sz))
Ethan Yonker71187742017-01-13 13:30:10 -0600646 return -1;
647 ptr = buf;
648 total_sz = sz;
649 }
650 else
651 total_sz += sz;
652
653 snprintf(ptr, T_BLOCKSIZE, "%d "CAPABILITIES_TAG, (int)sz);
654 memcpy(ptr + CAPABILITIES_TAG_LEN + 3, &t->th_buf.cap_data, sizeof(struct vfs_cap_data));
655 char *nlptr = ptr + sz - 1;
656 *nlptr = '\n';
657 ptr += sz;
658 }
Ethan Yonker8d039f72017-02-03 14:26:15 -0600659 if (t->options & TAR_STORE_ANDROID_USER_XATTR)
660 {
661 if (t->th_buf.has_user_default) {
662#ifdef DEBUG
663 printf("th_write(): has android user.default xattr\n");
664#endif
665 sz = ANDROID_USER_DEFAULT_TAG_LEN + 3 + 1;
666
667 if (total_sz + sz >= T_BLOCKSIZE)
668 {
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500669 if (th_write_extended(t, &buf[0], total_sz))
Ethan Yonker8d039f72017-02-03 14:26:15 -0600670 return -1;
671 ptr = buf;
672 total_sz = sz;
673 }
674 else
675 total_sz += sz;
676
677 snprintf(ptr, T_BLOCKSIZE, "%d "ANDROID_USER_DEFAULT_TAG, (int)sz);
678 char *nlptr = ptr + sz - 1;
679 *nlptr = '\n';
680 ptr += sz;
681 }
682 if (t->th_buf.has_user_cache) {
683#ifdef DEBUG
684 printf("th_write(): has android user.inode_cache xattr\n");
685#endif
686 sz = ANDROID_USER_CACHE_TAG_LEN + 3 + 1;
687
688 if (total_sz + sz >= T_BLOCKSIZE)
689 {
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500690 if (th_write_extended(t, &buf[0], total_sz))
Ethan Yonker8d039f72017-02-03 14:26:15 -0600691 return -1;
692 ptr = buf;
693 total_sz = sz;
694 }
695 else
696 total_sz += sz;
697
698 snprintf(ptr, T_BLOCKSIZE, "%d "ANDROID_USER_CACHE_TAG, (int)sz);
699 char *nlptr = ptr + sz - 1;
700 *nlptr = '\n';
701 ptr += sz;
702 }
703 if (t->th_buf.has_user_code_cache) {
704#ifdef DEBUG
705 printf("th_write(): has android user.inode_code_cache xattr\n");
706#endif
707 sz = ANDROID_USER_CODE_CACHE_TAG_LEN + 3 + 1;
708
709 if (total_sz + sz >= T_BLOCKSIZE)
710 {
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500711 if (th_write_extended(t, &buf[0], total_sz))
Ethan Yonker8d039f72017-02-03 14:26:15 -0600712 return -1;
713 ptr = buf;
714 total_sz = sz;
715 }
716 else
717 total_sz += sz;
718
719 snprintf(ptr, T_BLOCKSIZE, "%d "ANDROID_USER_CODE_CACHE_TAG, (int)sz);
720 char *nlptr = ptr + sz - 1;
721 *nlptr = '\n';
722 ptr += sz;
723 }
724 }
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500725 if (total_sz > 0 && th_write_extended(t, &buf[0], total_sz)) // write any outstanding tar extended header
Ethan Yonker71187742017-01-13 13:30:10 -0600726 return -1;
727
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500728 th_finish(t);
729
730#ifdef DEBUG
731 /* print tar header */
732 th_print(t);
733#endif
734
735 i = tar_block_write(t, &(t->th_buf));
736 if (i != T_BLOCKSIZE)
737 {
738 if (i != -1)
739 errno = EINVAL;
740 return -1;
741 }
742
743#ifdef DEBUG
744 puts("th_write(): returning 0");
745#endif
746 return 0;
747}
748
749