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; |
134 int good_partition_key_block_valid = 0; | 135 int good_partition_key_block_valid = 0; |
135 uint32_t tpm_version = 0; | 136 uint32_t tpm_version = 0; |
136 uint64_t lowest_version = LOWEST_TPM_VERSION; | 137 uint64_t lowest_version = LOWEST_TPM_VERSION; |
137 int rec_switch, dev_switch; | 138 int rec_switch, dev_switch; |
138 BootMode boot_mode; | 139 BootMode boot_mode; |
| 140 uint32_t test_err = 0; |
139 uint32_t status; | 141 uint32_t status; |
140 | 142 |
141 /* TODO: differentiate between finding an invalid kernel (found_partitions>0) | 143 int retval = LOAD_KERNEL_RECOVERY; |
142 * and not finding one at all. Right now we treat them the same, and return | |
143 * LOAD_KERNEL_INVALID for both. */ | |
144 int retval = LOAD_KERNEL_INVALID; | |
145 int recovery = VBNV_RECOVERY_RO_UNSPECIFIED; | 144 int recovery = VBNV_RECOVERY_RO_UNSPECIFIED; |
| 145 uint64_t timer_enter = VbGetTimer(); |
146 | 146 |
147 /* Setup NV storage */ | 147 /* Setup NV storage */ |
148 VbNvSetup(vnc); | 148 VbNvSetup(vnc); |
149 | 149 |
150 /* Sanity Checks */ | 150 /* Sanity Checks */ |
151 if (!params || | 151 if (!params || |
152 !params->bytes_per_lba || | 152 !params->bytes_per_lba || |
153 !params->ending_lba || | 153 !params->ending_lba || |
154 !params->kernel_buffer || | 154 !params->kernel_buffer || |
155 !params->kernel_buffer_size) { | 155 !params->kernel_buffer_size) { |
156 VBDEBUG(("LoadKernel() called with invalid params\n")); | 156 VBDEBUG(("LoadKernel() called with invalid params\n")); |
157 goto LoadKernelExit; | 157 goto LoadKernelExit; |
158 } | 158 } |
159 | 159 |
160 /* Initialization */ | |
161 blba = params->bytes_per_lba; | |
162 kbuf_sectors = KBUF_SIZE / blba; | |
163 if (0 == kbuf_sectors) { | |
164 VBDEBUG(("LoadKernel() called with sector size > KBUF_SIZE\n")); | |
165 goto LoadKernelExit; | |
166 } | |
167 | |
168 rec_switch = (BOOT_FLAG_RECOVERY & params->boot_flags ? 1 : 0); | |
169 dev_switch = (BOOT_FLAG_DEVELOPER & params->boot_flags ? 1 : 0); | |
170 | |
171 if (rec_switch) | |
172 boot_mode = kBootRecovery; | |
173 else if (BOOT_FLAG_DEV_FIRMWARE & params->boot_flags) { | |
174 if (!dev_switch) { | |
175 /* Dev firmware should be signed such that it never boots with the dev | |
176 * switch is off; so something is terribly wrong. */ | |
177 VBDEBUG(("LoadKernel() called with dev firmware but dev switch off\n")); | |
178 recovery = VBNV_RECOVERY_RW_DEV_MISMATCH; | |
179 goto LoadKernelExit; | |
180 } | |
181 boot_mode = kBootDev; | |
182 } else { | |
183 /* Normal firmware */ | |
184 boot_mode = kBootNormal; | |
185 dev_switch = 0; /* Always do a fully verified boot */ | |
186 } | |
187 | |
188 /* Clear output params in case we fail */ | 160 /* Clear output params in case we fail */ |
189 params->partition_number = 0; | 161 params->partition_number = 0; |
190 params->bootloader_address = 0; | 162 params->bootloader_address = 0; |
191 params->bootloader_size = 0; | 163 params->bootloader_size = 0; |
192 | 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 |
193 if (kBootRecovery == boot_mode) { | 178 if (kBootRecovery == boot_mode) { |
194 /* Initialize the shared data structure, since LoadFirmware() didn't do it | 179 /* Initialize the shared data structure, since LoadFirmware() didn't do it |
195 * for us. */ | 180 * for us. */ |
196 if (0 != VbSharedDataInit(shared, params->shared_data_size)) { | 181 if (0 != VbSharedDataInit(shared, params->shared_data_size)) { |
197 /* Error initializing the shared data, but we can keep going. We just | 182 /* Error initializing the shared data, but we can keep going. We just |
198 * can't use the shared data. */ | 183 * can't use the shared data. */ |
199 VBDEBUG(("Shared data init error\n")); | 184 VBDEBUG(("Shared data init error\n")); |
200 params->shared_data_size = 0; | 185 params->shared_data_size = 0; |
201 shared = NULL; | 186 shared = NULL; |
202 } | 187 } |
| 188 } |
203 | 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 |
| 203 /* Handle test errors */ |
| 204 VbNvGet(vnc, VBNV_TEST_ERROR_FUNC, &test_err); |
| 205 if (VBNV_TEST_ERROR_LOAD_KERNEL == test_err) { |
| 206 /* Get error code */ |
| 207 VbNvGet(vnc, VBNV_TEST_ERROR_NUM, &test_err); |
| 208 if (shcall) |
| 209 shcall->test_error_num = (uint8_t)test_err; |
| 210 /* Clear test params so we don't repeat the error */ |
| 211 VbNvSet(vnc, VBNV_TEST_ERROR_FUNC, 0); |
| 212 VbNvSet(vnc, VBNV_TEST_ERROR_NUM, 0); |
| 213 /* Handle error codes */ |
| 214 switch (test_err) { |
| 215 case LOAD_KERNEL_RECOVERY: |
| 216 recovery = VBNV_RECOVERY_RW_TEST_LK; |
| 217 goto LoadKernelExit; |
| 218 case LOAD_KERNEL_NOT_FOUND: |
| 219 case LOAD_KERNEL_INVALID: |
| 220 case LOAD_KERNEL_REBOOT: |
| 221 retval = test_err; |
| 222 goto LoadKernelExit; |
| 223 default: |
| 224 break; |
| 225 } |
| 226 } |
| 227 |
| 228 /* Initialization */ |
| 229 blba = params->bytes_per_lba; |
| 230 kbuf_sectors = KBUF_SIZE / blba; |
| 231 if (0 == kbuf_sectors) { |
| 232 VBDEBUG(("LoadKernel() called with sector size > KBUF_SIZE\n")); |
| 233 goto LoadKernelExit; |
| 234 } |
| 235 |
| 236 if (kBootDev == boot_mode && !dev_switch) { |
| 237 /* Dev firmware should be signed such that it never boots with the dev |
| 238 * switch is off; so something is terribly wrong. */ |
| 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; |
| 242 recovery = VBNV_RECOVERY_RW_DEV_MISMATCH; |
| 243 goto LoadKernelExit; |
| 244 } |
| 245 |
| 246 if (kBootRecovery == boot_mode) { |
204 /* Use the recovery key to verify the kernel */ | 247 /* Use the recovery key to verify the kernel */ |
205 kernel_subkey = (VbPublicKey*)((uint8_t*)gbb + gbb->recovery_key_offset); | 248 kernel_subkey = (VbPublicKey*)((uint8_t*)gbb + gbb->recovery_key_offset); |
206 | 249 |
207 /* Let the TPM know if we're in recovery mode */ | 250 /* Let the TPM know if we're in recovery mode */ |
208 if (0 != RollbackKernelRecovery(dev_switch)) { | 251 if (0 != RollbackKernelRecovery(dev_switch)) { |
209 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; |
210 /* Ignore return code, since we need to boot recovery mode to | 255 /* Ignore return code, since we need to boot recovery mode to |
211 * fix the TPM. */ | 256 * fix the TPM. */ |
212 } | 257 } |
| 258 |
| 259 /* Read the key indices from the TPM; ignore any errors */ |
| 260 if (shared) { |
| 261 RollbackFirmwareRead(&shared->fw_version_tpm); |
| 262 RollbackKernelRead(&shared->kernel_version_tpm); |
| 263 } |
213 } else { | 264 } else { |
214 /* Use the kernel subkey passed from LoadFirmware(). */ | 265 /* Use the kernel subkey passed from LoadFirmware(). */ |
215 kernel_subkey = &shared->kernel_subkey; | 266 kernel_subkey = &shared->kernel_subkey; |
216 | 267 |
217 /* Read current kernel key index from TPM. Assumes TPM is already | 268 /* Read current kernel key index from TPM. Assumes TPM is already |
218 * initialized. */ | 269 * initialized. */ |
219 status = RollbackKernelRead(&tpm_version); | 270 status = RollbackKernelRead(&tpm_version); |
220 if (0 != status) { | 271 if (0 != status) { |
221 VBDEBUG(("Unable to get kernel versions from TPM\n")); | 272 VBDEBUG(("Unable to get kernel versions from TPM\n")); |
222 if (status == TPM_E_MUST_REBOOT) | 273 if (status == TPM_E_MUST_REBOOT) |
223 retval = LOAD_KERNEL_REBOOT; | 274 retval = LOAD_KERNEL_REBOOT; |
224 else | 275 else |
225 recovery = VBNV_RECOVERY_RW_TPM_ERROR; | 276 recovery = VBNV_RECOVERY_RW_TPM_ERROR; |
226 goto LoadKernelExit; | 277 goto LoadKernelExit; |
227 } | 278 } |
| 279 if (shared) |
| 280 shared->kernel_version_tpm = tpm_version; |
228 } | 281 } |
229 | 282 |
230 do { | 283 do { |
231 /* Read GPT data */ | 284 /* Read GPT data */ |
232 gpt.sector_bytes = (uint32_t)blba; | 285 gpt.sector_bytes = (uint32_t)blba; |
233 gpt.drive_sectors = params->ending_lba + 1; | 286 gpt.drive_sectors = params->ending_lba + 1; |
234 if (0 != AllocAndReadGptData(&gpt)) { | 287 if (0 != AllocAndReadGptData(&gpt)) { |
235 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; |
236 break; | 291 break; |
237 } | 292 } |
238 | 293 |
239 /* Initialize GPT library */ | 294 /* Initialize GPT library */ |
240 if (GPT_SUCCESS != GptInit(&gpt)) { | 295 if (GPT_SUCCESS != GptInit(&gpt)) { |
241 VBDEBUG(("Error parsing GPT\n")); | 296 VBDEBUG(("Error parsing GPT\n")); |
| 297 if (shcall) |
| 298 shcall->check_result = VBSD_LKC_CHECK_GPT_PARSE_ERROR; |
242 break; | 299 break; |
243 } | 300 } |
244 | 301 |
245 /* Allocate kernel header buffers */ | 302 /* Allocate kernel header buffers */ |
246 kbuf = (uint8_t*)Malloc(KBUF_SIZE); | 303 kbuf = (uint8_t*)Malloc(KBUF_SIZE); |
247 if (!kbuf) | 304 if (!kbuf) |
248 break; | 305 break; |
249 | 306 |
250 /* Loop over candidate kernel partitions */ | 307 /* Loop over candidate kernel partitions */ |
251 while (GPT_SUCCESS == GptNextKernelEntry(&gpt, &part_start, &part_size)) { | 308 while (GPT_SUCCESS == GptNextKernelEntry(&gpt, &part_start, &part_size)) { |
| 309 VbSharedDataKernelPart* shpart = NULL; |
252 VbKeyBlockHeader* key_block; | 310 VbKeyBlockHeader* key_block; |
253 VbKernelPreambleHeader* preamble; | 311 VbKernelPreambleHeader* preamble; |
254 RSAPublicKey* data_key = NULL; | 312 RSAPublicKey* data_key = NULL; |
255 uint64_t key_version; | 313 uint64_t key_version; |
256 uint64_t combined_version; | 314 uint64_t combined_version; |
257 uint64_t body_offset; | 315 uint64_t body_offset; |
258 uint64_t body_offset_sectors; | 316 uint64_t body_offset_sectors; |
259 uint64_t body_sectors; | 317 uint64_t body_sectors; |
260 int key_block_valid = 1; | 318 int key_block_valid = 1; |
261 | 319 |
262 VBDEBUG(("Found kernel entry at %" PRIu64 " size %" PRIu64 "\n", | 320 VBDEBUG(("Found kernel entry at %" PRIu64 " size %" PRIu64 "\n", |
263 part_start, part_size)); | 321 part_start, part_size)); |
264 | 322 |
| 323 if (shcall) { |
| 324 /* Set up tracking for this partition. This wraps around if called |
| 325 * many times, so 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 |
265 /* Found at least one kernel partition. */ | 337 /* Found at least one kernel partition. */ |
266 found_partitions++; | 338 found_partitions++; |
267 | 339 |
268 /* Read the first part of the kernel partition. */ | 340 /* Read the first part of the kernel partition. */ |
269 if (part_size < kbuf_sectors) { | 341 if (part_size < kbuf_sectors) { |
270 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; |
271 goto bad_kernel; | 345 goto bad_kernel; |
272 } | 346 } |
273 | 347 |
274 if (0 != BootDeviceReadLBA(part_start, kbuf_sectors, kbuf)) { | 348 if (0 != BootDeviceReadLBA(part_start, kbuf_sectors, kbuf)) { |
275 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; |
276 goto bad_kernel; | 352 goto bad_kernel; |
277 } | 353 } |
278 | 354 |
279 /* Verify the key block. */ | 355 /* Verify the key block. */ |
280 key_block = (VbKeyBlockHeader*)kbuf; | 356 key_block = (VbKeyBlockHeader*)kbuf; |
281 if (0 != KeyBlockVerify(key_block, KBUF_SIZE, kernel_subkey, 0)) { | 357 if (0 != KeyBlockVerify(key_block, KBUF_SIZE, kernel_subkey, 0)) { |
282 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 |
283 key_block_valid = 0; | 362 key_block_valid = 0; |
284 | 363 |
285 /* If we're not in developer mode, this kernel is bad. */ | 364 /* If we're not in developer mode, this kernel is bad. */ |
286 if (kBootDev != boot_mode) | 365 if (kBootDev != boot_mode) |
287 goto bad_kernel; | 366 goto bad_kernel; |
288 | 367 |
289 /* 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 |
290 * block is valid. */ | 369 * block is valid. */ |
291 if (0 != KeyBlockVerify(key_block, KBUF_SIZE, kernel_subkey, 1)) { | 370 if (0 != KeyBlockVerify(key_block, KBUF_SIZE, kernel_subkey, 1)) { |
292 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; |
293 goto bad_kernel; | 374 goto bad_kernel; |
294 } | 375 } |
295 } | 376 } |
296 | 377 |
297 /* Check the key block flags against the current boot mode. */ | 378 /* Check the key block flags against the current boot mode. */ |
298 if (!(key_block->key_block_flags & | 379 if (!(key_block->key_block_flags & |
299 (dev_switch ? KEY_BLOCK_FLAG_DEVELOPER_1 : | 380 (dev_switch ? KEY_BLOCK_FLAG_DEVELOPER_1 : |
300 KEY_BLOCK_FLAG_DEVELOPER_0))) { | 381 KEY_BLOCK_FLAG_DEVELOPER_0))) { |
301 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; |
302 key_block_valid = 0; | 385 key_block_valid = 0; |
303 } | 386 } |
304 if (!(key_block->key_block_flags & | 387 if (!(key_block->key_block_flags & |
305 (rec_switch ? KEY_BLOCK_FLAG_RECOVERY_1 : | 388 (rec_switch ? KEY_BLOCK_FLAG_RECOVERY_1 : |
306 KEY_BLOCK_FLAG_RECOVERY_0))) { | 389 KEY_BLOCK_FLAG_RECOVERY_0))) { |
307 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; |
308 key_block_valid = 0; | 393 key_block_valid = 0; |
309 } | 394 } |
310 | 395 |
311 /* Check for rollback of key version except in recovery mode. */ | 396 /* Check for rollback of key version except in recovery mode. */ |
312 key_version = key_block->data_key.key_version; | 397 key_version = key_block->data_key.key_version; |
313 if (kBootRecovery != boot_mode) { | 398 if (kBootRecovery != boot_mode) { |
314 if (key_version < (tpm_version >> 16)) { | 399 if (key_version < (tpm_version >> 16)) { |
315 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; |
316 key_block_valid = 0; | 403 key_block_valid = 0; |
317 } | 404 } |
318 } | 405 } |
319 | 406 |
320 /* 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. */ |
321 if (kBootDev != boot_mode && !key_block_valid) { | 408 if (kBootDev != boot_mode && !key_block_valid) { |
322 VBDEBUG(("Key block is invalid.\n")); | 409 VBDEBUG(("Key block is invalid.\n")); |
323 goto bad_kernel; | 410 goto bad_kernel; |
324 } | 411 } |
325 | 412 |
326 /* Get the key for preamble/data verification from the key block. */ | 413 /* Get the key for preamble/data verification from the key block. */ |
327 data_key = PublicKeyToRSA(&key_block->data_key); | 414 data_key = PublicKeyToRSA(&key_block->data_key); |
328 if (!data_key) { | 415 if (!data_key) { |
329 VBDEBUG(("Data key bad.\n")); | 416 VBDEBUG(("Data key bad.\n")); |
| 417 if (shpart) |
| 418 shpart->check_result = VBSD_LKP_CHECK_DATA_KEY_PARSE; |
330 goto bad_kernel; | 419 goto bad_kernel; |
331 } | 420 } |
332 | 421 |
333 /* Verify the preamble, which follows the key block */ | 422 /* Verify the preamble, which follows the key block */ |
334 preamble = (VbKernelPreambleHeader*)(kbuf + key_block->key_block_size); | 423 preamble = (VbKernelPreambleHeader*)(kbuf + key_block->key_block_size); |
335 if ((0 != VerifyKernelPreamble(preamble, | 424 if ((0 != VerifyKernelPreamble(preamble, |
336 KBUF_SIZE - key_block->key_block_size, | 425 KBUF_SIZE - key_block->key_block_size, |
337 data_key))) { | 426 data_key))) { |
338 VBDEBUG(("Preamble verification failed.\n")); | 427 VBDEBUG(("Preamble verification failed.\n")); |
| 428 if (shpart) |
| 429 shpart->check_result = VBSD_LKP_CHECK_VERIFY_PREAMBLE; |
339 goto bad_kernel; | 430 goto bad_kernel; |
340 } | 431 } |
341 | 432 |
342 /* 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 |
343 * rollback of the kernel version. */ | 434 * rollback of the kernel version. */ |
344 combined_version = ((key_version << 16) | | 435 combined_version = ((key_version << 16) | |
345 (preamble->kernel_version & 0xFFFF)); | 436 (preamble->kernel_version & 0xFFFF)); |
| 437 if (shpart) |
| 438 shpart->combined_version = (uint32_t)combined_version; |
346 if (key_block_valid && kBootRecovery != boot_mode) { | 439 if (key_block_valid && kBootRecovery != boot_mode) { |
347 if (combined_version < tpm_version) { | 440 if (combined_version < tpm_version) { |
348 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; |
349 /* 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. */ |
350 if (kBootDev != boot_mode) | 445 if (kBootDev != boot_mode) |
351 goto bad_kernel; | 446 goto bad_kernel; |
352 } | 447 } |
353 } | 448 } |
354 | 449 |
355 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; |
356 | 453 |
357 /* Check for lowest version from a valid header. */ | 454 /* Check for lowest version from a valid header. */ |
358 if (key_block_valid && lowest_version > combined_version) | 455 if (key_block_valid && lowest_version > combined_version) |
359 lowest_version = combined_version; | 456 lowest_version = combined_version; |
360 else { | 457 else { |
361 VBDEBUG(("Key block valid: %d\n", key_block_valid)); | 458 VBDEBUG(("Key block valid: %d\n", key_block_valid)); |
362 VBDEBUG(("Combined version: %" PRIu64 "\n", combined_version)); | 459 VBDEBUG(("Combined version: %" PRIu64 "\n", combined_version)); |
363 } | 460 } |
364 | 461 |
365 /* 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 |
366 * 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 |
367 * rollback. So skip to the next kernel preamble. */ | 464 * rollback. So skip to the next kernel preamble. */ |
368 if (-1 != good_partition) | 465 if (-1 != good_partition) |
369 continue; | 466 continue; |
370 | 467 |
371 /* Verify body load address matches what we expect */ | 468 /* Verify body load address matches what we expect */ |
372 if ((preamble->body_load_address != (size_t)params->kernel_buffer) && | 469 if ((preamble->body_load_address != (size_t)params->kernel_buffer) && |
373 !(params->boot_flags & BOOT_FLAG_SKIP_ADDR_CHECK)) { | 470 !(params->boot_flags & BOOT_FLAG_SKIP_ADDR_CHECK)) { |
374 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; |
375 goto bad_kernel; | 474 goto bad_kernel; |
376 } | 475 } |
377 | 476 |
378 /* Verify kernel body starts at a multiple of the sector size. */ | 477 /* Verify kernel body starts at a multiple of the sector size. */ |
379 body_offset = key_block->key_block_size + preamble->preamble_size; | 478 body_offset = key_block->key_block_size + preamble->preamble_size; |
380 if (0 != body_offset % blba) { | 479 if (0 != body_offset % blba) { |
381 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; |
382 goto bad_kernel; | 483 goto bad_kernel; |
383 } | 484 } |
384 body_offset_sectors = body_offset / blba; | 485 body_offset_sectors = body_offset / blba; |
385 | 486 |
386 /* Verify kernel body fits in the buffer */ | 487 /* Verify kernel body fits in the buffer */ |
387 body_sectors = (preamble->body_signature.data_size + blba - 1) / blba; | 488 body_sectors = (preamble->body_signature.data_size + blba - 1) / blba; |
388 if (body_sectors * blba > params->kernel_buffer_size) { | 489 if (body_sectors * blba > params->kernel_buffer_size) { |
389 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; |
390 goto bad_kernel; | 493 goto bad_kernel; |
391 } | 494 } |
392 | 495 |
393 /* Verify kernel body fits in the partition */ | 496 /* Verify kernel body fits in the partition */ |
394 if (body_offset_sectors + body_sectors > part_size) { | 497 if (body_offset_sectors + body_sectors > part_size) { |
395 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; |
396 goto bad_kernel; | 501 goto bad_kernel; |
397 } | 502 } |
398 | 503 |
399 /* Read the kernel data */ | 504 /* Read the kernel data */ |
400 VBPERFSTART("VB_RKD"); | 505 VBPERFSTART("VB_RKD"); |
401 if (0 != BootDeviceReadLBA(part_start + body_offset_sectors, | 506 if (0 != BootDeviceReadLBA(part_start + body_offset_sectors, |
402 body_sectors, | 507 body_sectors, |
403 params->kernel_buffer)) { | 508 params->kernel_buffer)) { |
404 VBDEBUG(("Unable to read kernel data.\n")); | 509 VBDEBUG(("Unable to read kernel data.\n")); |
405 VBPERFEND("VB_RKD"); | 510 VBPERFEND("VB_RKD"); |
| 511 if (shpart) |
| 512 shpart->check_result = VBSD_LKP_CHECK_READ_DATA; |
406 goto bad_kernel; | 513 goto bad_kernel; |
407 } | 514 } |
408 VBPERFEND("VB_RKD"); | 515 VBPERFEND("VB_RKD"); |
409 | 516 |
410 /* Verify kernel data */ | 517 /* Verify kernel data */ |
411 if (0 != VerifyData((const uint8_t*)params->kernel_buffer, | 518 if (0 != VerifyData((const uint8_t*)params->kernel_buffer, |
412 params->kernel_buffer_size, | 519 params->kernel_buffer_size, |
413 &preamble->body_signature, data_key)) { | 520 &preamble->body_signature, data_key)) { |
414 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; |
415 goto bad_kernel; | 524 goto bad_kernel; |
416 } | 525 } |
417 | 526 |
418 /* Done with the kernel signing key, so can free it now */ | 527 /* Done with the kernel signing key, so can free it now */ |
419 RSAPublicKeyFree(data_key); | 528 RSAPublicKeyFree(data_key); |
420 data_key = NULL; | 529 data_key = NULL; |
421 | 530 |
422 /* If we're still here, the kernel is valid. */ | 531 /* If we're still here, the kernel is valid. */ |
423 /* 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 */ |
424 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 |
425 good_partition_key_block_valid = key_block_valid; | 540 good_partition_key_block_valid = key_block_valid; |
426 /* 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. |
427 * Adjust here, until cgptlib is fixed. */ | 542 * Adjust here, until cgptlib is fixed. */ |
428 good_partition = gpt.current_kernel + 1; | 543 good_partition = gpt.current_kernel + 1; |
429 params->partition_number = gpt.current_kernel + 1; | 544 params->partition_number = gpt.current_kernel + 1; |
430 GetCurrentKernelUniqueGuid(&gpt, ¶ms->partition_guid); | 545 GetCurrentKernelUniqueGuid(&gpt, ¶ms->partition_guid); |
431 /* TODO: GetCurrentKernelUniqueGuid() should take a destination size, or | 546 /* TODO: GetCurrentKernelUniqueGuid() should take a destination size, or |
432 * 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. */ |
433 params->bootloader_address = preamble->bootloader_address; | 548 params->bootloader_address = preamble->bootloader_address; |
434 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... |
471 /* Free kernel buffer */ | 586 /* Free kernel buffer */ |
472 if (kbuf) | 587 if (kbuf) |
473 Free(kbuf); | 588 Free(kbuf); |
474 | 589 |
475 /* Write and free GPT data */ | 590 /* Write and free GPT data */ |
476 WriteAndFreeGptData(&gpt); | 591 WriteAndFreeGptData(&gpt); |
477 | 592 |
478 /* Handle finding a good partition */ | 593 /* Handle finding a good partition */ |
479 if (good_partition >= 0) { | 594 if (good_partition >= 0) { |
480 VBDEBUG(("Good_partition >= 0\n")); | 595 VBDEBUG(("Good_partition >= 0\n")); |
| 596 if (shcall) |
| 597 shcall->check_result = VBSD_LKC_CHECK_GOOD_PARTITION; |
481 | 598 |
482 /* See if we need to update the TPM */ | 599 /* See if we need to update the TPM */ |
483 if (kBootRecovery != boot_mode && good_partition_key_block_valid) { | 600 if (kBootRecovery != boot_mode && good_partition_key_block_valid) { |
484 /* 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 |
485 * developer mode, we only advanced lowest_version for kernels with valid | 602 * developer mode, we only advanced lowest_version for kernels with valid |
486 * 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 |
487 * 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 |
488 * by the firmware when we go back to normal mode. */ | 605 * by the firmware when we go back to normal mode. */ |
489 VBDEBUG(("Boot_flags = not recovery\n")); | 606 VBDEBUG(("Boot_flags = not recovery\n")); |
490 | 607 |
491 if ((lowest_version > tpm_version) && | 608 if ((lowest_version > tpm_version) && |
492 (lowest_version != LOWEST_TPM_VERSION)) { | 609 (lowest_version != LOWEST_TPM_VERSION)) { |
493 status = RollbackKernelWrite((uint32_t)lowest_version); | 610 status = RollbackKernelWrite((uint32_t)lowest_version); |
494 if (0 != status) { | 611 if (0 != status) { |
495 VBDEBUG(("Error writing kernel versions to TPM.\n")); | 612 VBDEBUG(("Error writing kernel versions to TPM.\n")); |
496 if (status == TPM_E_MUST_REBOOT) | 613 if (status == TPM_E_MUST_REBOOT) |
497 retval = LOAD_KERNEL_REBOOT; | 614 retval = LOAD_KERNEL_REBOOT; |
498 else | 615 else |
499 recovery = VBNV_RECOVERY_RW_TPM_ERROR; | 616 recovery = VBNV_RECOVERY_RW_TPM_ERROR; |
500 goto LoadKernelExit; | 617 goto LoadKernelExit; |
501 } | 618 } |
| 619 if (shared) |
| 620 shared->kernel_version_tpm = (uint32_t)lowest_version; |
502 } | 621 } |
503 } | 622 } |
504 | 623 |
505 /* Lock the kernel versions */ | 624 /* Lock the kernel versions */ |
506 status = RollbackKernelLock(); | 625 status = RollbackKernelLock(); |
507 if (0 != status) { | 626 if (0 != status) { |
508 VBDEBUG(("Error locking kernel versions.\n")); | 627 VBDEBUG(("Error locking kernel versions.\n")); |
509 /* Don't reboot to recovery mode if we're already there */ | 628 /* Don't reboot to recovery mode if we're already there */ |
510 if (kBootRecovery != boot_mode) { | 629 if (kBootRecovery != boot_mode) { |
511 if (status == TPM_E_MUST_REBOOT) | 630 if (status == TPM_E_MUST_REBOOT) |
512 retval = LOAD_KERNEL_REBOOT; | 631 retval = LOAD_KERNEL_REBOOT; |
513 else | 632 else |
514 recovery = VBNV_RECOVERY_RW_TPM_ERROR; | 633 recovery = VBNV_RECOVERY_RW_TPM_ERROR; |
515 goto LoadKernelExit; | 634 goto LoadKernelExit; |
516 } | 635 } |
517 } | 636 } |
518 | 637 |
519 /* Success! */ | 638 /* Success! */ |
520 retval = LOAD_KERNEL_SUCCESS; | 639 retval = LOAD_KERNEL_SUCCESS; |
| 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 |
| 646 /* TODO: differentiate between finding an invalid kernel |
| 647 * (found_partitions>0) and not finding one at all. Right now we |
| 648 * treat them the same, and return LOAD_KERNEL_INVALID for both. */ |
| 649 retval = LOAD_KERNEL_INVALID; |
521 } | 650 } |
522 | 651 |
523 LoadKernelExit: | 652 LoadKernelExit: |
524 | 653 |
525 /* Save whether the good partition's key block was fully verified */ | |
526 VbNvSet(vnc, VBNV_FW_VERIFIED_KERNEL_KEY, good_partition_key_block_valid); | |
527 | |
528 /* Store recovery request, if any, then tear down non-volatile storage */ | 654 /* Store recovery request, if any, then tear down non-volatile storage */ |
529 VbNvSet(vnc, VBNV_RECOVERY_REQUEST, LOAD_KERNEL_RECOVERY == retval ? | 655 VbNvSet(vnc, VBNV_RECOVERY_REQUEST, LOAD_KERNEL_RECOVERY == retval ? |
530 recovery : VBNV_RECOVERY_NOT_REQUESTED); | 656 recovery : VBNV_RECOVERY_NOT_REQUESTED); |
531 VbNvTeardown(vnc); | 657 VbNvTeardown(vnc); |
532 | 658 |
533 /* Store how much shared data we used, if any */ | 659 if (shared) { |
534 if (shared) | 660 if (shcall) |
| 661 shcall->return_code = (uint8_t)retval; |
| 662 |
| 663 /* Save whether the good partition's key block was fully verified */ |
| 664 if (good_partition_key_block_valid) |
| 665 shared->flags |= VBSD_KERNEL_KEY_VERIFIED; |
| 666 |
| 667 /* Save timer values */ |
| 668 shared->timer_load_kernel_enter = timer_enter; |
| 669 shared->timer_load_kernel_exit = VbGetTimer(); |
| 670 /* Store how much shared data we used, if any */ |
535 params->shared_data_size = shared->data_used; | 671 params->shared_data_size = shared->data_used; |
| 672 } |
536 | 673 |
537 return retval; | 674 return retval; |
538 } | 675 } |
OLD | NEW |