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