| Index: vboot_firmware/lib/load_kernel_fw.c
|
| diff --git a/vboot_firmware/lib/load_kernel_fw.c b/vboot_firmware/lib/load_kernel_fw.c
|
| index e79e2457267deeba9aa85b8b8595eb3b34d8a9ab..cea6b771570b6c0cb86b729fe20594d50f0b5446 100644
|
| --- a/vboot_firmware/lib/load_kernel_fw.c
|
| +++ b/vboot_firmware/lib/load_kernel_fw.c
|
| @@ -63,12 +63,12 @@ void FakePartitionAttributes(GptData* gpt) {
|
| }
|
|
|
|
|
| -int AllocAndReadGptData(GptData *gptdata) {
|
| - /* Allocates and reads GPT data from the drive. The sector_bytes and
|
| - * 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. */
|
| +/* Allocates and reads GPT data from the drive. The sector_bytes and
|
| + * 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(GptData* gptdata) {
|
|
|
| uint64_t entries_sectors = GPT_ENTRIES_SIZE / gptdata->sector_bytes;
|
|
|
| @@ -100,42 +100,55 @@ int AllocAndReadGptData(GptData *gptdata) {
|
| return 0;
|
| }
|
|
|
| -void WriteAndFreeGptData(GptData *gptdata) {
|
| - /* Writes any changes for the GPT data back to the drive, then frees the
|
| - * buffers. */
|
| +
|
| +/* Writes any changes for the GPT data back to the drive, then frees
|
| + * the buffers.
|
| + *
|
| + * Returns 0 if successful, 1 if error. */
|
| +int WriteAndFreeGptData(GptData* gptdata) {
|
|
|
| uint64_t entries_sectors = GPT_ENTRIES_SIZE / gptdata->sector_bytes;
|
|
|
| if (gptdata->primary_header) {
|
| - if (gptdata->modified & GPT_MODIFIED_HEADER1)
|
| - BootDeviceWriteLBA(1, 1, gptdata->primary_header);
|
| + if (gptdata->modified & GPT_MODIFIED_HEADER1) {
|
| + if (0 != BootDeviceWriteLBA(1, 1, gptdata->primary_header))
|
| + return 1;
|
| + }
|
| Free(gptdata->primary_header);
|
| }
|
|
|
| if (gptdata->primary_entries) {
|
| - if (gptdata->modified & GPT_MODIFIED_ENTRIES1)
|
| - BootDeviceWriteLBA(2, entries_sectors, gptdata->primary_entries);
|
| + if (gptdata->modified & GPT_MODIFIED_ENTRIES1) {
|
| + if (0 != BootDeviceWriteLBA(2, entries_sectors,
|
| + gptdata->primary_entries))
|
| + return 1;
|
| + }
|
| Free(gptdata->primary_entries);
|
| }
|
|
|
| if (gptdata->secondary_entries) {
|
| - if (gptdata->modified & GPT_MODIFIED_ENTRIES2)
|
| - BootDeviceWriteLBA(gptdata->drive_sectors - entries_sectors - 1,
|
| - entries_sectors, gptdata->secondary_entries);
|
| + if (gptdata->modified & GPT_MODIFIED_ENTRIES2) {
|
| + if (0 != BootDeviceWriteLBA(gptdata->drive_sectors - entries_sectors - 1,
|
| + entries_sectors, gptdata->secondary_entries))
|
| + return 1;
|
| + }
|
| Free(gptdata->secondary_entries);
|
| }
|
|
|
| if (gptdata->secondary_header) {
|
| - if (gptdata->modified & GPT_MODIFIED_HEADER2)
|
| - BootDeviceWriteLBA(gptdata->drive_sectors - entries_sectors - 1,
|
| - 1, gptdata->secondary_header);
|
| - BootDeviceWriteLBA(gptdata->drive_sectors - 1, 1,
|
| - gptdata->secondary_header);
|
| + if (gptdata->modified & GPT_MODIFIED_HEADER2) {
|
| + if (0 != BootDeviceWriteLBA(gptdata->drive_sectors - 1, 1,
|
| + gptdata->secondary_header))
|
| + return 1;
|
| + }
|
| Free(gptdata->secondary_header);
|
| }
|
| - /* TODO: What to do with return codes from the writes? */
|
| +
|
| + /* Success */
|
| + return 0;
|
| }
|
|
|
| +
|
| #define KBUF_SIZE 65536 /* Bytes to read at start of kernel partition */
|
|
|
| int LoadKernel(LoadKernelParams* params) {
|
| @@ -157,15 +170,14 @@ int LoadKernel(LoadKernelParams* params) {
|
| params->bootloader_address = 0;
|
| params->bootloader_size = 0;
|
|
|
| - /* Read current kernel key index from TPM. Assumes TPM is already
|
| - * initialized. */
|
| - /* TODO: Is that a safe assumption? Normally, SetupTPM() would be called
|
| - * when the RW firmware is verified. Is it harmful to call SetupTPM()
|
| - * again if it's already initialized? It'd be easier if we could just do
|
| - * that. */
|
| - GetStoredVersions(KERNEL_VERSIONS,
|
| - &tpm_kernel_key_version,
|
| - &tpm_kernel_version);
|
| + if (BOOT_MODE_NORMAL == params->boot_mode) {
|
| + /* Read current kernel key index from TPM. Assumes TPM is already
|
| + * initialized. */
|
| + if (0 != GetStoredVersions(KERNEL_VERSIONS,
|
| + &tpm_kernel_key_version,
|
| + &tpm_kernel_version))
|
| + return LOAD_KERNEL_RECOVERY;
|
| + }
|
|
|
| do {
|
| /* Read GPT data */
|
| @@ -290,9 +302,16 @@ int LoadKernel(LoadKernelParams* params) {
|
| params->bootloader_address = kim->bootloader_offset;
|
| params->bootloader_size = kim->bootloader_size;
|
|
|
| - /* If the good partition's key version is the same as the tpm, then
|
| - * the TPM doesn't need updating; we can stop now. Otherwise, we'll
|
| - * check all the other headers to see if they contain a newer key. */
|
| + /* If we're in developer or recovery mode, there's no rollback
|
| + * protection, so we can stop at the first valid kernel. */
|
| + if (BOOT_MODE_NORMAL != params->boot_mode)
|
| + break;
|
| +
|
| + /* Otherwise, we're in normal boot mode, so we do care about
|
| + * the key index in the TPM. If the good partition's key
|
| + * version is the same as the tpm, then the TPM doesn't need
|
| + * updating; we can stop now. Otherwise, we'll check all the
|
| + * other headers to see if they contain a newer key. */
|
| if (kim->kernel_key_version == tpm_kernel_key_version &&
|
| kim->kernel_version == tpm_kernel_version)
|
| break;
|
| @@ -306,19 +325,22 @@ int LoadKernel(LoadKernelParams* params) {
|
| if (kim)
|
| Free(kim);
|
|
|
| - // Write and free GPT data
|
| + /* Write and free GPT data */
|
| WriteAndFreeGptData(&gpt);
|
|
|
| - // Handle finding a good partition
|
| + /* Handle finding a good partition */
|
| if (good_partition >= 0) {
|
|
|
| - /* See if we need to update the TPM */
|
| - if ((lowest_kernel_key_version > tpm_kernel_key_version) ||
|
| - (lowest_kernel_key_version == tpm_kernel_key_version &&
|
| - lowest_kernel_version > tpm_kernel_version)) {
|
| - WriteStoredVersions(KERNEL_VERSIONS,
|
| - lowest_kernel_key_version,
|
| - lowest_kernel_version);
|
| + if (BOOT_MODE_NORMAL == params->boot_mode) {
|
| + /* See if we need to update the TPM, for normal boot mode only. */
|
| + if ((lowest_kernel_key_version > tpm_kernel_key_version) ||
|
| + (lowest_kernel_key_version == tpm_kernel_key_version &&
|
| + lowest_kernel_version > tpm_kernel_version)) {
|
| + if (0 != WriteStoredVersions(KERNEL_VERSIONS,
|
| + lowest_kernel_key_version,
|
| + lowest_kernel_version))
|
| + return LOAD_KERNEL_RECOVERY;
|
| + }
|
| }
|
|
|
| if (BOOT_MODE_RECOVERY != params->boot_mode) {
|
| @@ -330,19 +352,17 @@ int LoadKernel(LoadKernelParams* params) {
|
| *
|
| * If we're already in recovery mode, we need to leave PP unlocked,
|
| * so don't lock the kernel versions. */
|
| - LockKernelVersionsByLockingPP();
|
| + if (0 != LockKernelVersionsByLockingPP())
|
| + return LOAD_KERNEL_RECOVERY;
|
| }
|
|
|
| /* Success! */
|
| return LOAD_KERNEL_SUCCESS;
|
| }
|
|
|
| - // Handle error cases
|
| + /* Handle error cases */
|
| if (found_partition)
|
| return LOAD_KERNEL_INVALID;
|
| else
|
| return LOAD_KERNEL_NOT_FOUND;
|
| - /* TODO: no error code for "internal error", but what would the firmware do
|
| - * with that anyway? So in the do-while(0) code above, the firmware just
|
| - * does 'break' to indicate an internal error... */
|
| }
|
|
|