blob: 66d9943e1dbca653eb4db4753e1aca20cdb17978 [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** append.c - libtar code to append files to a tar archive
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>
14
15#include <stdio.h>
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050016#include <stdlib.h>
17#include <string.h>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050018#include <errno.h>
19#include <fcntl.h>
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050020#include <time.h>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050021#include <sys/param.h>
22#include <sys/types.h>
Ethan Yonker79f88bd2016-12-09 14:52:12 -060023#include <stdbool.h>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050024
Ethan Yonker71187742017-01-13 13:30:10 -060025#include <sys/capability.h>
26#include <sys/xattr.h>
bigbiff7ba75002020-04-11 20:47:09 -040027#include <linux/fs.h>
Ethan Yonker71187742017-01-13 13:30:10 -060028#include <linux/xattr.h>
29
bigbiff bigbiff9c754052013-01-09 09:09:08 -050030#ifdef STDC_HEADERS
bigbiff7ba75002020-04-11 20:47:09 -040031#include <stdlib.h>
32#include <string.h>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050033#endif
34
35#ifdef HAVE_UNISTD_H
bigbiff7ba75002020-04-11 20:47:09 -040036#include <unistd.h>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050037#endif
38
Matt Mower87413642017-01-17 21:14:46 -060039#include <selinux/selinux.h>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050040
bigbiff7ba75002020-04-11 20:47:09 -040041#ifdef USE_FSCRYPT
42#include "fscrypt_policy.h"
43#endif
44
Ethan Yonker8d039f72017-02-03 14:26:15 -060045#include "android_utils.h"
Ethan Yonker79f88bd2016-12-09 14:52:12 -060046
bigbiffa957f072021-03-07 18:20:29 -050047#ifdef TW_LIBTAR_DEBUG
48#define DEBUG 1
49#endif
50
bigbiff bigbiff9c754052013-01-09 09:09:08 -050051struct tar_dev
52{
53 dev_t td_dev;
54 libtar_hash_t *td_h;
55};
56typedef struct tar_dev tar_dev_t;
57
58struct tar_ino
59{
60 ino_t ti_ino;
61 char ti_name[MAXPATHLEN];
62};
63typedef struct tar_ino tar_ino_t;
64
65
66/* free memory associated with a tar_dev_t */
67void
68tar_dev_free(tar_dev_t *tdp)
69{
70 libtar_hash_free(tdp->td_h, free);
71 free(tdp);
72}
73
74
75/* appends a file to the tar archive */
76int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050077tar_append_file(TAR *t, const char *realname, const char *savename)
bigbiff bigbiff9c754052013-01-09 09:09:08 -050078{
79 struct stat s;
80 int i;
81 libtar_hashptr_t hp;
82 tar_dev_t *td = NULL;
83 tar_ino_t *ti = NULL;
84 char path[MAXPATHLEN];
85
86#ifdef DEBUG
Mohd Faraz566ef6b2023-01-16 16:16:21 +010087 LOG("==> tar_append_file(TAR=0x%p (\"%s\"), realname=\"%s\", "
bigbiffa957f072021-03-07 18:20:29 -050088 "savename=\"%s\")\n", (void*) t, t->pathname, realname,
bigbiff bigbiff9c754052013-01-09 09:09:08 -050089 (savename ? savename : "[NULL]"));
90#endif
91
92 if (lstat(realname, &s) != 0)
93 {
94#ifdef DEBUG
95 perror("lstat()");
96#endif
97 return -1;
98 }
99
100 /* set header block */
101#ifdef DEBUG
Mohd Faraz566ef6b2023-01-16 16:16:21 +0100102 LOG("tar_append_file(): setting header block...");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500103#endif
104 memset(&(t->th_buf), 0, sizeof(struct tar_header));
105 th_set_from_stat(t, &s);
106
107 /* set the header path */
108#ifdef DEBUG
Mohd Faraz566ef6b2023-01-16 16:16:21 +0100109 LOG("tar_append_file(): setting header path...");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500110#endif
111 th_set_path(t, (savename ? savename : realname));
112
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200113 /* get selinux context */
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500114 if (t->options & TAR_STORE_SELINUX)
115 {
116 if (t->th_buf.selinux_context != NULL)
117 {
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200118 free(t->th_buf.selinux_context);
119 t->th_buf.selinux_context = NULL;
120 }
121
122 security_context_t selinux_context = NULL;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500123 if (lgetfilecon(realname, &selinux_context) >= 0)
124 {
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200125 t->th_buf.selinux_context = strdup(selinux_context);
Mohd Faraz566ef6b2023-01-16 16:16:21 +0100126 LOG(" ==> set selinux context: %s\n", selinux_context);
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200127 freecon(selinux_context);
128 }
129 else
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500130 {
131#ifdef DEBUG
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200132 perror("Failed to get selinux context");
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500133#endif
134 }
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200135 }
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500136
bigbiff7ba75002020-04-11 20:47:09 -0400137#ifdef USE_FSCRYPT
138 if (TH_ISDIR(t) && t->options & TAR_STORE_FSCRYPT_POL)
139 {
140 if (t->th_buf.fep != NULL)
141 {
142 free(t->th_buf.fep);
143 t->th_buf.fep = NULL;
144 }
bigbiffa957f072021-03-07 18:20:29 -0500145#ifdef USE_FSCRYPT_POLICY_V1
146 t->th_buf.fep = (struct fscrypt_policy_v1 *)malloc(sizeof(struct fscrypt_policy_v1));
147#else
148 t->th_buf.fep = (struct fscrypt_policy_v2 *)malloc(sizeof(struct fscrypt_policy_v2));
149#endif
bigbiff7ba75002020-04-11 20:47:09 -0400150 if (!t->th_buf.fep) {
Mohd Faraz566ef6b2023-01-16 16:16:21 +0100151 LOG("malloc fs_encryption_policy\n");
bigbiff7ba75002020-04-11 20:47:09 -0400152 return -1;
153 }
154
155 if (fscrypt_policy_get_struct(realname, t->th_buf.fep)) {
bigbiff2e344ab2021-05-07 10:41:55 -0400156#ifdef USE_FSCRYPT_POLICY_V1
157 uint8_t tar_policy[FS_KEY_DESCRIPTOR_SIZE];
158 char policy_hex[FS_KEY_DESCRIPTOR_SIZE_HEX];
159#else
bigbiffa957f072021-03-07 18:20:29 -0500160 uint8_t tar_policy[FSCRYPT_KEY_IDENTIFIER_SIZE];
bigbiffa957f072021-03-07 18:20:29 -0500161 char policy_hex[FSCRYPT_KEY_IDENTIFIER_HEX_SIZE];
bigbiff2e344ab2021-05-07 10:41:55 -0400162#endif
163 memset(tar_policy, 0, sizeof(tar_policy));
164#ifdef USE_FSCRYPT_POLICY_V1
165 bytes_to_hex(t->th_buf.fep->master_key_descriptor, FS_KEY_DESCRIPTOR_SIZE, policy_hex);
166#else
bigbiffa957f072021-03-07 18:20:29 -0500167 bytes_to_hex(t->th_buf.fep->master_key_identifier, FSCRYPT_KEY_IDENTIFIER_SIZE, policy_hex);
bigbiff2e344ab2021-05-07 10:41:55 -0400168#endif
bigbiffa957f072021-03-07 18:20:29 -0500169 if (lookup_ref_key(t->th_buf.fep, &tar_policy[0])) {
bigbiff2e344ab2021-05-07 10:41:55 -0400170 if (strncmp((char *) tar_policy, USER_CE_FSCRYPT_POLICY, sizeof(USER_CE_FSCRYPT_POLICY) - 1) == 0
171 || strncmp((char *) tar_policy, USER_DE_FSCRYPT_POLICY, sizeof(USER_DE_FSCRYPT_POLICY) - 1) == 0
172 || strncmp((char *) tar_policy, SYSTEM_DE_FSCRYPT_POLICY, sizeof(SYSTEM_DE_FSCRYPT_POLICY)) == 0) {
173#ifdef USE_FSCRYPT_POLICY_V1
174 memcpy(t->th_buf.fep->master_key_descriptor, tar_policy, FS_KEY_DESCRIPTOR_SIZE);
Mohd Faraz566ef6b2023-01-16 16:16:21 +0100175 LOG("found fscrypt policy '%s' - '%s' - '%s'\n", realname, t->th_buf.fep->master_key_descriptor, policy_hex);
bigbiff2e344ab2021-05-07 10:41:55 -0400176#else
bigbiffa957f072021-03-07 18:20:29 -0500177 memcpy(t->th_buf.fep->master_key_identifier, tar_policy, FSCRYPT_KEY_IDENTIFIER_SIZE);
Mohd Faraz566ef6b2023-01-16 16:16:21 +0100178 LOG("found fscrypt policy '%s' - '%s' - '%s'\n", realname, t->th_buf.fep->master_key_identifier, policy_hex);
bigbiff2e344ab2021-05-07 10:41:55 -0400179#endif
bigbiffa957f072021-03-07 18:20:29 -0500180 } else {
Mohd Faraz566ef6b2023-01-16 16:16:21 +0100181 LOG("failed to match fscrypt tar policy for '%s' - '%s'\n", realname, policy_hex);
bigbiffa957f072021-03-07 18:20:29 -0500182 free(t->th_buf.fep);
183 t->th_buf.fep = NULL;
184 }
bigbiff7ba75002020-04-11 20:47:09 -0400185 } else {
Mohd Faraz566ef6b2023-01-16 16:16:21 +0100186 LOG("failed to lookup fscrypt tar policy for '%s' - '%s'\n", realname, policy_hex);
bigbiff7ba75002020-04-11 20:47:09 -0400187 free(t->th_buf.fep);
188 t->th_buf.fep = NULL;
bigbiff7ba75002020-04-11 20:47:09 -0400189 }
190 }
191 else {
192 // no policy found, but this is not an error as not all dirs will have a policy
193 free(t->th_buf.fep);
194 t->th_buf.fep = NULL;
195 }
196 }
197#endif
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600198
Ethan Yonker71187742017-01-13 13:30:10 -0600199 /* get posix file capabilities */
200 if (TH_ISREG(t) && t->options & TAR_STORE_POSIX_CAP)
201 {
202 if (t->th_buf.has_cap_data)
203 {
204 memset(&t->th_buf.cap_data, 0, sizeof(struct vfs_cap_data));
205 t->th_buf.has_cap_data = 0;
206 }
207
208 if (getxattr(realname, XATTR_NAME_CAPS, &t->th_buf.cap_data, sizeof(struct vfs_cap_data)) >= 0)
209 {
210 t->th_buf.has_cap_data = 1;
211#if 1 //def DEBUG
212 print_caps(&t->th_buf.cap_data);
213#endif
214 }
215 }
216
Ethan Yonker8d039f72017-02-03 14:26:15 -0600217 /* get android user.default xattr */
218 if (TH_ISDIR(t) && t->options & TAR_STORE_ANDROID_USER_XATTR)
219 {
220 if (getxattr(realname, "user.default", NULL, 0) >= 0)
221 {
222 t->th_buf.has_user_default = 1;
223#if 1 //def DEBUG
Mohd Faraz566ef6b2023-01-16 16:16:21 +0100224 LOG("storing xattr user.default\n");
Ethan Yonker8d039f72017-02-03 14:26:15 -0600225#endif
226 }
227 if (getxattr(realname, "user.inode_cache", NULL, 0) >= 0)
228 {
229 t->th_buf.has_user_cache = 1;
230#if 1 //def DEBUG
Mohd Faraz566ef6b2023-01-16 16:16:21 +0100231 LOG("storing xattr user.inode_cache\n");
Ethan Yonker8d039f72017-02-03 14:26:15 -0600232#endif
233 }
234 if (getxattr(realname, "user.inode_code_cache", NULL, 0) >= 0)
235 {
236 t->th_buf.has_user_code_cache = 1;
237#if 1 //def DEBUG
Mohd Faraz566ef6b2023-01-16 16:16:21 +0100238 LOG("storing xattr user.inode_code_cache\n");
Ethan Yonker8d039f72017-02-03 14:26:15 -0600239#endif
240 }
241 }
242
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500243 /* check if it's a hardlink */
244#ifdef DEBUG
Mohd Faraz566ef6b2023-01-16 16:16:21 +0100245 LOG("tar_append_file(): checking inode cache for hardlink...");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500246#endif
247 libtar_hashptr_reset(&hp);
248 if (libtar_hash_getkey(t->h, &hp, &(s.st_dev),
249 (libtar_matchfunc_t)dev_match) != 0)
250 td = (tar_dev_t *)libtar_hashptr_data(&hp);
251 else
252 {
253#ifdef DEBUG
Mohd Faraz566ef6b2023-01-16 16:16:21 +0100254 LOG("+++ adding hash for device (0x%x, 0x%x)...\n",
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500255 major(s.st_dev), minor(s.st_dev));
256#endif
257 td = (tar_dev_t *)calloc(1, sizeof(tar_dev_t));
258 td->td_dev = s.st_dev;
259 td->td_h = libtar_hash_new(256, (libtar_hashfunc_t)ino_hash);
260 if (td->td_h == NULL)
261 return -1;
262 if (libtar_hash_add(t->h, td) == -1)
263 return -1;
264 }
265 libtar_hashptr_reset(&hp);
266 if (libtar_hash_getkey(td->td_h, &hp, &(s.st_ino),
267 (libtar_matchfunc_t)ino_match) != 0)
268 {
269 ti = (tar_ino_t *)libtar_hashptr_data(&hp);
270#ifdef DEBUG
Mohd Faraz566ef6b2023-01-16 16:16:21 +0100271 LOG(" tar_append_file(): encoding hard link \"%s\" "
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500272 "to \"%s\"...\n", realname, ti->ti_name);
273#endif
274 t->th_buf.typeflag = LNKTYPE;
275 th_set_link(t, ti->ti_name);
276 }
277 else
278 {
279#ifdef DEBUG
Mohd Faraz566ef6b2023-01-16 16:16:21 +0100280 LOG("+++ adding entry: device (0x%d,0x%x), inode %lu"
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500281 "(\"%s\")...\n", major(s.st_dev), minor(s.st_dev),
bigbiffa957f072021-03-07 18:20:29 -0500282 (unsigned long) s.st_ino, realname);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500283#endif
284 ti = (tar_ino_t *)calloc(1, sizeof(tar_ino_t));
285 if (ti == NULL)
286 return -1;
287 ti->ti_ino = s.st_ino;
288 snprintf(ti->ti_name, sizeof(ti->ti_name), "%s",
289 savename ? savename : realname);
290 libtar_hash_add(td->td_h, ti);
291 }
292
293 /* check if it's a symlink */
294 if (TH_ISSYM(t))
295 {
296 i = readlink(realname, path, sizeof(path));
297 if (i == -1)
298 return -1;
299 if (i >= MAXPATHLEN)
300 i = MAXPATHLEN - 1;
301 path[i] = '\0';
302#ifdef DEBUG
Mohd Faraz566ef6b2023-01-16 16:16:21 +0100303 LOG("tar_append_file(): encoding symlink \"%s\" -> "
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500304 "\"%s\"...\n", realname, path);
305#endif
306 th_set_link(t, path);
307 }
308
309 /* print file info */
310 if (t->options & TAR_VERBOSE)
Mohd Faraz566ef6b2023-01-16 16:16:21 +0100311 LOG("%s\n", th_get_pathname(t));
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500312
313#ifdef DEBUG
Mohd Faraz566ef6b2023-01-16 16:16:21 +0100314 LOG("tar_append_file(): writing header");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500315#endif
316 /* write header */
317 if (th_write(t) != 0)
318 {
319#ifdef DEBUG
Mohd Faraz566ef6b2023-01-16 16:16:21 +0100320 LOG("t->fd = %ld\n", t->fd);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500321#endif
322 return -1;
323 }
324#ifdef DEBUG
Mohd Faraz566ef6b2023-01-16 16:16:21 +0100325 LOG("tar_append_file(): back from th_write()");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500326#endif
327
328 /* if it's a regular file, write the contents as well */
329 if (TH_ISREG(t) && tar_append_regfile(t, realname) != 0)
330 return -1;
331
332 return 0;
333}
334
335
336/* write EOF indicator */
337int
338tar_append_eof(TAR *t)
339{
340 int i, j;
341 char block[T_BLOCKSIZE];
342
343 memset(&block, 0, T_BLOCKSIZE);
344 for (j = 0; j < 2; j++)
345 {
346 i = tar_block_write(t, &block);
347 if (i != T_BLOCKSIZE)
348 {
349 if (i != -1)
350 errno = EINVAL;
351 return -1;
352 }
353 }
354
355 return 0;
356}
357
358
359/* add file contents to a tarchive */
360int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500361tar_append_regfile(TAR *t, const char *realname)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500362{
363 char block[T_BLOCKSIZE];
364 int filefd;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500365 int64_t i, size;
366 ssize_t j;
367 int rv = -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500368
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500369#if defined(O_BINARY)
370 filefd = open(realname, O_RDONLY|O_BINARY);
371#else
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500372 filefd = open(realname, O_RDONLY);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500373#endif
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500374 if (filefd == -1)
375 {
376#ifdef DEBUG
377 perror("open()");
378#endif
379 return -1;
380 }
381
382 size = th_get_size(t);
383 for (i = size; i > T_BLOCKSIZE; i -= T_BLOCKSIZE)
384 {
385 j = read(filefd, &block, T_BLOCKSIZE);
386 if (j != T_BLOCKSIZE)
387 {
388 if (j != -1)
389 errno = EINVAL;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500390 goto fail;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500391 }
392 if (tar_block_write(t, &block) == -1)
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500393 goto fail;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500394 }
395
396 if (i > 0)
397 {
398 j = read(filefd, &block, i);
399 if (j == -1)
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500400 goto fail;
401 memset(&(block[i]), 0, T_BLOCKSIZE - i);
402 if (tar_block_write(t, &block) == -1)
403 goto fail;
404 }
405
406 /* success! */
407 rv = 0;
408fail:
409 close(filefd);
410
411 return rv;
412}
413
414
415/* add file contents to a tarchive */
416int
417tar_append_file_contents(TAR *t, const char *savename, mode_t mode,
418 uid_t uid, gid_t gid, void *buf, size_t len)
419{
420 struct stat st;
421
422 memset(&st, 0, sizeof(st));
423 st.st_mode = S_IFREG | mode;
424 st.st_uid = uid;
425 st.st_gid = gid;
426 st.st_mtime = time(NULL);
427 st.st_size = len;
428
429 th_set_from_stat(t, &st);
430 th_set_path(t, savename);
431
432 /* write header */
433 if (th_write(t) != 0)
434 {
435#ifdef DEBUG
bigbiffa957f072021-03-07 18:20:29 -0500436 fprintf(stderr, "tar_append_file_contents(): could not write header, t->fd = %ld\n", t->fd);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500437#endif
438 return -1;
439 }
440
441 return tar_append_buffer(t, buf, len);
442}
443
444int
445tar_append_buffer(TAR *t, void *buf, size_t len)
446{
447 char block[T_BLOCKSIZE];
Ethan Yonker58f21322018-08-24 11:17:36 -0500448 int i;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500449 size_t size = len;
450
451 for (i = size; i > T_BLOCKSIZE; i -= T_BLOCKSIZE)
452 {
453 if (tar_block_write(t, buf) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500454 return -1;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500455 buf = (char *)buf + T_BLOCKSIZE;
456 }
457
458 if (i > 0)
459 {
460 memcpy(block, buf, i);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500461 memset(&(block[i]), 0, T_BLOCKSIZE - i);
462 if (tar_block_write(t, &block) == -1)
463 return -1;
464 }
465
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500466 return 0;
467}
468