123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332 |
- /*
- * Copyright 2014 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
- #include <errno.h>
- #ifndef HAVE_MACOS
- #include <linux/fs.h> /* For BLKGETSIZE64 */
- #endif
- #include <stdarg.h>
- #include <stdint.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/ioctl.h>
- #include <sys/mman.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <sys/wait.h>
- #include <unistd.h>
- #include "2sysincludes.h"
- #include "2common.h"
- #include "2sha.h"
- #include "cgptlib_internal.h"
- #include "file_type.h"
- #include "futility.h"
- #include "gbb_header.h"
- /* Default is to support everything we can */
- enum vboot_version vboot_version = VBOOT_VERSION_ALL;
- int debugging_enabled;
- void Debug(const char *format, ...)
- {
- if (!debugging_enabled)
- return;
- va_list ap;
- va_start(ap, format);
- fprintf(stdout, "DEBUG: ");
- vfprintf(stdout, format, ap);
- va_end(ap);
- }
- static int is_null_terminated(const char *s, int len)
- {
- len--;
- s += len;
- while (len-- >= 0)
- if (!*s--)
- return 1;
- return 0;
- }
- static inline uint32_t max(uint32_t a, uint32_t b)
- {
- return a > b ? a : b;
- }
- enum futil_file_type ft_recognize_gbb(uint8_t *buf, uint32_t len)
- {
- GoogleBinaryBlockHeader *gbb = (GoogleBinaryBlockHeader *)buf;
- if (memcmp(gbb->signature, GBB_SIGNATURE, GBB_SIGNATURE_SIZE))
- return FILE_TYPE_UNKNOWN;
- if (gbb->major_version > GBB_MAJOR_VER)
- return FILE_TYPE_UNKNOWN;
- if (sizeof(GoogleBinaryBlockHeader) > len)
- return FILE_TYPE_UNKNOWN;
- /* close enough */
- return FILE_TYPE_GBB;
- }
- int futil_valid_gbb_header(GoogleBinaryBlockHeader *gbb, uint32_t len,
- uint32_t *maxlen_ptr)
- {
- if (len < sizeof(GoogleBinaryBlockHeader))
- return 0;
- if (memcmp(gbb->signature, GBB_SIGNATURE, GBB_SIGNATURE_SIZE))
- return 0;
- if (gbb->major_version != GBB_MAJOR_VER)
- return 0;
- /* Check limits first, to help identify problems */
- if (maxlen_ptr) {
- uint32_t maxlen = gbb->header_size;
- maxlen = max(maxlen,
- gbb->hwid_offset + gbb->hwid_size);
- maxlen = max(maxlen,
- gbb->rootkey_offset + gbb->rootkey_size);
- maxlen = max(maxlen,
- gbb->bmpfv_offset + gbb->bmpfv_size);
- maxlen = max(maxlen,
- gbb->recovery_key_offset + gbb->recovery_key_size);
- *maxlen_ptr = maxlen;
- }
- if (gbb->header_size != GBB_HEADER_SIZE || gbb->header_size > len)
- return 0;
- if (gbb->hwid_offset < GBB_HEADER_SIZE)
- return 0;
- if (gbb->hwid_offset + gbb->hwid_size > len)
- return 0;
- if (gbb->hwid_size) {
- const char *s = (const char *)
- ((uint8_t *)gbb + gbb->hwid_offset);
- if (!is_null_terminated(s, gbb->hwid_size))
- return 0;
- }
- if (gbb->rootkey_offset < GBB_HEADER_SIZE)
- return 0;
- if (gbb->rootkey_offset + gbb->rootkey_size > len)
- return 0;
- if (gbb->bmpfv_offset < GBB_HEADER_SIZE)
- return 0;
- if (gbb->bmpfv_offset + gbb->bmpfv_size > len)
- return 0;
- if (gbb->recovery_key_offset < GBB_HEADER_SIZE)
- return 0;
- if (gbb->recovery_key_offset + gbb->recovery_key_size > len)
- return 0;
- /* Seems legit... */
- return 1;
- }
- /* For GBB v1.2 and later, print the stored digest of the HWID (and whether
- * it's correct). Return true if it is correct. */
- int print_hwid_digest(GoogleBinaryBlockHeader *gbb,
- const char *banner, const char *footer)
- {
- printf("%s", banner);
- /* There isn't one for v1.1 and earlier, so assume it's good. */
- if (gbb->minor_version < 2) {
- printf("<none>%s", footer);
- return 1;
- }
- uint8_t *buf = (uint8_t *)gbb;
- char *hwid_str = (char *)(buf + gbb->hwid_offset);
- int is_valid = 0;
- uint8_t digest[VB2_SHA256_DIGEST_SIZE];
- if (VB2_SUCCESS == vb2_digest_buffer(buf + gbb->hwid_offset,
- strlen(hwid_str), VB2_HASH_SHA256,
- digest, sizeof(digest))) {
- int i;
- is_valid = 1;
- /* print it, comparing as we go */
- for (i = 0; i < VB2_SHA256_DIGEST_SIZE; i++) {
- printf("%02x", gbb->hwid_digest[i]);
- if (gbb->hwid_digest[i] != digest[i])
- is_valid = 0;
- }
- }
- printf(" %s", is_valid ? "valid" : "<invalid>");
- printf("%s", footer);
- return is_valid;
- }
- /* For GBB v1.2 and later, update the hwid_digest field. */
- void update_hwid_digest(GoogleBinaryBlockHeader *gbb)
- {
- /* There isn't one for v1.1 and earlier */
- if (gbb->minor_version < 2)
- return;
- uint8_t *buf = (uint8_t *)gbb;
- char *hwid_str = (char *)(buf + gbb->hwid_offset);
- vb2_digest_buffer(buf + gbb->hwid_offset, strlen(hwid_str),
- VB2_HASH_SHA256,
- gbb->hwid_digest, sizeof(gbb->hwid_digest));
- }
- /*
- * TODO: All sorts of race conditions likely here, and everywhere this is used.
- * Do we care? If so, fix it.
- */
- void futil_copy_file_or_die(const char *infile, const char *outfile)
- {
- pid_t pid;
- int status;
- Debug("%s(%s, %s)\n", __func__, infile, outfile);
- pid = fork();
- if (pid < 0) {
- fprintf(stderr, "Couldn't fork /bin/cp process: %s\n",
- strerror(errno));
- exit(1);
- }
- /* child */
- if (!pid) {
- execl("/bin/cp", "/bin/cp", infile, outfile, NULL);
- fprintf(stderr, "Child couldn't exec /bin/cp: %s\n",
- strerror(errno));
- exit(1);
- }
- /* parent - wait for child to finish */
- if (wait(&status) == -1) {
- fprintf(stderr,
- "Couldn't wait for /bin/cp process to exit: %s\n",
- strerror(errno));
- exit(1);
- }
- if (WIFEXITED(status)) {
- status = WEXITSTATUS(status);
- /* zero is normal exit */
- if (!status)
- return;
- fprintf(stderr, "/bin/cp exited with status %d\n", status);
- exit(1);
- }
- if (WIFSIGNALED(status)) {
- status = WTERMSIG(status);
- fprintf(stderr, "/bin/cp was killed with signal %d\n", status);
- exit(1);
- }
- fprintf(stderr, "I have no idea what just happened\n");
- exit(1);
- }
- enum futil_file_err futil_map_file(int fd, int writeable,
- uint8_t **buf, uint32_t *len)
- {
- struct stat sb;
- void *mmap_ptr;
- uint32_t reasonable_len;
- if (0 != fstat(fd, &sb)) {
- fprintf(stderr, "Can't stat input file: %s\n",
- strerror(errno));
- return FILE_ERR_STAT;
- }
- #ifndef HAVE_MACOS
- if (S_ISBLK(sb.st_mode))
- ioctl(fd, BLKGETSIZE64, &sb.st_size);
- #endif
- /* If the image is larger than 2^32 bytes, it's wrong. */
- if (sb.st_size < 0 || sb.st_size > UINT32_MAX) {
- fprintf(stderr, "Image size is unreasonable\n");
- return FILE_ERR_SIZE;
- }
- reasonable_len = (uint32_t)sb.st_size;
- if (writeable)
- mmap_ptr = mmap(0, sb.st_size,
- PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
- else
- mmap_ptr = mmap(0, sb.st_size,
- PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
- if (mmap_ptr == (void *)-1) {
- fprintf(stderr, "Can't mmap %s file: %s\n",
- writeable ? "output" : "input",
- strerror(errno));
- return FILE_ERR_MMAP;
- }
- *buf = (uint8_t *)mmap_ptr;
- *len = reasonable_len;
- return FILE_ERR_NONE;
- }
- enum futil_file_err futil_unmap_file(int fd, int writeable,
- uint8_t *buf, uint32_t len)
- {
- void *mmap_ptr = buf;
- enum futil_file_err err = FILE_ERR_NONE;
- if (writeable &&
- (0 != msync(mmap_ptr, len, MS_SYNC|MS_INVALIDATE))) {
- fprintf(stderr, "msync failed: %s\n", strerror(errno));
- err = FILE_ERR_MSYNC;
- }
- if (0 != munmap(mmap_ptr, len)) {
- fprintf(stderr, "Can't munmap pointer: %s\n",
- strerror(errno));
- if (err == FILE_ERR_NONE)
- err = FILE_ERR_MUNMAP;
- }
- return err;
- }
- #define DISK_SECTOR_SIZE 512
- enum futil_file_type ft_recognize_gpt(uint8_t *buf, uint32_t len)
- {
- GptHeader *h;
- /* GPT header starts at sector 1, is one sector long */
- if (len < 2 * DISK_SECTOR_SIZE)
- return FILE_TYPE_UNKNOWN;
- h = (GptHeader *)(buf + DISK_SECTOR_SIZE);
- if (memcmp(h->signature, GPT_HEADER_SIGNATURE,
- GPT_HEADER_SIGNATURE_SIZE) &&
- memcmp(h->signature, GPT_HEADER_SIGNATURE2,
- GPT_HEADER_SIGNATURE_SIZE))
- return FILE_TYPE_UNKNOWN;
- if (h->revision != GPT_HEADER_REVISION)
- return FILE_TYPE_UNKNOWN;
- if (h->size < MIN_SIZE_OF_HEADER || h->size > MAX_SIZE_OF_HEADER)
- return FILE_TYPE_UNKNOWN;
- if (HeaderCrc(h) != h->header_crc32)
- return FILE_TYPE_UNKNOWN;
- return FILE_TYPE_CHROMIUMOS_DISK;
- }
|