static int do_vbexport_test_malloc_size(uint32_t size) { char *mem = VbExMalloc(size); int i, line_size; #if CONFIG_ARM line_size = dcache_get_line_size(); #elif defined CACHE_LINE_SIZE line_size = CACHE_LINE_SIZE; #else line_size = __BIGGEST_ALIGNMENT__; #endif VbExDebug("Trying to malloc a memory block for %lu bytes...", size); if ((uintptr_t)mem % line_size != 0) { VbExDebug("\nMemory not algined with a cache line!\n"); VbExFree(mem); return 1; } for (i = 0; i < size; i++) { mem[i] = i % 0x100; } for (i = 0; i < size; i++) { if (mem[i] != i % 0x100) { VbExDebug("\nMemory verification failed!\n"); VbExFree(mem); return 1; } } VbExFree(mem); VbExDebug(" - SUCCESS\n"); return 0; }
/** * Show an image on the screen at the given location */ static int show_image(ImageInfo *image, int x, int y) { uint32_t inoutsize; void *rawimg; int err; inoutsize = image->original_size; if (COMPRESS_NONE == image->compression) { rawimg = NULL; } else { rawimg = VbExMalloc(inoutsize); if (VbExDecompress(image + 1, image->compressed_size, image->compression, rawimg, &inoutsize)) { return -1; } } err = VbExDisplayImage(x, y, rawimg ? rawimg : image + 1, inoutsize); if (rawimg) VbExFree(rawimg); return err ? -1 : 0; }
/* Reset mock data (for use before each test) */ static void ResetMocks(void) { int gbb_used; Memset(gbb_data, 0, sizeof(gbb_data)); gbb->major_version = GBB_MAJOR_VER; gbb->minor_version = GBB_MINOR_VER; gbb->flags = 0; gbb_used = sizeof(GoogleBinaryBlockHeader); gbb->hwid_offset = gbb_used; strcpy(gbb_data + gbb->hwid_offset, "Test HWID"); gbb->hwid_size = strlen(gbb_data + gbb->hwid_offset) + 1; gbb_used = (gbb_used + gbb->hwid_size + 7) & ~7; gbb->bmpfv_offset = gbb_used; bhdr = (BmpBlockHeader *)(gbb_data + gbb->bmpfv_offset); gbb->bmpfv_size = sizeof(BmpBlockHeader); gbb_used = (gbb_used + gbb->bmpfv_size + 7) & ~7; memcpy(bhdr->signature, BMPBLOCK_SIGNATURE, BMPBLOCK_SIGNATURE_SIZE); bhdr->major_version = BMPBLOCK_MAJOR_VERSION; bhdr->minor_version = BMPBLOCK_MINOR_VERSION; bhdr->number_of_localizations = 3; Memset(&cparams, 0, sizeof(cparams)); cparams.shared_data_size = sizeof(shared_data); cparams.shared_data_blob = shared_data; cparams.gbb_data = gbb; cparams.gbb_size = sizeof(gbb_data); /* * Note, VbApiKernelFree() expects this to be allocated by * VbExMalloc(), so we cannot just assign it staticly. */ cparams.gbb = VbExMalloc(sizeof(*gbb)); gbb->header_size = sizeof(*gbb); gbb->rootkey_offset = gbb_used; gbb->rootkey_size = 64; gbb_used += 64; gbb->recovery_key_offset = gbb_used; gbb->recovery_key_size = 64; gbb_used += 64; memcpy(cparams.gbb, gbb, sizeof(*gbb)); Memset(&vnc, 0, sizeof(vnc)); VbNvSetup(&vnc); VbNvTeardown(&vnc); /* So CRC gets generated */ Memset(&shared_data, 0, sizeof(shared_data)); VbSharedDataInit(shared, sizeof(shared_data)); *debug_info = 0; }
/* * Allocates 1-block-sized memory to block_buf_ptr and fills it as the first * block of the disk. * Returns 0 for success, non-zero for failure. */ static int get_nvcxt_block_of_disk(const VbDiskInfo *disk, uint8_t **block_buf_ptr) { uint8_t *block_buf = NULL; block_buf = VbExMalloc(disk->bytes_per_lba); if (VbExDiskRead(disk->handle, CHROMEOS_VBNVCONTEXT_LBA, 1, block_buf)) { VBDEBUG("Failed to read internal disk!\n"); VbExFree(block_buf); return 1; } *block_buf_ptr = block_buf; return 0; }
VbError_t VbExStreamOpen(VbExDiskHandle_t handle, uint64_t lba_start, uint64_t lba_count, VbExStream_t *stream) { struct disk_stream *s; if (!handle) { *stream = NULL; return VBERROR_UNKNOWN; } s = VbExMalloc(sizeof(*s)); s->handle = handle; s->sector = lba_start; s->sectors_left = lba_count; *stream = (void *)s; return VBERROR_SUCCESS; }
/** * Allocate and read GPT data from the drive. * * The sector_bytes and gpt_drive_sectors fields should be filled on input. The * primary and secondary header and entries are filled on output. * * Returns 0 if successful, 1 if error. */ int AllocAndReadGptData(VbExDiskHandle_t disk_handle, GptData *gptdata) { uint64_t max_entries_bytes = MAX_NUMBER_OF_ENTRIES * sizeof(GptEntry); int primary_valid = 0, secondary_valid = 0; /* No data to be written yet */ gptdata->modified = 0; /* Allocate all buffers */ gptdata->primary_header = (uint8_t *)VbExMalloc(gptdata->sector_bytes); gptdata->secondary_header = (uint8_t *)VbExMalloc(gptdata->sector_bytes); gptdata->primary_entries = (uint8_t *)VbExMalloc(max_entries_bytes); gptdata->secondary_entries = (uint8_t *)VbExMalloc(max_entries_bytes); if (gptdata->primary_header == NULL || gptdata->secondary_header == NULL || gptdata->primary_entries == NULL || gptdata->secondary_entries == NULL) return 1; /* Read primary header from the drive, skipping the protective MBR */ if (0 != VbExDiskRead(disk_handle, 1, 1, gptdata->primary_header)) { VBDEBUG(("Read error in primary GPT header\n")); Memset(gptdata->primary_header, 0, gptdata->sector_bytes); } /* Only read primary GPT if the primary header is valid */ GptHeader* primary_header = (GptHeader*)gptdata->primary_header; if (0 == CheckHeader(primary_header, 0, gptdata->streaming_drive_sectors, gptdata->gpt_drive_sectors, gptdata->flags)) { primary_valid = 1; uint64_t entries_bytes = primary_header->number_of_entries * primary_header->size_of_entry; uint64_t entries_sectors = entries_bytes / gptdata->sector_bytes; if (0 != VbExDiskRead(disk_handle, primary_header->entries_lba, entries_sectors, gptdata->primary_entries)) { VBDEBUG(("Read error in primary GPT entries\n")); primary_valid = 0; } } else { VBDEBUG(("Primary GPT header invalid!\n")); } /* Read secondary header from the end of the drive */ if (0 != VbExDiskRead(disk_handle, gptdata->gpt_drive_sectors - 1, 1, gptdata->secondary_header)) { VBDEBUG(("Read error in secondary GPT header\n")); Memset(gptdata->secondary_header, 0, gptdata->sector_bytes); } /* Only read secondary GPT if the secondary header is valid */ GptHeader* secondary_header = (GptHeader*)gptdata->secondary_header; if (0 == CheckHeader(secondary_header, 1, gptdata->streaming_drive_sectors, gptdata->gpt_drive_sectors, gptdata->flags)) { secondary_valid = 1; uint64_t entries_bytes = secondary_header->number_of_entries * secondary_header->size_of_entry; uint64_t entries_sectors = entries_bytes / gptdata->sector_bytes; if (0 != VbExDiskRead(disk_handle, secondary_header->entries_lba, entries_sectors, gptdata->secondary_entries)) { VBDEBUG(("Read error in secondary GPT entries\n")); secondary_valid = 0; } } else { VBDEBUG(("Secondary GPT header invalid!\n")); } /* Return 0 if least one GPT header was valid */ return (primary_valid || secondary_valid) ? 0 : 1; }
/** * Find and return a valid set of note events. * * We'll use the user's struct if possible, but we will still enforce the * 30-second timeout and require at least a second of audible noise within that * period. We allocate storage for two reasons: the user's struct will be in * flash, which is slow to read, and we may need one extra note at the end to * pad out the user's notes to a full 30 seconds. The caller should free it * when finished. */ static void VbGetDevMusicNotes(VbAudioContext *audio, int use_short) { VbDevMusicNote *notebuf = 0; VbDevMusicNote *builtin = 0; VbDevMusic *hdr = CUSTOM_MUSIC_NOTES; uint32_t maxsize = CUSTOM_MUSIC_MAXSIZE; /* always <= flash size (8M) */ uint32_t maxnotes, mysum, mylen, i; uint32_t this_msecs, on_msecs, total_msecs; uint32_t count; VBDEBUG(("VbGetDevMusicNotes: use_short is %d, hdr is %lx, " "maxsize is %d\n", use_short, hdr, maxsize)); if (use_short) { builtin = short_notes_; count = short_count_; goto nope; } builtin = default_notes_; count = default_count_; /* If we can't beep in the background, don't allow customization. */ if (!audio->background_beep) goto nope; if (!hdr || maxsize < sizeof(VbDevMusic)) goto nope; if (0 != Memcmp(hdr->sig, "$SND", sizeof(hdr->sig))) { VBDEBUG(("VbGetDevMusicNotes: bad sig\n")); goto nope; } /* * How many notes will fit in the flash region? One more than you'd * think, because there's one note in the header itself. */ maxnotes = 1 + (maxsize - sizeof(VbDevMusic)) / sizeof(VbDevMusicNote); if (hdr->count == 0 || hdr->count > maxnotes) { VBDEBUG(("VbGetDevMusicNotes: count=%d maxnotes=%d\n", hdr->count, maxnotes)); goto nope; } /* * CUSTOM_MUSIC_MAXSIZE can't be larger than the size of the flash * (around 8M or so) so this isn't really necessary, but let's be safe * anyway. */ if ((sizeof(VbDevMusicNote) > UINT_MAX / hdr->count) || (sizeof(hdr->count) > UINT_MAX - hdr->count * sizeof(VbDevMusicNote))) { VBDEBUG(("VbGetDevMusicNotes: count=%d, just isn't right\n")); goto nope; } /* Now we know this won't overflow */ mylen = (uint32_t)(sizeof(hdr->count) + hdr->count * sizeof(VbDevMusicNote)); mysum = Crc32(&(hdr->count), mylen); if (mysum != hdr->checksum) { VBDEBUG(("VbGetDevMusicNotes: mysum=%08x, want=%08x\n", mysum, hdr->checksum)); goto nope; } VBDEBUG(("VbGetDevMusicNotes: custom notes struct at %lx\n", hdr)); /* * Measure the audible sound up to the first 22 seconds, being careful * to avoid rollover. The note time is 16 bits, and the note count is * 32 bits. The product should fit in 64 bits. */ total_msecs = 0; on_msecs = 0; for (i=0; i < hdr->count; i++) { this_msecs = hdr->notes[i].msec ; if (this_msecs) { total_msecs += this_msecs; if (total_msecs <= REQUIRED_NOISE_WITHIN && hdr->notes[i].frequency >= 100 && hdr->notes[i].frequency <= 2000) on_msecs += this_msecs; } } /* We require at least one second of noise in the first 22 seconds */ VBDEBUG(("VbGetDevMusicNotes: with %ld msecs of sound to begin\n", on_msecs)); if (on_msecs < REQUIRED_NOISE_TIME) goto nope; /* * We'll also require that the total time be less than a minute. No * real reason, it just gives us less to worry about. */ VBDEBUG(("VbGetDevMusicNotes: lasting %ld msecs\n", total_msecs)); if (total_msecs > MAX_CUSTOM_DELAY) { goto nope; } /* One more check, just to be paranoid. */ if (hdr->count > (UINT_MAX / sizeof(VbDevMusicNote) - 1)) { VBDEBUG(("VbGetDevMusicNotes: they're all out to get me!\n")); goto nope; } /* Looks good. Allocate the space (plus one) and copy it over. */ notebuf = VbExMalloc((hdr->count + 1) * sizeof(VbDevMusicNote)); Memcpy(notebuf, hdr->notes, hdr->count * sizeof(VbDevMusicNote)); count = hdr->count; /* We also require at least 30 seconds of delay. */ if (total_msecs < REQUIRED_TOTAL_DELAY) { /* * If the total time is less than 30 seconds, the needed * difference will fit in 16 bits. */ this_msecs = (REQUIRED_TOTAL_DELAY - total_msecs) & 0xffff; notebuf[hdr->count].msec = this_msecs; notebuf[hdr->count].frequency = 0; count++; VBDEBUG(("VbGetDevMusicNotes: adding %ld msecs of silence\n", this_msecs)); } /* Done */ audio->music_notes = notebuf; audio->note_count = count; audio->free_notes_when_done = 1; return; nope: /* No custom notes, use the default. The count is already set. */ VBDEBUG(("VbGetDevMusicNotes: using %d default notes\n", count)); audio->music_notes = builtin; audio->note_count = count; audio->free_notes_when_done = 0; }
static int do_vbexport_test_diskrw(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { int ret = 0; VbDiskInfo *disk_info; VbExDiskHandle_t handle; uint32_t disk_count, test_lba_count, buf_byte_count, i; uint8_t *original_buf, *target_buf, *verify_buf; uint64_t t0, t1; switch (argc) { case 1: /* if no argument given, use the default lba count */ test_lba_count = DEFAULT_TEST_LBA_COUNT; break; case 2: /* use argument */ test_lba_count = simple_strtoul(argv[1], NULL, 10); if (!test_lba_count) { VbExDebug("The first argument is not a number!\n"); return cmd_usage(cmdtp); } break; default: return cmd_usage(cmdtp); } /* We perform read/write operations on the first internal disk. */ if (VbExDiskGetInfo(&disk_info, &disk_count, VB_DISK_FLAG_FIXED) || disk_count == 0) { VbExDebug("No internal disk found!\n"); return 1; } handle = disk_info[0].handle; buf_byte_count = disk_info[0].bytes_per_lba * test_lba_count; VbExDiskFreeInfo(disk_info, handle); /* Allocate the buffer and fill the target test pattern. */ original_buf = VbExMalloc(buf_byte_count); target_buf = VbExMalloc(buf_byte_count); verify_buf = VbExMalloc(buf_byte_count); /* Fill the target test pattern. */ for (i = 0; i < buf_byte_count; i++) target_buf[i] = i & 0xff; t0 = VbExGetTimer(); if (VbExDiskRead(handle, TEST_LBA_START, test_lba_count, original_buf)) { VbExDebug("Failed to read disk.\n"); goto out; } t1 = VbExGetTimer(); VbExDebug("test_diskrw: disk_read, lba_count: %u, time: %llu\n", test_lba_count, t1 - t0); t0 = VbExGetTimer(); ret = VbExDiskWrite(handle, TEST_LBA_START, test_lba_count, target_buf); t1 = VbExGetTimer(); VbExDebug("test_diskrw: disk_write, lba_count: %u, time: %llu\n", test_lba_count, t1 - t0); if (ret) { VbExDebug("Failed to write disk.\n"); ret = 1; } else { /* Read back and verify the data. */ VbExDiskRead(handle, TEST_LBA_START, test_lba_count, verify_buf); if (memcmp(target_buf, verify_buf, buf_byte_count) != 0) { VbExDebug("Verify failed. The target data wrote " "wrong.\n"); ret = 1; } } /* Write the original data back. */ if (VbExDiskWrite(handle, TEST_LBA_START, test_lba_count, original_buf)) { VbExDebug("Failed to write the original data back. The disk " "may now be corrupt.\n"); } out: VbExDiskFreeInfo(disk_info, NULL); VbExFree(original_buf); VbExFree(target_buf); VbExFree(verify_buf); if (ret == 0) VbExDebug("Read and write disk test SUCCESS.\n"); return ret; }
VbError_t VbSelectAndLoadKernel(VbCommonParams *cparams, VbSelectAndLoadKernelParams *kparams) { VbSharedDataHeader *shared = (VbSharedDataHeader *)cparams->shared_data_blob; VbError_t retval = VBERROR_SUCCESS; LoadKernelParams p; uint32_t tpm_status = 0; /* Start timer */ shared->timer_vb_select_and_load_kernel_enter = VbExGetTimer(); VbExNvStorageRead(vnc.raw); VbNvSetup(&vnc); /* Clear output params in case we fail */ kparams->disk_handle = NULL; kparams->partition_number = 0; kparams->bootloader_address = 0; kparams->bootloader_size = 0; kparams->flags = 0; Memset(kparams->partition_guid, 0, sizeof(kparams->partition_guid)); cparams->bmp = NULL; cparams->gbb = VbExMalloc(sizeof(*cparams->gbb)); retval = VbGbbReadHeader_static(cparams, cparams->gbb); if (VBERROR_SUCCESS != retval) goto VbSelectAndLoadKernel_exit; /* Do EC software sync if necessary */ if ((shared->flags & VBSD_EC_SOFTWARE_SYNC) && !(cparams->gbb->flags & GBB_FLAG_DISABLE_EC_SOFTWARE_SYNC)) { int oprom_mismatch = 0; retval = VbEcSoftwareSync(0, cparams); /* Save reboot requested until after possible PD sync */ if (retval == VBERROR_VGA_OPROM_MISMATCH) oprom_mismatch = 1; else if (retval != VBERROR_SUCCESS) goto VbSelectAndLoadKernel_exit; #ifdef PD_SYNC if (!(cparams->gbb->flags & GBB_FLAG_DISABLE_PD_SOFTWARE_SYNC)) { retval = VbEcSoftwareSync(1, cparams); if (retval == VBERROR_VGA_OPROM_MISMATCH) oprom_mismatch = 1; else if (retval != VBERROR_SUCCESS) goto VbSelectAndLoadKernel_exit; } #endif /* Request reboot to unload VGA Option ROM */ if (oprom_mismatch) { retval = VBERROR_VGA_OPROM_MISMATCH; goto VbSelectAndLoadKernel_exit; } } /* Read kernel version from the TPM. Ignore errors in recovery mode. */ tpm_status = RollbackKernelRead(&shared->kernel_version_tpm); if (0 != tpm_status) { VBDEBUG(("Unable to get kernel versions from TPM\n")); if (!shared->recovery_reason) { VbSetRecoveryRequest(VBNV_RECOVERY_RW_TPM_R_ERROR); retval = VBERROR_TPM_READ_KERNEL; goto VbSelectAndLoadKernel_exit; } } shared->kernel_version_tpm_start = shared->kernel_version_tpm; /* Fill in params for calls to LoadKernel() */ Memset(&p, 0, sizeof(p)); p.shared_data_blob = cparams->shared_data_blob; p.shared_data_size = cparams->shared_data_size; p.gbb_data = cparams->gbb_data; p.gbb_size = cparams->gbb_size; /* * This could be set to NULL, in which case the vboot header * information about the load address and size will be used. */ p.kernel_buffer = kparams->kernel_buffer; p.kernel_buffer_size = kparams->kernel_buffer_size; p.nv_context = &vnc; p.boot_flags = 0; if (shared->flags & VBSD_BOOT_DEV_SWITCH_ON) p.boot_flags |= BOOT_FLAG_DEVELOPER; /* Handle separate normal and developer firmware builds. */ #if defined(VBOOT_FIRMWARE_TYPE_NORMAL) /* Normal-type firmware always acts like the dev switch is off. */ p.boot_flags &= ~BOOT_FLAG_DEVELOPER; #elif defined(VBOOT_FIRMWARE_TYPE_DEVELOPER) /* Developer-type firmware fails if the dev switch is off. */ if (!(p.boot_flags & BOOT_FLAG_DEVELOPER)) { /* * Dev firmware should be signed with a key that only verifies * when the dev switch is on, so we should never get here. */ VBDEBUG(("Developer firmware called with dev switch off!\n")); VbSetRecoveryRequest(VBNV_RECOVERY_RW_DEV_MISMATCH); retval = VBERROR_DEV_FIRMWARE_SWITCH_MISMATCH; goto VbSelectAndLoadKernel_exit; } #else /* * Recovery firmware, or merged normal+developer firmware. No need to * override flags. */ #endif /* Select boot path */ if (shared->recovery_reason) { /* Recovery boot */ p.boot_flags |= BOOT_FLAG_RECOVERY; retval = VbBootRecovery(cparams, &p); VbExEcEnteringMode(0, VB_EC_RECOVERY); VbDisplayScreen(cparams, VB_SCREEN_BLANK, 0, &vnc); } else if (p.boot_flags & BOOT_FLAG_DEVELOPER) { /* Developer boot */ retval = VbBootDeveloper(cparams, &p); VbExEcEnteringMode(0, VB_EC_DEVELOPER); VbDisplayScreen(cparams, VB_SCREEN_BLANK, 0, &vnc); } else { /* Normal boot */ VbExEcEnteringMode(0, VB_EC_NORMAL); retval = VbBootNormal(cparams, &p); if ((1 == shared->firmware_index) && (shared->flags & VBSD_FWB_TRIED)) { /* * Special cases for when we're trying a new firmware * B. These are needed because firmware updates also * usually change the kernel key, which means that the * B firmware can only boot a new kernel, and the old * firmware in A can only boot the previous kernel. * * Don't advance the TPM if we're trying a new firmware * B, because we don't yet know if the new kernel will * successfully boot. We still want to be able to fall * back to the previous firmware+kernel if the new * firmware+kernel fails. * * If we found only invalid kernels, reboot and try * again. This allows us to fall back to the previous * firmware+kernel instead of giving up and going to * recovery mode right away. We'll still go to * recovery mode if we run out of tries and the old * firmware can't find a kernel it likes. */ if (VBERROR_INVALID_KERNEL_FOUND == retval) { VBDEBUG(("Trying firmware B, " "and only found invalid kernels.\n")); VbSetRecoveryRequest(VBNV_RECOVERY_NOT_REQUESTED); goto VbSelectAndLoadKernel_exit; } } else { /* Not trying a new firmware B. */ /* See if we need to update the TPM. */ VBDEBUG(("Checking if TPM kernel version needs " "advancing\n")); if (shared->kernel_version_tpm > shared->kernel_version_tpm_start) { tpm_status = RollbackKernelWrite( shared->kernel_version_tpm); if (0 != tpm_status) { VBDEBUG(("Error writing kernel " "versions to TPM.\n")); VbSetRecoveryRequest(VBNV_RECOVERY_RW_TPM_W_ERROR); retval = VBERROR_TPM_WRITE_KERNEL; goto VbSelectAndLoadKernel_exit; } } } } if (VBERROR_SUCCESS != retval) goto VbSelectAndLoadKernel_exit; /* Save disk parameters */ kparams->disk_handle = p.disk_handle; kparams->partition_number = (uint32_t)p.partition_number; kparams->bootloader_address = p.bootloader_address; kparams->bootloader_size = (uint32_t)p.bootloader_size; kparams->flags = p.flags; Memcpy(kparams->partition_guid, p.partition_guid, sizeof(kparams->partition_guid)); /* Lock the kernel versions. Ignore errors in recovery mode. */ tpm_status = RollbackKernelLock(shared->recovery_reason); if (0 != tpm_status) { VBDEBUG(("Error locking kernel versions.\n")); if (!shared->recovery_reason) { VbSetRecoveryRequest(VBNV_RECOVERY_RW_TPM_L_ERROR); retval = VBERROR_TPM_LOCK_KERNEL; goto VbSelectAndLoadKernel_exit; } } VbSelectAndLoadKernel_exit: VbApiKernelFree(cparams); VbNvTeardown(&vnc); if (vnc.raw_changed) VbExNvStorageWrite(vnc.raw); /* Stop timer */ shared->timer_vb_select_and_load_kernel_exit = VbExGetTimer(); kparams->kernel_buffer = p.kernel_buffer; kparams->kernel_buffer_size = p.kernel_buffer_size; VBDEBUG(("VbSelectAndLoadKernel() returning %d\n", (int)retval)); /* Pass through return value from boot path */ return retval; }
VbError_t VbVerifyMemoryBootImage(VbCommonParams *cparams, VbSelectAndLoadKernelParams *kparams, void *boot_image, size_t image_size) { VbError_t retval; VbPublicKey* kernel_subkey = NULL; uint8_t *kbuf; VbKeyBlockHeader *key_block; VbSharedDataHeader *shared = (VbSharedDataHeader *)cparams->shared_data_blob; RSAPublicKey *data_key = NULL; VbKernelPreambleHeader *preamble; uint64_t body_offset; int hash_only = 0; int dev_switch; if ((boot_image == NULL) || (image_size == 0)) return VBERROR_INVALID_PARAMETER; /* Clear output params in case we fail. */ kparams->disk_handle = NULL; kparams->partition_number = 0; kparams->bootloader_address = 0; kparams->bootloader_size = 0; kparams->flags = 0; Memset(kparams->partition_guid, 0, sizeof(kparams->partition_guid)); kbuf = boot_image; /* Read GBB Header */ cparams->bmp = NULL; cparams->gbb = VbExMalloc(sizeof(*cparams->gbb)); retval = VbGbbReadHeader_static(cparams, cparams->gbb); if (VBERROR_SUCCESS != retval) { VBDEBUG(("Gbb read header failed.\n")); return retval; } /* * We don't care verifying the image if: * 1. dev-mode switch is on and * 2. GBB_FLAG_FORCE_DEV_BOOT_FASTBOOT_FULL_CAP is set. * * Check only the integrity of the image. */ dev_switch = shared->flags & VBSD_BOOT_DEV_SWITCH_ON; if (dev_switch && (cparams->gbb->flags & GBB_FLAG_FORCE_DEV_BOOT_FASTBOOT_FULL_CAP)) { VBDEBUG(("Only performing integrity-check.\n")); hash_only = 1; } else { /* Get recovery key. */ retval = VbGbbReadRecoveryKey(cparams, &kernel_subkey); if (VBERROR_SUCCESS != retval) { VBDEBUG(("Gbb Read Recovery key failed.\n")); return retval; } } /* If we fail at any step, retval returned would be invalid kernel. */ retval = VBERROR_INVALID_KERNEL_FOUND; /* Verify the key block. */ key_block = (VbKeyBlockHeader *)kbuf; if (0 != KeyBlockVerify(key_block, image_size, kernel_subkey, hash_only)) { VBDEBUG(("Verifying key block signature/hash failed.\n")); goto fail; } /* Check the key block flags against the current boot mode. */ if (!(key_block->key_block_flags & (dev_switch ? KEY_BLOCK_FLAG_DEVELOPER_1 : KEY_BLOCK_FLAG_DEVELOPER_0))) { VBDEBUG(("Key block developer flag mismatch.\n")); if (hash_only == 0) goto fail; } if (!(key_block->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_1)) { VBDEBUG(("Key block recovery flag mismatch.\n")); if (hash_only == 0) goto fail; } /* Get key for preamble/data verification from the key block. */ data_key = PublicKeyToRSA(&key_block->data_key); if (!data_key) { VBDEBUG(("Data key bad.\n")); goto fail; } /* Verify the preamble, which follows the key block */ preamble = (VbKernelPreambleHeader *)(kbuf + key_block->key_block_size); if ((0 != VerifyKernelPreamble(preamble, image_size - key_block->key_block_size, data_key))) { VBDEBUG(("Preamble verification failed.\n")); goto fail; } VBDEBUG(("Kernel preamble is good.\n")); /* Verify kernel data */ body_offset = key_block->key_block_size + preamble->preamble_size; if (0 != VerifyData((const uint8_t *)(kbuf + body_offset), image_size - body_offset, &preamble->body_signature, data_key)) { VBDEBUG(("Kernel data verification failed.\n")); goto fail; } VBDEBUG(("Kernel is good.\n")); /* Fill in output parameters. */ kparams->kernel_buffer = kbuf + body_offset; kparams->kernel_buffer_size = image_size - body_offset; kparams->bootloader_address = preamble->bootloader_address; kparams->bootloader_size = preamble->bootloader_size; if (VbKernelHasFlags(preamble) == VBOOT_SUCCESS) kparams->flags = preamble->flags; retval = VBERROR_SUCCESS; fail: VbApiKernelFree(cparams); if (NULL != data_key) RSAPublicKeyFree(data_key); if (NULL != kernel_subkey) VbExFree(kernel_subkey); return retval; }