blob: aaedc8e895b436d04b0174eda6e66a532d8ac0df [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
Mohd Faraz15247642023-01-16 16:16:21 +010075 LOG("==> th_read_internal(TAR=\"%s\")\n", t->pathname);
bigbiff bigbiff9c754052013-01-09 09:09:08 -050076#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
Mohd Faraz15247642023-01-16 16:16:21 +010096 LOG("!!! unknown magic value in tar header");
bigbiff bigbiff9c754052013-01-09 09:09:08 -050097#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
Mohd Faraz15247642023-01-16 16:16:21 +0100105 LOG("!!! unknown version value in tar header");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500106#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
Mohd Faraz15247642023-01-16 16:16:21 +0100115 LOG("!!! tar header checksum error");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500116#endif
117 return -2;
118 }
119
120 break;
121 }
122
123#ifdef DEBUG
Mohd Faraz15247642023-01-16 16:16:21 +0100124 LOG("<== th_read_internal(): returning %d\n", i);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500125#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
Mohd Faraz15247642023-01-16 16:16:21 +0100139 LOG("==> 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
Mohd Faraz15247642023-01-16 16:16:21 +0100186 LOG(" 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
Mohd Faraz15247642023-01-16 16:16:21 +0100197 LOG(" 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
Mohd Faraz15247642023-01-16 16:16:21 +0100208 LOG(" th_read(): read block == \"%s\"\n", ptr);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500209#endif
210 }
211#ifdef DEBUG
Mohd Faraz15247642023-01-16 16:16:21 +0100212 LOG(" th_read(): t->th_buf.gnu_longlink == \"%s\"\n",
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500213 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
Mohd Faraz15247642023-01-16 16:16:21 +0100236 LOG(" 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
Mohd Faraz15247642023-01-16 16:16:21 +0100247 LOG(" 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
Mohd Faraz15247642023-01-16 16:16:21 +0100258 LOG(" th_read(): read block == \"%s\"\n", ptr);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500259#endif
260 }
261#ifdef DEBUG
Mohd Faraz15247642023-01-16 16:16:21 +0100262 LOG(" th_read(): t->th_buf.gnu_longname == \"%s\"\n",
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500263 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
Mohd Faraz15247642023-01-16 16:16:21 +0100283 LOG(" th_read(): Extended header is too long!\n");
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200284#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
Mohd Faraz15247642023-01-16 16:16:21 +0100309 LOG(" th_read(): Posix capabilities detected\n");
Ethan Yonker71187742017-01-13 13:30:10 -0600310#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
Mohd Faraz15247642023-01-16 16:16:21 +0100322 LOG(" th_read(): SELinux context xattr detected: %s\n", t->th_buf.selinux_context);
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200323#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
Mohd Faraz15247642023-01-16 16:16:21 +0100332 LOG(" th_read(): android user.default xattr detected\n");
Ethan Yonker8d039f72017-02-03 14:26:15 -0600333#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
Mohd Faraz15247642023-01-16 16:16:21 +0100341 LOG(" th_read(): android user.inode_cache xattr detected\n");
Ethan Yonker8d039f72017-02-03 14:26:15 -0600342#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
Mohd Faraz15247642023-01-16 16:16:21 +0100350 LOG(" th_read(): android user.inode_code_cache xattr detected\n");
Ethan Yonker8d039f72017-02-03 14:26:15 -0600351#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) {
Mohd Faraz1e6061c2023-01-07 21:26:56 +0100357 t->th_buf.fep = (fscrypt_policy*)malloc(sizeof(fscrypt_policy));
bigbiff7ba75002020-04-11 20:47:09 -0400358 if (!t->th_buf.fep) {
Mohd Faraz15247642023-01-16 16:16:21 +0100359 LOG("malloc failed for fscrypt policy\n");
bigbiff7ba75002020-04-11 20:47:09 -0400360 return -1;
361 }
362 start += FSCRYPT_TAG_LEN;
363 if (*start == '0') {
364 start++;
Mohd Faraz1e6061c2023-01-07 21:26:56 +0100365 memcpy(get_policy(t->th_buf.fep), start, fscrypt_policy_size(t->th_buf.fep));
bigbiff7ba75002020-04-11 20:47:09 -0400366#ifdef DEBUG
Mohd Faraz1e6061c2023-01-07 21:26:56 +0100367 uint8_t version;
368 char content[50];
369 memcpy(&version, start, sizeof(version));
370 get_policy_content(t->th_buf.fep, content);
371 LOG("version: %u\n", version);
372 LOG(" th_read(): FSCrypt policy detected: %s\n", content);
bigbiff2e344ab2021-05-07 10:41:55 -0400373#endif
bigbiff7ba75002020-04-11 20:47:09 -0400374 }
375 else {
Mohd Faraz15247642023-01-16 16:16:21 +0100376 LOG(" invalid fscrypt header found\n");
bigbiff7ba75002020-04-11 20:47:09 -0400377 }
378 }
379#endif // USE_FSCRYPT
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600380 }
381
382 i = th_read_internal(t);
383 if (i != T_BLOCKSIZE)
384 {
385 if (i != -1)
386 errno = EINVAL;
387 return -1;
388 }
389 }
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600390
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500391 return 0;
392}
393
Ethan Yonker71187742017-01-13 13:30:10 -0600394/* write an extended block */
395static int
396th_write_extended(TAR *t, char* buf, uint64_t sz)
397{
398 char type2;
399 uint64_t sz2;
400 int i;
401
402 /* save old size and type */
403 type2 = t->th_buf.typeflag;
404 sz2 = th_get_size(t);
405
406 /* write out initial header block with fake size and type */
407 t->th_buf.typeflag = TH_EXT_TYPE;
408
409 if(sz >= T_BLOCKSIZE) // impossible
410 {
411 errno = EINVAL;
412 return -1;
413 }
414
415 th_set_size(t, sz);
416 th_finish(t);
417 i = tar_block_write(t, &(t->th_buf));
418 if (i != T_BLOCKSIZE)
419 {
420 if (i != -1)
421 errno = EINVAL;
422 return -1;
423 }
424
425 i = tar_block_write(t, buf);
426 if (i != T_BLOCKSIZE)
427 {
428 if (i != -1)
429 errno = EINVAL;
430 return -1;
431 }
432
433 /* reset type and size to original values */
434 t->th_buf.typeflag = type2;
435 th_set_size(t, sz2);
436 memset(buf, 0, T_BLOCKSIZE);
437 return 0;
438}
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500439
440/* write a header block */
441int
442th_write(TAR *t)
443{
444 int i, j;
445 char type2;
Ethan Yonker71187742017-01-13 13:30:10 -0600446 uint64_t sz, sz2, total_sz = 0;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500447 char *ptr;
448 char buf[T_BLOCKSIZE];
449
450#ifdef DEBUG
Mohd Faraz15247642023-01-16 16:16:21 +0100451 LOG("==> th_write(TAR=\"%s\")\n", t->pathname);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500452 th_print(t);
453#endif
454
455 if ((t->options & TAR_GNU) && t->th_buf.gnu_longlink != NULL)
456 {
457#ifdef DEBUG
Mohd Faraz15247642023-01-16 16:16:21 +0100458 LOG("th_write(): using gnu_longlink (\"%s\")\n",
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500459 t->th_buf.gnu_longlink);
460#endif
461 /* save old size and type */
462 type2 = t->th_buf.typeflag;
463 sz2 = th_get_size(t);
464
465 /* write out initial header block with fake size and type */
466 t->th_buf.typeflag = GNU_LONGLINK_TYPE;
467 sz = strlen(t->th_buf.gnu_longlink);
468 th_set_size(t, sz);
469 th_finish(t);
470 i = tar_block_write(t, &(t->th_buf));
471 if (i != T_BLOCKSIZE)
472 {
473 if (i != -1)
474 errno = EINVAL;
475 return -1;
476 }
477
478 /* write out extra blocks containing long name */
479 for (j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0),
480 ptr = t->th_buf.gnu_longlink; j > 1;
481 j--, ptr += T_BLOCKSIZE)
482 {
483 i = tar_block_write(t, ptr);
484 if (i != T_BLOCKSIZE)
485 {
486 if (i != -1)
487 errno = EINVAL;
488 return -1;
489 }
490 }
491 memset(buf, 0, T_BLOCKSIZE);
492 strncpy(buf, ptr, T_BLOCKSIZE);
493 i = tar_block_write(t, &buf);
494 if (i != T_BLOCKSIZE)
495 {
496 if (i != -1)
497 errno = EINVAL;
498 return -1;
499 }
500
501 /* reset type and size to original values */
502 t->th_buf.typeflag = type2;
503 th_set_size(t, sz2);
504 }
505
506 if ((t->options & TAR_GNU) && t->th_buf.gnu_longname != NULL)
507 {
508#ifdef DEBUG
Mohd Faraz15247642023-01-16 16:16:21 +0100509 LOG("th_write(): using gnu_longname (\"%s\")\n",
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500510 t->th_buf.gnu_longname);
511#endif
512 /* save old size and type */
513 type2 = t->th_buf.typeflag;
514 sz2 = th_get_size(t);
515
516 /* write out initial header block with fake size and type */
517 t->th_buf.typeflag = GNU_LONGNAME_TYPE;
518 sz = strlen(t->th_buf.gnu_longname);
519 th_set_size(t, sz);
520 th_finish(t);
521 i = tar_block_write(t, &(t->th_buf));
522 if (i != T_BLOCKSIZE)
523 {
524 if (i != -1)
525 errno = EINVAL;
526 return -1;
527 }
528
529 /* write out extra blocks containing long name */
530 for (j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0),
531 ptr = t->th_buf.gnu_longname; j > 1;
532 j--, ptr += T_BLOCKSIZE)
533 {
534 i = tar_block_write(t, ptr);
535 if (i != T_BLOCKSIZE)
536 {
537 if (i != -1)
538 errno = EINVAL;
539 return -1;
540 }
541 }
542 memset(buf, 0, T_BLOCKSIZE);
543 strncpy(buf, ptr, T_BLOCKSIZE);
544 i = tar_block_write(t, &buf);
545 if (i != T_BLOCKSIZE)
546 {
547 if (i != -1)
548 errno = EINVAL;
549 return -1;
550 }
551
552 /* reset type and size to original values */
553 t->th_buf.typeflag = type2;
554 th_set_size(t, sz2);
555 }
556
Ethan Yonker71187742017-01-13 13:30:10 -0600557 memset(buf, 0, T_BLOCKSIZE);
558 ptr = buf;
Matt Mower87413642017-01-17 21:14:46 -0600559
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200560 if((t->options & TAR_STORE_SELINUX) && t->th_buf.selinux_context != NULL)
561 {
562#ifdef DEBUG
Mohd Faraz15247642023-01-16 16:16:21 +0100563 LOG("th_write(): using selinux_context (\"%s\")\n",
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200564 t->th_buf.selinux_context);
565#endif
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200566 /* setup size - EXT header has format "*size of this whole tag as ascii numbers* *space* *content* *newline* */
567 // size newline
568 sz = SELINUX_TAG_LEN + strlen(t->th_buf.selinux_context) + 3 + 1;
569
570 if(sz >= 100) // another ascci digit for size
571 ++sz;
572
Ethan Yonker71187742017-01-13 13:30:10 -0600573 total_sz += sz;
574 snprintf(ptr, T_BLOCKSIZE, "%d "SELINUX_TAG"%s\n", (int)sz, t->th_buf.selinux_context);
575 ptr += sz;
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200576 }
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200577
bigbiff7ba75002020-04-11 20:47:09 -0400578#ifdef USE_FSCRYPT
579 if((t->options & TAR_STORE_FSCRYPT_POL) && t->th_buf.fep != NULL)
580 {
bigbiff7ba75002020-04-11 20:47:09 -0400581 /* setup size - EXT header has format "*size of this whole tag as ascii numbers* *space* *version code* *content* *newline* */
582 // size newline
Mohd Faraz1e6061c2023-01-07 21:26:56 +0100583 uint8_t size, *descriptor;
584 size = fscrypt_policy_size(t->th_buf.fep);
585 descriptor = get_policy_descriptor(t->th_buf.fep);
586#ifdef DEBUG
587 LOG("th_write(): using fscrypt_policy %s\n", descriptor);
bigbiffa957f072021-03-07 18:20:29 -0500588#endif
Mohd Faraz1e6061c2023-01-07 21:26:56 +0100589 sz = FSCRYPT_TAG_LEN + size + 1 + 3 + 1;
bigbiff7ba75002020-04-11 20:47:09 -0400590 if(sz >= 100) // another ascci digit for size
591 ++sz;
592
593 if (total_sz + sz >= T_BLOCKSIZE)
594 {
595 if (th_write_extended(t, &buf[0], total_sz))
596 return -1;
597 ptr = buf;
598 total_sz = sz;
599 }
600 else
601 total_sz += sz;
602
603 snprintf(ptr, T_BLOCKSIZE, "%d "FSCRYPT_TAG"0", (int)sz);
Mohd Faraz1e6061c2023-01-07 21:26:56 +0100604 memcpy(ptr + sz - size - 1, get_policy(t->th_buf.fep), size);
bigbiff7ba75002020-04-11 20:47:09 -0400605 char *nlptr = ptr + sz - 1;
606 *nlptr = '\n';
607 ptr += sz;
608 }
609#endif
610
Ethan Yonker71187742017-01-13 13:30:10 -0600611 if((t->options & TAR_STORE_POSIX_CAP) && t->th_buf.has_cap_data)
612 {
613#ifdef DEBUG
Mohd Faraz15247642023-01-16 16:16:21 +0100614 LOG("th_write(): has a posix capability\n");
Ethan Yonker71187742017-01-13 13:30:10 -0600615#endif
616 sz = CAPABILITIES_TAG_LEN + sizeof(struct vfs_cap_data) + 3 + 1;
617
618 if(sz >= 100) // another ascci digit for size
619 ++sz;
620
621 if (total_sz + sz >= T_BLOCKSIZE)
622 {
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500623 if (th_write_extended(t, &buf[0], total_sz))
Ethan Yonker71187742017-01-13 13:30:10 -0600624 return -1;
625 ptr = buf;
626 total_sz = sz;
627 }
628 else
629 total_sz += sz;
630
631 snprintf(ptr, T_BLOCKSIZE, "%d "CAPABILITIES_TAG, (int)sz);
632 memcpy(ptr + CAPABILITIES_TAG_LEN + 3, &t->th_buf.cap_data, sizeof(struct vfs_cap_data));
633 char *nlptr = ptr + sz - 1;
634 *nlptr = '\n';
635 ptr += sz;
636 }
Ethan Yonker8d039f72017-02-03 14:26:15 -0600637 if (t->options & TAR_STORE_ANDROID_USER_XATTR)
638 {
639 if (t->th_buf.has_user_default) {
640#ifdef DEBUG
Mohd Faraz15247642023-01-16 16:16:21 +0100641 LOG("th_write(): has android user.default xattr\n");
Ethan Yonker8d039f72017-02-03 14:26:15 -0600642#endif
643 sz = ANDROID_USER_DEFAULT_TAG_LEN + 3 + 1;
644
645 if (total_sz + sz >= T_BLOCKSIZE)
646 {
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500647 if (th_write_extended(t, &buf[0], total_sz))
Ethan Yonker8d039f72017-02-03 14:26:15 -0600648 return -1;
649 ptr = buf;
650 total_sz = sz;
651 }
652 else
653 total_sz += sz;
654
655 snprintf(ptr, T_BLOCKSIZE, "%d "ANDROID_USER_DEFAULT_TAG, (int)sz);
656 char *nlptr = ptr + sz - 1;
657 *nlptr = '\n';
658 ptr += sz;
659 }
660 if (t->th_buf.has_user_cache) {
661#ifdef DEBUG
Mohd Faraz15247642023-01-16 16:16:21 +0100662 LOG("th_write(): has android user.inode_cache xattr\n");
Ethan Yonker8d039f72017-02-03 14:26:15 -0600663#endif
664 sz = ANDROID_USER_CACHE_TAG_LEN + 3 + 1;
665
666 if (total_sz + sz >= T_BLOCKSIZE)
667 {
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500668 if (th_write_extended(t, &buf[0], total_sz))
Ethan Yonker8d039f72017-02-03 14:26:15 -0600669 return -1;
670 ptr = buf;
671 total_sz = sz;
672 }
673 else
674 total_sz += sz;
675
676 snprintf(ptr, T_BLOCKSIZE, "%d "ANDROID_USER_CACHE_TAG, (int)sz);
677 char *nlptr = ptr + sz - 1;
678 *nlptr = '\n';
679 ptr += sz;
680 }
681 if (t->th_buf.has_user_code_cache) {
682#ifdef DEBUG
Mohd Faraz15247642023-01-16 16:16:21 +0100683 LOG("th_write(): has android user.inode_code_cache xattr\n");
Ethan Yonker8d039f72017-02-03 14:26:15 -0600684#endif
685 sz = ANDROID_USER_CODE_CACHE_TAG_LEN + 3 + 1;
686
687 if (total_sz + sz >= T_BLOCKSIZE)
688 {
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500689 if (th_write_extended(t, &buf[0], total_sz))
Ethan Yonker8d039f72017-02-03 14:26:15 -0600690 return -1;
691 ptr = buf;
692 total_sz = sz;
693 }
694 else
695 total_sz += sz;
696
697 snprintf(ptr, T_BLOCKSIZE, "%d "ANDROID_USER_CODE_CACHE_TAG, (int)sz);
698 char *nlptr = ptr + sz - 1;
699 *nlptr = '\n';
700 ptr += sz;
701 }
702 }
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500703 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 -0600704 return -1;
705
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500706 th_finish(t);
707
708#ifdef DEBUG
709 /* print tar header */
710 th_print(t);
711#endif
712
713 i = tar_block_write(t, &(t->th_buf));
714 if (i != T_BLOCKSIZE)
715 {
716 if (i != -1)
717 errno = EINVAL;
718 return -1;
719 }
720
721#ifdef DEBUG
bigbiffc9a28c22023-04-11 19:55:06 -0400722 LOG("th_write(): returning 0\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500723#endif
724 return 0;
725}
726
727