1 /* Copyright 2018 The ChromiumOS Authors
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 *
5 * Accessing updater resources from an archive.
6 */
7
8 #include <assert.h>
9 #include <errno.h>
10 #if defined(__OpenBSD__)
11 #include <sys/types.h>
12 #endif
13 #include <fts.h>
14 #include <sys/stat.h>
15 #include <sys/time.h>
16 #include <unistd.h>
17
18 #ifdef HAVE_LIBARCHIVE
19 #include <archive.h>
20 #include <archive_entry.h>
21 #endif
22
23 #ifdef HAVE_LIBZIP
24 #ifndef __clang__
25 /* If libzip headers were built for Clang but later get included with GCC you
26 need this. This check should really be in libzip but apparently they think
27 it's fine to ship compiler-specific system headers or something... */
28 #define _Nullable
29 #define _Nonnull
30 #endif
31 #include <zip.h>
32 #endif
33
34 #include "host_misc.h"
35 #include "updater.h"
36
37 /*
38 * A firmware update package (archive) is a file packed by either shar(1) or
39 * zip(1). See https://chromium.googlesource.com/chromiumos/platform/firmware/
40 * for more information.
41 */
42
43 struct u_archive {
44 void *handle;
45
46 void * (*open)(const char *name);
47 int (*close)(void *handle);
48
49 int (*walk)(void *handle, void *arg,
50 int (*callback)(const char *path, void *arg));
51 int (*has_entry)(void *handle, const char *name);
52 int (*read_file)(void *handle, const char *fname,
53 uint8_t **data, uint32_t *size, int64_t *mtime);
54 int (*write_file)(void *handle, const char *fname,
55 uint8_t *data, uint32_t size, int64_t mtime);
56 };
57
58 /*
59 * -- The fallback driver (using general file system). --
60 */
61
62 /* Callback for archive_open on a general file system. */
archive_fallback_open(const char * name)63 static void *archive_fallback_open(const char *name)
64 {
65 assert(name && *name);
66 return strdup(name);
67 }
68
69 /* Callback for archive_close on a general file system. */
archive_fallback_close(void * handle)70 static int archive_fallback_close(void *handle)
71 {
72 free(handle);
73 return 0;
74 }
75
76 /* Callback for archive_walk on a general file system. */
archive_fallback_walk(void * handle,void * arg,int (* callback)(const char * path,void * arg))77 static int archive_fallback_walk(
78 void *handle, void *arg,
79 int (*callback)(const char *path, void *arg))
80 {
81 FTS *fts_handle;
82 FTSENT *ent;
83 char *fts_argv[2] = {};
84 char default_path[] = ".";
85 char *root = default_path;
86 size_t root_len;
87
88 if (handle)
89 root = (char *)handle;
90 root_len = strlen(root);
91 fts_argv[0] = root;
92
93 fts_handle = fts_open(fts_argv, FTS_NOCHDIR, NULL);
94 if (!fts_handle)
95 return -1;
96
97 while ((ent = fts_read(fts_handle)) != NULL) {
98 char *path = ent->fts_path + root_len;
99 if (ent->fts_info != FTS_F && ent->fts_info != FTS_SL)
100 continue;
101 while (*path == '/')
102 path++;
103 if (!*path)
104 continue;
105 if (callback(path, arg))
106 break;
107 }
108 return 0;
109 }
110
111 /* Callback for fallback drivers to get full path easily. */
archive_fallback_get_path(void * handle,const char * fname,char ** temp_path)112 static const char *archive_fallback_get_path(void *handle, const char *fname,
113 char **temp_path)
114 {
115 if (handle && *fname != '/') {
116 ASPRINTF(temp_path, "%s/%s", (char *)handle, fname);
117 return *temp_path;
118 }
119 return fname;
120 }
121
122 /* Callback for archive_has_entry on a general file system. */
archive_fallback_has_entry(void * handle,const char * fname)123 static int archive_fallback_has_entry(void *handle, const char *fname)
124 {
125 int r;
126 char *temp_path = NULL;
127 const char *path = archive_fallback_get_path(handle, fname, &temp_path);
128
129 VB2_DEBUG("Checking %s\n", path);
130 r = access(path, R_OK);
131 free(temp_path);
132 return r == 0;
133 }
134
135 /* Callback for archive_read_file on a general file system. */
archive_fallback_read_file(void * handle,const char * fname,uint8_t ** data,uint32_t * size,int64_t * mtime)136 static int archive_fallback_read_file(void *handle, const char *fname,
137 uint8_t **data, uint32_t *size, int64_t *mtime)
138 {
139 int r;
140 char *temp_path = NULL;
141 const char *path = archive_fallback_get_path(handle, fname, &temp_path);
142 struct stat st;
143
144 VB2_DEBUG("Reading %s\n", path);
145 *data = NULL;
146 *size = 0;
147 /* vb2_read_file already has an extra '\0' in the end. */
148 r = vb2_read_file(path, data, size) != VB2_SUCCESS;
149 if (mtime) {
150 if (stat(path, &st) == 0)
151 *mtime = st.st_mtime;
152 else
153 WARN("Unable to stat %s: %s\n", path, strerror(errno));
154 }
155 free(temp_path);
156 return r;
157 }
158
159 /* Callback for archive_write_file on a general file system. */
archive_fallback_write_file(void * handle,const char * fname,uint8_t * data,uint32_t size,int64_t mtime)160 static int archive_fallback_write_file(void *handle, const char *fname,
161 uint8_t *data, uint32_t size, int64_t mtime)
162 {
163 int r;
164 char *temp_path = NULL;
165 const char *path = archive_fallback_get_path(handle, fname, &temp_path);
166
167 VB2_DEBUG("Writing %s\n", path);
168 if (strchr(path, '/')) {
169 char *dirname = strdup(path);
170 *strrchr(dirname, '/') = '\0';
171 /* TODO(hungte): call mkdir(2) instead of shell invocation. */
172 if (access(dirname, W_OK) != 0) {
173 char *command;
174 ASPRINTF(&command, "mkdir -p %s", dirname);
175 free(host_shell(command));
176 free(command);
177 }
178 free(dirname);
179 }
180 r = vb2_write_file(path, data, size) != VB2_SUCCESS;
181 if (mtime) {
182 struct timeval times[2] = {
183 {.tv_sec = mtime, .tv_usec = 0},
184 {.tv_sec = mtime, .tv_usec = 0},
185 };
186 if (utimes(path, times) != 0)
187 WARN("Unable to set times on %s: %s\n", path, strerror(errno));
188 }
189 free(temp_path);
190 return r;
191 }
192
193 /*
194 * -- The cache driver (used by other drivers). --
195 */
196
197 #ifdef HAVE_LIBARCHIVE
198
199 /*
200 * For stream-based archives (e.g., tar+gz) we want to create a cache for
201 * storing the names and contents for later processing.
202 */
203 struct archive_cache {
204 char *name;
205 uint8_t *data;
206 int64_t mtime;
207 size_t size;
208 int has_data;
209 struct archive_cache *next;
210 };
211
212 /* Add a new cache node to an existing cache list and return the new head. */
archive_cache_new(struct archive_cache * cache,const char * name)213 static struct archive_cache *archive_cache_new(struct archive_cache *cache,
214 const char *name)
215 {
216 struct archive_cache *c;
217
218 c = (struct archive_cache *)calloc(sizeof(*c), 1);
219 if (!c)
220 return NULL;
221
222 c->name = strdup(name);
223 if (!c->name) {
224 free(c);
225 return NULL;
226 }
227
228 c->next = cache;
229 return c;
230 }
231
232 /* Find and return an entry (by name) from the cache. */
archive_cache_find(struct archive_cache * c,const char * name)233 static struct archive_cache *archive_cache_find(struct archive_cache *c,
234 const char *name)
235 {
236 for (; c; c = c->next) {
237 assert(c->name);
238 if (!strcmp(c->name, name))
239 return c;
240 }
241 return NULL;
242 }
243
244 /* Callback for archive_walk to process all entries in the cache. */
archive_cache_walk(struct archive_cache * c,void * arg,int (* callback)(const char * name,void * arg))245 static int archive_cache_walk(
246 struct archive_cache *c, void *arg,
247 int (*callback)(const char *name, void *arg))
248 {
249 for (; c; c = c->next) {
250 assert(c->name);
251 if (callback(c->name, arg))
252 break;
253 }
254 return 0;
255 }
256
257 /* Delete all entries in the cache. */
archive_cache_free(struct archive_cache * c)258 static void *archive_cache_free(struct archive_cache *c)
259 {
260 struct archive_cache *next;
261
262 while (c) {
263 next = c->next;
264 free(c->name);
265 free(c->data);
266 free(c);
267 c = next;
268 }
269 return NULL;
270 }
271
272 /*
273 * -- The libarchive driver (multiple formats but very slow). --
274 */
275
276 enum {
277 FILTER_IGNORE,
278 FILTER_ABORT,
279 FILTER_NAME_ONLY,
280 FILTER_READ_ALL,
281 };
282
libarchive_read_file_entries(const char * fpath,int (* filter)(struct archive_entry * entry))283 static struct archive_cache *libarchive_read_file_entries(
284 const char *fpath, int (*filter)(struct archive_entry *entry))
285 {
286 struct archive *a = archive_read_new();
287 struct archive_entry *entry;
288 struct archive_cache *c, *cache = NULL;
289 int r;
290
291 assert(a);
292 archive_read_support_filter_all(a);
293 archive_read_support_format_all(a);
294 r = archive_read_open_filename(a, fpath, 10240);
295 if (r != ARCHIVE_OK) {
296 ERROR("Failed parsing archive using libarchive: %s\n", fpath);
297 archive_read_free(a);
298 return NULL;
299 }
300
301 WARN("Loading data from archive: %s ", fpath);
302 while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
303 fputc('.', stderr);
304 if (archive_entry_filetype(entry) != AE_IFREG)
305 continue;
306 if (filter)
307 r = filter(entry);
308 else
309 r = FILTER_READ_ALL;
310
311 if (r == FILTER_ABORT)
312 break;
313 if (r == FILTER_IGNORE)
314 continue;
315
316 c = archive_cache_new(cache, archive_entry_pathname(entry));
317 if (!c) {
318 ERROR("Internal error: out of memory.\n");
319 archive_cache_free(cache);
320 archive_read_free(a);
321 return NULL;
322 }
323 cache = c;
324
325 if (r == FILTER_NAME_ONLY)
326 continue;
327
328 assert(r == FILTER_READ_ALL);
329 c->size = archive_entry_size(entry);
330 c->mtime = archive_entry_mtime(entry);
331 c->data = (uint8_t *)calloc(1, c->size + 1);
332 if (!c->data) {
333 WARN("Out of memory when loading: %s\n", c->name);
334 continue;
335 }
336 if (archive_read_data(a, c->data, c->size) != c->size) {
337 WARN("Failed reading from archive: %s\n", c->name);
338 continue;
339 }
340 c->has_data = 1;
341 }
342 fputs("\r\n", stderr); /* Flush the '.' */
343 VB2_DEBUG("Finished loading from archive: %s.\n", fpath);
344
345 archive_read_free(a);
346 return cache;
347 }
348
349 /* Callback for archive_open on an ARCHIVE file. */
archive_libarchive_open(const char * name)350 static void *archive_libarchive_open(const char *name)
351 {
352 /*
353 * The firmware archives today can usually all load into memory
354 * so we are using a NULL filter. Change that to a specific list in
355 * future if the /build/$BOARD/firmware archive becomes too large.
356 */
357 return libarchive_read_file_entries(name, NULL);
358 }
359
360 /* Callback for archive_close on an ARCHIVE file. */
archive_libarchive_close(void * handle)361 static int archive_libarchive_close(void *handle)
362 {
363 archive_cache_free(handle);
364 return 0;
365 }
366
367 /* Callback for archive_has_entry on an ARCHIVE file. */
archive_libarchive_has_entry(void * handle,const char * fname)368 static int archive_libarchive_has_entry(void *handle, const char *fname)
369 {
370 return archive_cache_find(handle, fname) != NULL;
371 }
372
373 /* Callback for archive_walk on an ARCHIVE file. */
archive_libarchive_walk(void * handle,void * arg,int (* callback)(const char * name,void * arg))374 static int archive_libarchive_walk(
375 void *handle, void *arg,
376 int (*callback)(const char *name, void *arg))
377 {
378 return archive_cache_walk(handle, arg, callback);
379 }
380
381 /* Callback for archive_read_file on an ARCHIVE file. */
archive_libarchive_read_file(void * handle,const char * fname,uint8_t ** data,uint32_t * size,int64_t * mtime)382 static int archive_libarchive_read_file(
383 void *handle, const char *fname, uint8_t **data,
384 uint32_t *size, int64_t *mtime)
385 {
386 struct archive_cache *c = archive_cache_find(handle, fname);
387
388 if (!c)
389 return 1;
390
391 if (!c->has_data) {
392 /* TODO(hungte) Re-read. */
393 ERROR("Not in the cache: %s\n", fname);
394 return 1;
395 }
396
397 if (mtime)
398 *mtime = c->mtime;
399 if (size)
400 *size = c->size;
401 *data = (uint8_t *)malloc(c->size + 1);
402 if (!*data) {
403 ERROR("Out of memory when reading: %s\n", c->name);
404 return 1;
405 }
406 memcpy(*data, c->data, c->size);
407 (*data)[c->size] = '\0';
408 return 0;
409 }
410
411 /* Callback for archive_write_file on an ARCHIVE file. */
archive_libarchive_write_file(void * handle,const char * fname,uint8_t * data,uint32_t size,int64_t mtime)412 static int archive_libarchive_write_file(
413 void *handle, const char *fname, uint8_t *data, uint32_t size,
414 int64_t mtime)
415 {
416 ERROR("Not implemented!\n");
417 return 1;
418 }
419 #endif
420
421 /*
422 * -- The libzip driver (for ZIP, the official format for CrOS fw updater). --
423 */
424
425 #ifdef HAVE_LIBZIP
426
427 /* Callback for archive_open on a ZIP file. */
archive_zip_open(const char * name)428 static void *archive_zip_open(const char *name)
429 {
430 return zip_open(name, 0, NULL);
431 }
432
433 /* Callback for archive_close on a ZIP file. */
archive_zip_close(void * handle)434 static int archive_zip_close(void *handle)
435 {
436 struct zip *zip = (struct zip *)handle;
437
438 if (zip)
439 return zip_close(zip);
440 return 0;
441 }
442
443 /* Callback for archive_has_entry on a ZIP file. */
archive_zip_has_entry(void * handle,const char * fname)444 static int archive_zip_has_entry(void *handle, const char *fname)
445 {
446 struct zip *zip = (struct zip *)handle;
447 assert(zip);
448 return zip_name_locate(zip, fname, 0) != -1;
449 }
450
451 /* Callback for archive_walk on a ZIP file. */
archive_zip_walk(void * handle,void * arg,int (* callback)(const char * name,void * arg))452 static int archive_zip_walk(
453 void *handle, void *arg,
454 int (*callback)(const char *name, void *arg))
455 {
456 zip_int64_t num, i;
457 struct zip *zip = (struct zip *)handle;
458 assert(zip);
459
460 num = zip_get_num_entries(zip, 0);
461 if (num < 0)
462 return 1;
463 for (i = 0; i < num; i++) {
464 const char *name = zip_get_name(zip, i, 0);
465 if (*name && name[strlen(name) - 1] == '/')
466 continue;
467 if (callback(name, arg))
468 break;
469 }
470 return 0;
471 }
472
473 /* Callback for archive_zip_read_file on a ZIP file. */
archive_zip_read_file(void * handle,const char * fname,uint8_t ** data,uint32_t * size,int64_t * mtime)474 static int archive_zip_read_file(void *handle, const char *fname,
475 uint8_t **data, uint32_t *size, int64_t *mtime)
476 {
477 struct zip *zip = (struct zip *)handle;
478 struct zip_file *fp;
479 struct zip_stat stat;
480
481 assert(zip);
482 *data = NULL;
483 *size = 0;
484 zip_stat_init(&stat);
485 if (zip_stat(zip, fname, 0, &stat)) {
486 ERROR("Fail to stat entry in ZIP: %s\n", fname);
487 return 1;
488 }
489 fp = zip_fopen(zip, fname, 0);
490 if (!fp) {
491 ERROR("Failed to open entry in ZIP: %s\n", fname);
492 return 1;
493 }
494 *data = (uint8_t *)malloc(stat.size + 1);
495 if (*data) {
496 if (zip_fread(fp, *data, stat.size) == stat.size) {
497 if (mtime)
498 *mtime = stat.mtime;
499 *size = stat.size;
500 (*data)[stat.size] = '\0';
501 } else {
502 ERROR("Failed to read entry in zip: %s\n", fname);
503 free(*data);
504 *data = NULL;
505 }
506 }
507 zip_fclose(fp);
508 return *data == NULL;
509 }
510
511 /* Callback for archive_zip_write_file on a ZIP file. */
archive_zip_write_file(void * handle,const char * fname,uint8_t * data,uint32_t size,int64_t mtime)512 static int archive_zip_write_file(void *handle, const char *fname,
513 uint8_t *data, uint32_t size, int64_t mtime)
514 {
515 struct zip *zip = (struct zip *)handle;
516 struct zip_source *src;
517
518 VB2_DEBUG("Writing %s\n", fname);
519 assert(zip);
520 src = zip_source_buffer(zip, data, size, 0);
521 if (!src) {
522 ERROR("Internal error: cannot allocate buffer: %s\n", fname);
523 return 1;
524 }
525
526 if (zip_file_add(zip, fname, src, ZIP_FL_OVERWRITE) < 0) {
527 zip_source_free(src);
528 ERROR("Internal error: failed to add: %s\n", fname);
529 return 1;
530 }
531 /* zip_source_free is not needed if zip_file_add success. */
532 #if LIBZIP_VERSION_MAJOR >= 1
533 zip_file_set_mtime(zip, zip_name_locate(zip, fname, 0), mtime, 0);
534 #endif
535 return 0;
536 }
537 #endif
538
539 /*
540 * -- The public functions for using u_archive. --
541 */
542
archive_open(const char * path)543 struct u_archive *archive_open(const char *path)
544 {
545 struct stat path_stat;
546 struct u_archive *ar;
547
548 if (stat(path, &path_stat) != 0) {
549 ERROR("Cannot identify type of path: %s\n", path);
550 return NULL;
551 }
552
553 ar = (struct u_archive *)calloc(sizeof(*ar), 1);
554 if (!ar) {
555 ERROR("Internal error: allocation failure.\n");
556 return NULL;
557 }
558
559 if (S_ISDIR(path_stat.st_mode)) {
560 VB2_DEBUG("Found directory, use fallback (fs) driver: %s\n",
561 path);
562 /* Regular file system. */
563 ar->open = archive_fallback_open;
564 ar->close = archive_fallback_close;
565 ar->walk = archive_fallback_walk;
566 ar->has_entry = archive_fallback_has_entry;
567 ar->read_file = archive_fallback_read_file;
568 ar->write_file = archive_fallback_write_file;
569 }
570
571 /* Format detection must try ZIP (the official format) first. */
572 #ifdef HAVE_LIBZIP
573 if (!ar->open) {
574 ar->handle = archive_zip_open(path);
575
576 if (ar->handle) {
577 VB2_DEBUG("Found a ZIP file: %s\n", path);
578 ar->open = archive_zip_open;
579 ar->close = archive_zip_close;
580 ar->walk = archive_zip_walk;
581 ar->has_entry = archive_zip_has_entry;
582 ar->read_file = archive_zip_read_file;
583 ar->write_file = archive_zip_write_file;
584 }
585 }
586 #endif
587
588 /* LIBARCHIVE must be the last driver. */
589 #ifdef HAVE_LIBARCHIVE
590 if (!ar->open) {
591 VB2_DEBUG("Found a file, use libarchive: %s\n", path);
592 ar->open = archive_libarchive_open;
593 ar->close = archive_libarchive_close;
594 ar->walk = archive_libarchive_walk;
595 ar->has_entry = archive_libarchive_has_entry;
596 ar->read_file = archive_libarchive_read_file;
597 ar->write_file = archive_libarchive_write_file;
598 }
599 #endif
600
601 if (!ar->open) {
602 ERROR("Found a file, but no drivers were selected: %s\n", path);
603 free(ar);
604 return NULL;
605 }
606
607 /* Some drivers may have already opened the archive. */
608 if (!ar->handle)
609 ar->handle = ar->open(path);
610
611 if (!ar->handle) {
612 ERROR("Failed to open archive: %s\n", path);
613 free(ar);
614 return NULL;
615 }
616 return ar;
617 }
618
archive_close(struct u_archive * ar)619 int archive_close(struct u_archive *ar)
620 {
621 int r = ar->close(ar->handle);
622 free(ar);
623 return r;
624 }
625
archive_has_entry(struct u_archive * ar,const char * name)626 int archive_has_entry(struct u_archive *ar, const char *name)
627 {
628 if (!ar || *name == '/')
629 return archive_fallback_has_entry(NULL, name);
630 return ar->has_entry(ar->handle, name);
631 }
632
archive_walk(struct u_archive * ar,void * arg,int (* callback)(const char * path,void * arg))633 int archive_walk(struct u_archive *ar, void *arg,
634 int (*callback)(const char *path, void *arg))
635 {
636 if (!ar)
637 return archive_fallback_walk(NULL, arg, callback);
638 return ar->walk(ar->handle, arg, callback);
639 }
640
archive_read_file(struct u_archive * ar,const char * fname,uint8_t ** data,uint32_t * size,int64_t * mtime)641 int archive_read_file(struct u_archive *ar, const char *fname,
642 uint8_t **data, uint32_t *size, int64_t *mtime)
643 {
644 if (!ar || *fname == '/')
645 return archive_fallback_read_file(NULL, fname, data, size, mtime);
646 return ar->read_file(ar->handle, fname, data, size, mtime);
647 }
648
archive_write_file(struct u_archive * ar,const char * fname,uint8_t * data,uint32_t size,int64_t mtime)649 int archive_write_file(struct u_archive *ar, const char *fname,
650 uint8_t *data, uint32_t size, int64_t mtime)
651 {
652 if (!ar || *fname == '/')
653 return archive_fallback_write_file(NULL, fname, data, size, mtime);
654 return ar->write_file(ar->handle, fname, data, size, mtime);
655 }
656
657 struct _copy_arg {
658 struct u_archive *from, *to;
659 };
660
661 /* Callback for archive_copy. */
archive_copy_callback(const char * path,void * _arg)662 static int archive_copy_callback(const char *path, void *_arg)
663 {
664 const struct _copy_arg *arg = (const struct _copy_arg*)_arg;
665 uint32_t size;
666 uint8_t *data;
667 int64_t mtime;
668 int r;
669
670 INFO("Copying: %s\n", path);
671 if (archive_read_file(arg->from, path, &data, &size, &mtime)) {
672 ERROR("Failed reading: %s\n", path);
673 return 1;
674 }
675 r = archive_write_file(arg->to, path, data, size, mtime);
676 VB2_DEBUG("result=%d\n", r);
677 free(data);
678 return r;
679 }
680
archive_copy(struct u_archive * from,struct u_archive * to)681 int archive_copy(struct u_archive *from, struct u_archive *to)
682 {
683 struct _copy_arg arg = { .from = from, .to = to };
684 return archive_walk(from, &arg, archive_copy_callback);
685 }
686