blob: 91342c25ac33cd11d89c0babae4499304ac95632 [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) {
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) {
Mohd Faraz15247642023-01-16 16:16:21 +0100363 LOG("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')
Mohd Faraz15247642023-01-16 16:16:21 +0100375 LOG("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
Mohd Faraz15247642023-01-16 16:16:21 +0100382 LOG(" 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,
bigbiff2e344ab2021-05-07 10:41:55 -0400387#ifdef USE_FSCRYPT_POLICY_V1
388 t->th_buf.fep->master_key_descriptor);
389#else
bigbiffa957f072021-03-07 18:20:29 -0500390 t->th_buf.fep->master_key_identifier);
bigbiff7ba75002020-04-11 20:47:09 -0400391#endif
bigbiff2e344ab2021-05-07 10:41:55 -0400392#endif
bigbiff7ba75002020-04-11 20:47:09 -0400393 }
394 else {
Mohd Faraz15247642023-01-16 16:16:21 +0100395 LOG(" invalid fscrypt header found\n");
bigbiff7ba75002020-04-11 20:47:09 -0400396 }
397 }
398#endif // USE_FSCRYPT
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600399 }
400
401 i = th_read_internal(t);
402 if (i != T_BLOCKSIZE)
403 {
404 if (i != -1)
405 errno = EINVAL;
406 return -1;
407 }
408 }
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600409
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500410 return 0;
411}
412
Ethan Yonker71187742017-01-13 13:30:10 -0600413/* write an extended block */
414static int
415th_write_extended(TAR *t, char* buf, uint64_t sz)
416{
417 char type2;
418 uint64_t sz2;
419 int i;
420
421 /* save old size and type */
422 type2 = t->th_buf.typeflag;
423 sz2 = th_get_size(t);
424
425 /* write out initial header block with fake size and type */
426 t->th_buf.typeflag = TH_EXT_TYPE;
427
428 if(sz >= T_BLOCKSIZE) // impossible
429 {
430 errno = EINVAL;
431 return -1;
432 }
433
434 th_set_size(t, sz);
435 th_finish(t);
436 i = tar_block_write(t, &(t->th_buf));
437 if (i != T_BLOCKSIZE)
438 {
439 if (i != -1)
440 errno = EINVAL;
441 return -1;
442 }
443
444 i = tar_block_write(t, buf);
445 if (i != T_BLOCKSIZE)
446 {
447 if (i != -1)
448 errno = EINVAL;
449 return -1;
450 }
451
452 /* reset type and size to original values */
453 t->th_buf.typeflag = type2;
454 th_set_size(t, sz2);
455 memset(buf, 0, T_BLOCKSIZE);
456 return 0;
457}
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500458
459/* write a header block */
460int
461th_write(TAR *t)
462{
463 int i, j;
464 char type2;
Ethan Yonker71187742017-01-13 13:30:10 -0600465 uint64_t sz, sz2, total_sz = 0;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500466 char *ptr;
467 char buf[T_BLOCKSIZE];
468
469#ifdef DEBUG
Mohd Faraz15247642023-01-16 16:16:21 +0100470 LOG("==> th_write(TAR=\"%s\")\n", t->pathname);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500471 th_print(t);
472#endif
473
474 if ((t->options & TAR_GNU) && t->th_buf.gnu_longlink != NULL)
475 {
476#ifdef DEBUG
Mohd Faraz15247642023-01-16 16:16:21 +0100477 LOG("th_write(): using gnu_longlink (\"%s\")\n",
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500478 t->th_buf.gnu_longlink);
479#endif
480 /* save old size and type */
481 type2 = t->th_buf.typeflag;
482 sz2 = th_get_size(t);
483
484 /* write out initial header block with fake size and type */
485 t->th_buf.typeflag = GNU_LONGLINK_TYPE;
486 sz = strlen(t->th_buf.gnu_longlink);
487 th_set_size(t, sz);
488 th_finish(t);
489 i = tar_block_write(t, &(t->th_buf));
490 if (i != T_BLOCKSIZE)
491 {
492 if (i != -1)
493 errno = EINVAL;
494 return -1;
495 }
496
497 /* write out extra blocks containing long name */
498 for (j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0),
499 ptr = t->th_buf.gnu_longlink; j > 1;
500 j--, ptr += T_BLOCKSIZE)
501 {
502 i = tar_block_write(t, ptr);
503 if (i != T_BLOCKSIZE)
504 {
505 if (i != -1)
506 errno = EINVAL;
507 return -1;
508 }
509 }
510 memset(buf, 0, T_BLOCKSIZE);
511 strncpy(buf, ptr, T_BLOCKSIZE);
512 i = tar_block_write(t, &buf);
513 if (i != T_BLOCKSIZE)
514 {
515 if (i != -1)
516 errno = EINVAL;
517 return -1;
518 }
519
520 /* reset type and size to original values */
521 t->th_buf.typeflag = type2;
522 th_set_size(t, sz2);
523 }
524
525 if ((t->options & TAR_GNU) && t->th_buf.gnu_longname != NULL)
526 {
527#ifdef DEBUG
Mohd Faraz15247642023-01-16 16:16:21 +0100528 LOG("th_write(): using gnu_longname (\"%s\")\n",
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500529 t->th_buf.gnu_longname);
530#endif
531 /* save old size and type */
532 type2 = t->th_buf.typeflag;
533 sz2 = th_get_size(t);
534
535 /* write out initial header block with fake size and type */
536 t->th_buf.typeflag = GNU_LONGNAME_TYPE;
537 sz = strlen(t->th_buf.gnu_longname);
538 th_set_size(t, sz);
539 th_finish(t);
540 i = tar_block_write(t, &(t->th_buf));
541 if (i != T_BLOCKSIZE)
542 {
543 if (i != -1)
544 errno = EINVAL;
545 return -1;
546 }
547
548 /* write out extra blocks containing long name */
549 for (j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0),
550 ptr = t->th_buf.gnu_longname; j > 1;
551 j--, ptr += T_BLOCKSIZE)
552 {
553 i = tar_block_write(t, ptr);
554 if (i != T_BLOCKSIZE)
555 {
556 if (i != -1)
557 errno = EINVAL;
558 return -1;
559 }
560 }
561 memset(buf, 0, T_BLOCKSIZE);
562 strncpy(buf, ptr, T_BLOCKSIZE);
563 i = tar_block_write(t, &buf);
564 if (i != T_BLOCKSIZE)
565 {
566 if (i != -1)
567 errno = EINVAL;
568 return -1;
569 }
570
571 /* reset type and size to original values */
572 t->th_buf.typeflag = type2;
573 th_set_size(t, sz2);
574 }
575
Ethan Yonker71187742017-01-13 13:30:10 -0600576 memset(buf, 0, T_BLOCKSIZE);
577 ptr = buf;
Matt Mower87413642017-01-17 21:14:46 -0600578
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200579 if((t->options & TAR_STORE_SELINUX) && t->th_buf.selinux_context != NULL)
580 {
581#ifdef DEBUG
Mohd Faraz15247642023-01-16 16:16:21 +0100582 LOG("th_write(): using selinux_context (\"%s\")\n",
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200583 t->th_buf.selinux_context);
584#endif
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200585 /* setup size - EXT header has format "*size of this whole tag as ascii numbers* *space* *content* *newline* */
586 // size newline
587 sz = SELINUX_TAG_LEN + strlen(t->th_buf.selinux_context) + 3 + 1;
588
589 if(sz >= 100) // another ascci digit for size
590 ++sz;
591
Ethan Yonker71187742017-01-13 13:30:10 -0600592 total_sz += sz;
593 snprintf(ptr, T_BLOCKSIZE, "%d "SELINUX_TAG"%s\n", (int)sz, t->th_buf.selinux_context);
594 ptr += sz;
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200595 }
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200596
bigbiff7ba75002020-04-11 20:47:09 -0400597#ifdef USE_FSCRYPT
598 if((t->options & TAR_STORE_FSCRYPT_POL) && t->th_buf.fep != NULL)
599 {
600#ifdef DEBUG
bigbiff2e344ab2021-05-07 10:41:55 -0400601#ifdef USE_FSCRYPT_POLICY_V1
Mohd Faraz15247642023-01-16 16:16:21 +0100602 LOG("th_write(): using fscrypt_policy %s\n",
bigbiff2e344ab2021-05-07 10:41:55 -0400603 t->th_buf.fep->master_key_descriptor);
604#else
Mohd Faraz15247642023-01-16 16:16:21 +0100605 LOG("th_write(): using fscrypt_policy %s\n",
bigbiffa957f072021-03-07 18:20:29 -0500606 t->th_buf.fep->master_key_identifier);
bigbiff7ba75002020-04-11 20:47:09 -0400607#endif
bigbiff2e344ab2021-05-07 10:41:55 -0400608#endif
bigbiff7ba75002020-04-11 20:47:09 -0400609 /* setup size - EXT header has format "*size of this whole tag as ascii numbers* *space* *version code* *content* *newline* */
610 // size newline
bigbiffa957f072021-03-07 18:20:29 -0500611#ifdef USE_FSCRYPT_POLICY_V1
612 sz = FSCRYPT_TAG_LEN + sizeof(struct fscrypt_policy_v1) + 1 + 3 + 1;
613#else
614 sz = FSCRYPT_TAG_LEN + sizeof(struct fscrypt_policy_v2) + 1 + 3 + 1;
615#endif
bigbiff7ba75002020-04-11 20:47:09 -0400616
617 if(sz >= 100) // another ascci digit for size
618 ++sz;
619
620 if (total_sz + sz >= T_BLOCKSIZE)
621 {
622 if (th_write_extended(t, &buf[0], total_sz))
623 return -1;
624 ptr = buf;
625 total_sz = sz;
626 }
627 else
628 total_sz += sz;
629
630 snprintf(ptr, T_BLOCKSIZE, "%d "FSCRYPT_TAG"0", (int)sz);
bigbiffa957f072021-03-07 18:20:29 -0500631#ifdef USE_FSCRYPT_POLICY_V1
632 memcpy(ptr + sz - sizeof(struct fscrypt_policy_v1) - 1, t->th_buf.fep, sizeof(struct fscrypt_policy_v1));
633#else
634 memcpy(ptr + sz - sizeof(struct fscrypt_policy_v2) - 1, t->th_buf.fep, sizeof(struct fscrypt_policy_v2));
635#endif
bigbiff7ba75002020-04-11 20:47:09 -0400636 char *nlptr = ptr + sz - 1;
637 *nlptr = '\n';
638 ptr += sz;
639 }
640#endif
641
Ethan Yonker71187742017-01-13 13:30:10 -0600642 if((t->options & TAR_STORE_POSIX_CAP) && t->th_buf.has_cap_data)
643 {
644#ifdef DEBUG
Mohd Faraz15247642023-01-16 16:16:21 +0100645 LOG("th_write(): has a posix capability\n");
Ethan Yonker71187742017-01-13 13:30:10 -0600646#endif
647 sz = CAPABILITIES_TAG_LEN + sizeof(struct vfs_cap_data) + 3 + 1;
648
649 if(sz >= 100) // another ascci digit for size
650 ++sz;
651
652 if (total_sz + sz >= T_BLOCKSIZE)
653 {
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500654 if (th_write_extended(t, &buf[0], total_sz))
Ethan Yonker71187742017-01-13 13:30:10 -0600655 return -1;
656 ptr = buf;
657 total_sz = sz;
658 }
659 else
660 total_sz += sz;
661
662 snprintf(ptr, T_BLOCKSIZE, "%d "CAPABILITIES_TAG, (int)sz);
663 memcpy(ptr + CAPABILITIES_TAG_LEN + 3, &t->th_buf.cap_data, sizeof(struct vfs_cap_data));
664 char *nlptr = ptr + sz - 1;
665 *nlptr = '\n';
666 ptr += sz;
667 }
Ethan Yonker8d039f72017-02-03 14:26:15 -0600668 if (t->options & TAR_STORE_ANDROID_USER_XATTR)
669 {
670 if (t->th_buf.has_user_default) {
671#ifdef DEBUG
Mohd Faraz15247642023-01-16 16:16:21 +0100672 LOG("th_write(): has android user.default xattr\n");
Ethan Yonker8d039f72017-02-03 14:26:15 -0600673#endif
674 sz = ANDROID_USER_DEFAULT_TAG_LEN + 3 + 1;
675
676 if (total_sz + sz >= T_BLOCKSIZE)
677 {
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500678 if (th_write_extended(t, &buf[0], total_sz))
Ethan Yonker8d039f72017-02-03 14:26:15 -0600679 return -1;
680 ptr = buf;
681 total_sz = sz;
682 }
683 else
684 total_sz += sz;
685
686 snprintf(ptr, T_BLOCKSIZE, "%d "ANDROID_USER_DEFAULT_TAG, (int)sz);
687 char *nlptr = ptr + sz - 1;
688 *nlptr = '\n';
689 ptr += sz;
690 }
691 if (t->th_buf.has_user_cache) {
692#ifdef DEBUG
Mohd Faraz15247642023-01-16 16:16:21 +0100693 LOG("th_write(): has android user.inode_cache xattr\n");
Ethan Yonker8d039f72017-02-03 14:26:15 -0600694#endif
695 sz = ANDROID_USER_CACHE_TAG_LEN + 3 + 1;
696
697 if (total_sz + sz >= T_BLOCKSIZE)
698 {
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500699 if (th_write_extended(t, &buf[0], total_sz))
Ethan Yonker8d039f72017-02-03 14:26:15 -0600700 return -1;
701 ptr = buf;
702 total_sz = sz;
703 }
704 else
705 total_sz += sz;
706
707 snprintf(ptr, T_BLOCKSIZE, "%d "ANDROID_USER_CACHE_TAG, (int)sz);
708 char *nlptr = ptr + sz - 1;
709 *nlptr = '\n';
710 ptr += sz;
711 }
712 if (t->th_buf.has_user_code_cache) {
713#ifdef DEBUG
Mohd Faraz15247642023-01-16 16:16:21 +0100714 LOG("th_write(): has android user.inode_code_cache xattr\n");
Ethan Yonker8d039f72017-02-03 14:26:15 -0600715#endif
716 sz = ANDROID_USER_CODE_CACHE_TAG_LEN + 3 + 1;
717
718 if (total_sz + sz >= T_BLOCKSIZE)
719 {
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500720 if (th_write_extended(t, &buf[0], total_sz))
Ethan Yonker8d039f72017-02-03 14:26:15 -0600721 return -1;
722 ptr = buf;
723 total_sz = sz;
724 }
725 else
726 total_sz += sz;
727
728 snprintf(ptr, T_BLOCKSIZE, "%d "ANDROID_USER_CODE_CACHE_TAG, (int)sz);
729 char *nlptr = ptr + sz - 1;
730 *nlptr = '\n';
731 ptr += sz;
732 }
733 }
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500734 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 -0600735 return -1;
736
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500737 th_finish(t);
738
739#ifdef DEBUG
740 /* print tar header */
741 th_print(t);
742#endif
743
744 i = tar_block_write(t, &(t->th_buf));
745 if (i != T_BLOCKSIZE)
746 {
747 if (i != -1)
748 errno = EINVAL;
749 return -1;
750 }
751
752#ifdef DEBUG
Mohd Faraz15247642023-01-16 16:16:21 +0100753 LOG("th_write(): returning 0");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500754#endif
755 return 0;
756}
757
758