| OLD | NEW |
| 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 loading a kernel from disk. | 5 * Functions for loading a kernel from disk. |
| 6 * (Firmware portion) | 6 * (Firmware portion) |
| 7 */ | 7 */ |
| 8 | 8 |
| 9 #include "load_kernel_fw.h" | 9 #include "load_kernel_fw.h" |
| 10 | 10 |
| 11 #include "boot_device.h" | 11 #include "boot_device.h" |
| 12 #include "cgptlib.h" | 12 #include "cgptlib.h" |
| 13 #include "kernel_image_fw.h" | 13 #include "kernel_image_fw.h" |
| 14 #include "rollback_index.h" | 14 #include "rollback_index.h" |
| 15 #include "utility.h" | 15 #include "utility.h" |
| 16 | 16 |
| 17 #define GPT_ENTRIES_SIZE 16384 /* Bytes to read for GPT entries */ | 17 #define GPT_ENTRIES_SIZE 16384 /* Bytes to read for GPT entries */ |
| 18 | 18 |
| 19 // TODO: for testing | 19 // TODO: for testing |
| 20 #include <stdio.h> | 20 #include <stdio.h> |
| 21 #include <inttypes.h> /* For PRIu64 macro */ |
| 21 #include "cgptlib_internal.h" | 22 #include "cgptlib_internal.h" |
| 22 | 23 |
| 23 /* TODO: Remove this terrible hack which fakes partition attributes | 24 /* TODO: Remove this terrible hack which fakes partition attributes |
| 24 * for the kernel partitions so that GptNextKernelEntry() won't | 25 * for the kernel partitions so that GptNextKernelEntry() won't |
| 25 * choke. */ | 26 * choke. */ |
| 26 void FakePartitionAttributes(GptData* gpt) { | 27 void FakePartitionAttributes(GptData* gpt) { |
| 27 GptEntry* entries = (GptEntry*)gpt->primary_entries; | 28 GptEntry* entries = (GptEntry*)gpt->primary_entries; |
| 28 GptEntry* e; | 29 GptEntry* e; |
| 29 int i; | 30 int i; |
| 30 printf("Hacking partition attributes...\n"); | 31 printf("Hacking partition attributes...\n"); |
| 31 printf("Note that GUIDs below have first 3 fields endian-swapped\n"); | |
| 32 | 32 |
| 33 for (i = 0, e = entries; i < 12; i++, e++) { | 33 for (i = 0, e = entries; i < 12; i++, e++) { |
| 34 | 34 |
| 35 printf("%2d %08x %04x %04x %02x %02x %02x %02x %02x %02x %02x %02x\n", | 35 printf("%2d %08x %04x %04x %02x %02x %02x %02x %02x %02x %02x %02x", |
| 36 i, | 36 i, |
| 37 e->type.u.Uuid.time_low, | 37 e->type.u.Uuid.time_low, |
| 38 e->type.u.Uuid.time_mid, | 38 e->type.u.Uuid.time_mid, |
| 39 e->type.u.Uuid.time_high_and_version, | 39 e->type.u.Uuid.time_high_and_version, |
| 40 e->type.u.Uuid.clock_seq_high_and_reserved, | 40 e->type.u.Uuid.clock_seq_high_and_reserved, |
| 41 e->type.u.Uuid.clock_seq_low, | 41 e->type.u.Uuid.clock_seq_low, |
| 42 e->type.u.Uuid.node[0], | 42 e->type.u.Uuid.node[0], |
| 43 e->type.u.Uuid.node[1], | 43 e->type.u.Uuid.node[1], |
| 44 e->type.u.Uuid.node[2], | 44 e->type.u.Uuid.node[2], |
| 45 e->type.u.Uuid.node[3], | 45 e->type.u.Uuid.node[3], |
| 46 e->type.u.Uuid.node[4], | 46 e->type.u.Uuid.node[4], |
| 47 e->type.u.Uuid.node[5] | 47 e->type.u.Uuid.node[5] |
| 48 ); | 48 ); |
| 49 printf(" %8" PRIu64 " %8" PRIu64"\n", e->starting_lba, |
| 50 e->ending_lba - e->starting_lba + 1); |
| 49 if (!IsKernelEntry(e)) | 51 if (!IsKernelEntry(e)) |
| 50 continue; | 52 continue; |
| 51 printf("Hacking attributes for kernel partition %d\n", i); | 53 printf("Hacking attributes for kernel partition %d\n", i); |
| 52 SetEntryPriority(e, 2); | 54 SetEntryPriority(e, 2); |
| 53 SetEntrySuccessful(e, 1); | 55 SetEntrySuccessful(e, 1); |
| 54 } | 56 } |
| 55 } | 57 } |
| 56 | 58 |
| 57 | 59 |
| 58 int AllocAndReadGptData(GptData *gptdata) { | 60 int AllocAndReadGptData(GptData *gptdata) { |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 137 uint64_t blba = params->bytes_per_lba; | 139 uint64_t blba = params->bytes_per_lba; |
| 138 uint8_t* kbuf = NULL; | 140 uint8_t* kbuf = NULL; |
| 139 uint64_t kbuf_sectors; | 141 uint64_t kbuf_sectors; |
| 140 int found_partition = 0; | 142 int found_partition = 0; |
| 141 int good_partition = -1; | 143 int good_partition = -1; |
| 142 uint16_t tpm_kernel_key_version, tpm_kernel_version; | 144 uint16_t tpm_kernel_key_version, tpm_kernel_version; |
| 143 uint16_t lowest_kernel_key_version = 0xFFFF; | 145 uint16_t lowest_kernel_key_version = 0xFFFF; |
| 144 uint16_t lowest_kernel_version = 0xFFFF; | 146 uint16_t lowest_kernel_version = 0xFFFF; |
| 145 KernelImage *kim = NULL; | 147 KernelImage *kim = NULL; |
| 146 | 148 |
| 149 /* Clear output params in case we fail */ |
| 150 params->partition_number = 0; |
| 151 params->bootloader_address = 0; |
| 152 params->bootloader_size = 0; |
| 153 |
| 147 /* Read current kernel key index from TPM. Assumes TPM is already | 154 /* Read current kernel key index from TPM. Assumes TPM is already |
| 148 * initialized. */ | 155 * initialized. */ |
| 149 /* TODO: Is that a safe assumption? Normally, SetupTPM() would be called | 156 /* TODO: Is that a safe assumption? Normally, SetupTPM() would be called |
| 150 * when the RW firmware is verified. Is it harmful to call SetupTPM() | 157 * when the RW firmware is verified. Is it harmful to call SetupTPM() |
| 151 * again if it's already initialized? It'd be easier if we could just do | 158 * again if it's already initialized? It'd be easier if we could just do |
| 152 * that. */ | 159 * that. */ |
| 153 GetStoredVersions(KERNEL_VERSIONS, | 160 GetStoredVersions(KERNEL_VERSIONS, |
| 154 &tpm_kernel_key_version, | 161 &tpm_kernel_key_version, |
| 155 &tpm_kernel_version); | 162 &tpm_kernel_version); |
| 156 | 163 |
| 157 do { | 164 do { |
| 158 /* Read GPT data */ | 165 /* Read GPT data */ |
| 159 gpt.sector_bytes = blba; | 166 gpt.sector_bytes = blba; |
| 160 gpt.drive_sectors = params->ending_lba + 1; | 167 gpt.drive_sectors = params->ending_lba + 1; |
| 161 if (0 != AllocAndReadGptData(&gpt)) | 168 if (0 != AllocAndReadGptData(&gpt)) |
| 162 break; | 169 break; |
| 163 | 170 |
| 164 fprintf(stderr, "RRS1\n"); | |
| 165 | |
| 166 /* Initialize GPT library */ | 171 /* Initialize GPT library */ |
| 167 if (GPT_SUCCESS != GptInit(&gpt)) | 172 if (GPT_SUCCESS != GptInit(&gpt)) |
| 168 break; | 173 break; |
| 169 | 174 |
| 170 /* TODO: TERRIBLE KLUDGE - fake partition attributes */ | 175 /* TODO: TERRIBLE KLUDGE - fake partition attributes */ |
| 171 FakePartitionAttributes(&gpt); | 176 FakePartitionAttributes(&gpt); |
| 172 | 177 |
| 173 /* Allocate kernel header and image work buffers */ | 178 /* Allocate kernel header and image work buffers */ |
| 174 kbuf = (uint8_t*)Malloc(KBUF_SIZE); | 179 kbuf = (uint8_t*)Malloc(KBUF_SIZE); |
| 175 if (!kbuf) | 180 if (!kbuf) |
| 176 break; | 181 break; |
| 177 | 182 |
| 178 kbuf_sectors = KBUF_SIZE / blba; | 183 kbuf_sectors = KBUF_SIZE / blba; |
| 179 kim = (KernelImage*)Malloc(sizeof(KernelImage)); | 184 kim = (KernelImage*)Malloc(sizeof(KernelImage)); |
| 180 if (!kim) | 185 if (!kim) |
| 181 break; | 186 break; |
| 182 | 187 |
| 183 fprintf(stderr, "RRS2\n"); | |
| 184 | |
| 185 /* Loop over candidate kernel partitions */ | 188 /* Loop over candidate kernel partitions */ |
| 186 while (GPT_SUCCESS == GptNextKernelEntry(&gpt, &part_start, &part_size)) { | 189 while (GPT_SUCCESS == GptNextKernelEntry(&gpt, &part_start, &part_size)) { |
| 187 RSAPublicKey *kernel_sign_key = NULL; | 190 RSAPublicKey *kernel_sign_key = NULL; |
| 188 int kernel_start, kernel_sectors; | 191 int kernel_start, kernel_sectors; |
| 189 | 192 |
| 190 fprintf(stderr, "RRS3\n"); | |
| 191 | |
| 192 /* Found at least one kernel partition. */ | 193 /* Found at least one kernel partition. */ |
| 193 found_partition = 1; | 194 found_partition = 1; |
| 194 | 195 |
| 195 /* Read the first part of the kernel partition */ | 196 /* Read the first part of the kernel partition */ |
| 196 if (part_size < kbuf_sectors) | 197 if (part_size < kbuf_sectors) |
| 197 continue; | 198 continue; |
| 198 if (0 != BootDeviceReadLBA(part_start, kbuf_sectors, kbuf)) | 199 if (0 != BootDeviceReadLBA(part_start, kbuf_sectors, kbuf)) |
| 199 continue; | 200 continue; |
| 200 | 201 |
| 201 fprintf(stderr, "RRS4\n"); | |
| 202 | |
| 203 /* Verify the kernel header and preamble */ | 202 /* Verify the kernel header and preamble */ |
| 204 if (VERIFY_KERNEL_SUCCESS != VerifyKernelHeader( | 203 if (VERIFY_KERNEL_SUCCESS != VerifyKernelHeader( |
| 205 params->header_sign_key_blob, | 204 params->header_sign_key_blob, |
| 206 kbuf, | 205 kbuf, |
| 207 KBUF_SIZE, | 206 KBUF_SIZE, |
| 208 (BOOT_MODE_DEVELOPER == params->boot_mode ? 1 : 0), | 207 (BOOT_MODE_DEVELOPER == params->boot_mode ? 1 : 0), |
| 209 kim, | 208 kim, |
| 210 &kernel_sign_key)) { | 209 &kernel_sign_key)) { |
| 211 continue; | 210 continue; |
| 212 } | 211 } |
| 213 | 212 |
| 214 fprintf(stderr, "RRS5\n"); | 213 printf("Kernel header:\n"); |
| 214 printf("header version: %d\n", kim->header_version); |
| 215 printf("header len: %d\n", kim->header_len); |
| 216 printf("firmware sign alg: %d\n", kim->firmware_sign_algorithm); |
| 217 printf("kernel sign alg: %d\n", kim->kernel_sign_algorithm); |
| 218 printf("kernel key version: %d\n", kim->kernel_key_version); |
| 219 printf("kernel version: %d\n", kim->kernel_version); |
| 220 printf("kernel len: %" PRIu64 "\n", kim->kernel_len); |
| 221 printf("bootloader addr: %" PRIu64 "\n", kim->bootloader_offset); |
| 222 printf("bootloader size: %" PRIu64 "\n", kim->bootloader_size); |
| 223 printf("padded header size: %" PRIu64 "\n", kim->padded_header_size); |
| 215 | 224 |
| 216 /* Check for rollback of key version */ | 225 /* Check for rollback of key version */ |
| 217 if (kim->kernel_key_version < tpm_kernel_key_version) { | 226 if (kim->kernel_key_version < tpm_kernel_key_version) { |
| 218 RSAPublicKeyFree(kernel_sign_key); | 227 RSAPublicKeyFree(kernel_sign_key); |
| 219 continue; | 228 continue; |
| 220 } | 229 } |
| 221 | 230 |
| 222 /* Check for rollback of kernel version */ | 231 /* Check for rollback of kernel version */ |
| 223 if (kim->kernel_key_version == tpm_kernel_key_version && | 232 if (kim->kernel_key_version == tpm_kernel_key_version && |
| 224 kim->kernel_version < tpm_kernel_version) { | 233 kim->kernel_version < tpm_kernel_version) { |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 263 } | 272 } |
| 264 | 273 |
| 265 /* Done with the kernel signing key, so can free it now */ | 274 /* Done with the kernel signing key, so can free it now */ |
| 266 RSAPublicKeyFree(kernel_sign_key); | 275 RSAPublicKeyFree(kernel_sign_key); |
| 267 | 276 |
| 268 /* If we're still here, the kernel is valid. */ | 277 /* If we're still here, the kernel is valid. */ |
| 269 /* Save the first good partition we find; that's the one we'll boot */ | 278 /* Save the first good partition we find; that's the one we'll boot */ |
| 270 if (-1 == good_partition) { | 279 if (-1 == good_partition) { |
| 271 good_partition = gpt.current_kernel; | 280 good_partition = gpt.current_kernel; |
| 272 params->partition_number = gpt.current_kernel; | 281 params->partition_number = gpt.current_kernel; |
| 273 params->bootloader_start = (uint8_t*)params->kernel_buffer + | 282 params->bootloader_address = kim->bootloader_offset; |
| 274 kim->bootloader_offset; | |
| 275 params->bootloader_size = kim->bootloader_size; | 283 params->bootloader_size = kim->bootloader_size; |
| 276 | 284 |
| 277 /* If the good partition's key version is the same as the tpm, then | 285 /* If the good partition's key version is the same as the tpm, then |
| 278 * the TPM doesn't need updating; we can stop now. Otherwise, we'll | 286 * the TPM doesn't need updating; we can stop now. Otherwise, we'll |
| 279 * check all the other headers to see if they contain a newer key. */ | 287 * check all the other headers to see if they contain a newer key. */ |
| 280 if (kim->kernel_key_version == tpm_kernel_key_version && | 288 if (kim->kernel_key_version == tpm_kernel_key_version && |
| 281 kim->kernel_version == tpm_kernel_version) | 289 kim->kernel_version == tpm_kernel_version) |
| 282 break; | 290 break; |
| 283 } | 291 } |
| 284 } /* while(GptNextKernelEntry) */ | 292 } /* while(GptNextKernelEntry) */ |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 323 | 331 |
| 324 // Handle error cases | 332 // Handle error cases |
| 325 if (found_partition) | 333 if (found_partition) |
| 326 return LOAD_KERNEL_INVALID; | 334 return LOAD_KERNEL_INVALID; |
| 327 else | 335 else |
| 328 return LOAD_KERNEL_NOT_FOUND; | 336 return LOAD_KERNEL_NOT_FOUND; |
| 329 /* TODO: no error code for "internal error", but what would the firmware do | 337 /* TODO: no error code for "internal error", but what would the firmware do |
| 330 * with that anyway? So in the do-while(0) code above, the firmware just | 338 * with that anyway? So in the do-while(0) code above, the firmware just |
| 331 * does 'break' to indicate an internal error... */ | 339 * does 'break' to indicate an internal error... */ |
| 332 } | 340 } |
| OLD | NEW |