blob: d0adb2bcd3720224a1b63cd3e1e0f5e16ad98aee [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++;
360 if (start + sizeof(struct ext4_encryption_policy) != '\n')
361 printf("did not find newline char in expected location, continuing anyway...\n");
362 memcpy(t->th_buf.eep, start, sizeof(struct ext4_encryption_policy));
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600363#ifdef DEBUG
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500364 printf(" th_read(): E4Crypt policy v2 detected: %i %i %i %i %s\n",
365 (int)t->th_buf.eep->version,
366 (int)t->th_buf.eep->contents_encryption_mode,
367 (int)t->th_buf.eep->filenames_encryption_mode,
368 (int)t->th_buf.eep->flags,
369 t->th_buf.eep->master_key_descriptor);
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600370#endif
371 }
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500372 else
373 {
374 e4crypt_policy_fill_default_struct(t->th_buf.eep);
375 char *end = strchr(start, '\n');
376 if(!end)
377 end = strchr(start, '\0');
378 if(end)
379 {
380 strncpy(t->th_buf.eep->master_key_descriptor, start, end-start);
381#ifdef DEBUG
382 printf(" th_read(): E4Crypt policy v1 detected: %s\n", t->th_buf.eep->master_key_descriptor);
383#endif
384 }
385 }
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600386 }
Ethan Yonker71187742017-01-13 13:30:10 -0600387#endif // HAVE_EXT4_CRYPT
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600388 }
389
390 i = th_read_internal(t);
391 if (i != T_BLOCKSIZE)
392 {
393 if (i != -1)
394 errno = EINVAL;
395 return -1;
396 }
397 }
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600398
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500399 return 0;
400}
401
Ethan Yonker71187742017-01-13 13:30:10 -0600402/* write an extended block */
403static int
404th_write_extended(TAR *t, char* buf, uint64_t sz)
405{
406 char type2;
407 uint64_t sz2;
408 int i;
409
410 /* save old size and type */
411 type2 = t->th_buf.typeflag;
412 sz2 = th_get_size(t);
413
414 /* write out initial header block with fake size and type */
415 t->th_buf.typeflag = TH_EXT_TYPE;
416
417 if(sz >= T_BLOCKSIZE) // impossible
418 {
419 errno = EINVAL;
420 return -1;
421 }
422
423 th_set_size(t, sz);
424 th_finish(t);
425 i = tar_block_write(t, &(t->th_buf));
426 if (i != T_BLOCKSIZE)
427 {
428 if (i != -1)
429 errno = EINVAL;
430 return -1;
431 }
432
433 i = tar_block_write(t, buf);
434 if (i != T_BLOCKSIZE)
435 {
436 if (i != -1)
437 errno = EINVAL;
438 return -1;
439 }
440
441 /* reset type and size to original values */
442 t->th_buf.typeflag = type2;
443 th_set_size(t, sz2);
444 memset(buf, 0, T_BLOCKSIZE);
445 return 0;
446}
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500447
448/* write a header block */
449int
450th_write(TAR *t)
451{
452 int i, j;
453 char type2;
Ethan Yonker71187742017-01-13 13:30:10 -0600454 uint64_t sz, sz2, total_sz = 0;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500455 char *ptr;
456 char buf[T_BLOCKSIZE];
457
458#ifdef DEBUG
459 printf("==> th_write(TAR=\"%s\")\n", t->pathname);
460 th_print(t);
461#endif
462
463 if ((t->options & TAR_GNU) && t->th_buf.gnu_longlink != NULL)
464 {
465#ifdef DEBUG
466 printf("th_write(): using gnu_longlink (\"%s\")\n",
467 t->th_buf.gnu_longlink);
468#endif
469 /* save old size and type */
470 type2 = t->th_buf.typeflag;
471 sz2 = th_get_size(t);
472
473 /* write out initial header block with fake size and type */
474 t->th_buf.typeflag = GNU_LONGLINK_TYPE;
475 sz = strlen(t->th_buf.gnu_longlink);
476 th_set_size(t, sz);
477 th_finish(t);
478 i = tar_block_write(t, &(t->th_buf));
479 if (i != T_BLOCKSIZE)
480 {
481 if (i != -1)
482 errno = EINVAL;
483 return -1;
484 }
485
486 /* write out extra blocks containing long name */
487 for (j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0),
488 ptr = t->th_buf.gnu_longlink; j > 1;
489 j--, ptr += T_BLOCKSIZE)
490 {
491 i = tar_block_write(t, ptr);
492 if (i != T_BLOCKSIZE)
493 {
494 if (i != -1)
495 errno = EINVAL;
496 return -1;
497 }
498 }
499 memset(buf, 0, T_BLOCKSIZE);
500 strncpy(buf, ptr, T_BLOCKSIZE);
501 i = tar_block_write(t, &buf);
502 if (i != T_BLOCKSIZE)
503 {
504 if (i != -1)
505 errno = EINVAL;
506 return -1;
507 }
508
509 /* reset type and size to original values */
510 t->th_buf.typeflag = type2;
511 th_set_size(t, sz2);
512 }
513
514 if ((t->options & TAR_GNU) && t->th_buf.gnu_longname != NULL)
515 {
516#ifdef DEBUG
517 printf("th_write(): using gnu_longname (\"%s\")\n",
518 t->th_buf.gnu_longname);
519#endif
520 /* save old size and type */
521 type2 = t->th_buf.typeflag;
522 sz2 = th_get_size(t);
523
524 /* write out initial header block with fake size and type */
525 t->th_buf.typeflag = GNU_LONGNAME_TYPE;
526 sz = strlen(t->th_buf.gnu_longname);
527 th_set_size(t, sz);
528 th_finish(t);
529 i = tar_block_write(t, &(t->th_buf));
530 if (i != T_BLOCKSIZE)
531 {
532 if (i != -1)
533 errno = EINVAL;
534 return -1;
535 }
536
537 /* write out extra blocks containing long name */
538 for (j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0),
539 ptr = t->th_buf.gnu_longname; j > 1;
540 j--, ptr += T_BLOCKSIZE)
541 {
542 i = tar_block_write(t, ptr);
543 if (i != T_BLOCKSIZE)
544 {
545 if (i != -1)
546 errno = EINVAL;
547 return -1;
548 }
549 }
550 memset(buf, 0, T_BLOCKSIZE);
551 strncpy(buf, ptr, T_BLOCKSIZE);
552 i = tar_block_write(t, &buf);
553 if (i != T_BLOCKSIZE)
554 {
555 if (i != -1)
556 errno = EINVAL;
557 return -1;
558 }
559
560 /* reset type and size to original values */
561 t->th_buf.typeflag = type2;
562 th_set_size(t, sz2);
563 }
564
Ethan Yonker71187742017-01-13 13:30:10 -0600565 memset(buf, 0, T_BLOCKSIZE);
566 ptr = buf;
Matt Mower87413642017-01-17 21:14:46 -0600567
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200568 if((t->options & TAR_STORE_SELINUX) && t->th_buf.selinux_context != NULL)
569 {
570#ifdef DEBUG
571 printf("th_write(): using selinux_context (\"%s\")\n",
572 t->th_buf.selinux_context);
573#endif
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200574 /* setup size - EXT header has format "*size of this whole tag as ascii numbers* *space* *content* *newline* */
575 // size newline
576 sz = SELINUX_TAG_LEN + strlen(t->th_buf.selinux_context) + 3 + 1;
577
578 if(sz >= 100) // another ascci digit for size
579 ++sz;
580
Ethan Yonker71187742017-01-13 13:30:10 -0600581 total_sz += sz;
582 snprintf(ptr, T_BLOCKSIZE, "%d "SELINUX_TAG"%s\n", (int)sz, t->th_buf.selinux_context);
583 ptr += sz;
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200584 }
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200585
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600586#ifdef HAVE_EXT4_CRYPT
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500587 if((t->options & TAR_STORE_EXT4_POL) && t->th_buf.eep != NULL)
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600588 {
589#ifdef DEBUG
590 printf("th_write(): using e4crypt_policy %s\n",
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500591 t->th_buf.eep->master_key_descriptor);
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600592#endif
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500593 /* 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 -0600594 // size newline
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500595 sz = E4CRYPT_TAG_LEN + sizeof(struct ext4_encryption_policy) + 1 + 3 + 1;
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600596
597 if(sz >= 100) // another ascci digit for size
598 ++sz;
599
Ethan Yonker71187742017-01-13 13:30:10 -0600600 if (total_sz + sz >= T_BLOCKSIZE)
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600601 {
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500602 if (th_write_extended(t, &buf[0], total_sz))
Ethan Yonker71187742017-01-13 13:30:10 -0600603 return -1;
604 ptr = buf;
605 total_sz = sz;
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600606 }
Ethan Yonker71187742017-01-13 13:30:10 -0600607 else
608 total_sz += sz;
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600609
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500610 snprintf(ptr, T_BLOCKSIZE, "%d "E4CRYPT_TAG"2", (int)sz);
611 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 -0600612 char *nlptr = ptr + sz - 1;
613 *nlptr = '\n';
614 ptr += sz;
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600615 }
616#endif
617
Ethan Yonker71187742017-01-13 13:30:10 -0600618 if((t->options & TAR_STORE_POSIX_CAP) && t->th_buf.has_cap_data)
619 {
620#ifdef DEBUG
621 printf("th_write(): has a posix capability\n");
622#endif
623 sz = CAPABILITIES_TAG_LEN + sizeof(struct vfs_cap_data) + 3 + 1;
624
625 if(sz >= 100) // another ascci digit for size
626 ++sz;
627
628 if (total_sz + sz >= T_BLOCKSIZE)
629 {
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500630 if (th_write_extended(t, &buf[0], total_sz))
Ethan Yonker71187742017-01-13 13:30:10 -0600631 return -1;
632 ptr = buf;
633 total_sz = sz;
634 }
635 else
636 total_sz += sz;
637
638 snprintf(ptr, T_BLOCKSIZE, "%d "CAPABILITIES_TAG, (int)sz);
639 memcpy(ptr + CAPABILITIES_TAG_LEN + 3, &t->th_buf.cap_data, sizeof(struct vfs_cap_data));
640 char *nlptr = ptr + sz - 1;
641 *nlptr = '\n';
642 ptr += sz;
643 }
Ethan Yonker8d039f72017-02-03 14:26:15 -0600644 if (t->options & TAR_STORE_ANDROID_USER_XATTR)
645 {
646 if (t->th_buf.has_user_default) {
647#ifdef DEBUG
648 printf("th_write(): has android user.default xattr\n");
649#endif
650 sz = ANDROID_USER_DEFAULT_TAG_LEN + 3 + 1;
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 Yonker8d039f72017-02-03 14:26:15 -0600655 return -1;
656 ptr = buf;
657 total_sz = sz;
658 }
659 else
660 total_sz += sz;
661
662 snprintf(ptr, T_BLOCKSIZE, "%d "ANDROID_USER_DEFAULT_TAG, (int)sz);
663 char *nlptr = ptr + sz - 1;
664 *nlptr = '\n';
665 ptr += sz;
666 }
667 if (t->th_buf.has_user_cache) {
668#ifdef DEBUG
669 printf("th_write(): has android user.inode_cache xattr\n");
670#endif
671 sz = ANDROID_USER_CACHE_TAG_LEN + 3 + 1;
672
673 if (total_sz + sz >= T_BLOCKSIZE)
674 {
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500675 if (th_write_extended(t, &buf[0], total_sz))
Ethan Yonker8d039f72017-02-03 14:26:15 -0600676 return -1;
677 ptr = buf;
678 total_sz = sz;
679 }
680 else
681 total_sz += sz;
682
683 snprintf(ptr, T_BLOCKSIZE, "%d "ANDROID_USER_CACHE_TAG, (int)sz);
684 char *nlptr = ptr + sz - 1;
685 *nlptr = '\n';
686 ptr += sz;
687 }
688 if (t->th_buf.has_user_code_cache) {
689#ifdef DEBUG
690 printf("th_write(): has android user.inode_code_cache xattr\n");
691#endif
692 sz = ANDROID_USER_CODE_CACHE_TAG_LEN + 3 + 1;
693
694 if (total_sz + sz >= T_BLOCKSIZE)
695 {
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500696 if (th_write_extended(t, &buf[0], total_sz))
Ethan Yonker8d039f72017-02-03 14:26:15 -0600697 return -1;
698 ptr = buf;
699 total_sz = sz;
700 }
701 else
702 total_sz += sz;
703
704 snprintf(ptr, T_BLOCKSIZE, "%d "ANDROID_USER_CODE_CACHE_TAG, (int)sz);
705 char *nlptr = ptr + sz - 1;
706 *nlptr = '\n';
707 ptr += sz;
708 }
709 }
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500710 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 -0600711 return -1;
712
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500713 th_finish(t);
714
715#ifdef DEBUG
716 /* print tar header */
717 th_print(t);
718#endif
719
720 i = tar_block_write(t, &(t->th_buf));
721 if (i != T_BLOCKSIZE)
722 {
723 if (i != -1)
724 errno = EINVAL;
725 return -1;
726 }
727
728#ifdef DEBUG
729 puts("th_write(): returning 0");
730#endif
731 return 0;
732}
733
734