blob: 6285547ef1a8e0e621765adb6d46f7f4bf2c39d3 [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
Ethan Yonkerfefe5912017-09-30 22:22:13 -050025#ifdef HAVE_EXT4_CRYPT
bigbiff7ba75002020-04-11 20:47:09 -040026#include "ext4crypt_tar.h"
27#endif
28
29#ifdef USE_FSCRYPT
30#include "fscrypt_policy.h"
Ethan Yonkerfefe5912017-09-30 22:22:13 -050031#endif
32
bigbiff bigbiff9c754052013-01-09 09:09:08 -050033#define BIT_ISSET(bitmask, bit) ((bitmask) & (bit))
34
Vojtech Bocek25fd68d2013-08-27 03:10:10 +020035// Used to identify selinux_context in extended ('x')
36// metadata. From RedHat implementation.
37#define SELINUX_TAG "RHT.security.selinux="
Ethan Yonker8d039f72017-02-03 14:26:15 -060038#define SELINUX_TAG_LEN strlen(SELINUX_TAG)
bigbiff bigbiff9c754052013-01-09 09:09:08 -050039
Ethan Yonker79f88bd2016-12-09 14:52:12 -060040// Used to identify e4crypt_policy in extended ('x')
41#define E4CRYPT_TAG "TWRP.security.e4crypt="
Ethan Yonker8d039f72017-02-03 14:26:15 -060042#define E4CRYPT_TAG_LEN strlen(E4CRYPT_TAG)
Ethan Yonker79f88bd2016-12-09 14:52:12 -060043
bigbiff7ba75002020-04-11 20:47:09 -040044// Used to identify fscrypt_policy in extended ('x')
45#define FSCRYPT_TAG "TWRP.security.fscrypt="
46#define FSCRYPT_TAG_LEN strlen(FSCRYPT_TAG)
47
Ethan Yonker71187742017-01-13 13:30:10 -060048// Used to identify Posix capabilities in extended ('x')
49#define CAPABILITIES_TAG "SCHILY.xattr.security.capability="
Ethan Yonker8d039f72017-02-03 14:26:15 -060050#define CAPABILITIES_TAG_LEN strlen(CAPABILITIES_TAG)
51
52// Used to identify Android user.default xattr in extended ('x')
53#define ANDROID_USER_DEFAULT_TAG "ANDROID.user.default"
54#define ANDROID_USER_DEFAULT_TAG_LEN strlen(ANDROID_USER_DEFAULT_TAG)
55
56// Used to identify Android user.inode_cache xattr in extended ('x')
57#define ANDROID_USER_CACHE_TAG "ANDROID.user.inode_cache"
58#define ANDROID_USER_CACHE_TAG_LEN strlen(ANDROID_USER_CACHE_TAG)
59
60// Used to identify Android user.inode_code_cache xattr in extended ('x')
61#define ANDROID_USER_CODE_CACHE_TAG "ANDROID.user.inode_code_cache"
62#define ANDROID_USER_CODE_CACHE_TAG_LEN strlen(ANDROID_USER_CODE_CACHE_TAG)
Ethan Yonker71187742017-01-13 13:30:10 -060063
bigbiff bigbiff9c754052013-01-09 09:09:08 -050064/* read a header block */
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050065/* FIXME: the return value of this function should match the return value
66 of tar_block_read(), which is a macro which references a prototype
67 that returns a ssize_t. So far, this is safe, since tar_block_read()
68 only ever reads 512 (T_BLOCKSIZE) bytes at a time, so any difference
69 in size of ssize_t and int is of negligible risk. BUT, if
70 T_BLOCKSIZE ever changes, or ever becomes a variable parameter
71 controllable by the user, all the code that calls it,
72 including this function and all code that calls it, should be
73 fixed for security reasons.
74 Thanks to Chris Palmer for the critique.
75*/
bigbiff bigbiff9c754052013-01-09 09:09:08 -050076int
77th_read_internal(TAR *t)
78{
79 int i;
80 int num_zero_blocks = 0;
81
82#ifdef DEBUG
83 printf("==> th_read_internal(TAR=\"%s\")\n", t->pathname);
84#endif
85
86 while ((i = tar_block_read(t, &(t->th_buf))) == T_BLOCKSIZE)
87 {
88 /* two all-zero blocks mark EOF */
89 if (t->th_buf.name[0] == '\0')
90 {
91 num_zero_blocks++;
92 if (!BIT_ISSET(t->options, TAR_IGNORE_EOT)
93 && num_zero_blocks >= 2)
94 return 0; /* EOF */
95 else
96 continue;
97 }
98
99 /* verify magic and version */
100 if (BIT_ISSET(t->options, TAR_CHECK_MAGIC)
101 && strncmp(t->th_buf.magic, TMAGIC, TMAGLEN - 1) != 0)
102 {
103#ifdef DEBUG
104 puts("!!! unknown magic value in tar header");
105#endif
106 return -2;
107 }
108
109 if (BIT_ISSET(t->options, TAR_CHECK_VERSION)
110 && strncmp(t->th_buf.version, TVERSION, TVERSLEN) != 0)
111 {
112#ifdef DEBUG
113 puts("!!! unknown version value in tar header");
114#endif
115 return -2;
116 }
117
118 /* check chksum */
119 if (!BIT_ISSET(t->options, TAR_IGNORE_CRC)
120 && !th_crc_ok(t))
121 {
122#ifdef DEBUG
123 puts("!!! tar header checksum error");
124#endif
125 return -2;
126 }
127
128 break;
129 }
130
131#ifdef DEBUG
132 printf("<== th_read_internal(): returning %d\n", i);
133#endif
134 return i;
135}
136
137
138/* wrapper function for th_read_internal() to handle GNU extensions */
139int
140th_read(TAR *t)
141{
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500142 int i;
143 size_t sz, j, blocks;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500144 char *ptr;
145
146#ifdef DEBUG
bigbiff7ba75002020-04-11 20:47:09 -0400147 printf("==> th_read(t=0x%p)\n", (void *)t);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500148#endif
149
150 if (t->th_buf.gnu_longname != NULL)
151 free(t->th_buf.gnu_longname);
152 if (t->th_buf.gnu_longlink != NULL)
153 free(t->th_buf.gnu_longlink);
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200154 if (t->th_buf.selinux_context != NULL)
155 free(t->th_buf.selinux_context);
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600156#ifdef HAVE_EXT4_CRYPT
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500157 if (t->th_buf.eep != NULL)
158 free(t->th_buf.eep);
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600159#endif
bigbiff7ba75002020-04-11 20:47:09 -0400160
161#ifdef USE_FSCRYPT
162 if (t->th_buf.fep != NULL)
163 free(t->th_buf.fep);
164#endif
165
Ethan Yonker71187742017-01-13 13:30:10 -0600166 if (t->th_buf.has_cap_data)
167 {
168 memset(&t->th_buf.cap_data, 0, sizeof(struct vfs_cap_data));
169 t->th_buf.has_cap_data = 0;
170 }
Ethan Yonker8d039f72017-02-03 14:26:15 -0600171 t->th_buf.has_user_default = 0;
172 t->th_buf.has_user_cache = 0;
173 t->th_buf.has_user_code_cache = 0;
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200174
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500175 memset(&(t->th_buf), 0, sizeof(struct tar_header));
176
177 i = th_read_internal(t);
178 if (i == 0)
179 return 1;
180 else if (i != T_BLOCKSIZE)
181 {
182 if (i != -1)
183 errno = EINVAL;
184 return -1;
185 }
186
187 /* check for GNU long link extention */
188 if (TH_ISLONGLINK(t))
189 {
190 sz = th_get_size(t);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500191 blocks = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0);
192 if (blocks > ((size_t)-1 / T_BLOCKSIZE))
193 {
194 errno = E2BIG;
195 return -1;
196 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500197#ifdef DEBUG
198 printf(" th_read(): GNU long linkname detected "
bigbiff7ba75002020-04-11 20:47:09 -0400199 "(%zu bytes, %zu blocks)\n", sz, blocks);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500200#endif
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500201 t->th_buf.gnu_longlink = (char *)malloc(blocks * T_BLOCKSIZE);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500202 if (t->th_buf.gnu_longlink == NULL)
203 return -1;
204
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500205 for (j = 0, ptr = t->th_buf.gnu_longlink; j < blocks;
206 j++, ptr += T_BLOCKSIZE)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500207 {
208#ifdef DEBUG
209 printf(" th_read(): reading long linkname "
bigbiff7ba75002020-04-11 20:47:09 -0400210 "(%zu blocks left, ptr == %p)\n", blocks-j, (void *) ptr);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500211#endif
212 i = tar_block_read(t, ptr);
213 if (i != T_BLOCKSIZE)
214 {
215 if (i != -1)
216 errno = EINVAL;
217 return -1;
218 }
219#ifdef DEBUG
220 printf(" th_read(): read block == \"%s\"\n", ptr);
221#endif
222 }
223#ifdef DEBUG
224 printf(" th_read(): t->th_buf.gnu_longlink == \"%s\"\n",
225 t->th_buf.gnu_longlink);
226#endif
227
228 i = th_read_internal(t);
229 if (i != T_BLOCKSIZE)
230 {
231 if (i != -1)
232 errno = EINVAL;
233 return -1;
234 }
235 }
236
237 /* check for GNU long name extention */
238 if (TH_ISLONGNAME(t))
239 {
240 sz = th_get_size(t);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500241 blocks = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0);
242 if (blocks > ((size_t)-1 / T_BLOCKSIZE))
243 {
244 errno = E2BIG;
245 return -1;
246 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500247#ifdef DEBUG
248 printf(" th_read(): GNU long filename detected "
bigbiff7ba75002020-04-11 20:47:09 -0400249 "(%zu bytes, %zu blocks)\n", sz, blocks);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500250#endif
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500251 t->th_buf.gnu_longname = (char *)malloc(blocks * T_BLOCKSIZE);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500252 if (t->th_buf.gnu_longname == NULL)
253 return -1;
254
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500255 for (j = 0, ptr = t->th_buf.gnu_longname; j < blocks;
256 j++, ptr += T_BLOCKSIZE)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500257 {
258#ifdef DEBUG
259 printf(" th_read(): reading long filename "
bigbiff7ba75002020-04-11 20:47:09 -0400260 "(%zu blocks left, ptr == %p)\n", blocks-j, (void *) ptr);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500261#endif
262 i = tar_block_read(t, ptr);
263 if (i != T_BLOCKSIZE)
264 {
265 if (i != -1)
266 errno = EINVAL;
267 return -1;
268 }
269#ifdef DEBUG
270 printf(" th_read(): read block == \"%s\"\n", ptr);
271#endif
272 }
273#ifdef DEBUG
274 printf(" th_read(): t->th_buf.gnu_longname == \"%s\"\n",
275 t->th_buf.gnu_longname);
276#endif
277
278 i = th_read_internal(t);
279 if (i != T_BLOCKSIZE)
280 {
281 if (i != -1)
282 errno = EINVAL;
283 return -1;
284 }
285 }
286
bigbiff7ba75002020-04-11 20:47:09 -0400287 // Extended headers (selinux contexts, posix file capabilities and encryption policies)
Ethan Yonker71187742017-01-13 13:30:10 -0600288 while(TH_ISEXTHEADER(t) || TH_ISPOLHEADER(t))
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200289 {
290 sz = th_get_size(t);
291
292 if(sz >= T_BLOCKSIZE) // Not supported
293 {
294#ifdef DEBUG
295 printf(" th_read(): Extended header is too long!\n");
296#endif
297 }
298 else
299 {
300 char buf[T_BLOCKSIZE];
301 i = tar_block_read(t, buf);
302 if (i != T_BLOCKSIZE)
303 {
304 if (i != -1)
305 errno = EINVAL;
306 return -1;
307 }
308
309 // To be sure
310 buf[T_BLOCKSIZE-1] = 0;
311
312 int len = strlen(buf);
Ethan Yonker71187742017-01-13 13:30:10 -0600313 // posix capabilities
314 char *start = strstr(buf, CAPABILITIES_TAG);
Ethan Yonker8d039f72017-02-03 14:26:15 -0600315 if (start && start+CAPABILITIES_TAG_LEN < buf+len)
Ethan Yonker71187742017-01-13 13:30:10 -0600316 {
317 start += CAPABILITIES_TAG_LEN;
318 memcpy(&t->th_buf.cap_data, start, sizeof(struct vfs_cap_data));
319 t->th_buf.has_cap_data = 1;
320#ifdef DEBUG
321 printf(" th_read(): Posix capabilities detected\n");
322#endif
323 } // end posix capabilities
Matt Mower87413642017-01-17 21:14:46 -0600324 // selinux contexts
Ethan Yonker71187742017-01-13 13:30:10 -0600325 start = strstr(buf, SELINUX_TAG);
Ethan Yonker8d039f72017-02-03 14:26:15 -0600326 if (start && start+SELINUX_TAG_LEN < buf+len)
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200327 {
328 start += SELINUX_TAG_LEN;
329 char *end = strchr(start, '\n');
330 if(end)
331 {
332 t->th_buf.selinux_context = strndup(start, end-start);
333#ifdef DEBUG
334 printf(" th_read(): SELinux context xattr detected: %s\n", t->th_buf.selinux_context);
335#endif
336 }
Matt Mower87413642017-01-17 21:14:46 -0600337 } // end selinux contexts
Ethan Yonker8d039f72017-02-03 14:26:15 -0600338 // android user.default xattr
339 start = strstr(buf, ANDROID_USER_DEFAULT_TAG);
340 if (start)
341 {
342 t->th_buf.has_user_default = 1;
343#ifdef DEBUG
344 printf(" th_read(): android user.default xattr detected\n");
345#endif
346 } // end android user.default xattr
347 // android user.inode_cache xattr
348 start = strstr(buf, ANDROID_USER_CACHE_TAG);
349 if (start)
350 {
351 t->th_buf.has_user_cache = 1;
352#ifdef DEBUG
353 printf(" th_read(): android user.inode_cache xattr detected\n");
354#endif
355 } // end android user.inode_cache xattr
356 // android user.inode_code_cache xattr
357 start = strstr(buf, ANDROID_USER_CODE_CACHE_TAG);
358 if (start)
359 {
360 t->th_buf.has_user_code_cache = 1;
361#ifdef DEBUG
362 printf(" th_read(): android user.inode_code_cache xattr detected\n");
363#endif
364 } // end android user.inode_code_cache xattr
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600365#ifdef HAVE_EXT4_CRYPT
Ethan Yonker71187742017-01-13 13:30:10 -0600366 start = strstr(buf, E4CRYPT_TAG);
Ethan Yonker8d039f72017-02-03 14:26:15 -0600367 if (start && start+E4CRYPT_TAG_LEN < buf+len)
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600368 {
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500369 t->th_buf.eep = (struct ext4_encryption_policy*)malloc(sizeof(struct ext4_encryption_policy));
370 if (!t->th_buf.eep) {
371 printf("malloc ext4_encryption_policy\n");
372 return -1;
373 }
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600374 start += E4CRYPT_TAG_LEN;
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500375 if (*start == '2')
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600376 {
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500377 start++;
Ethan Yonker58f21322018-08-24 11:17:36 -0500378 char *newline_check = start + sizeof(struct ext4_encryption_policy);
379 if (*newline_check != '\n')
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500380 printf("did not find newline char in expected location, continuing anyway...\n");
381 memcpy(t->th_buf.eep, start, sizeof(struct ext4_encryption_policy));
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600382#ifdef DEBUG
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500383 printf(" th_read(): E4Crypt policy v2 detected: %i %i %i %i %s\n",
384 (int)t->th_buf.eep->version,
385 (int)t->th_buf.eep->contents_encryption_mode,
386 (int)t->th_buf.eep->filenames_encryption_mode,
387 (int)t->th_buf.eep->flags,
388 t->th_buf.eep->master_key_descriptor);
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600389#endif
390 }
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500391 else
392 {
393 e4crypt_policy_fill_default_struct(t->th_buf.eep);
394 char *end = strchr(start, '\n');
395 if(!end)
396 end = strchr(start, '\0');
397 if(end)
398 {
399 strncpy(t->th_buf.eep->master_key_descriptor, start, end-start);
400#ifdef DEBUG
401 printf(" th_read(): E4Crypt policy v1 detected: %s\n", t->th_buf.eep->master_key_descriptor);
402#endif
403 }
404 }
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600405 }
Ethan Yonker71187742017-01-13 13:30:10 -0600406#endif // HAVE_EXT4_CRYPT
bigbiff7ba75002020-04-11 20:47:09 -0400407
408#ifdef USE_FSCRYPT
409 start = strstr(buf, FSCRYPT_TAG);
410 if (start && start+FSCRYPT_TAG_LEN < buf+len) {
411 t->th_buf.fep = (struct fscrypt_encryption_policy*)malloc(sizeof(struct fscrypt_encryption_policy));
412 if (!t->th_buf.fep) {
413 printf("malloc fscrypt_encryption_policy\n");
414 return -1;
415 }
416 start += FSCRYPT_TAG_LEN;
417 if (*start == '0') {
418 start++;
419 char *newline_check = start + sizeof(struct fscrypt_encryption_policy);
420 if (*newline_check != '\n')
421 printf("did not find newline char in expected location, continuing anyway...\n");
422 memcpy(t->th_buf.fep, start, sizeof(struct fscrypt_encryption_policy));
423#ifdef DEBUG
424 printf(" th_read(): FSCrypt policy v1 detected: %i %i %i %i %s\n",
425 (int)t->th_buf.fep->version,
426 (int)t->th_buf.fep->contents_encryption_mode,
427 (int)t->th_buf.fep->filenames_encryption_mode,
428 (int)t->th_buf.fep->flags,
429 t->th_buf.fep->master_key_descriptor);
430#endif
431 }
432 else {
433 printf(" invalid fscrypt header found\n");
434 }
435 }
436#endif // USE_FSCRYPT
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600437 }
438
439 i = th_read_internal(t);
440 if (i != T_BLOCKSIZE)
441 {
442 if (i != -1)
443 errno = EINVAL;
444 return -1;
445 }
446 }
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600447
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500448 return 0;
449}
450
Ethan Yonker71187742017-01-13 13:30:10 -0600451/* write an extended block */
452static int
453th_write_extended(TAR *t, char* buf, uint64_t sz)
454{
455 char type2;
456 uint64_t sz2;
457 int i;
458
459 /* save old size and type */
460 type2 = t->th_buf.typeflag;
461 sz2 = th_get_size(t);
462
463 /* write out initial header block with fake size and type */
464 t->th_buf.typeflag = TH_EXT_TYPE;
465
466 if(sz >= T_BLOCKSIZE) // impossible
467 {
468 errno = EINVAL;
469 return -1;
470 }
471
472 th_set_size(t, sz);
473 th_finish(t);
474 i = tar_block_write(t, &(t->th_buf));
475 if (i != T_BLOCKSIZE)
476 {
477 if (i != -1)
478 errno = EINVAL;
479 return -1;
480 }
481
482 i = tar_block_write(t, buf);
483 if (i != T_BLOCKSIZE)
484 {
485 if (i != -1)
486 errno = EINVAL;
487 return -1;
488 }
489
490 /* reset type and size to original values */
491 t->th_buf.typeflag = type2;
492 th_set_size(t, sz2);
493 memset(buf, 0, T_BLOCKSIZE);
494 return 0;
495}
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500496
497/* write a header block */
498int
499th_write(TAR *t)
500{
501 int i, j;
502 char type2;
Ethan Yonker71187742017-01-13 13:30:10 -0600503 uint64_t sz, sz2, total_sz = 0;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500504 char *ptr;
505 char buf[T_BLOCKSIZE];
506
507#ifdef DEBUG
508 printf("==> th_write(TAR=\"%s\")\n", t->pathname);
509 th_print(t);
510#endif
511
512 if ((t->options & TAR_GNU) && t->th_buf.gnu_longlink != NULL)
513 {
514#ifdef DEBUG
515 printf("th_write(): using gnu_longlink (\"%s\")\n",
516 t->th_buf.gnu_longlink);
517#endif
518 /* save old size and type */
519 type2 = t->th_buf.typeflag;
520 sz2 = th_get_size(t);
521
522 /* write out initial header block with fake size and type */
523 t->th_buf.typeflag = GNU_LONGLINK_TYPE;
524 sz = strlen(t->th_buf.gnu_longlink);
525 th_set_size(t, sz);
526 th_finish(t);
527 i = tar_block_write(t, &(t->th_buf));
528 if (i != T_BLOCKSIZE)
529 {
530 if (i != -1)
531 errno = EINVAL;
532 return -1;
533 }
534
535 /* write out extra blocks containing long name */
536 for (j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0),
537 ptr = t->th_buf.gnu_longlink; j > 1;
538 j--, ptr += T_BLOCKSIZE)
539 {
540 i = tar_block_write(t, ptr);
541 if (i != T_BLOCKSIZE)
542 {
543 if (i != -1)
544 errno = EINVAL;
545 return -1;
546 }
547 }
548 memset(buf, 0, T_BLOCKSIZE);
549 strncpy(buf, ptr, T_BLOCKSIZE);
550 i = tar_block_write(t, &buf);
551 if (i != T_BLOCKSIZE)
552 {
553 if (i != -1)
554 errno = EINVAL;
555 return -1;
556 }
557
558 /* reset type and size to original values */
559 t->th_buf.typeflag = type2;
560 th_set_size(t, sz2);
561 }
562
563 if ((t->options & TAR_GNU) && t->th_buf.gnu_longname != NULL)
564 {
565#ifdef DEBUG
566 printf("th_write(): using gnu_longname (\"%s\")\n",
567 t->th_buf.gnu_longname);
568#endif
569 /* save old size and type */
570 type2 = t->th_buf.typeflag;
571 sz2 = th_get_size(t);
572
573 /* write out initial header block with fake size and type */
574 t->th_buf.typeflag = GNU_LONGNAME_TYPE;
575 sz = strlen(t->th_buf.gnu_longname);
576 th_set_size(t, sz);
577 th_finish(t);
578 i = tar_block_write(t, &(t->th_buf));
579 if (i != T_BLOCKSIZE)
580 {
581 if (i != -1)
582 errno = EINVAL;
583 return -1;
584 }
585
586 /* write out extra blocks containing long name */
587 for (j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0),
588 ptr = t->th_buf.gnu_longname; j > 1;
589 j--, ptr += T_BLOCKSIZE)
590 {
591 i = tar_block_write(t, ptr);
592 if (i != T_BLOCKSIZE)
593 {
594 if (i != -1)
595 errno = EINVAL;
596 return -1;
597 }
598 }
599 memset(buf, 0, T_BLOCKSIZE);
600 strncpy(buf, ptr, T_BLOCKSIZE);
601 i = tar_block_write(t, &buf);
602 if (i != T_BLOCKSIZE)
603 {
604 if (i != -1)
605 errno = EINVAL;
606 return -1;
607 }
608
609 /* reset type and size to original values */
610 t->th_buf.typeflag = type2;
611 th_set_size(t, sz2);
612 }
613
Ethan Yonker71187742017-01-13 13:30:10 -0600614 memset(buf, 0, T_BLOCKSIZE);
615 ptr = buf;
Matt Mower87413642017-01-17 21:14:46 -0600616
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200617 if((t->options & TAR_STORE_SELINUX) && t->th_buf.selinux_context != NULL)
618 {
619#ifdef DEBUG
620 printf("th_write(): using selinux_context (\"%s\")\n",
621 t->th_buf.selinux_context);
622#endif
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200623 /* setup size - EXT header has format "*size of this whole tag as ascii numbers* *space* *content* *newline* */
624 // size newline
625 sz = SELINUX_TAG_LEN + strlen(t->th_buf.selinux_context) + 3 + 1;
626
627 if(sz >= 100) // another ascci digit for size
628 ++sz;
629
Ethan Yonker71187742017-01-13 13:30:10 -0600630 total_sz += sz;
631 snprintf(ptr, T_BLOCKSIZE, "%d "SELINUX_TAG"%s\n", (int)sz, t->th_buf.selinux_context);
632 ptr += sz;
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200633 }
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200634
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600635#ifdef HAVE_EXT4_CRYPT
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500636 if((t->options & TAR_STORE_EXT4_POL) && t->th_buf.eep != NULL)
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600637 {
638#ifdef DEBUG
639 printf("th_write(): using e4crypt_policy %s\n",
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500640 t->th_buf.eep->master_key_descriptor);
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600641#endif
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500642 /* setup size - EXT header has format "*size of this whole tag as ascii numbers* *space* *version code* *content* *newline* */
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600643 // size newline
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500644 sz = E4CRYPT_TAG_LEN + sizeof(struct ext4_encryption_policy) + 1 + 3 + 1;
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600645
646 if(sz >= 100) // another ascci digit for size
647 ++sz;
648
Ethan Yonker71187742017-01-13 13:30:10 -0600649 if (total_sz + sz >= T_BLOCKSIZE)
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600650 {
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500651 if (th_write_extended(t, &buf[0], total_sz))
Ethan Yonker71187742017-01-13 13:30:10 -0600652 return -1;
653 ptr = buf;
654 total_sz = sz;
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600655 }
Ethan Yonker71187742017-01-13 13:30:10 -0600656 else
657 total_sz += sz;
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600658
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500659 snprintf(ptr, T_BLOCKSIZE, "%d "E4CRYPT_TAG"2", (int)sz);
660 memcpy(ptr + sz - sizeof(struct ext4_encryption_policy) - 1, t->th_buf.eep, sizeof(struct ext4_encryption_policy));
Ethan Yonker71187742017-01-13 13:30:10 -0600661 char *nlptr = ptr + sz - 1;
662 *nlptr = '\n';
663 ptr += sz;
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600664 }
665#endif
666
bigbiff7ba75002020-04-11 20:47:09 -0400667#ifdef USE_FSCRYPT
668 if((t->options & TAR_STORE_FSCRYPT_POL) && t->th_buf.fep != NULL)
669 {
670#ifdef DEBUG
671 printf("th_write(): using fscrypt_policy %s\n",
672 t->th_buf.fep->master_key_descriptor);
673#endif
674 /* setup size - EXT header has format "*size of this whole tag as ascii numbers* *space* *version code* *content* *newline* */
675 // size newline
676 sz = FSCRYPT_TAG_LEN + sizeof(struct fscrypt_encryption_policy) + 1 + 3 + 1;
677
678 if(sz >= 100) // another ascci digit for size
679 ++sz;
680
681 if (total_sz + sz >= T_BLOCKSIZE)
682 {
683 if (th_write_extended(t, &buf[0], total_sz))
684 return -1;
685 ptr = buf;
686 total_sz = sz;
687 }
688 else
689 total_sz += sz;
690
691 snprintf(ptr, T_BLOCKSIZE, "%d "FSCRYPT_TAG"0", (int)sz);
692 memcpy(ptr + sz - sizeof(struct fscrypt_encryption_policy) - 1, t->th_buf.fep, sizeof(struct fscrypt_encryption_policy));
693 char *nlptr = ptr + sz - 1;
694 *nlptr = '\n';
695 ptr += sz;
696 }
697#endif
698
Ethan Yonker71187742017-01-13 13:30:10 -0600699 if((t->options & TAR_STORE_POSIX_CAP) && t->th_buf.has_cap_data)
700 {
701#ifdef DEBUG
702 printf("th_write(): has a posix capability\n");
703#endif
704 sz = CAPABILITIES_TAG_LEN + sizeof(struct vfs_cap_data) + 3 + 1;
705
706 if(sz >= 100) // another ascci digit for size
707 ++sz;
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 Yonker71187742017-01-13 13:30:10 -0600712 return -1;
713 ptr = buf;
714 total_sz = sz;
715 }
716 else
717 total_sz += sz;
718
719 snprintf(ptr, T_BLOCKSIZE, "%d "CAPABILITIES_TAG, (int)sz);
720 memcpy(ptr + CAPABILITIES_TAG_LEN + 3, &t->th_buf.cap_data, sizeof(struct vfs_cap_data));
721 char *nlptr = ptr + sz - 1;
722 *nlptr = '\n';
723 ptr += sz;
724 }
Ethan Yonker8d039f72017-02-03 14:26:15 -0600725 if (t->options & TAR_STORE_ANDROID_USER_XATTR)
726 {
727 if (t->th_buf.has_user_default) {
728#ifdef DEBUG
729 printf("th_write(): has android user.default xattr\n");
730#endif
731 sz = ANDROID_USER_DEFAULT_TAG_LEN + 3 + 1;
732
733 if (total_sz + sz >= T_BLOCKSIZE)
734 {
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500735 if (th_write_extended(t, &buf[0], total_sz))
Ethan Yonker8d039f72017-02-03 14:26:15 -0600736 return -1;
737 ptr = buf;
738 total_sz = sz;
739 }
740 else
741 total_sz += sz;
742
743 snprintf(ptr, T_BLOCKSIZE, "%d "ANDROID_USER_DEFAULT_TAG, (int)sz);
744 char *nlptr = ptr + sz - 1;
745 *nlptr = '\n';
746 ptr += sz;
747 }
748 if (t->th_buf.has_user_cache) {
749#ifdef DEBUG
750 printf("th_write(): has android user.inode_cache xattr\n");
751#endif
752 sz = ANDROID_USER_CACHE_TAG_LEN + 3 + 1;
753
754 if (total_sz + sz >= T_BLOCKSIZE)
755 {
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500756 if (th_write_extended(t, &buf[0], total_sz))
Ethan Yonker8d039f72017-02-03 14:26:15 -0600757 return -1;
758 ptr = buf;
759 total_sz = sz;
760 }
761 else
762 total_sz += sz;
763
764 snprintf(ptr, T_BLOCKSIZE, "%d "ANDROID_USER_CACHE_TAG, (int)sz);
765 char *nlptr = ptr + sz - 1;
766 *nlptr = '\n';
767 ptr += sz;
768 }
769 if (t->th_buf.has_user_code_cache) {
770#ifdef DEBUG
771 printf("th_write(): has android user.inode_code_cache xattr\n");
772#endif
773 sz = ANDROID_USER_CODE_CACHE_TAG_LEN + 3 + 1;
774
775 if (total_sz + sz >= T_BLOCKSIZE)
776 {
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500777 if (th_write_extended(t, &buf[0], total_sz))
Ethan Yonker8d039f72017-02-03 14:26:15 -0600778 return -1;
779 ptr = buf;
780 total_sz = sz;
781 }
782 else
783 total_sz += sz;
784
785 snprintf(ptr, T_BLOCKSIZE, "%d "ANDROID_USER_CODE_CACHE_TAG, (int)sz);
786 char *nlptr = ptr + sz - 1;
787 *nlptr = '\n';
788 ptr += sz;
789 }
790 }
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500791 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 -0600792 return -1;
793
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500794 th_finish(t);
795
796#ifdef DEBUG
797 /* print tar header */
798 th_print(t);
799#endif
800
801 i = tar_block_write(t, &(t->th_buf));
802 if (i != T_BLOCKSIZE)
803 {
804 if (i != -1)
805 errno = EINVAL;
806 return -1;
807 }
808
809#ifdef DEBUG
810 puts("th_write(): returning 0");
811#endif
812 return 0;
813}
814
815