Home | History | Annotate | Download | only in futility
      1 /*
      2  * Copyright 2014 The Chromium OS Authors. All rights reserved.
      3  * Use of this source code is governed by a BSD-style license that can be
      4  * found in the LICENSE file.
      5  */
      6 
      7 #include <errno.h>
      8 #ifndef HAVE_MACOS
      9 #include <linux/fs.h>		/* For BLKGETSIZE64 */
     10 #endif
     11 #include <stdarg.h>
     12 #include <stdint.h>
     13 #include <stdio.h>
     14 #include <stdlib.h>
     15 #include <string.h>
     16 #include <sys/ioctl.h>
     17 #include <sys/mman.h>
     18 #include <sys/stat.h>
     19 #include <sys/types.h>
     20 #include <sys/wait.h>
     21 #include <unistd.h>
     22 
     23 #include "cgptlib_internal.h"
     24 #include "file_type.h"
     25 #include "futility.h"
     26 #include "gbb_header.h"
     27 
     28 int debugging_enabled;
     29 void Debug(const char *format, ...)
     30 {
     31 	if (!debugging_enabled)
     32 		return;
     33 
     34 	va_list ap;
     35 	va_start(ap, format);
     36 	fprintf(stderr, "DEBUG: ");
     37 	vfprintf(stderr, format, ap);
     38 	va_end(ap);
     39 }
     40 
     41 static int is_null_terminated(const char *s, int len)
     42 {
     43 	len--;
     44 	s += len;
     45 	while (len-- >= 0)
     46 		if (!*s--)
     47 			return 1;
     48 	return 0;
     49 }
     50 
     51 static inline uint32_t max(uint32_t a, uint32_t b)
     52 {
     53 	return a > b ? a : b;
     54 }
     55 
     56 enum futil_file_type recognize_gbb(uint8_t *buf, uint32_t len)
     57 {
     58 	GoogleBinaryBlockHeader *gbb = (GoogleBinaryBlockHeader *)buf;
     59 
     60 	if (memcmp(gbb->signature, GBB_SIGNATURE, GBB_SIGNATURE_SIZE))
     61 		return FILE_TYPE_UNKNOWN;
     62 	if (gbb->major_version > GBB_MAJOR_VER)
     63 		return FILE_TYPE_UNKNOWN;
     64 	if (sizeof(GoogleBinaryBlockHeader) > len)
     65 		return FILE_TYPE_UNKNOWN;
     66 
     67 	/* close enough */
     68 	return FILE_TYPE_GBB;
     69 }
     70 
     71 int futil_valid_gbb_header(GoogleBinaryBlockHeader *gbb, uint32_t len,
     72 			   uint32_t *maxlen_ptr)
     73 {
     74 	if (len < sizeof(GoogleBinaryBlockHeader))
     75 		return 0;
     76 
     77 	if (memcmp(gbb->signature, GBB_SIGNATURE, GBB_SIGNATURE_SIZE))
     78 		return 0;
     79 	if (gbb->major_version != GBB_MAJOR_VER)
     80 		return 0;
     81 
     82 	/* Check limits first, to help identify problems */
     83 	if (maxlen_ptr) {
     84 		uint32_t maxlen = gbb->header_size;
     85 		maxlen = max(maxlen,
     86 			     gbb->hwid_offset + gbb->hwid_size);
     87 		maxlen = max(maxlen,
     88 			     gbb->rootkey_offset + gbb->rootkey_size);
     89 		maxlen = max(maxlen,
     90 			     gbb->bmpfv_offset + gbb->bmpfv_size);
     91 		maxlen = max(maxlen,
     92 			     gbb->recovery_key_offset + gbb->recovery_key_size);
     93 		*maxlen_ptr = maxlen;
     94 	}
     95 
     96 	if (gbb->header_size != GBB_HEADER_SIZE || gbb->header_size > len)
     97 		return 0;
     98 	if (gbb->hwid_offset < GBB_HEADER_SIZE)
     99 		return 0;
    100 	if (gbb->hwid_offset + gbb->hwid_size > len)
    101 		return 0;
    102 	if (gbb->hwid_size) {
    103 		const char *s = (const char *)
    104 			((uint8_t *)gbb + gbb->hwid_offset);
    105 		if (!is_null_terminated(s, gbb->hwid_size))
    106 			return 0;
    107 	}
    108 	if (gbb->rootkey_offset < GBB_HEADER_SIZE)
    109 		return 0;
    110 	if (gbb->rootkey_offset + gbb->rootkey_size > len)
    111 		return 0;
    112 
    113 	if (gbb->bmpfv_offset < GBB_HEADER_SIZE)
    114 		return 0;
    115 	if (gbb->bmpfv_offset + gbb->bmpfv_size > len)
    116 		return 0;
    117 	if (gbb->recovery_key_offset < GBB_HEADER_SIZE)
    118 		return 0;
    119 	if (gbb->recovery_key_offset + gbb->recovery_key_size > len)
    120 		return 0;
    121 
    122 	/* Seems legit... */
    123 	return 1;
    124 }
    125 
    126 /* For GBB v1.2 and later, print the stored digest of the HWID (and whether
    127  * it's correct). Return true if it is correct. */
    128 int print_hwid_digest(GoogleBinaryBlockHeader *gbb,
    129 		      const char *banner, const char *footer)
    130 {
    131 	printf("%s", banner);
    132 
    133 	/* There isn't one for v1.1 and earlier, so assume it's good. */
    134 	if (gbb->minor_version < 2) {
    135 		printf("<none>%s", footer);
    136 		return 1;
    137 	}
    138 
    139 	uint8_t *buf = (uint8_t *)gbb;
    140 	char *hwid_str = (char *)(buf + gbb->hwid_offset);
    141 	int is_valid = 0;
    142 	uint8_t *digest = DigestBuf(buf + gbb->hwid_offset,
    143 				    strlen(hwid_str),
    144 				    SHA256_DIGEST_ALGORITHM);
    145 	if (digest) {
    146 		int i;
    147 		is_valid = 1;
    148 		/* print it, comparing as we go */
    149 		for (i = 0; i < SHA256_DIGEST_SIZE; i++) {
    150 			printf("%02x", gbb->hwid_digest[i]);
    151 			if (gbb->hwid_digest[i] != digest[i])
    152 				is_valid = 0;
    153 		}
    154 		free(digest);
    155 	}
    156 
    157 	printf("   %s", is_valid ? "valid" : "<invalid>");
    158 	printf("%s", footer);
    159 	return is_valid;
    160 }
    161 
    162 /* For GBB v1.2 and later, update the hwid_digest field. */
    163 void update_hwid_digest(GoogleBinaryBlockHeader *gbb)
    164 {
    165 	/* There isn't one for v1.1 and earlier */
    166 	if (gbb->minor_version < 2)
    167 		return;
    168 
    169 	uint8_t *buf = (uint8_t *)gbb;
    170 	char *hwid_str = (char *)(buf + gbb->hwid_offset);
    171 	uint8_t *digest = DigestBuf(buf + gbb->hwid_offset,
    172 				    strlen(hwid_str),
    173 				    SHA256_DIGEST_ALGORITHM);
    174 	memcpy(gbb->hwid_digest, digest, SHA256_DIGEST_SIZE);
    175 	free(digest);
    176 }
    177 
    178 /*
    179  * TODO: All sorts of race conditions likely here, and everywhere this is used.
    180  * Do we care? If so, fix it.
    181  */
    182 void futil_copy_file_or_die(const char *infile, const char *outfile)
    183 {
    184 	pid_t pid;
    185 	int status;
    186 
    187 	Debug("%s(%s, %s)\n", __func__, infile, outfile);
    188 
    189 	pid = fork();
    190 
    191 	if (pid < 0) {
    192 		fprintf(stderr, "Couldn't fork /bin/cp process: %s\n",
    193 			strerror(errno));
    194 		exit(1);
    195 	}
    196 
    197 	/* child */
    198 	if (!pid) {
    199 		execl("/bin/cp", "/bin/cp", infile, outfile, NULL);
    200 		fprintf(stderr, "Child couldn't exec /bin/cp: %s\n",
    201 			strerror(errno));
    202 		exit(1);
    203 	}
    204 
    205 	/* parent - wait for child to finish */
    206 	if (wait(&status) == -1) {
    207 		fprintf(stderr,
    208 			"Couldn't wait for /bin/cp process to exit: %s\n",
    209 			strerror(errno));
    210 		exit(1);
    211 	}
    212 
    213 	if (WIFEXITED(status)) {
    214 		status = WEXITSTATUS(status);
    215 		/* zero is normal exit */
    216 		if (!status)
    217 			return;
    218 		fprintf(stderr, "/bin/cp exited with status %d\n", status);
    219 		exit(1);
    220 	}
    221 
    222 	if (WIFSIGNALED(status)) {
    223 		status = WTERMSIG(status);
    224 		fprintf(stderr, "/bin/cp was killed with signal %d\n", status);
    225 		exit(1);
    226 	}
    227 
    228 	fprintf(stderr, "I have no idea what just happened\n");
    229 	exit(1);
    230 }
    231 
    232 
    233 enum futil_file_err futil_map_file(int fd, int writeable,
    234 				   uint8_t **buf, uint32_t *len)
    235 {
    236 	struct stat sb;
    237 	void *mmap_ptr;
    238 	uint32_t reasonable_len;
    239 
    240 	if (0 != fstat(fd, &sb)) {
    241 		fprintf(stderr, "Can't stat input file: %s\n",
    242 			strerror(errno));
    243 		return FILE_ERR_STAT;
    244 	}
    245 
    246 #ifndef HAVE_MACOS
    247 	if (S_ISBLK(sb.st_mode))
    248 		ioctl(fd, BLKGETSIZE64, &sb.st_size);
    249 #endif
    250 
    251 	/* If the image is larger than 2^32 bytes, it's wrong. */
    252 	if (sb.st_size < 0 || sb.st_size > UINT32_MAX) {
    253 		fprintf(stderr, "Image size is unreasonable\n");
    254 		return FILE_ERR_SIZE;
    255 	}
    256 	reasonable_len = (uint32_t)sb.st_size;
    257 
    258 	if (writeable)
    259 		mmap_ptr = mmap(0, sb.st_size,
    260 				PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
    261 	else
    262 		mmap_ptr = mmap(0, sb.st_size,
    263 				PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
    264 
    265 	if (mmap_ptr == (void *)-1) {
    266 		fprintf(stderr, "Can't mmap %s file: %s\n",
    267 			writeable ? "output" : "input",
    268 			strerror(errno));
    269 		return FILE_ERR_MMAP;
    270 	}
    271 
    272 	*buf = (uint8_t *)mmap_ptr;
    273 	*len = reasonable_len;
    274 	return FILE_ERR_NONE;
    275 }
    276 
    277 enum futil_file_err futil_unmap_file(int fd, int writeable,
    278 				     uint8_t *buf, uint32_t len)
    279 {
    280 	void *mmap_ptr = buf;
    281 	enum futil_file_err err = FILE_ERR_NONE;
    282 
    283 	if (writeable &&
    284 	    (0 != msync(mmap_ptr, len, MS_SYNC|MS_INVALIDATE))) {
    285 		fprintf(stderr, "msync failed: %s\n", strerror(errno));
    286 		err = FILE_ERR_MSYNC;
    287 	}
    288 
    289 	if (0 != munmap(mmap_ptr, len)) {
    290 		fprintf(stderr, "Can't munmap pointer: %s\n",
    291 			strerror(errno));
    292 		if (err == FILE_ERR_NONE)
    293 			err = FILE_ERR_MUNMAP;
    294 	}
    295 
    296 	return err;
    297 }
    298 
    299 
    300 #define DISK_SECTOR_SIZE 512
    301 enum futil_file_type recognize_gpt(uint8_t *buf, uint32_t len)
    302 {
    303 	GptHeader *h;
    304 
    305 	/* GPT header starts at sector 1, is one sector long */
    306 	if (len < 2 * DISK_SECTOR_SIZE)
    307 		return FILE_TYPE_UNKNOWN;
    308 
    309 	h = (GptHeader *)(buf + DISK_SECTOR_SIZE);
    310 
    311 	if (memcmp(h->signature, GPT_HEADER_SIGNATURE,
    312 		   GPT_HEADER_SIGNATURE_SIZE) &&
    313 	    memcmp(h->signature, GPT_HEADER_SIGNATURE2,
    314 		   GPT_HEADER_SIGNATURE_SIZE))
    315 		return FILE_TYPE_UNKNOWN;
    316 	if (h->revision != GPT_HEADER_REVISION)
    317 		return FILE_TYPE_UNKNOWN;
    318 	if (h->size < MIN_SIZE_OF_HEADER || h->size > MAX_SIZE_OF_HEADER)
    319 		return FILE_TYPE_UNKNOWN;
    320 
    321 	if (HeaderCrc(h) != h->header_crc32)
    322 		return FILE_TYPE_UNKNOWN;
    323 
    324 	return FILE_TYPE_CHROMIUMOS_DISK;
    325 }
    326