OLD | NEW |
1 /* Copyright (c) 2011 The Chromium OS Authors. All rights reserved. | 1 /* Copyright (c) 2011 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 "vboot_kernel.h" | 9 #include "vboot_kernel.h" |
10 | 10 |
11 #include "boot_device.h" | 11 #include "boot_device.h" |
12 #include "cgptlib.h" | 12 #include "cgptlib.h" |
13 #include "cgptlib_internal.h" | 13 #include "cgptlib_internal.h" |
14 #include "gbb_header.h" | 14 #include "gbb_header.h" |
15 #include "load_kernel_fw.h" | 15 #include "load_kernel_fw.h" |
16 #include "rollback_index.h" | 16 #include "rollback_index.h" |
17 #include "utility.h" | 17 #include "utility.h" |
18 #include "vboot_common.h" | 18 #include "vboot_common.h" |
19 | 19 |
20 #define KBUF_SIZE 65536 /* Bytes to read at start of kernel partition */ | 20 #define KBUF_SIZE 65536 /* Bytes to read at start of kernel partition */ |
21 #define LOWEST_TPM_VERSION 0xffffffff | 21 #define LOWEST_TPM_VERSION 0xffffffff |
22 | 22 |
23 typedef enum BootMode { | 23 typedef enum BootMode { |
24 kBootNormal, /* Normal firmware */ | 24 kBootRecovery = 0, /* Recovery firmware, regardless of dev switch position */ |
25 kBootDev, /* Dev firmware AND dev switch is on */ | 25 kBootNormal = 1, /* Normal firmware */ |
26 kBootRecovery /* Recovery firmware, regardless of dev switch position */ | 26 kBootDev = 2 /* Dev firmware AND dev switch is on */ |
27 } BootMode; | 27 } BootMode; |
28 | 28 |
29 | 29 |
30 /* Allocates and reads GPT data from the drive. The sector_bytes and | 30 /* Allocates and reads GPT data from the drive. The sector_bytes and |
31 * drive_sectors fields should be filled on input. The primary and | 31 * drive_sectors fields should be filled on input. The primary and |
32 * secondary header and entries are filled on output. | 32 * secondary header and entries are filled on output. |
33 * | 33 * |
34 * Returns 0 if successful, 1 if error. */ | 34 * Returns 0 if successful, 1 if error. */ |
35 int AllocAndReadGptData(GptData* gptdata) { | 35 int AllocAndReadGptData(GptData* gptdata) { |
36 | 36 |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
114 | 114 |
115 /* Success */ | 115 /* Success */ |
116 return 0; | 116 return 0; |
117 } | 117 } |
118 | 118 |
119 /* disable MSVC warning on const logical expression (as in } while(0);) */ | 119 /* disable MSVC warning on const logical expression (as in } while(0);) */ |
120 __pragma(warning(disable: 4127)) | 120 __pragma(warning(disable: 4127)) |
121 | 121 |
122 int LoadKernel(LoadKernelParams* params) { | 122 int LoadKernel(LoadKernelParams* params) { |
123 VbSharedDataHeader* shared = (VbSharedDataHeader*)params->shared_data_blob; | 123 VbSharedDataHeader* shared = (VbSharedDataHeader*)params->shared_data_blob; |
| 124 VbSharedDataKernelCall* shcall = NULL; |
124 VbNvContext* vnc = params->nv_context; | 125 VbNvContext* vnc = params->nv_context; |
125 GoogleBinaryBlockHeader* gbb = (GoogleBinaryBlockHeader*)params->gbb_data; | 126 GoogleBinaryBlockHeader* gbb = (GoogleBinaryBlockHeader*)params->gbb_data; |
126 VbPublicKey* kernel_subkey; | 127 VbPublicKey* kernel_subkey; |
127 GptData gpt; | 128 GptData gpt; |
128 uint64_t part_start, part_size; | 129 uint64_t part_start, part_size; |
129 uint64_t blba; | 130 uint64_t blba; |
130 uint64_t kbuf_sectors; | 131 uint64_t kbuf_sectors; |
131 uint8_t* kbuf = NULL; | 132 uint8_t* kbuf = NULL; |
132 int found_partitions = 0; | 133 int found_partitions = 0; |
133 int good_partition = -1; | 134 int good_partition = -1; |
(...skipping 20 matching lines...) Expand all Loading... |
154 !params->kernel_buffer_size) { | 155 !params->kernel_buffer_size) { |
155 VBDEBUG(("LoadKernel() called with invalid params\n")); | 156 VBDEBUG(("LoadKernel() called with invalid params\n")); |
156 goto LoadKernelExit; | 157 goto LoadKernelExit; |
157 } | 158 } |
158 | 159 |
159 /* Clear output params in case we fail */ | 160 /* Clear output params in case we fail */ |
160 params->partition_number = 0; | 161 params->partition_number = 0; |
161 params->bootloader_address = 0; | 162 params->bootloader_address = 0; |
162 params->bootloader_size = 0; | 163 params->bootloader_size = 0; |
163 | 164 |
| 165 /* Calculate switch positions and boot mode */ |
| 166 rec_switch = (BOOT_FLAG_RECOVERY & params->boot_flags ? 1 : 0); |
| 167 dev_switch = (BOOT_FLAG_DEVELOPER & params->boot_flags ? 1 : 0); |
| 168 if (rec_switch) |
| 169 boot_mode = kBootRecovery; |
| 170 else if (BOOT_FLAG_DEV_FIRMWARE & params->boot_flags) |
| 171 boot_mode = kBootDev; |
| 172 else { |
| 173 /* Normal firmware */ |
| 174 boot_mode = kBootNormal; |
| 175 dev_switch = 0; /* Always do a fully verified boot */ |
| 176 } |
| 177 |
| 178 if (kBootRecovery == boot_mode) { |
| 179 /* Initialize the shared data structure, since LoadFirmware() didn't do it |
| 180 * for us. */ |
| 181 if (0 != VbSharedDataInit(shared, params->shared_data_size)) { |
| 182 /* Error initializing the shared data, but we can keep going. We just |
| 183 * can't use the shared data. */ |
| 184 VBDEBUG(("Shared data init error\n")); |
| 185 params->shared_data_size = 0; |
| 186 shared = NULL; |
| 187 } |
| 188 } |
| 189 |
| 190 if (shared) { |
| 191 /* Set up tracking for this call. This wraps around if called many times, |
| 192 * so we need to initialize the call entry each time. */ |
| 193 shcall = shared->lk_calls + (shared->lk_call_count |
| 194 & (VBSD_MAX_KERNEL_CALLS - 1)); |
| 195 Memset(shcall, 0, sizeof(VbSharedDataKernelCall)); |
| 196 shcall->boot_flags = (uint32_t)params->boot_flags; |
| 197 shcall->boot_mode = boot_mode; |
| 198 shcall->sector_size = (uint32_t)params->bytes_per_lba; |
| 199 shcall->sector_count = params->ending_lba + 1; |
| 200 shared->lk_call_count++; |
| 201 } |
| 202 |
164 /* Handle test errors */ | 203 /* Handle test errors */ |
165 VbNvGet(vnc, VBNV_TEST_ERROR_FUNC, &test_err); | 204 VbNvGet(vnc, VBNV_TEST_ERROR_FUNC, &test_err); |
166 if (VBNV_TEST_ERROR_LOAD_KERNEL == test_err) { | 205 if (VBNV_TEST_ERROR_LOAD_KERNEL == test_err) { |
167 /* Get error code */ | 206 /* Get error code */ |
168 VbNvGet(vnc, VBNV_TEST_ERROR_NUM, &test_err); | 207 VbNvGet(vnc, VBNV_TEST_ERROR_NUM, &test_err); |
| 208 if (shcall) |
| 209 shcall->test_error_num = (uint8_t)test_err; |
169 /* Clear test params so we don't repeat the error */ | 210 /* Clear test params so we don't repeat the error */ |
170 VbNvSet(vnc, VBNV_TEST_ERROR_FUNC, 0); | 211 VbNvSet(vnc, VBNV_TEST_ERROR_FUNC, 0); |
171 VbNvSet(vnc, VBNV_TEST_ERROR_NUM, 0); | 212 VbNvSet(vnc, VBNV_TEST_ERROR_NUM, 0); |
172 /* Handle error codes */ | 213 /* Handle error codes */ |
173 switch (test_err) { | 214 switch (test_err) { |
174 case LOAD_KERNEL_RECOVERY: | 215 case LOAD_KERNEL_RECOVERY: |
175 recovery = VBNV_RECOVERY_RW_TEST_LK; | 216 recovery = VBNV_RECOVERY_RW_TEST_LK; |
176 goto LoadKernelExit; | 217 goto LoadKernelExit; |
177 case LOAD_KERNEL_NOT_FOUND: | 218 case LOAD_KERNEL_NOT_FOUND: |
178 case LOAD_KERNEL_INVALID: | 219 case LOAD_KERNEL_INVALID: |
179 case LOAD_KERNEL_REBOOT: | 220 case LOAD_KERNEL_REBOOT: |
180 retval = test_err; | 221 retval = test_err; |
181 goto LoadKernelExit; | 222 goto LoadKernelExit; |
182 default: | 223 default: |
183 break; | 224 break; |
184 } | 225 } |
185 } | 226 } |
186 | 227 |
187 /* Initialization */ | 228 /* Initialization */ |
188 blba = params->bytes_per_lba; | 229 blba = params->bytes_per_lba; |
189 kbuf_sectors = KBUF_SIZE / blba; | 230 kbuf_sectors = KBUF_SIZE / blba; |
190 if (0 == kbuf_sectors) { | 231 if (0 == kbuf_sectors) { |
191 VBDEBUG(("LoadKernel() called with sector size > KBUF_SIZE\n")); | 232 VBDEBUG(("LoadKernel() called with sector size > KBUF_SIZE\n")); |
192 goto LoadKernelExit; | 233 goto LoadKernelExit; |
193 } | 234 } |
194 | 235 |
195 rec_switch = (BOOT_FLAG_RECOVERY & params->boot_flags ? 1 : 0); | 236 if (kBootDev == boot_mode && !dev_switch) { |
196 dev_switch = (BOOT_FLAG_DEVELOPER & params->boot_flags ? 1 : 0); | |
197 | |
198 if (rec_switch) | |
199 boot_mode = kBootRecovery; | |
200 else if (BOOT_FLAG_DEV_FIRMWARE & params->boot_flags) { | |
201 if (!dev_switch) { | |
202 /* Dev firmware should be signed such that it never boots with the dev | 237 /* Dev firmware should be signed such that it never boots with the dev |
203 * switch is off; so something is terribly wrong. */ | 238 * switch is off; so something is terribly wrong. */ |
204 VBDEBUG(("LoadKernel() called with dev firmware but dev switch off\n")); | 239 VBDEBUG(("LoadKernel() called with dev firmware but dev switch off\n")); |
| 240 if (shcall) |
| 241 shcall->check_result = VBSD_LKC_CHECK_DEV_SWITCH_MISMATCH; |
205 recovery = VBNV_RECOVERY_RW_DEV_MISMATCH; | 242 recovery = VBNV_RECOVERY_RW_DEV_MISMATCH; |
206 goto LoadKernelExit; | 243 goto LoadKernelExit; |
207 } | 244 } |
208 boot_mode = kBootDev; | |
209 } else { | |
210 /* Normal firmware */ | |
211 boot_mode = kBootNormal; | |
212 dev_switch = 0; /* Always do a fully verified boot */ | |
213 } | |
214 | 245 |
215 if (kBootRecovery == boot_mode) { | 246 if (kBootRecovery == boot_mode) { |
216 /* Initialize the shared data structure, since LoadFirmware() didn't do it | |
217 * for us. */ | |
218 if (0 != VbSharedDataInit(shared, params->shared_data_size)) { | |
219 /* Error initializing the shared data, but we can keep going. We just | |
220 * can't use the shared data. */ | |
221 VBDEBUG(("Shared data init error\n")); | |
222 params->shared_data_size = 0; | |
223 shared = NULL; | |
224 } | |
225 | |
226 /* Use the recovery key to verify the kernel */ | 247 /* Use the recovery key to verify the kernel */ |
227 kernel_subkey = (VbPublicKey*)((uint8_t*)gbb + gbb->recovery_key_offset); | 248 kernel_subkey = (VbPublicKey*)((uint8_t*)gbb + gbb->recovery_key_offset); |
228 | 249 |
229 /* Let the TPM know if we're in recovery mode */ | 250 /* Let the TPM know if we're in recovery mode */ |
230 if (0 != RollbackKernelRecovery(dev_switch)) { | 251 if (0 != RollbackKernelRecovery(dev_switch)) { |
231 VBDEBUG(("Error setting up TPM for recovery kernel\n")); | 252 VBDEBUG(("Error setting up TPM for recovery kernel\n")); |
| 253 if (shcall) |
| 254 shcall->flags |= VBSD_LK_FLAG_REC_TPM_INIT_ERROR; |
232 /* Ignore return code, since we need to boot recovery mode to | 255 /* Ignore return code, since we need to boot recovery mode to |
233 * fix the TPM. */ | 256 * fix the TPM. */ |
234 } | 257 } |
235 | 258 |
236 /* Read the key indices from the TPM; ignore any errors */ | 259 /* Read the key indices from the TPM; ignore any errors */ |
237 if (shared) { | 260 if (shared) { |
238 RollbackFirmwareRead(&shared->fw_version_tpm); | 261 RollbackFirmwareRead(&shared->fw_version_tpm); |
239 RollbackKernelRead(&shared->kernel_version_tpm); | 262 RollbackKernelRead(&shared->kernel_version_tpm); |
240 } | 263 } |
241 } else { | 264 } else { |
(...skipping 14 matching lines...) Expand all Loading... |
256 if (shared) | 279 if (shared) |
257 shared->kernel_version_tpm = tpm_version; | 280 shared->kernel_version_tpm = tpm_version; |
258 } | 281 } |
259 | 282 |
260 do { | 283 do { |
261 /* Read GPT data */ | 284 /* Read GPT data */ |
262 gpt.sector_bytes = (uint32_t)blba; | 285 gpt.sector_bytes = (uint32_t)blba; |
263 gpt.drive_sectors = params->ending_lba + 1; | 286 gpt.drive_sectors = params->ending_lba + 1; |
264 if (0 != AllocAndReadGptData(&gpt)) { | 287 if (0 != AllocAndReadGptData(&gpt)) { |
265 VBDEBUG(("Unable to read GPT data\n")); | 288 VBDEBUG(("Unable to read GPT data\n")); |
| 289 if (shcall) |
| 290 shcall->check_result = VBSD_LKC_CHECK_GPT_READ_ERROR; |
266 break; | 291 break; |
267 } | 292 } |
268 | 293 |
269 /* Initialize GPT library */ | 294 /* Initialize GPT library */ |
270 if (GPT_SUCCESS != GptInit(&gpt)) { | 295 if (GPT_SUCCESS != GptInit(&gpt)) { |
271 VBDEBUG(("Error parsing GPT\n")); | 296 VBDEBUG(("Error parsing GPT\n")); |
| 297 if (shcall) |
| 298 shcall->check_result = VBSD_LKC_CHECK_GPT_PARSE_ERROR; |
272 break; | 299 break; |
273 } | 300 } |
274 | 301 |
275 /* Allocate kernel header buffers */ | 302 /* Allocate kernel header buffers */ |
276 kbuf = (uint8_t*)Malloc(KBUF_SIZE); | 303 kbuf = (uint8_t*)Malloc(KBUF_SIZE); |
277 if (!kbuf) | 304 if (!kbuf) |
278 break; | 305 break; |
279 | 306 |
280 /* Loop over candidate kernel partitions */ | 307 /* Loop over candidate kernel partitions */ |
281 while (GPT_SUCCESS == GptNextKernelEntry(&gpt, &part_start, &part_size)) { | 308 while (GPT_SUCCESS == GptNextKernelEntry(&gpt, &part_start, &part_size)) { |
| 309 VbSharedDataKernelPart* shpart = NULL; |
282 VbKeyBlockHeader* key_block; | 310 VbKeyBlockHeader* key_block; |
283 VbKernelPreambleHeader* preamble; | 311 VbKernelPreambleHeader* preamble; |
284 RSAPublicKey* data_key = NULL; | 312 RSAPublicKey* data_key = NULL; |
285 uint64_t key_version; | 313 uint64_t key_version; |
286 uint64_t combined_version; | 314 uint64_t combined_version; |
287 uint64_t body_offset; | 315 uint64_t body_offset; |
288 uint64_t body_offset_sectors; | 316 uint64_t body_offset_sectors; |
289 uint64_t body_sectors; | 317 uint64_t body_sectors; |
290 int key_block_valid = 1; | 318 int key_block_valid = 1; |
291 | 319 |
292 VBDEBUG(("Found kernel entry at %" PRIu64 " size %" PRIu64 "\n", | 320 VBDEBUG(("Found kernel entry at %" PRIu64 " size %" PRIu64 "\n", |
293 part_start, part_size)); | 321 part_start, part_size)); |
294 | 322 |
| 323 if (shcall) { |
| 324 /* Set up tracking for this call. This wraps around if called many |
| 325 * times, so we need to initialize the partition entry each time. */ |
| 326 shpart = shcall->parts + (shcall->kernel_parts_found |
| 327 & (VBSD_MAX_KERNEL_PARTS - 1)); |
| 328 Memset(shpart, 0, sizeof(VbSharedDataKernelPart)); |
| 329 shpart->sector_start = part_start; |
| 330 shpart->sector_count = part_size; |
| 331 /* TODO: GPT partitions start at 1, but cgptlib starts them at 0. |
| 332 * Adjust here, until cgptlib is fixed. */ |
| 333 shpart->gpt_index = (uint8_t)(gpt.current_kernel + 1); |
| 334 shcall->kernel_parts_found++; |
| 335 } |
| 336 |
295 /* Found at least one kernel partition. */ | 337 /* Found at least one kernel partition. */ |
296 found_partitions++; | 338 found_partitions++; |
297 | 339 |
298 /* Read the first part of the kernel partition. */ | 340 /* Read the first part of the kernel partition. */ |
299 if (part_size < kbuf_sectors) { | 341 if (part_size < kbuf_sectors) { |
300 VBDEBUG(("Partition too small to hold kernel.\n")); | 342 VBDEBUG(("Partition too small to hold kernel.\n")); |
| 343 if (shpart) |
| 344 shpart->check_result = VBSD_LKP_CHECK_TOO_SMALL; |
301 goto bad_kernel; | 345 goto bad_kernel; |
302 } | 346 } |
303 | 347 |
304 if (0 != BootDeviceReadLBA(part_start, kbuf_sectors, kbuf)) { | 348 if (0 != BootDeviceReadLBA(part_start, kbuf_sectors, kbuf)) { |
305 VBDEBUG(("Unable to read start of partition.\n")); | 349 VBDEBUG(("Unable to read start of partition.\n")); |
| 350 if (shpart) |
| 351 shpart->check_result = VBSD_LKP_CHECK_READ_START; |
306 goto bad_kernel; | 352 goto bad_kernel; |
307 } | 353 } |
308 | 354 |
309 /* Verify the key block. */ | 355 /* Verify the key block. */ |
310 key_block = (VbKeyBlockHeader*)kbuf; | 356 key_block = (VbKeyBlockHeader*)kbuf; |
311 if (0 != KeyBlockVerify(key_block, KBUF_SIZE, kernel_subkey, 0)) { | 357 if (0 != KeyBlockVerify(key_block, KBUF_SIZE, kernel_subkey, 0)) { |
312 VBDEBUG(("Verifying key block signature failed.\n")); | 358 VBDEBUG(("Verifying key block signature failed.\n")); |
| 359 if (shpart) |
| 360 shpart->check_result = VBSD_LKP_CHECK_KEY_BLOCK_SIG; |
| 361 |
313 key_block_valid = 0; | 362 key_block_valid = 0; |
314 | 363 |
315 /* If we're not in developer mode, this kernel is bad. */ | 364 /* If we're not in developer mode, this kernel is bad. */ |
316 if (kBootDev != boot_mode) | 365 if (kBootDev != boot_mode) |
317 goto bad_kernel; | 366 goto bad_kernel; |
318 | 367 |
319 /* In developer mode, we can continue if the SHA-512 hash of the key | 368 /* In developer mode, we can continue if the SHA-512 hash of the key |
320 * block is valid. */ | 369 * block is valid. */ |
321 if (0 != KeyBlockVerify(key_block, KBUF_SIZE, kernel_subkey, 1)) { | 370 if (0 != KeyBlockVerify(key_block, KBUF_SIZE, kernel_subkey, 1)) { |
322 VBDEBUG(("Verifying key block hash failed.\n")); | 371 VBDEBUG(("Verifying key block hash failed.\n")); |
| 372 if (shpart) |
| 373 shpart->check_result = VBSD_LKP_CHECK_KEY_BLOCK_HASH; |
323 goto bad_kernel; | 374 goto bad_kernel; |
324 } | 375 } |
325 } | 376 } |
326 | 377 |
327 /* Check the key block flags against the current boot mode. */ | 378 /* Check the key block flags against the current boot mode. */ |
328 if (!(key_block->key_block_flags & | 379 if (!(key_block->key_block_flags & |
329 (dev_switch ? KEY_BLOCK_FLAG_DEVELOPER_1 : | 380 (dev_switch ? KEY_BLOCK_FLAG_DEVELOPER_1 : |
330 KEY_BLOCK_FLAG_DEVELOPER_0))) { | 381 KEY_BLOCK_FLAG_DEVELOPER_0))) { |
331 VBDEBUG(("Key block developer flag mismatch.\n")); | 382 VBDEBUG(("Key block developer flag mismatch.\n")); |
| 383 if (shpart) |
| 384 shpart->check_result = VBSD_LKP_CHECK_DEV_MISMATCH; |
332 key_block_valid = 0; | 385 key_block_valid = 0; |
333 } | 386 } |
334 if (!(key_block->key_block_flags & | 387 if (!(key_block->key_block_flags & |
335 (rec_switch ? KEY_BLOCK_FLAG_RECOVERY_1 : | 388 (rec_switch ? KEY_BLOCK_FLAG_RECOVERY_1 : |
336 KEY_BLOCK_FLAG_RECOVERY_0))) { | 389 KEY_BLOCK_FLAG_RECOVERY_0))) { |
337 VBDEBUG(("Key block recovery flag mismatch.\n")); | 390 VBDEBUG(("Key block recovery flag mismatch.\n")); |
| 391 if (shpart) |
| 392 shpart->check_result = VBSD_LKP_CHECK_REC_MISMATCH; |
338 key_block_valid = 0; | 393 key_block_valid = 0; |
339 } | 394 } |
340 | 395 |
341 /* Check for rollback of key version except in recovery mode. */ | 396 /* Check for rollback of key version except in recovery mode. */ |
342 key_version = key_block->data_key.key_version; | 397 key_version = key_block->data_key.key_version; |
343 if (kBootRecovery != boot_mode) { | 398 if (kBootRecovery != boot_mode) { |
344 if (key_version < (tpm_version >> 16)) { | 399 if (key_version < (tpm_version >> 16)) { |
345 VBDEBUG(("Key version too old.\n")); | 400 VBDEBUG(("Key version too old.\n")); |
| 401 if (shpart) |
| 402 shpart->check_result = VBSD_LKP_CHECK_KEY_ROLLBACK; |
346 key_block_valid = 0; | 403 key_block_valid = 0; |
347 } | 404 } |
348 } | 405 } |
349 | 406 |
350 /* If we're not in developer mode, require the key block to be valid. */ | 407 /* If we're not in developer mode, require the key block to be valid. */ |
351 if (kBootDev != boot_mode && !key_block_valid) { | 408 if (kBootDev != boot_mode && !key_block_valid) { |
352 VBDEBUG(("Key block is invalid.\n")); | 409 VBDEBUG(("Key block is invalid.\n")); |
353 goto bad_kernel; | 410 goto bad_kernel; |
354 } | 411 } |
355 | 412 |
356 /* Get the key for preamble/data verification from the key block. */ | 413 /* Get the key for preamble/data verification from the key block. */ |
357 data_key = PublicKeyToRSA(&key_block->data_key); | 414 data_key = PublicKeyToRSA(&key_block->data_key); |
358 if (!data_key) { | 415 if (!data_key) { |
359 VBDEBUG(("Data key bad.\n")); | 416 VBDEBUG(("Data key bad.\n")); |
| 417 if (shpart) |
| 418 shpart->check_result = VBSD_LKP_CHECK_DATA_KEY_PARSE; |
360 goto bad_kernel; | 419 goto bad_kernel; |
361 } | 420 } |
362 | 421 |
363 /* Verify the preamble, which follows the key block */ | 422 /* Verify the preamble, which follows the key block */ |
364 preamble = (VbKernelPreambleHeader*)(kbuf + key_block->key_block_size); | 423 preamble = (VbKernelPreambleHeader*)(kbuf + key_block->key_block_size); |
365 if ((0 != VerifyKernelPreamble(preamble, | 424 if ((0 != VerifyKernelPreamble(preamble, |
366 KBUF_SIZE - key_block->key_block_size, | 425 KBUF_SIZE - key_block->key_block_size, |
367 data_key))) { | 426 data_key))) { |
368 VBDEBUG(("Preamble verification failed.\n")); | 427 VBDEBUG(("Preamble verification failed.\n")); |
| 428 if (shpart) |
| 429 shpart->check_result = VBSD_LKP_CHECK_VERIFY_PREAMBLE; |
369 goto bad_kernel; | 430 goto bad_kernel; |
370 } | 431 } |
371 | 432 |
372 /* If the key block is valid and we're not in recovery mode, check for | 433 /* If the key block is valid and we're not in recovery mode, check for |
373 * rollback of the kernel version. */ | 434 * rollback of the kernel version. */ |
374 combined_version = ((key_version << 16) | | 435 combined_version = ((key_version << 16) | |
375 (preamble->kernel_version & 0xFFFF)); | 436 (preamble->kernel_version & 0xFFFF)); |
| 437 if (shpart) |
| 438 shpart->combined_version = (uint32_t)combined_version; |
376 if (key_block_valid && kBootRecovery != boot_mode) { | 439 if (key_block_valid && kBootRecovery != boot_mode) { |
377 if (combined_version < tpm_version) { | 440 if (combined_version < tpm_version) { |
378 VBDEBUG(("Kernel version too low.\n")); | 441 VBDEBUG(("Kernel version too low.\n")); |
| 442 if (shpart) |
| 443 shpart->check_result = VBSD_LKP_CHECK_KERNEL_ROLLBACK; |
379 /* If we're not in developer mode, kernel version must be valid. */ | 444 /* If we're not in developer mode, kernel version must be valid. */ |
380 if (kBootDev != boot_mode) | 445 if (kBootDev != boot_mode) |
381 goto bad_kernel; | 446 goto bad_kernel; |
382 } | 447 } |
383 } | 448 } |
384 | 449 |
385 VBDEBUG(("Kernel preamble is good.\n")); | 450 VBDEBUG(("Kernel preamble is good.\n")); |
| 451 if (shpart) |
| 452 shpart->check_result = VBSD_LKP_CHECK_PREAMBLE_VALID; |
386 | 453 |
387 /* Check for lowest version from a valid header. */ | 454 /* Check for lowest version from a valid header. */ |
388 if (key_block_valid && lowest_version > combined_version) | 455 if (key_block_valid && lowest_version > combined_version) |
389 lowest_version = combined_version; | 456 lowest_version = combined_version; |
390 else { | 457 else { |
391 VBDEBUG(("Key block valid: %d\n", key_block_valid)); | 458 VBDEBUG(("Key block valid: %d\n", key_block_valid)); |
392 VBDEBUG(("Combined version: %" PRIu64 "\n", combined_version)); | 459 VBDEBUG(("Combined version: %" PRIu64 "\n", combined_version)); |
393 } | 460 } |
394 | 461 |
395 /* If we already have a good kernel, no need to read another | 462 /* If we already have a good kernel, no need to read another |
396 * one; we only needed to look at the versions to check for | 463 * one; we only needed to look at the versions to check for |
397 * rollback. So skip to the next kernel preamble. */ | 464 * rollback. So skip to the next kernel preamble. */ |
398 if (-1 != good_partition) | 465 if (-1 != good_partition) |
399 continue; | 466 continue; |
400 | 467 |
401 /* Verify body load address matches what we expect */ | 468 /* Verify body load address matches what we expect */ |
402 if ((preamble->body_load_address != (size_t)params->kernel_buffer) && | 469 if ((preamble->body_load_address != (size_t)params->kernel_buffer) && |
403 !(params->boot_flags & BOOT_FLAG_SKIP_ADDR_CHECK)) { | 470 !(params->boot_flags & BOOT_FLAG_SKIP_ADDR_CHECK)) { |
404 VBDEBUG(("Wrong body load address.\n")); | 471 VBDEBUG(("Wrong body load address.\n")); |
| 472 if (shpart) |
| 473 shpart->check_result = VBSD_LKP_CHECK_BODY_ADDRESS; |
405 goto bad_kernel; | 474 goto bad_kernel; |
406 } | 475 } |
407 | 476 |
408 /* Verify kernel body starts at a multiple of the sector size. */ | 477 /* Verify kernel body starts at a multiple of the sector size. */ |
409 body_offset = key_block->key_block_size + preamble->preamble_size; | 478 body_offset = key_block->key_block_size + preamble->preamble_size; |
410 if (0 != body_offset % blba) { | 479 if (0 != body_offset % blba) { |
411 VBDEBUG(("Kernel body not at multiple of sector size.\n")); | 480 VBDEBUG(("Kernel body not at multiple of sector size.\n")); |
| 481 if (shpart) |
| 482 shpart->check_result = VBSD_LKP_CHECK_BODY_OFFSET; |
412 goto bad_kernel; | 483 goto bad_kernel; |
413 } | 484 } |
414 body_offset_sectors = body_offset / blba; | 485 body_offset_sectors = body_offset / blba; |
415 | 486 |
416 /* Verify kernel body fits in the buffer */ | 487 /* Verify kernel body fits in the buffer */ |
417 body_sectors = (preamble->body_signature.data_size + blba - 1) / blba; | 488 body_sectors = (preamble->body_signature.data_size + blba - 1) / blba; |
418 if (body_sectors * blba > params->kernel_buffer_size) { | 489 if (body_sectors * blba > params->kernel_buffer_size) { |
419 VBDEBUG(("Kernel body doesn't fit in memory.\n")); | 490 VBDEBUG(("Kernel body doesn't fit in memory.\n")); |
| 491 if (shpart) |
| 492 shpart->check_result = VBSD_LKP_CHECK_BODY_EXCEEDS_MEM; |
420 goto bad_kernel; | 493 goto bad_kernel; |
421 } | 494 } |
422 | 495 |
423 /* Verify kernel body fits in the partition */ | 496 /* Verify kernel body fits in the partition */ |
424 if (body_offset_sectors + body_sectors > part_size) { | 497 if (body_offset_sectors + body_sectors > part_size) { |
425 VBDEBUG(("Kernel body doesn't fit in partition.\n")); | 498 VBDEBUG(("Kernel body doesn't fit in partition.\n")); |
| 499 if (shpart) |
| 500 shpart->check_result = VBSD_LKP_CHECK_BODY_EXCEEDS_PART; |
426 goto bad_kernel; | 501 goto bad_kernel; |
427 } | 502 } |
428 | 503 |
429 /* Read the kernel data */ | 504 /* Read the kernel data */ |
430 VBPERFSTART("VB_RKD"); | 505 VBPERFSTART("VB_RKD"); |
431 if (0 != BootDeviceReadLBA(part_start + body_offset_sectors, | 506 if (0 != BootDeviceReadLBA(part_start + body_offset_sectors, |
432 body_sectors, | 507 body_sectors, |
433 params->kernel_buffer)) { | 508 params->kernel_buffer)) { |
434 VBDEBUG(("Unable to read kernel data.\n")); | 509 VBDEBUG(("Unable to read kernel data.\n")); |
435 VBPERFEND("VB_RKD"); | 510 VBPERFEND("VB_RKD"); |
| 511 if (shpart) |
| 512 shpart->check_result = VBSD_LKP_CHECK_READ_DATA; |
436 goto bad_kernel; | 513 goto bad_kernel; |
437 } | 514 } |
438 VBPERFEND("VB_RKD"); | 515 VBPERFEND("VB_RKD"); |
439 | 516 |
440 /* Verify kernel data */ | 517 /* Verify kernel data */ |
441 if (0 != VerifyData((const uint8_t*)params->kernel_buffer, | 518 if (0 != VerifyData((const uint8_t*)params->kernel_buffer, |
442 params->kernel_buffer_size, | 519 params->kernel_buffer_size, |
443 &preamble->body_signature, data_key)) { | 520 &preamble->body_signature, data_key)) { |
444 VBDEBUG(("Kernel data verification failed.\n")); | 521 VBDEBUG(("Kernel data verification failed.\n")); |
| 522 if (shpart) |
| 523 shpart->check_result = VBSD_LKP_CHECK_VERIFY_DATA; |
445 goto bad_kernel; | 524 goto bad_kernel; |
446 } | 525 } |
447 | 526 |
448 /* Done with the kernel signing key, so can free it now */ | 527 /* Done with the kernel signing key, so can free it now */ |
449 RSAPublicKeyFree(data_key); | 528 RSAPublicKeyFree(data_key); |
450 data_key = NULL; | 529 data_key = NULL; |
451 | 530 |
452 /* If we're still here, the kernel is valid. */ | 531 /* If we're still here, the kernel is valid. */ |
453 /* Save the first good partition we find; that's the one we'll boot */ | 532 /* Save the first good partition we find; that's the one we'll boot */ |
454 VBDEBUG(("Partition is good.\n")); | 533 VBDEBUG(("Partition is good.\n")); |
| 534 if (shpart) { |
| 535 shpart->check_result = VBSD_LKP_CHECK_KERNEL_GOOD; |
| 536 if (key_block_valid) |
| 537 shpart->flags |= VBSD_LKP_FLAG_KEY_BLOCK_VALID; |
| 538 } |
| 539 |
455 good_partition_key_block_valid = key_block_valid; | 540 good_partition_key_block_valid = key_block_valid; |
456 /* TODO: GPT partitions start at 1, but cgptlib starts them at 0. | 541 /* TODO: GPT partitions start at 1, but cgptlib starts them at 0. |
457 * Adjust here, until cgptlib is fixed. */ | 542 * Adjust here, until cgptlib is fixed. */ |
458 good_partition = gpt.current_kernel + 1; | 543 good_partition = gpt.current_kernel + 1; |
459 params->partition_number = gpt.current_kernel + 1; | 544 params->partition_number = gpt.current_kernel + 1; |
460 GetCurrentKernelUniqueGuid(&gpt, ¶ms->partition_guid); | 545 GetCurrentKernelUniqueGuid(&gpt, ¶ms->partition_guid); |
461 /* TODO: GetCurrentKernelUniqueGuid() should take a destination size, or | 546 /* TODO: GetCurrentKernelUniqueGuid() should take a destination size, or |
462 * the dest should be a struct, so we know it's big enough. */ | 547 * the dest should be a struct, so we know it's big enough. */ |
463 params->bootloader_address = preamble->bootloader_address; | 548 params->bootloader_address = preamble->bootloader_address; |
464 params->bootloader_size = preamble->bootloader_size; | 549 params->bootloader_size = preamble->bootloader_size; |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
501 /* Free kernel buffer */ | 586 /* Free kernel buffer */ |
502 if (kbuf) | 587 if (kbuf) |
503 Free(kbuf); | 588 Free(kbuf); |
504 | 589 |
505 /* Write and free GPT data */ | 590 /* Write and free GPT data */ |
506 WriteAndFreeGptData(&gpt); | 591 WriteAndFreeGptData(&gpt); |
507 | 592 |
508 /* Handle finding a good partition */ | 593 /* Handle finding a good partition */ |
509 if (good_partition >= 0) { | 594 if (good_partition >= 0) { |
510 VBDEBUG(("Good_partition >= 0\n")); | 595 VBDEBUG(("Good_partition >= 0\n")); |
| 596 if (shcall) |
| 597 shcall->check_result = VBSD_LKC_CHECK_GOOD_PARTITION; |
511 | 598 |
512 /* See if we need to update the TPM */ | 599 /* See if we need to update the TPM */ |
513 if (kBootRecovery != boot_mode && good_partition_key_block_valid) { | 600 if (kBootRecovery != boot_mode && good_partition_key_block_valid) { |
514 /* We only update the TPM in normal and developer boot modes. In | 601 /* We only update the TPM in normal and developer boot modes. In |
515 * developer mode, we only advanced lowest_version for kernels with valid | 602 * developer mode, we only advanced lowest_version for kernels with valid |
516 * key blocks, and didn't count self-signed key blocks. In recovery | 603 * key blocks, and didn't count self-signed key blocks. In recovery |
517 * mode, the TPM stays PP-unlocked, so anything we write gets blown away | 604 * mode, the TPM stays PP-unlocked, so anything we write gets blown away |
518 * by the firmware when we go back to normal mode. */ | 605 * by the firmware when we go back to normal mode. */ |
519 VBDEBUG(("Boot_flags = not recovery\n")); | 606 VBDEBUG(("Boot_flags = not recovery\n")); |
520 | 607 |
(...skipping 23 matching lines...) Expand all Loading... |
544 retval = LOAD_KERNEL_REBOOT; | 631 retval = LOAD_KERNEL_REBOOT; |
545 else | 632 else |
546 recovery = VBNV_RECOVERY_RW_TPM_ERROR; | 633 recovery = VBNV_RECOVERY_RW_TPM_ERROR; |
547 goto LoadKernelExit; | 634 goto LoadKernelExit; |
548 } | 635 } |
549 } | 636 } |
550 | 637 |
551 /* Success! */ | 638 /* Success! */ |
552 retval = LOAD_KERNEL_SUCCESS; | 639 retval = LOAD_KERNEL_SUCCESS; |
553 } else { | 640 } else { |
| 641 if (shcall) |
| 642 shcall->check_result = (found_partitions > 0 |
| 643 ? VBSD_LKC_CHECK_INVALID_PARTITIONS |
| 644 : VBSD_LKC_CHECK_NO_PARTITIONS); |
| 645 |
554 /* TODO: differentiate between finding an invalid kernel | 646 /* TODO: differentiate between finding an invalid kernel |
555 * (found_partitions>0) and not finding one at all. Right now we | 647 * (found_partitions>0) and not finding one at all. Right now we |
556 * treat them the same, and return LOAD_KERNEL_INVALID for both. */ | 648 * treat them the same, and return LOAD_KERNEL_INVALID for both. */ |
557 retval = LOAD_KERNEL_INVALID; | 649 retval = LOAD_KERNEL_INVALID; |
558 } | 650 } |
559 | 651 |
560 LoadKernelExit: | 652 LoadKernelExit: |
561 | 653 |
562 /* Save whether the good partition's key block was fully verified */ | 654 /* Save whether the good partition's key block was fully verified */ |
563 VbNvSet(vnc, VBNV_FW_VERIFIED_KERNEL_KEY, good_partition_key_block_valid); | 655 VbNvSet(vnc, VBNV_FW_VERIFIED_KERNEL_KEY, good_partition_key_block_valid); |
564 | 656 |
565 /* Store recovery request, if any, then tear down non-volatile storage */ | 657 /* Store recovery request, if any, then tear down non-volatile storage */ |
566 VbNvSet(vnc, VBNV_RECOVERY_REQUEST, LOAD_KERNEL_RECOVERY == retval ? | 658 VbNvSet(vnc, VBNV_RECOVERY_REQUEST, LOAD_KERNEL_RECOVERY == retval ? |
567 recovery : VBNV_RECOVERY_NOT_REQUESTED); | 659 recovery : VBNV_RECOVERY_NOT_REQUESTED); |
568 VbNvTeardown(vnc); | 660 VbNvTeardown(vnc); |
569 | 661 |
570 if (shared) { | 662 if (shared) { |
| 663 if (shcall) |
| 664 shcall->return_code = (uint8_t)retval; |
| 665 |
| 666 /* Save whether the good partition's key block was fully verified */ |
| 667 if (good_partition_key_block_valid) |
| 668 shared->flags |= VBSD_KERNEL_KEY_VERIFIED; |
| 669 |
571 /* Save timer values */ | 670 /* Save timer values */ |
572 shared->timer_load_kernel_enter = timer_enter; | 671 shared->timer_load_kernel_enter = timer_enter; |
573 shared->timer_load_kernel_exit = VbGetTimer(); | 672 shared->timer_load_kernel_exit = VbGetTimer(); |
574 /* Store how much shared data we used, if any */ | 673 /* Store how much shared data we used, if any */ |
575 params->shared_data_size = shared->data_used; | 674 params->shared_data_size = shared->data_used; |
576 } | 675 } |
577 | 676 |
578 return retval; | 677 return retval; |
579 } | 678 } |
OLD | NEW |