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;
}
Exemple #3
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;
}
Exemple #6
0
/**
 * 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;
}