blob: 834c164ada68f363a2bd3b6cab9cf65248ac5db3 [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
Ethan Yonkerfefe5912017-09-30 22:22:13 -050021#ifdef HAVE_EXT4_CRYPT
22# include "ext4crypt_tar.h"
23#endif
24
bigbiff bigbiff9c754052013-01-09 09:09:08 -050025#define BIT_ISSET(bitmask, bit) ((bitmask) & (bit))
26
Vojtech Bocek25fd68d2013-08-27 03:10:10 +020027// Used to identify selinux_context in extended ('x')
28// metadata. From RedHat implementation.
29#define SELINUX_TAG "RHT.security.selinux="
Ethan Yonker8d039f72017-02-03 14:26:15 -060030#define SELINUX_TAG_LEN strlen(SELINUX_TAG)
bigbiff bigbiff9c754052013-01-09 09:09:08 -050031
Ethan Yonker79f88bd2016-12-09 14:52:12 -060032// Used to identify e4crypt_policy in extended ('x')
33#define E4CRYPT_TAG "TWRP.security.e4crypt="
Ethan Yonker8d039f72017-02-03 14:26:15 -060034#define E4CRYPT_TAG_LEN strlen(E4CRYPT_TAG)
Ethan Yonker79f88bd2016-12-09 14:52:12 -060035
Ethan Yonker71187742017-01-13 13:30:10 -060036// Used to identify Posix capabilities in extended ('x')
37#define CAPABILITIES_TAG "SCHILY.xattr.security.capability="
Ethan Yonker8d039f72017-02-03 14:26:15 -060038#define CAPABILITIES_TAG_LEN strlen(CAPABILITIES_TAG)
39
40// Used to identify Android user.default xattr in extended ('x')
41#define ANDROID_USER_DEFAULT_TAG "ANDROID.user.default"
42#define ANDROID_USER_DEFAULT_TAG_LEN strlen(ANDROID_USER_DEFAULT_TAG)
43
44// Used to identify Android user.inode_cache xattr in extended ('x')
45#define ANDROID_USER_CACHE_TAG "ANDROID.user.inode_cache"
46#define ANDROID_USER_CACHE_TAG_LEN strlen(ANDROID_USER_CACHE_TAG)
47
48// Used to identify Android user.inode_code_cache xattr in extended ('x')
49#define ANDROID_USER_CODE_CACHE_TAG "ANDROID.user.inode_code_cache"
50#define ANDROID_USER_CODE_CACHE_TAG_LEN strlen(ANDROID_USER_CODE_CACHE_TAG)
Ethan Yonker71187742017-01-13 13:30:10 -060051
bigbiff bigbiff9c754052013-01-09 09:09:08 -050052/* read a header block */
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050053/* FIXME: the return value of this function should match the return value
54 of tar_block_read(), which is a macro which references a prototype
55 that returns a ssize_t. So far, this is safe, since tar_block_read()
56 only ever reads 512 (T_BLOCKSIZE) bytes at a time, so any difference
57 in size of ssize_t and int is of negligible risk. BUT, if
58 T_BLOCKSIZE ever changes, or ever becomes a variable parameter
59 controllable by the user, all the code that calls it,
60 including this function and all code that calls it, should be
61 fixed for security reasons.
62 Thanks to Chris Palmer for the critique.
63*/
bigbiff bigbiff9c754052013-01-09 09:09:08 -050064int
65th_read_internal(TAR *t)
66{
67 int i;
68 int num_zero_blocks = 0;
69
70#ifdef DEBUG
71 printf("==> th_read_internal(TAR=\"%s\")\n", t->pathname);
72#endif
73
74 while ((i = tar_block_read(t, &(t->th_buf))) == T_BLOCKSIZE)
75 {
76 /* two all-zero blocks mark EOF */
77 if (t->th_buf.name[0] == '\0')
78 {
79 num_zero_blocks++;
80 if (!BIT_ISSET(t->options, TAR_IGNORE_EOT)
81 && num_zero_blocks >= 2)
82 return 0; /* EOF */
83 else
84 continue;
85 }
86
87 /* verify magic and version */
88 if (BIT_ISSET(t->options, TAR_CHECK_MAGIC)
89 && strncmp(t->th_buf.magic, TMAGIC, TMAGLEN - 1) != 0)
90 {
91#ifdef DEBUG
92 puts("!!! unknown magic value in tar header");
93#endif
94 return -2;
95 }
96
97 if (BIT_ISSET(t->options, TAR_CHECK_VERSION)
98 && strncmp(t->th_buf.version, TVERSION, TVERSLEN) != 0)
99 {
100#ifdef DEBUG
101 puts("!!! unknown version value in tar header");
102#endif
103 return -2;
104 }
105
106 /* check chksum */
107 if (!BIT_ISSET(t->options, TAR_IGNORE_CRC)
108 && !th_crc_ok(t))
109 {
110#ifdef DEBUG
111 puts("!!! tar header checksum error");
112#endif
113 return -2;
114 }
115
116 break;
117 }
118
119#ifdef DEBUG
120 printf("<== th_read_internal(): returning %d\n", i);
121#endif
122 return i;
123}
124
125
126/* wrapper function for th_read_internal() to handle GNU extensions */
127int
128th_read(TAR *t)
129{
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500130 int i;
131 size_t sz, j, blocks;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500132 char *ptr;
133
134#ifdef DEBUG
135 printf("==> th_read(t=0x%lx)\n", t);
136#endif
137
138 if (t->th_buf.gnu_longname != NULL)
139 free(t->th_buf.gnu_longname);
140 if (t->th_buf.gnu_longlink != NULL)
141 free(t->th_buf.gnu_longlink);
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200142 if (t->th_buf.selinux_context != NULL)
143 free(t->th_buf.selinux_context);
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600144#ifdef HAVE_EXT4_CRYPT
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500145 if (t->th_buf.eep != NULL)
146 free(t->th_buf.eep);
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600147#endif
Ethan Yonker71187742017-01-13 13:30:10 -0600148 if (t->th_buf.has_cap_data)
149 {
150 memset(&t->th_buf.cap_data, 0, sizeof(struct vfs_cap_data));
151 t->th_buf.has_cap_data = 0;
152 }
Ethan Yonker8d039f72017-02-03 14:26:15 -0600153 t->th_buf.has_user_default = 0;
154 t->th_buf.has_user_cache = 0;
155 t->th_buf.has_user_code_cache = 0;
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200156
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500157 memset(&(t->th_buf), 0, sizeof(struct tar_header));
158
159 i = th_read_internal(t);
160 if (i == 0)
161 return 1;
162 else if (i != T_BLOCKSIZE)
163 {
164 if (i != -1)
165 errno = EINVAL;
166 return -1;
167 }
168
169 /* check for GNU long link extention */
170 if (TH_ISLONGLINK(t))
171 {
172 sz = th_get_size(t);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500173 blocks = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0);
174 if (blocks > ((size_t)-1 / T_BLOCKSIZE))
175 {
176 errno = E2BIG;
177 return -1;
178 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500179#ifdef DEBUG
180 printf(" th_read(): GNU long linkname detected "
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500181 "(%ld bytes, %d blocks)\n", sz, blocks);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500182#endif
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500183 t->th_buf.gnu_longlink = (char *)malloc(blocks * T_BLOCKSIZE);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500184 if (t->th_buf.gnu_longlink == NULL)
185 return -1;
186
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500187 for (j = 0, ptr = t->th_buf.gnu_longlink; j < blocks;
188 j++, ptr += T_BLOCKSIZE)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500189 {
190#ifdef DEBUG
191 printf(" th_read(): reading long linkname "
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500192 "(%d blocks left, ptr == %ld)\n", blocks-j, ptr);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500193#endif
194 i = tar_block_read(t, ptr);
195 if (i != T_BLOCKSIZE)
196 {
197 if (i != -1)
198 errno = EINVAL;
199 return -1;
200 }
201#ifdef DEBUG
202 printf(" th_read(): read block == \"%s\"\n", ptr);
203#endif
204 }
205#ifdef DEBUG
206 printf(" th_read(): t->th_buf.gnu_longlink == \"%s\"\n",
207 t->th_buf.gnu_longlink);
208#endif
209
210 i = th_read_internal(t);
211 if (i != T_BLOCKSIZE)
212 {
213 if (i != -1)
214 errno = EINVAL;
215 return -1;
216 }
217 }
218
219 /* check for GNU long name extention */
220 if (TH_ISLONGNAME(t))
221 {
222 sz = th_get_size(t);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500223 blocks = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0);
224 if (blocks > ((size_t)-1 / T_BLOCKSIZE))
225 {
226 errno = E2BIG;
227 return -1;
228 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500229#ifdef DEBUG
230 printf(" th_read(): GNU long filename detected "
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500231 "(%ld bytes, %d blocks)\n", sz, blocks);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500232#endif
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500233 t->th_buf.gnu_longname = (char *)malloc(blocks * T_BLOCKSIZE);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500234 if (t->th_buf.gnu_longname == NULL)
235 return -1;
236
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500237 for (j = 0, ptr = t->th_buf.gnu_longname; j < blocks;
238 j++, ptr += T_BLOCKSIZE)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500239 {
240#ifdef DEBUG
241 printf(" th_read(): reading long filename "
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500242 "(%d blocks left, ptr == %ld)\n", blocks-j, ptr);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500243#endif
244 i = tar_block_read(t, ptr);
245 if (i != T_BLOCKSIZE)
246 {
247 if (i != -1)
248 errno = EINVAL;
249 return -1;
250 }
251#ifdef DEBUG
252 printf(" th_read(): read block == \"%s\"\n", ptr);
253#endif
254 }
255#ifdef DEBUG
256 printf(" th_read(): t->th_buf.gnu_longname == \"%s\"\n",
257 t->th_buf.gnu_longname);
258#endif
259
260 i = th_read_internal(t);
261 if (i != T_BLOCKSIZE)
262 {
263 if (i != -1)
264 errno = EINVAL;
265 return -1;
266 }
267 }
268
Ethan Yonker71187742017-01-13 13:30:10 -0600269 // Extended headers (selinux contexts, posix file capabilities, ext4 encryption policies)
270 while(TH_ISEXTHEADER(t) || TH_ISPOLHEADER(t))
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200271 {
272 sz = th_get_size(t);
273
274 if(sz >= T_BLOCKSIZE) // Not supported
275 {
276#ifdef DEBUG
277 printf(" th_read(): Extended header is too long!\n");
278#endif
279 }
280 else
281 {
282 char buf[T_BLOCKSIZE];
283 i = tar_block_read(t, buf);
284 if (i != T_BLOCKSIZE)
285 {
286 if (i != -1)
287 errno = EINVAL;
288 return -1;
289 }
290
291 // To be sure
292 buf[T_BLOCKSIZE-1] = 0;
293
294 int len = strlen(buf);
Ethan Yonker71187742017-01-13 13:30:10 -0600295 // posix capabilities
296 char *start = strstr(buf, CAPABILITIES_TAG);
Ethan Yonker8d039f72017-02-03 14:26:15 -0600297 if (start && start+CAPABILITIES_TAG_LEN < buf+len)
Ethan Yonker71187742017-01-13 13:30:10 -0600298 {
299 start += CAPABILITIES_TAG_LEN;
300 memcpy(&t->th_buf.cap_data, start, sizeof(struct vfs_cap_data));
301 t->th_buf.has_cap_data = 1;
302#ifdef DEBUG
303 printf(" th_read(): Posix capabilities detected\n");
304#endif
305 } // end posix capabilities
Matt Mower87413642017-01-17 21:14:46 -0600306 // selinux contexts
Ethan Yonker71187742017-01-13 13:30:10 -0600307 start = strstr(buf, SELINUX_TAG);
Ethan Yonker8d039f72017-02-03 14:26:15 -0600308 if (start && start+SELINUX_TAG_LEN < buf+len)
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200309 {
310 start += SELINUX_TAG_LEN;
311 char *end = strchr(start, '\n');
312 if(end)
313 {
314 t->th_buf.selinux_context = strndup(start, end-start);
315#ifdef DEBUG
316 printf(" th_read(): SELinux context xattr detected: %s\n", t->th_buf.selinux_context);
317#endif
318 }
Matt Mower87413642017-01-17 21:14:46 -0600319 } // end selinux contexts
Ethan Yonker8d039f72017-02-03 14:26:15 -0600320 // android user.default xattr
321 start = strstr(buf, ANDROID_USER_DEFAULT_TAG);
322 if (start)
323 {
324 t->th_buf.has_user_default = 1;
325#ifdef DEBUG
326 printf(" th_read(): android user.default xattr detected\n");
327#endif
328 } // end android user.default xattr
329 // android user.inode_cache xattr
330 start = strstr(buf, ANDROID_USER_CACHE_TAG);
331 if (start)
332 {
333 t->th_buf.has_user_cache = 1;
334#ifdef DEBUG
335 printf(" th_read(): android user.inode_cache xattr detected\n");
336#endif
337 } // end android user.inode_cache xattr
338 // android user.inode_code_cache xattr
339 start = strstr(buf, ANDROID_USER_CODE_CACHE_TAG);
340 if (start)
341 {
342 t->th_buf.has_user_code_cache = 1;
343#ifdef DEBUG
344 printf(" th_read(): android user.inode_code_cache xattr detected\n");
345#endif
346 } // end android user.inode_code_cache xattr
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600347#ifdef HAVE_EXT4_CRYPT
Ethan Yonker71187742017-01-13 13:30:10 -0600348 start = strstr(buf, E4CRYPT_TAG);
Ethan Yonker8d039f72017-02-03 14:26:15 -0600349 if (start && start+E4CRYPT_TAG_LEN < buf+len)
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600350 {
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500351 t->th_buf.eep = (struct ext4_encryption_policy*)malloc(sizeof(struct ext4_encryption_policy));
352 if (!t->th_buf.eep) {
353 printf("malloc ext4_encryption_policy\n");
354 return -1;
355 }
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600356 start += E4CRYPT_TAG_LEN;
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500357 if (*start == '2')
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600358 {
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500359 start++;
Ethan Yonker58f21322018-08-24 11:17:36 -0500360 char *newline_check = start + sizeof(struct ext4_encryption_policy);
361 if (*newline_check != '\n')
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500362 printf("did not find newline char in expected location, continuing anyway...\n");
363 memcpy(t->th_buf.eep, start, sizeof(struct ext4_encryption_policy));
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600364#ifdef DEBUG
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500365 printf(" th_read(): E4Crypt policy v2 detected: %i %i %i %i %s\n",
366 (int)t->th_buf.eep->version,
367 (int)t->th_buf.eep->contents_encryption_mode,
368 (int)t->th_buf.eep->filenames_encryption_mode,
369 (int)t->th_buf.eep->flags,
370 t->th_buf.eep->master_key_descriptor);
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600371#endif
372 }
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500373 else
374 {
375 e4crypt_policy_fill_default_struct(t->th_buf.eep);
376 char *end = strchr(start, '\n');
377 if(!end)
378 end = strchr(start, '\0');
379 if(end)
380 {
381 strncpy(t->th_buf.eep->master_key_descriptor, start, end-start);
382#ifdef DEBUG
383 printf(" th_read(): E4Crypt policy v1 detected: %s\n", t->th_buf.eep->master_key_descriptor);
384#endif
385 }
386 }
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600387 }
Ethan Yonker71187742017-01-13 13:30:10 -0600388#endif // HAVE_EXT4_CRYPT
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600389 }
390
391 i = th_read_internal(t);
392 if (i != T_BLOCKSIZE)
393 {
394 if (i != -1)
395 errno = EINVAL;
396 return -1;
397 }
398 }
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600399
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500400 return 0;
401}
402
Ethan Yonker71187742017-01-13 13:30:10 -0600403/* write an extended block */
404static int
405th_write_extended(TAR *t, char* buf, uint64_t sz)
406{
407 char type2;
408 uint64_t sz2;
409 int i;
410
411 /* save old size and type */
412 type2 = t->th_buf.typeflag;
413 sz2 = th_get_size(t);
414
415 /* write out initial header block with fake size and type */
416 t->th_buf.typeflag = TH_EXT_TYPE;
417
418 if(sz >= T_BLOCKSIZE) // impossible
419 {
420 errno = EINVAL;
421 return -1;
422 }
423
424 th_set_size(t, sz);
425 th_finish(t);
426 i = tar_block_write(t, &(t->th_buf));
427 if (i != T_BLOCKSIZE)
428 {
429 if (i != -1)
430 errno = EINVAL;
431 return -1;
432 }
433
434 i = tar_block_write(t, buf);
435 if (i != T_BLOCKSIZE)
436 {
437 if (i != -1)
438 errno = EINVAL;
439 return -1;
440 }
441
442 /* reset type and size to original values */
443 t->th_buf.typeflag = type2;
444 th_set_size(t, sz2);
445 memset(buf, 0, T_BLOCKSIZE);
446 return 0;
447}
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500448
449/* write a header block */
450int
451th_write(TAR *t)
452{
453 int i, j;
454 char type2;
Ethan Yonker71187742017-01-13 13:30:10 -0600455 uint64_t sz, sz2, total_sz = 0;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500456 char *ptr;
457 char buf[T_BLOCKSIZE];
458
459#ifdef DEBUG
460 printf("==> th_write(TAR=\"%s\")\n", t->pathname);
461 th_print(t);
462#endif
463
464 if ((t->options & TAR_GNU) && t->th_buf.gnu_longlink != NULL)
465 {
466#ifdef DEBUG
467 printf("th_write(): using gnu_longlink (\"%s\")\n",
468 t->th_buf.gnu_longlink);
469#endif
470 /* save old size and type */
471 type2 = t->th_buf.typeflag;
472 sz2 = th_get_size(t);
473
474 /* write out initial header block with fake size and type */
475 t->th_buf.typeflag = GNU_LONGLINK_TYPE;
476 sz = strlen(t->th_buf.gnu_longlink);
477 th_set_size(t, sz);
478 th_finish(t);
479 i = tar_block_write(t, &(t->th_buf));
480 if (i != T_BLOCKSIZE)
481 {
482 if (i != -1)
483 errno = EINVAL;
484 return -1;
485 }
486
487 /* write out extra blocks containing long name */
488 for (j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0),
489 ptr = t->th_buf.gnu_longlink; j > 1;
490 j--, ptr += T_BLOCKSIZE)
491 {
492 i = tar_block_write(t, ptr);
493 if (i != T_BLOCKSIZE)
494 {
495 if (i != -1)
496 errno = EINVAL;
497 return -1;
498 }
499 }
500 memset(buf, 0, T_BLOCKSIZE);
501 strncpy(buf, ptr, T_BLOCKSIZE);
502 i = tar_block_write(t, &buf);
503 if (i != T_BLOCKSIZE)
504 {
505 if (i != -1)
506 errno = EINVAL;
507 return -1;
508 }
509
510 /* reset type and size to original values */
511 t->th_buf.typeflag = type2;
512 th_set_size(t, sz2);
513 }
514
515 if ((t->options & TAR_GNU) && t->th_buf.gnu_longname != NULL)
516 {
517#ifdef DEBUG
518 printf("th_write(): using gnu_longname (\"%s\")\n",
519 t->th_buf.gnu_longname);
520#endif
521 /* save old size and type */
522 type2 = t->th_buf.typeflag;
523 sz2 = th_get_size(t);
524
525 /* write out initial header block with fake size and type */
526 t->th_buf.typeflag = GNU_LONGNAME_TYPE;
527 sz = strlen(t->th_buf.gnu_longname);
528 th_set_size(t, sz);
529 th_finish(t);
530 i = tar_block_write(t, &(t->th_buf));
531 if (i != T_BLOCKSIZE)
532 {
533 if (i != -1)
534 errno = EINVAL;
535 return -1;
536 }
537
538 /* write out extra blocks containing long name */
539 for (j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0),
540 ptr = t->th_buf.gnu_longname; j > 1;
541 j--, ptr += T_BLOCKSIZE)
542 {
543 i = tar_block_write(t, ptr);
544 if (i != T_BLOCKSIZE)
545 {
546 if (i != -1)
547 errno = EINVAL;
548 return -1;
549 }
550 }
551 memset(buf, 0, T_BLOCKSIZE);
552 strncpy(buf, ptr, T_BLOCKSIZE);
553 i = tar_block_write(t, &buf);
554 if (i != T_BLOCKSIZE)
555 {
556 if (i != -1)
557 errno = EINVAL;
558 return -1;
559 }
560
561 /* reset type and size to original values */
562 t->th_buf.typeflag = type2;
563 th_set_size(t, sz2);
564 }
565
Ethan Yonker71187742017-01-13 13:30:10 -0600566 memset(buf, 0, T_BLOCKSIZE);
567 ptr = buf;
Matt Mower87413642017-01-17 21:14:46 -0600568
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200569 if((t->options & TAR_STORE_SELINUX) && t->th_buf.selinux_context != NULL)
570 {
571#ifdef DEBUG
572 printf("th_write(): using selinux_context (\"%s\")\n",
573 t->th_buf.selinux_context);
574#endif
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200575 /* setup size - EXT header has format "*size of this whole tag as ascii numbers* *space* *content* *newline* */
576 // size newline
577 sz = SELINUX_TAG_LEN + strlen(t->th_buf.selinux_context) + 3 + 1;
578
579 if(sz >= 100) // another ascci digit for size
580 ++sz;
581
Ethan Yonker71187742017-01-13 13:30:10 -0600582 total_sz += sz;
583 snprintf(ptr, T_BLOCKSIZE, "%d "SELINUX_TAG"%s\n", (int)sz, t->th_buf.selinux_context);
584 ptr += sz;
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200585 }
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200586
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600587#ifdef HAVE_EXT4_CRYPT
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500588 if((t->options & TAR_STORE_EXT4_POL) && t->th_buf.eep != NULL)
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600589 {
590#ifdef DEBUG
591 printf("th_write(): using e4crypt_policy %s\n",
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500592 t->th_buf.eep->master_key_descriptor);
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600593#endif
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500594 /* 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 -0600595 // size newline
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500596 sz = E4CRYPT_TAG_LEN + sizeof(struct ext4_encryption_policy) + 1 + 3 + 1;
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600597
598 if(sz >= 100) // another ascci digit for size
599 ++sz;
600
Ethan Yonker71187742017-01-13 13:30:10 -0600601 if (total_sz + sz >= T_BLOCKSIZE)
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600602 {
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500603 if (th_write_extended(t, &buf[0], total_sz))
Ethan Yonker71187742017-01-13 13:30:10 -0600604 return -1;
605 ptr = buf;
606 total_sz = sz;
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600607 }
Ethan Yonker71187742017-01-13 13:30:10 -0600608 else
609 total_sz += sz;
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600610
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500611 snprintf(ptr, T_BLOCKSIZE, "%d "E4CRYPT_TAG"2", (int)sz);
612 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 -0600613 char *nlptr = ptr + sz - 1;
614 *nlptr = '\n';
615 ptr += sz;
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600616 }
617#endif
618
Ethan Yonker71187742017-01-13 13:30:10 -0600619 if((t->options & TAR_STORE_POSIX_CAP) && t->th_buf.has_cap_data)
620 {
621#ifdef DEBUG
622 printf("th_write(): has a posix capability\n");
623#endif
624 sz = CAPABILITIES_TAG_LEN + sizeof(struct vfs_cap_data) + 3 + 1;
625
626 if(sz >= 100) // another ascci digit for size
627 ++sz;
628
629 if (total_sz + sz >= T_BLOCKSIZE)
630 {
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500631 if (th_write_extended(t, &buf[0], total_sz))
Ethan Yonker71187742017-01-13 13:30:10 -0600632 return -1;
633 ptr = buf;
634 total_sz = sz;
635 }
636 else
637 total_sz += sz;
638
639 snprintf(ptr, T_BLOCKSIZE, "%d "CAPABILITIES_TAG, (int)sz);
640 memcpy(ptr + CAPABILITIES_TAG_LEN + 3, &t->th_buf.cap_data, sizeof(struct vfs_cap_data));
641 char *nlptr = ptr + sz - 1;
642 *nlptr = '\n';
643 ptr += sz;
644 }
Ethan Yonker8d039f72017-02-03 14:26:15 -0600645 if (t->options & TAR_STORE_ANDROID_USER_XATTR)
646 {
647 if (t->th_buf.has_user_default) {
648#ifdef DEBUG
649 printf("th_write(): has android user.default xattr\n");
650#endif
651 sz = ANDROID_USER_DEFAULT_TAG_LEN + 3 + 1;
652
653 if (total_sz + sz >= T_BLOCKSIZE)
654 {
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500655 if (th_write_extended(t, &buf[0], total_sz))
Ethan Yonker8d039f72017-02-03 14:26:15 -0600656 return -1;
657 ptr = buf;
658 total_sz = sz;
659 }
660 else
661 total_sz += sz;
662
663 snprintf(ptr, T_BLOCKSIZE, "%d "ANDROID_USER_DEFAULT_TAG, (int)sz);
664 char *nlptr = ptr + sz - 1;
665 *nlptr = '\n';
666 ptr += sz;
667 }
668 if (t->th_buf.has_user_cache) {
669#ifdef DEBUG
670 printf("th_write(): has android user.inode_cache xattr\n");
671#endif
672 sz = ANDROID_USER_CACHE_TAG_LEN + 3 + 1;
673
674 if (total_sz + sz >= T_BLOCKSIZE)
675 {
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500676 if (th_write_extended(t, &buf[0], total_sz))
Ethan Yonker8d039f72017-02-03 14:26:15 -0600677 return -1;
678 ptr = buf;
679 total_sz = sz;
680 }
681 else
682 total_sz += sz;
683
684 snprintf(ptr, T_BLOCKSIZE, "%d "ANDROID_USER_CACHE_TAG, (int)sz);
685 char *nlptr = ptr + sz - 1;
686 *nlptr = '\n';
687 ptr += sz;
688 }
689 if (t->th_buf.has_user_code_cache) {
690#ifdef DEBUG
691 printf("th_write(): has android user.inode_code_cache xattr\n");
692#endif
693 sz = ANDROID_USER_CODE_CACHE_TAG_LEN + 3 + 1;
694
695 if (total_sz + sz >= T_BLOCKSIZE)
696 {
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500697 if (th_write_extended(t, &buf[0], total_sz))
Ethan Yonker8d039f72017-02-03 14:26:15 -0600698 return -1;
699 ptr = buf;
700 total_sz = sz;
701 }
702 else
703 total_sz += sz;
704
705 snprintf(ptr, T_BLOCKSIZE, "%d "ANDROID_USER_CODE_CACHE_TAG, (int)sz);
706 char *nlptr = ptr + sz - 1;
707 *nlptr = '\n';
708 ptr += sz;
709 }
710 }
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500711 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 -0600712 return -1;
713
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500714 th_finish(t);
715
716#ifdef DEBUG
717 /* print tar header */
718 th_print(t);
719#endif
720
721 i = tar_block_write(t, &(t->th_buf));
722 if (i != T_BLOCKSIZE)
723 {
724 if (i != -1)
725 errno = EINVAL;
726 return -1;
727 }
728
729#ifdef DEBUG
730 puts("th_write(): returning 0");
731#endif
732 return 0;
733}
734
735