Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(30)

Side by Side Diff: src/platform/vboot_reference/utils/kernel_image.c

Issue 1320010: VBoot Reference: Add kernel rollback prevention and choosing logic. (Closed)
Patch Set: fix priority in test case Created 10 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/platform/vboot_reference/utils/firmware_image.c ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* Copyright (c) 2010 The Chromium OS Authors. All rights reserved. 1 /* Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
2 * Use of this source code is governed by a BSD-style license that can be 2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file. 3 * found in the LICENSE file.
4 * 4 *
5 * Functions for generating and manipulating a verified boot kernel image. 5 * Functions for generating and manipulating a verified boot kernel image.
6 */ 6 */
7 7
8 #include "kernel_image.h" 8 #include "kernel_image.h"
9 9
10 #include <fcntl.h> 10 #include <fcntl.h>
11 #include <stdio.h> 11 #include <stdio.h>
12 #include <sys/types.h> 12 #include <sys/types.h>
13 #include <sys/stat.h> 13 #include <sys/stat.h>
14 #include <unistd.h> 14 #include <unistd.h>
15 15
16 #include "file_keys.h" 16 #include "file_keys.h"
17 #include "padding.h" 17 #include "padding.h"
18 #include "rollback_index.h"
18 #include "rsa_utility.h" 19 #include "rsa_utility.h"
19 #include "sha_utility.h" 20 #include "sha_utility.h"
20 #include "signature_digest.h" 21 #include "signature_digest.h"
21 #include "utility.h" 22 #include "utility.h"
22 23
23 /* Macro to determine the size of a field structure in the KernelImage 24 /* Macro to determine the size of a field structure in the KernelImage
24 * structure. */ 25 * structure. */
25 #define FIELD_LEN(field) (sizeof(((KernelImage*)0)->field)) 26 #define FIELD_LEN(field) (sizeof(((KernelImage*)0)->field))
26 27
27 KernelImage* KernelImageNew(void) { 28 KernelImage* KernelImageNew(void) {
(...skipping 675 matching lines...) Expand 10 before | Expand all | Expand 10 after
703 kernel_signing_key_file, 704 kernel_signing_key_file,
704 image->kernel_sign_algorithm))) { 705 image->kernel_sign_algorithm))) {
705 fprintf(stderr, "Could not compute signature on the kernel.\n"); 706 fprintf(stderr, "Could not compute signature on the kernel.\n");
706 return 0; 707 return 0;
707 } 708 }
708 image->kernel_signature = (uint8_t*) Malloc(signature_len); 709 image->kernel_signature = (uint8_t*) Malloc(signature_len);
709 Memcpy(image->kernel_signature, kernel_signature, signature_len); 710 Memcpy(image->kernel_signature, kernel_signature, signature_len);
710 Free(kernel_signature); 711 Free(kernel_signature);
711 return 1; 712 return 1;
712 } 713 }
714
715 uint32_t GetLogicalKernelVersion(uint8_t* kernel_blob) {
716 uint8_t* kernel_ptr;
717 uint16_t kernel_key_version;
718 uint16_t kernel_version;
719 uint16_t firmware_sign_algorithm;
720 uint16_t kernel_sign_algorithm;
721 int kernel_key_signature_len;
722 int kernel_sign_key_len;
723 kernel_ptr = kernel_blob + (FIELD_LEN(magic) +
724 FIELD_LEN(header_version) +
725 FIELD_LEN(header_len));
726 Memcpy(&firmware_sign_algorithm, kernel_ptr, sizeof(firmware_sign_algorithm));
727 kernel_ptr += FIELD_LEN(firmware_sign_algorithm);
728 Memcpy(&kernel_sign_algorithm, kernel_ptr, sizeof(kernel_sign_algorithm));
729 kernel_ptr += FIELD_LEN(kernel_sign_algorithm);
730 Memcpy(&kernel_key_version, kernel_ptr, sizeof(kernel_key_version));
731
732 if (firmware_sign_algorithm >= kNumAlgorithms)
733 return 0;
734 if (kernel_sign_algorithm >= kNumAlgorithms)
735 return 0;
736 kernel_key_signature_len = siglen_map[firmware_sign_algorithm];
737 kernel_sign_key_len = RSAProcessedKeySize(kernel_sign_algorithm);
738 kernel_ptr += (FIELD_LEN(kernel_key_version) +
739 kernel_sign_key_len +
740 FIELD_LEN(header_checksum) +
741 kernel_key_signature_len);
742 Memcpy(&kernel_version, kernel_ptr, sizeof(kernel_version));
743 return CombineUint16Pair(kernel_key_version, kernel_version);
744 }
745
746 void PrintKernelEntry(kernel_entry* entry) {
747 fprintf(stderr, "Boot Priority = %d\n", entry->boot_priority);
748 fprintf(stderr, "Boot Tries Remaining = %d\n", entry->boot_tries_remaining);
749 fprintf(stderr, "Boot Success Flag = %d\n", entry->boot_success_flag);
750 }
751
752 int VerifyKernelDriver_f(uint8_t* firmware_key_blob,
753 kernel_entry* kernelA,
754 kernel_entry* kernelB,
755 int dev_mode) {
756 int i;
757 /* Contains the logical kernel version (32-bit) which is calculated as
758 * (kernel_key_version << 16 | kernel_version) where
759 * [kernel_key_version], [firmware_version] are both 16-bit.
760 */
761 uint32_t kernelA_lversion, kernelB_lversion;
762 uint32_t min_lversion; /* Minimum of kernel A and kernel B lversion. */
763 uint32_t stored_lversion; /* Stored logical version in the TPM. */
764 kernel_entry* try_kernel[2]; /* Kernel in try order. */
765 int try_kernel_which[2]; /* Which corresponding kernel in the try order */
766 uint32_t try_kernel_lversion[2]; /* Their logical versions. */
767
768 /* [kernel_to_boot] will eventually contain the boot path to follow
769 * and is returned to the caller. Initially, we set it to recovery. If
770 * a valid bootable kernel is found, it will be set to that. */
771 int kernel_to_boot = BOOT_KERNEL_RECOVERY_CONTINUE;
772
773
774 /* The TPM must already have be initialized, so no need to call SetupTPM(). */
775
776 /* We get the key versions by reading directly from the image blobs without
777 * any additional (expensive) sanity checking on the blob since it's faster to
778 * outright reject a kernel with an older kernel key version. A malformed
779 * or corrupted kernel blob will still fail when VerifyKernel() is called
780 * on it.
781 */
782 kernelA_lversion = GetLogicalKernelVersion(kernelA->kernel_blob);
783 kernelB_lversion = GetLogicalKernelVersion(kernelB->kernel_blob);
784 min_lversion = Min(kernelA_lversion, kernelB_lversion);
785 stored_lversion = CombineUint16Pair(GetStoredVersion(KERNEL_KEY_VERSION),
786 GetStoredVersion(KERNEL_VERSION));
787
788 /* TODO(gauravsh): The kernel entries kernelA and kernelB come from the
789 * partition table - verify its signature/checksum before proceeding
790 * further. */
791
792 /* The logic for deciding which kernel to boot from is taken from the
793 * the Chromium OS Drive Map design document.
794 *
795 * We went to consider the kernels in their according to their boot
796 * priority attribute value.
797 */
798
799 if (kernelA->boot_priority >= kernelB->boot_priority) {
800 try_kernel[0] = kernelA;
801 try_kernel_which[0] = BOOT_KERNEL_A_CONTINUE;
802 try_kernel_lversion[0] = kernelA_lversion;
803 try_kernel[1] = kernelB;
804 try_kernel_which[1] = BOOT_KERNEL_B_CONTINUE;
805 try_kernel_lversion[1] = kernelB_lversion;
806 } else {
807 try_kernel[0] = kernelB;
808 try_kernel_which[0] = BOOT_KERNEL_B_CONTINUE;
809 try_kernel_lversion[0] = kernelB_lversion;
810 try_kernel[1] = kernelA;
811 try_kernel_which[1] = BOOT_KERNEL_A_CONTINUE;
812 try_kernel_lversion[1] = kernelA_lversion;
813 }
814
815 /* TODO(gauravsh): Changes to boot_tries_remaining and boot_priority
816 * below should be propagated to partition table. This will be added
817 * once the firmware parition table parsing code is in. */
818 for (i = 0; i < 2; i++) {
819 if ((try_kernel[i]->boot_success_flag ||
820 try_kernel[i]->boot_tries_remaining) &&
821 (VERIFY_KERNEL_SUCCESS == VerifyKernel(firmware_key_blob,
822 try_kernel[i]->kernel_blob,
823 dev_mode))) {
824 if (try_kernel[i]->boot_tries_remaining > 0)
825 try_kernel[i]->boot_tries_remaining--;
826 if (stored_lversion > try_kernel_lversion[i])
827 continue; /* Rollback: I am afraid I can't let you do that Dave. */
828 if (i == 0 && (stored_lversion < try_kernel_lversion[1])) {
829 /* The higher priority kernel is valid and bootable, See if we
830 * need to update the stored version for rollback prevention. */
831 if (VERIFY_KERNEL_SUCCESS == VerifyKernel(firmware_key_blob,
832 try_kernel[1]->kernel_blob,
833 dev_mode)) {
834 WriteStoredVersion(KERNEL_KEY_VERSION,
835 (uint16_t) (min_lversion >> 16));
836 WriteStoredVersion(KERNEL_VERSION,
837 (uint16_t) (min_lversion & 0xFFFF));
838 stored_lversion = min_lversion; /* Update stored version as it's
839 * used later. */
840 }
841 }
842 kernel_to_boot = try_kernel_which[i];
843 break; /* We found a valid kernel. */
844 }
845 try_kernel[i]->boot_priority = 0;
846 } /* for loop. */
847
848 /* Lock Kernel TPM rollback indices from further writes.
849 * TODO(gauravsh): Figure out if these can be combined into one
850 * 32-bit location since we seem to always use them together. This can help
851 * us minimize the number of NVRAM writes/locks (which are limited over flash
852 * memory lifetimes.
853 */
854 LockStoredVersion(KERNEL_KEY_VERSION);
855 LockStoredVersion(KERNEL_VERSION);
856 return kernel_to_boot;
857 }
OLDNEW
« no previous file with comments | « src/platform/vboot_reference/utils/firmware_image.c ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698