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 #include <inttypes.h> /* For PRIu64 */ 9 #include <stdio.h> 10 #include <string.h> 11 #include <unistd.h> 12 #include <openssl/rsa.h> 13 14 #include "file_type.h" 15 #include "futility.h" 16 #include "host_common.h" 17 #include "kernel_blob.h" 18 #include "util_misc.h" 19 #include "vb1_helper.h" 20 21 /****************************************************************************/ 22 /* Here are globals containing all the bits & pieces I'm working on. 23 * 24 * kernel vblock = keyblock + kernel preamble + padding to 64K (or whatever) 25 * kernel blob = 32-bit kernel + config file + params + bootloader stub + 26 * vmlinuz_header 27 * kernel partition = kernel vblock + kernel blob 28 * 29 * The VbKernelPreambleHeader.preamble_size includes the padding. 30 */ 31 32 /* The keyblock, preamble, and kernel blob are kept in separate places. */ 33 static VbKeyBlockHeader *g_keyblock; 34 static VbKernelPreambleHeader *g_preamble; 35 static uint8_t *g_kernel_blob_data; 36 static uint64_t g_kernel_blob_size; 37 38 /* These refer to individual parts within the kernel blob. */ 39 static uint8_t *g_kernel_data; 40 static uint64_t g_kernel_size; 41 static uint8_t *g_config_data; 42 static uint64_t g_config_size; 43 static uint8_t *g_param_data; 44 static uint64_t g_param_size; 45 static uint8_t *g_bootloader_data; 46 static uint64_t g_bootloader_size; 47 static uint8_t *g_vmlinuz_header_data; 48 static uint64_t g_vmlinuz_header_size; 49 50 static uint64_t g_ondisk_bootloader_addr; 51 static uint64_t g_ondisk_vmlinuz_header_addr; 52 53 54 /* 55 * Read the kernel command line from a file. Get rid of \n characters along 56 * the way and verify that the line fits into a 4K buffer. 57 * 58 * Return the buffer contaning the line on success (and set the line length 59 * using the passed in parameter), or NULL in case something goes wrong. 60 */ 61 uint8_t *ReadConfigFile(const char *config_file, uint64_t *config_size) 62 { 63 uint8_t *config_buf; 64 int i; 65 66 config_buf = ReadFile(config_file, config_size); 67 if (!config_buf) 68 return NULL; 69 Debug(" config file size=0x%" PRIx64 "\n", *config_size); 70 if (CROS_CONFIG_SIZE <= *config_size) { /* room for trailing '\0' */ 71 fprintf(stderr, "Config file %s is too large (>= %d bytes)\n", 72 config_file, CROS_CONFIG_SIZE); 73 return NULL; 74 } 75 76 /* Replace newlines with spaces */ 77 for (i = 0; i < *config_size; i++) 78 if ('\n' == config_buf[i]) 79 config_buf[i] = ' '; 80 81 return config_buf; 82 } 83 84 /****************************************************************************/ 85 86 /* Return the smallest integral multiple of [alignment] that is equal 87 * to or greater than [val]. Used to determine the number of 88 * pages/sectors/blocks/whatever needed to contain [val] 89 * items/bytes/etc. */ 90 static uint64_t roundup(uint64_t val, uint64_t alignment) 91 { 92 uint64_t rem = val % alignment; 93 if (rem) 94 return val + (alignment - rem); 95 return val; 96 } 97 98 /* Match regexp /\b--\b/ to delimit the start of the kernel commandline. If we 99 * don't find one, we'll use the whole thing. */ 100 static unsigned int find_cmdline_start(uint8_t *buf_ptr, unsigned int max_len) 101 { 102 char *input = (char *)buf_ptr; 103 int start = 0; 104 int i; 105 for (i = 0; i < max_len - 1 && input[i]; i++) { 106 if ('-' == input[i] && '-' == input[i + 1]) { 107 if ((i == 0 || ' ' == input[i - 1]) && 108 (i + 2 >= max_len || ' ' == input[i + 2])) { 109 /* found "--" with nothing before or after it */ 110 start = i + 2; /* hope for a trailing '\0' */ 111 break; 112 } 113 } 114 } 115 while (' ' == input[start]) /* skip leading spaces */ 116 start++; 117 118 return start; 119 } 120 121 /* Offset of kernel command line string from the start of the kernel blob */ 122 uint64_t KernelCmdLineOffset(VbKernelPreambleHeader *preamble) 123 { 124 return preamble->bootloader_address - preamble->body_load_address - 125 CROS_CONFIG_SIZE - CROS_PARAMS_SIZE; 126 } 127 128 /* Returns the size of the 32-bit kernel, or negative on error. */ 129 static int KernelSize(uint8_t *kernel_buf, uint64_t kernel_size, 130 enum arch_t arch) 131 { 132 uint64_t kernel32_start = 0; 133 struct linux_kernel_params *lh; 134 135 /* Except for x86, the kernel is the kernel. */ 136 if (arch != ARCH_X86) 137 return kernel_size; 138 139 /* The first part of the x86 vmlinuz is a header, followed by 140 * a real-mode boot stub. We only want the 32-bit part. */ 141 lh = (struct linux_kernel_params *)kernel_buf; 142 kernel32_start = (lh->setup_sects + 1) << 9; 143 if (kernel32_start >= kernel_size) { 144 fprintf(stderr, "Malformed kernel\n"); 145 return -1; 146 } 147 return kernel_size - kernel32_start; 148 } 149 150 /* This extracts g_kernel_* and g_param_* from a standard vmlinuz file. 151 * It returns nonzero on error. */ 152 static int PickApartVmlinuz(uint8_t *kernel_buf, uint64_t kernel_size, 153 enum arch_t arch, 154 uint64_t kernel_body_load_address) 155 { 156 uint64_t kernel32_start = 0; 157 uint64_t kernel32_size = kernel_size; 158 struct linux_kernel_params *lh, *params; 159 160 /* Except for x86, the kernel is the kernel. */ 161 if (arch == ARCH_X86) { 162 /* The first part of the x86 vmlinuz is a header, followed by 163 * a real-mode boot stub. We only want the 32-bit part. */ 164 lh = (struct linux_kernel_params *)kernel_buf; 165 kernel32_start = (lh->setup_sects + 1) << 9; 166 if (kernel32_start >= kernel_size) { 167 fprintf(stderr, "Malformed kernel\n"); 168 return -1; 169 } 170 kernel32_size = kernel_size - kernel32_start; 171 172 Debug(" kernel16_start=0x%" PRIx64 "\n", 0); 173 Debug(" kernel16_size=0x%" PRIx64 "\n", kernel32_start); 174 175 /* Copy the original zeropage data from kernel_buf into 176 * g_param_data, then tweak a few fields for our purposes */ 177 params = (struct linux_kernel_params *)(g_param_data); 178 Memcpy(&(params->setup_sects), &(lh->setup_sects), 179 offsetof(struct linux_kernel_params, e820_entries) 180 - offsetof(struct linux_kernel_params, setup_sects)); 181 params->boot_flag = 0; 182 params->ramdisk_image = 0; /* we don't support initrd */ 183 params->ramdisk_size = 0; 184 params->type_of_loader = 0xff; 185 /* We need to point to the kernel commandline arg. On disk, it 186 * will come right after the 32-bit part of the kernel. */ 187 params->cmd_line_ptr = kernel_body_load_address + 188 roundup(kernel32_size, CROS_ALIGN) + 189 find_cmdline_start(g_config_data, g_config_size); 190 Debug(" cmdline_addr=0x%x\n", params->cmd_line_ptr); 191 Debug(" version=0x%x\n", params->version); 192 Debug(" kernel_alignment=0x%x\n", params->kernel_alignment); 193 Debug(" relocatable_kernel=0x%x\n", params->relocatable_kernel); 194 /* Add a fake e820 memory map with 2 entries. */ 195 params->n_e820_entry = 2; 196 params->e820_entries[0].start_addr = 0x00000000; 197 params->e820_entries[0].segment_size = 0x00001000; 198 params->e820_entries[0].segment_type = E820_TYPE_RAM; 199 params->e820_entries[1].start_addr = 0xfffff000; 200 params->e820_entries[1].segment_size = 0x00001000; 201 params->e820_entries[1].segment_type = E820_TYPE_RESERVED; 202 } 203 204 Debug(" kernel32_start=0x%" PRIx64 "\n", kernel32_start); 205 Debug(" kernel32_size=0x%" PRIx64 "\n", kernel32_size); 206 207 /* Keep just the 32-bit kernel. */ 208 if (kernel32_size) { 209 g_kernel_size = kernel32_size; 210 Memcpy(g_kernel_data, kernel_buf + kernel32_start, 211 g_kernel_size); 212 } 213 214 /* done */ 215 return 0; 216 } 217 218 /* Split a kernel blob into separate g_kernel, g_param, g_config, 219 * g_bootloader, and g_vmlinuz_header parts. */ 220 static void UnpackKernelBlob(uint8_t *kernel_blob_data) 221 { 222 uint64_t now; 223 uint64_t vmlinuz_header_size = 0; 224 uint64_t vmlinuz_header_address = 0; 225 226 /* We have to work backwards from the end, because the preamble 227 only describes the bootloader and vmlinuz stubs. */ 228 229 /* Vmlinuz Header is at the end */ 230 if (VbGetKernelVmlinuzHeader(g_preamble, 231 &vmlinuz_header_address, 232 &vmlinuz_header_size) 233 != VBOOT_SUCCESS) { 234 fprintf(stderr, "Unable to retrieve Vmlinuz Header!"); 235 return; 236 } 237 if (vmlinuz_header_size) { 238 now = vmlinuz_header_address - g_preamble->body_load_address; 239 g_vmlinuz_header_size = vmlinuz_header_size; 240 g_vmlinuz_header_data = kernel_blob_data + now; 241 242 Debug("vmlinuz_header_size = 0x%" PRIx64 "\n", 243 g_vmlinuz_header_size); 244 Debug("vmlinuz_header_ofs = 0x%" PRIx64 "\n", now); 245 } 246 247 /* Where does the bootloader stub begin? */ 248 now = g_preamble->bootloader_address - g_preamble->body_load_address; 249 250 /* Bootloader is at the end */ 251 g_bootloader_size = g_preamble->bootloader_size; 252 g_bootloader_data = kernel_blob_data + now; 253 /* TODO: What to do if this is beyond the end of the blob? */ 254 255 Debug("bootloader_size = 0x%" PRIx64 "\n", g_bootloader_size); 256 Debug("bootloader_ofs = 0x%" PRIx64 "\n", now); 257 258 /* Before that is the params */ 259 now -= CROS_PARAMS_SIZE; 260 g_param_size = CROS_PARAMS_SIZE; 261 g_param_data = kernel_blob_data + now; 262 Debug("param_ofs = 0x%" PRIx64 "\n", now); 263 264 /* Before that is the config */ 265 now -= CROS_CONFIG_SIZE; 266 g_config_size = CROS_CONFIG_SIZE; 267 g_config_data = kernel_blob_data + now; 268 Debug("config_ofs = 0x%" PRIx64 "\n", now); 269 270 /* The kernel starts at offset 0 and extends up to the config */ 271 g_kernel_data = kernel_blob_data; 272 g_kernel_size = now; 273 Debug("kernel_size = 0x%" PRIx64 "\n", g_kernel_size); 274 } 275 276 277 /* Replaces the config section of the specified kernel blob. 278 * Return nonzero on error. */ 279 int UpdateKernelBlobConfig(uint8_t *kblob_data, uint64_t kblob_size, 280 uint8_t *config_data, uint64_t config_size) 281 { 282 /* We should have already examined this blob. If not, we could do it 283 * again, but it's more likely due to an error. */ 284 if (kblob_data != g_kernel_blob_data || 285 kblob_size != g_kernel_blob_size) { 286 fprintf(stderr, "Trying to update some other blob\n"); 287 return -1; 288 } 289 290 Memset(g_config_data, 0, g_config_size); 291 Memcpy(g_config_data, config_data, config_size); 292 293 return 0; 294 } 295 296 /* Split a kernel partition into separate vblock and blob parts. */ 297 uint8_t *UnpackKPart(uint8_t *kpart_data, uint64_t kpart_size, 298 uint64_t padding, 299 VbKeyBlockHeader **keyblock_ptr, 300 VbKernelPreambleHeader **preamble_ptr, 301 uint64_t *blob_size_ptr) 302 { 303 VbKeyBlockHeader *keyblock; 304 VbKernelPreambleHeader *preamble; 305 uint64_t vmlinuz_header_size = 0; 306 uint64_t vmlinuz_header_address = 0; 307 uint64_t now = 0; 308 uint32_t flags = 0; 309 310 /* Sanity-check the keyblock */ 311 keyblock = (VbKeyBlockHeader *)kpart_data; 312 Debug("Keyblock is 0x%" PRIx64 " bytes\n", keyblock->key_block_size); 313 now += keyblock->key_block_size; 314 if (now > kpart_size) { 315 fprintf(stderr, 316 "key_block_size advances past the end of the blob\n"); 317 return NULL; 318 } 319 if (now > padding) { 320 fprintf(stderr, 321 "key_block_size advances past %" PRIu64 322 " byte padding\n", 323 padding); 324 return NULL; 325 } 326 327 /* LGTM */ 328 g_keyblock = keyblock; 329 330 /* And the preamble */ 331 preamble = (VbKernelPreambleHeader *)(kpart_data + now); 332 Debug("Preamble is 0x%" PRIx64 " bytes\n", preamble->preamble_size); 333 now += preamble->preamble_size; 334 if (now > kpart_size) { 335 fprintf(stderr, 336 "preamble_size advances past the end of the blob\n"); 337 return NULL; 338 } 339 if (now > padding) { 340 fprintf(stderr, "preamble_size advances past %" PRIu64 341 " byte padding\n", padding); 342 return NULL; 343 } 344 /* LGTM */ 345 Debug(" kernel_version = %d\n", preamble->kernel_version); 346 Debug(" bootloader_address = 0x%" PRIx64 "\n", 347 preamble->bootloader_address); 348 Debug(" bootloader_size = 0x%" PRIx64 "\n", preamble->bootloader_size); 349 Debug(" kern_blob_size = 0x%" PRIx64 "\n", 350 preamble->body_signature.data_size); 351 352 if (VbKernelHasFlags(preamble) == VBOOT_SUCCESS) 353 flags = preamble->flags; 354 Debug(" flags = 0x%" PRIx32 "\n", flags); 355 356 g_preamble = preamble; 357 g_ondisk_bootloader_addr = g_preamble->bootloader_address; 358 359 if (VbGetKernelVmlinuzHeader(preamble, 360 &vmlinuz_header_address, 361 &vmlinuz_header_size) 362 != VBOOT_SUCCESS) { 363 fprintf(stderr, "Unable to retrieve Vmlinuz Header!"); 364 return NULL; 365 } 366 if (vmlinuz_header_size) { 367 Debug(" vmlinuz_header_address = 0x%" PRIx64 "\n", 368 vmlinuz_header_address); 369 Debug(" vmlinuz_header_size = 0x%" PRIx64 "\n", 370 vmlinuz_header_size); 371 g_ondisk_vmlinuz_header_addr = vmlinuz_header_address; 372 } 373 374 Debug("kernel blob is at offset 0x%" PRIx64 "\n", now); 375 g_kernel_blob_data = kpart_data + now; 376 g_kernel_blob_size = preamble->body_signature.data_size; 377 378 /* Sanity check */ 379 if (g_kernel_blob_size < preamble->body_signature.data_size) 380 fprintf(stderr, 381 "Warning: kernel file only has 0x%" PRIx64 " bytes\n", 382 g_kernel_blob_size); 383 384 /* Update the blob pointers */ 385 UnpackKernelBlob(g_kernel_blob_data); 386 387 if (keyblock_ptr) 388 *keyblock_ptr = keyblock; 389 if (preamble_ptr) 390 *preamble_ptr = preamble; 391 if (blob_size_ptr) 392 *blob_size_ptr = g_kernel_blob_size; 393 394 return g_kernel_blob_data; 395 } 396 397 uint8_t *SignKernelBlob(uint8_t *kernel_blob, uint64_t kernel_size, 398 uint64_t padding, 399 int version, uint64_t kernel_body_load_address, 400 VbKeyBlockHeader *keyblock, VbPrivateKey *signpriv_key, 401 uint32_t flags, uint64_t *vblock_size_ptr) 402 { 403 VbSignature *body_sig; 404 VbKernelPreambleHeader *preamble; 405 uint64_t min_size = padding > keyblock->key_block_size 406 ? padding - keyblock->key_block_size : 0; 407 void *outbuf; 408 uint64_t outsize; 409 410 /* Sign the kernel data */ 411 body_sig = CalculateSignature(kernel_blob, kernel_size, signpriv_key); 412 if (!body_sig) { 413 fprintf(stderr, "Error calculating body signature\n"); 414 return NULL; 415 } 416 417 /* Create preamble */ 418 preamble = CreateKernelPreamble(version, 419 kernel_body_load_address, 420 g_ondisk_bootloader_addr, 421 g_bootloader_size, 422 body_sig, 423 g_ondisk_vmlinuz_header_addr, 424 g_vmlinuz_header_size, 425 flags, 426 min_size, 427 signpriv_key); 428 if (!preamble) { 429 fprintf(stderr, "Error creating preamble.\n"); 430 return 0; 431 } 432 433 outsize = keyblock->key_block_size + preamble->preamble_size; 434 outbuf = malloc(outsize); 435 Memset(outbuf, 0, outsize); 436 Memcpy(outbuf, keyblock, keyblock->key_block_size); 437 Memcpy(outbuf + keyblock->key_block_size, 438 preamble, preamble->preamble_size); 439 440 if (vblock_size_ptr) 441 *vblock_size_ptr = outsize; 442 return outbuf; 443 } 444 445 /* Returns zero on success */ 446 int WriteSomeParts(const char *outfile, 447 void *part1_data, uint64_t part1_size, 448 void *part2_data, uint64_t part2_size) 449 { 450 FILE *f; 451 452 /* Write the output file */ 453 Debug("writing %s with 0x%" PRIx64 ", 0x%" PRIx64 "\n", 454 outfile, part1_size, part2_size); 455 456 f = fopen(outfile, "wb"); 457 if (!f) { 458 fprintf(stderr, "Can't open output file %s: %s\n", 459 outfile, strerror(errno)); 460 return -1; 461 } 462 463 if (part1_data && part1_size) { 464 if (1 != fwrite(part1_data, part1_size, 1, f)) { 465 fprintf(stderr, "Can't write output file %s: %s\n", 466 outfile, strerror(errno)); 467 fclose(f); 468 unlink(outfile); 469 return -1; 470 } 471 } 472 473 if (part2_data && part2_size) { 474 if (1 != fwrite(part2_data, part2_size, 1, f)) { 475 fprintf(stderr, "Can't write output file %s: %s\n", 476 outfile, strerror(errno)); 477 fclose(f); 478 unlink(outfile); 479 return -1; 480 } 481 } 482 483 fclose(f); 484 485 /* Success */ 486 return 0; 487 } 488 489 /* Returns 0 on success */ 490 int VerifyKernelBlob(uint8_t *kernel_blob, 491 uint64_t kernel_size, 492 VbPublicKey *signpub_key, 493 const char *keyblock_outfile, 494 uint64_t min_version) 495 { 496 VbPublicKey *data_key; 497 RSAPublicKey *rsa; 498 int rv = -1; 499 uint64_t vmlinuz_header_size = 0; 500 uint64_t vmlinuz_header_address = 0; 501 502 if (0 != KeyBlockVerify(g_keyblock, g_keyblock->key_block_size, 503 signpub_key, (0 == signpub_key))) { 504 fprintf(stderr, "Error verifying key block.\n"); 505 goto done; 506 } 507 508 printf("Key block:\n"); 509 data_key = &g_keyblock->data_key; 510 printf(" Signature: %s\n", 511 signpub_key ? "valid" : "ignored"); 512 printf(" Size: 0x%" PRIx64 "\n", 513 g_keyblock->key_block_size); 514 printf(" Flags: %" PRIu64 " ", 515 g_keyblock->key_block_flags); 516 if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_0) 517 printf(" !DEV"); 518 if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_1) 519 printf(" DEV"); 520 if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_0) 521 printf(" !REC"); 522 if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_1) 523 printf(" REC"); 524 printf("\n"); 525 printf(" Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm, 526 (data_key->algorithm < kNumAlgorithms ? 527 algo_strings[data_key->algorithm] : "(invalid)")); 528 printf(" Data key version: %" PRIu64 "\n", data_key->key_version); 529 printf(" Data key sha1sum: "); 530 PrintPubKeySha1Sum(data_key); 531 printf("\n"); 532 533 if (keyblock_outfile) { 534 FILE *f = NULL; 535 f = fopen(keyblock_outfile, "wb"); 536 if (!f) { 537 fprintf(stderr, "Can't open key block file %s: %s\n", 538 keyblock_outfile, strerror(errno)); 539 goto done; 540 } 541 if (1 != fwrite(g_keyblock, g_keyblock->key_block_size, 1, f)) { 542 fprintf(stderr, "Can't write key block file %s: %s\n", 543 keyblock_outfile, strerror(errno)); 544 fclose(f); 545 goto done; 546 } 547 fclose(f); 548 } 549 550 if (data_key->key_version < (min_version >> 16)) { 551 fprintf(stderr, "Data key version %" PRIu64 552 " is lower than minimum %" PRIu64 ".\n", 553 data_key->key_version, (min_version >> 16)); 554 goto done; 555 } 556 557 rsa = PublicKeyToRSA(data_key); 558 if (!rsa) { 559 fprintf(stderr, "Error parsing data key.\n"); 560 goto done; 561 } 562 563 /* Verify preamble */ 564 if (0 != VerifyKernelPreamble(g_preamble, 565 g_preamble->preamble_size, rsa)) { 566 fprintf(stderr, "Error verifying preamble.\n"); 567 goto done; 568 } 569 570 printf("Preamble:\n"); 571 printf(" Size: 0x%" PRIx64 "\n", 572 g_preamble->preamble_size); 573 printf(" Header version: %" PRIu32 ".%" PRIu32 "\n", 574 g_preamble->header_version_major, 575 g_preamble->header_version_minor); 576 printf(" Kernel version: %" PRIu64 "\n", 577 g_preamble->kernel_version); 578 printf(" Body load address: 0x%" PRIx64 "\n", 579 g_preamble->body_load_address); 580 printf(" Body size: 0x%" PRIx64 "\n", 581 g_preamble->body_signature.data_size); 582 printf(" Bootloader address: 0x%" PRIx64 "\n", 583 g_preamble->bootloader_address); 584 printf(" Bootloader size: 0x%" PRIx64 "\n", 585 g_preamble->bootloader_size); 586 587 if (VbGetKernelVmlinuzHeader(g_preamble, 588 &vmlinuz_header_address, 589 &vmlinuz_header_size) 590 != VBOOT_SUCCESS) { 591 fprintf(stderr, "Unable to retrieve Vmlinuz Header!"); 592 goto done; 593 } 594 if (vmlinuz_header_size) { 595 printf(" Vmlinuz header address: 0x%" PRIx64 "\n", 596 vmlinuz_header_address); 597 printf(" Vmlinuz header size: 0x%" PRIx64 "\n", 598 vmlinuz_header_size); 599 } 600 601 if (VbKernelHasFlags(g_preamble) == VBOOT_SUCCESS) 602 printf(" Flags : 0x%" PRIx32 "\n", 603 g_preamble->flags); 604 605 if (g_preamble->kernel_version < (min_version & 0xFFFF)) { 606 fprintf(stderr, 607 "Kernel version %" PRIu64 " is lower than minimum %" 608 PRIu64 ".\n", g_preamble->kernel_version, 609 (min_version & 0xFFFF)); 610 goto done; 611 } 612 613 /* Verify body */ 614 if (0 != VerifyData(kernel_blob, kernel_size, 615 &g_preamble->body_signature, rsa)) { 616 fprintf(stderr, "Error verifying kernel body.\n"); 617 goto done; 618 } 619 printf("Body verification succeeded.\n"); 620 621 printf("Config:\n%s\n", kernel_blob + KernelCmdLineOffset(g_preamble)); 622 623 rv = 0; 624 done: 625 return rv; 626 } 627 628 629 uint8_t *CreateKernelBlob(uint8_t *vmlinuz_buf, uint64_t vmlinuz_size, 630 enum arch_t arch, uint64_t kernel_body_load_address, 631 uint8_t *config_data, uint64_t config_size, 632 uint8_t *bootloader_data, uint64_t bootloader_size, 633 uint64_t *blob_size_ptr) 634 { 635 uint64_t now = 0; 636 int tmp; 637 638 /* We have all the parts. How much room do we need? */ 639 tmp = KernelSize(vmlinuz_buf, vmlinuz_size, arch); 640 if (tmp < 0) 641 return NULL; 642 g_kernel_size = tmp; 643 g_config_size = CROS_CONFIG_SIZE; 644 g_param_size = CROS_PARAMS_SIZE; 645 g_bootloader_size = roundup(bootloader_size, CROS_ALIGN); 646 g_vmlinuz_header_size = vmlinuz_size-g_kernel_size; 647 g_kernel_blob_size = 648 roundup(g_kernel_size, CROS_ALIGN) + 649 g_config_size + 650 g_param_size + 651 g_bootloader_size + 652 g_vmlinuz_header_size; 653 Debug("g_kernel_blob_size 0x%" PRIx64 "\n", g_kernel_blob_size); 654 655 /* Allocate space for the blob. */ 656 g_kernel_blob_data = malloc(g_kernel_blob_size); 657 Memset(g_kernel_blob_data, 0, g_kernel_blob_size); 658 659 /* Assign the sub-pointers */ 660 g_kernel_data = g_kernel_blob_data + now; 661 Debug("g_kernel_size 0x%" PRIx64 " ofs 0x%" PRIx64 "\n", 662 g_kernel_size, now); 663 now += roundup(g_kernel_size, CROS_ALIGN); 664 665 g_config_data = g_kernel_blob_data + now; 666 Debug("g_config_size 0x%" PRIx64 " ofs 0x%" PRIx64 "\n", 667 g_config_size, now); 668 now += g_config_size; 669 670 g_param_data = g_kernel_blob_data + now; 671 Debug("g_param_size 0x%" PRIx64 " ofs 0x%" PRIx64 "\n", 672 g_param_size, now); 673 now += g_param_size; 674 675 g_bootloader_data = g_kernel_blob_data + now; 676 Debug("g_bootloader_size 0x%" PRIx64 " ofs 0x%" PRIx64 "\n", 677 g_bootloader_size, now); 678 g_ondisk_bootloader_addr = kernel_body_load_address + now; 679 Debug("g_ondisk_bootloader_addr 0x%" PRIx64 "\n", 680 g_ondisk_bootloader_addr); 681 now += g_bootloader_size; 682 683 if (g_vmlinuz_header_size) { 684 g_vmlinuz_header_data = g_kernel_blob_data + now; 685 Debug("g_vmlinuz_header_size 0x%" PRIx64 " ofs 0x%" PRIx64 "\n", 686 g_vmlinuz_header_size, now); 687 g_ondisk_vmlinuz_header_addr = kernel_body_load_address + now; 688 Debug("g_ondisk_vmlinuz_header_addr 0x%" PRIx64 "\n", 689 g_ondisk_vmlinuz_header_addr); 690 } 691 692 Debug("end of kern_blob at kern_blob+0x%" PRIx64 "\n", now); 693 694 /* Copy the kernel and params bits into the correct places */ 695 if (0 != PickApartVmlinuz(vmlinuz_buf, vmlinuz_size, 696 arch, kernel_body_load_address)) { 697 fprintf(stderr, "Error picking apart kernel file.\n"); 698 free(g_kernel_blob_data); 699 g_kernel_blob_data = NULL; 700 g_kernel_blob_size = 0; 701 return NULL; 702 } 703 704 /* Copy the other bits too */ 705 Memcpy(g_config_data, config_data, config_size); 706 Memcpy(g_bootloader_data, bootloader_data, bootloader_size); 707 if (g_vmlinuz_header_size) { 708 Memcpy(g_vmlinuz_header_data, 709 vmlinuz_buf, 710 g_vmlinuz_header_size); 711 } 712 713 if (blob_size_ptr) 714 *blob_size_ptr = g_kernel_blob_size; 715 return g_kernel_blob_data; 716 } 717 718 enum futil_file_type recognize_vblock1(uint8_t *buf, uint32_t len) 719 { 720 VbKeyBlockHeader *key_block = (VbKeyBlockHeader *)buf; 721 VbPublicKey *pubkey = (VbPublicKey *)buf; 722 VbFirmwarePreambleHeader *fw_preamble; 723 VbKernelPreambleHeader *kern_preamble; 724 RSAPublicKey *rsa; 725 726 if (VBOOT_SUCCESS == KeyBlockVerify(key_block, len, NULL, 1)) { 727 rsa = PublicKeyToRSA(&key_block->data_key); 728 uint32_t more = key_block->key_block_size; 729 730 /* and firmware preamble too? */ 731 fw_preamble = (VbFirmwarePreambleHeader *)(buf + more); 732 if (VBOOT_SUCCESS == 733 VerifyFirmwarePreamble(fw_preamble, len - more, rsa)) 734 return FILE_TYPE_FW_PREAMBLE; 735 736 /* or maybe kernel preamble? */ 737 kern_preamble = (VbKernelPreambleHeader *)(buf + more); 738 if (VBOOT_SUCCESS == 739 VerifyKernelPreamble(kern_preamble, len - more, rsa)) 740 return FILE_TYPE_KERN_PREAMBLE; 741 742 /* no, just keyblock */ 743 return FILE_TYPE_KEYBLOCK; 744 } 745 746 /* Maybe just a VbPublicKey? */ 747 if (PublicKeyLooksOkay(pubkey, len)) 748 return FILE_TYPE_PUBKEY; 749 750 return FILE_TYPE_UNKNOWN; 751 } 752 753 enum futil_file_type recognize_privkey(uint8_t *buf, uint32_t len) 754 { 755 VbPrivateKey key; 756 const unsigned char *start; 757 758 if (len < sizeof(key.algorithm)) 759 return FILE_TYPE_UNKNOWN; 760 761 key.algorithm = *(typeof(key.algorithm) *)buf; 762 start = buf + sizeof(key.algorithm); 763 key.rsa_private_key = d2i_RSAPrivateKey(NULL, &start, 764 len - sizeof(key.algorithm)); 765 766 if (key.rsa_private_key) { 767 RSA_free(key.rsa_private_key); 768 return FILE_TYPE_PRIVKEY; 769 } 770 771 return FILE_TYPE_UNKNOWN; 772 } 773