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 "vboot_kernel.h" | 9 #include "vboot_kernel.h" |
10 | 10 |
| 11 #include <inttypes.h> /* For PRIu64 */ |
11 #include "boot_device.h" | 12 #include "boot_device.h" |
12 #include "cgptlib.h" | 13 #include "cgptlib.h" |
13 #include "load_kernel_fw.h" | 14 #include "load_kernel_fw.h" |
14 #include "rollback_index.h" | 15 #include "rollback_index.h" |
15 #include "utility.h" | 16 #include "utility.h" |
16 #include "vboot_common.h" | 17 #include "vboot_common.h" |
17 | 18 |
18 | 19 |
19 #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 */ |
20 | 21 |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
128 /* Clear output params in case we fail */ | 129 /* Clear output params in case we fail */ |
129 params->partition_number = 0; | 130 params->partition_number = 0; |
130 params->bootloader_address = 0; | 131 params->bootloader_address = 0; |
131 params->bootloader_size = 0; | 132 params->bootloader_size = 0; |
132 | 133 |
133 if (is_normal) { | 134 if (is_normal) { |
134 /* Read current kernel key index from TPM. Assumes TPM is already | 135 /* Read current kernel key index from TPM. Assumes TPM is already |
135 * initialized. */ | 136 * initialized. */ |
136 if (0 != GetStoredVersions(KERNEL_VERSIONS, | 137 if (0 != GetStoredVersions(KERNEL_VERSIONS, |
137 &tpm_key_version, | 138 &tpm_key_version, |
138 &tpm_kernel_version)) | 139 &tpm_kernel_version)) { |
| 140 debug("Unable to get stored version from TPM\n"); |
139 return LOAD_KERNEL_RECOVERY; | 141 return LOAD_KERNEL_RECOVERY; |
| 142 } |
140 } else if (is_dev) { | 143 } else if (is_dev) { |
141 /* In developer mode, we ignore the kernel subkey, and just use | 144 /* In developer mode, we ignore the kernel subkey, and just use |
142 * the SHA-512 hash to verify the key block. */ | 145 * the SHA-512 hash to verify the key block. */ |
143 kernel_subkey = NULL; | 146 kernel_subkey = NULL; |
144 } | 147 } |
145 | 148 |
146 do { | 149 do { |
147 /* Read GPT data */ | 150 /* Read GPT data */ |
148 gpt.sector_bytes = blba; | 151 gpt.sector_bytes = blba; |
149 gpt.drive_sectors = params->ending_lba + 1; | 152 gpt.drive_sectors = params->ending_lba + 1; |
150 if (0 != AllocAndReadGptData(&gpt)) | 153 if (0 != AllocAndReadGptData(&gpt)) { |
| 154 debug("Unable to read GPT data\n"); |
151 break; | 155 break; |
| 156 } |
152 | 157 |
153 /* Initialize GPT library */ | 158 /* Initialize GPT library */ |
154 if (GPT_SUCCESS != GptInit(&gpt)) | 159 if (GPT_SUCCESS != GptInit(&gpt)) { |
| 160 debug("Error parsing GPT\n"); |
155 break; | 161 break; |
| 162 } |
156 | 163 |
157 /* Allocate kernel header buffers */ | 164 /* Allocate kernel header buffers */ |
158 kbuf = (uint8_t*)Malloc(KBUF_SIZE); | 165 kbuf = (uint8_t*)Malloc(KBUF_SIZE); |
159 if (!kbuf) | 166 if (!kbuf) |
160 break; | 167 break; |
161 | 168 |
162 /* Loop over candidate kernel partitions */ | 169 /* Loop over candidate kernel partitions */ |
163 while (GPT_SUCCESS == GptNextKernelEntry(&gpt, &part_start, &part_size)) { | 170 while (GPT_SUCCESS == GptNextKernelEntry(&gpt, &part_start, &part_size)) { |
164 VbKeyBlockHeader* key_block; | 171 VbKeyBlockHeader* key_block; |
165 VbKernelPreambleHeader* preamble; | 172 VbKernelPreambleHeader* preamble; |
166 RSAPublicKey* data_key; | 173 RSAPublicKey* data_key; |
167 uint64_t key_version; | 174 uint64_t key_version; |
168 uint64_t body_offset; | 175 uint64_t body_offset; |
169 | 176 |
| 177 debug("Found kernel entry at %" PRIu64 " size %" PRIu64 "\n", |
| 178 part_start, part_size); |
| 179 |
170 /* Found at least one kernel partition. */ | 180 /* Found at least one kernel partition. */ |
171 found_partitions++; | 181 found_partitions++; |
172 | 182 |
173 /* Read the first part of the kernel partition */ | 183 /* Read the first part of the kernel partition */ |
174 if (part_size < kbuf_sectors) | 184 if (part_size < kbuf_sectors) |
175 continue; | 185 continue; |
176 if (0 != BootDeviceReadLBA(part_start, kbuf_sectors, kbuf)) | 186 if (0 != BootDeviceReadLBA(part_start, kbuf_sectors, kbuf)) |
177 continue; | 187 continue; |
178 | 188 |
179 /* Verify the key block */ | 189 /* Verify the key block */ |
180 key_block = (VbKeyBlockHeader*)kbuf; | 190 key_block = (VbKeyBlockHeader*)kbuf; |
181 if ((0 != KeyBlockVerify(key_block, KBUF_SIZE, kernel_subkey))) | 191 if ((0 != KeyBlockVerify(key_block, KBUF_SIZE, kernel_subkey))) { |
| 192 debug("Verifying key block failed.\n"); |
182 continue; | 193 continue; |
| 194 } |
183 | 195 |
184 /* Check the key block flags against the current boot mode */ | 196 /* Check the key block flags against the current boot mode */ |
185 if (!(key_block->key_block_flags && | 197 if (!(key_block->key_block_flags && |
186 ((BOOT_FLAG_DEVELOPER & params->boot_flags) ? | 198 ((BOOT_FLAG_DEVELOPER & params->boot_flags) ? |
187 KEY_BLOCK_FLAG_DEVELOPER_1 : KEY_BLOCK_FLAG_DEVELOPER_0))) | 199 KEY_BLOCK_FLAG_DEVELOPER_1 : KEY_BLOCK_FLAG_DEVELOPER_0))) { |
| 200 debug("Developer flag mismatch.\n"); |
188 continue; | 201 continue; |
| 202 } |
189 if (!(key_block->key_block_flags && | 203 if (!(key_block->key_block_flags && |
190 ((BOOT_FLAG_RECOVERY & params->boot_flags) ? | 204 ((BOOT_FLAG_RECOVERY & params->boot_flags) ? |
191 KEY_BLOCK_FLAG_RECOVERY_1 : KEY_BLOCK_FLAG_RECOVERY_0))) | 205 KEY_BLOCK_FLAG_RECOVERY_1 : KEY_BLOCK_FLAG_RECOVERY_0))) { |
| 206 debug("Recovery flag mismatch.\n"); |
192 continue; | 207 continue; |
| 208 } |
193 | 209 |
194 /* Check for rollback of key version. Note this is implicitly | 210 /* Check for rollback of key version. Note this is implicitly |
195 * skipped in recovery and developer modes because those set | 211 * skipped in recovery and developer modes because those set |
196 * key_version=0 above. */ | 212 * key_version=0 above. */ |
197 key_version = key_block->data_key.key_version; | 213 key_version = key_block->data_key.key_version; |
198 if (key_version < tpm_key_version) | 214 if (key_version < tpm_key_version) { |
| 215 debug("Key version too old.\n"); |
199 continue; | 216 continue; |
| 217 } |
200 | 218 |
201 /* Get the key for preamble/data verification from the key block */ | 219 /* Get the key for preamble/data verification from the key block */ |
202 data_key = PublicKeyToRSA(&key_block->data_key); | 220 data_key = PublicKeyToRSA(&key_block->data_key); |
203 if (!data_key) | 221 if (!data_key) |
204 continue; | 222 continue; |
205 | 223 |
206 /* Verify the preamble, which follows the key block */ | 224 /* Verify the preamble, which follows the key block */ |
207 preamble = (VbKernelPreambleHeader*)(kbuf + key_block->key_block_size); | 225 preamble = (VbKernelPreambleHeader*)(kbuf + key_block->key_block_size); |
208 if ((0 != VerifyKernelPreamble2(preamble, | 226 if ((0 != VerifyKernelPreamble2(preamble, |
209 KBUF_SIZE - key_block->key_block_size, | 227 KBUF_SIZE - key_block->key_block_size, |
210 data_key))) { | 228 data_key))) { |
| 229 debug("Preamble verification failed.\n"); |
211 RSAPublicKeyFree(data_key); | 230 RSAPublicKeyFree(data_key); |
212 continue; | 231 continue; |
213 } | 232 } |
214 | 233 |
215 /* Check for rollback of kernel version. Note this is implicitly | 234 /* Check for rollback of kernel version. Note this is implicitly |
216 * skipped in recovery and developer modes because those set | 235 * skipped in recovery and developer modes because those set |
217 * key_version=0 and kernel_version=0 above. */ | 236 * key_version=0 and kernel_version=0 above. */ |
218 if (key_version == tpm_key_version && | 237 if (key_version == tpm_key_version && |
219 preamble->kernel_version < tpm_kernel_version) { | 238 preamble->kernel_version < tpm_kernel_version) { |
| 239 debug("Kernel version too low.\n"); |
220 RSAPublicKeyFree(data_key); | 240 RSAPublicKeyFree(data_key); |
221 continue; | 241 continue; |
222 } | 242 } |
223 | 243 |
| 244 debug("Kernel preamble is good.\n"); |
| 245 |
224 /* Check for lowest key version from a valid header. */ | 246 /* Check for lowest key version from a valid header. */ |
225 if (lowest_key_version > key_version) { | 247 if (lowest_key_version > key_version) { |
226 lowest_key_version = key_version; | 248 lowest_key_version = key_version; |
227 lowest_kernel_version = preamble->kernel_version; | 249 lowest_kernel_version = preamble->kernel_version; |
228 } | 250 } |
229 else if (lowest_key_version == key_version && | 251 else if (lowest_key_version == key_version && |
230 lowest_kernel_version > preamble->kernel_version) { | 252 lowest_kernel_version > preamble->kernel_version) { |
231 lowest_kernel_version = preamble->kernel_version; | 253 lowest_kernel_version = preamble->kernel_version; |
232 } | 254 } |
233 | 255 |
234 /* If we already have a good kernel, no need to read another | 256 /* If we already have a good kernel, no need to read another |
235 * one; we only needed to look at the versions to check for | 257 * one; we only needed to look at the versions to check for |
236 * rollback. */ | 258 * rollback. */ |
237 if (-1 != good_partition) | 259 if (-1 != good_partition) |
238 continue; | 260 continue; |
239 | 261 |
240 /* Verify body load address matches what we expect */ | 262 /* Verify body load address matches what we expect */ |
241 if (preamble->body_load_address != (size_t)params->kernel_buffer) { | 263 if ((preamble->body_load_address != (size_t)params->kernel_buffer) && |
| 264 !(params->boot_flags & BOOT_FLAG_SKIP_ADDR_CHECK)) { |
| 265 debug("Wrong body load address.\n"); |
242 RSAPublicKeyFree(data_key); | 266 RSAPublicKeyFree(data_key); |
243 continue; | 267 continue; |
244 } | 268 } |
245 | 269 |
246 /* Verify kernel body starts at a multiple of the sector size. */ | 270 /* Verify kernel body starts at a multiple of the sector size. */ |
247 body_offset = key_block->key_block_size + preamble->preamble_size; | 271 body_offset = key_block->key_block_size + preamble->preamble_size; |
248 if (0 != body_offset % blba) { | 272 if (0 != body_offset % blba) { |
| 273 debug("Kernel body not at multiple of sector size.\n"); |
249 RSAPublicKeyFree(data_key); | 274 RSAPublicKeyFree(data_key); |
250 continue; | 275 continue; |
251 } | 276 } |
252 | 277 |
253 /* Verify kernel body fits in the partition */ | 278 /* Verify kernel body fits in the partition */ |
254 if (body_offset + preamble->body_signature.data_size > | 279 if (body_offset + preamble->body_signature.data_size > |
255 part_size * blba) { | 280 part_size * blba) { |
| 281 debug("Kernel body doesn't fit in partition.\n"); |
256 RSAPublicKeyFree(data_key); | 282 RSAPublicKeyFree(data_key); |
257 continue; | 283 continue; |
258 } | 284 } |
259 | 285 |
260 /* Read the kernel data */ | 286 /* Read the kernel data */ |
261 if (0 != BootDeviceReadLBA( | 287 if (0 != BootDeviceReadLBA( |
262 part_start + (body_offset / blba), | 288 part_start + (body_offset / blba), |
263 (preamble->body_signature.data_size + blba - 1) / blba, | 289 (preamble->body_signature.data_size + blba - 1) / blba, |
264 params->kernel_buffer)) { | 290 params->kernel_buffer)) { |
| 291 debug("Unable to read kernel data.\n"); |
265 RSAPublicKeyFree(data_key); | 292 RSAPublicKeyFree(data_key); |
266 continue; | 293 continue; |
267 } | 294 } |
268 | 295 |
269 /* Verify kernel data */ | 296 /* Verify kernel data */ |
270 if (0 != VerifyData((const uint8_t*)params->kernel_buffer, | 297 if (0 != VerifyData((const uint8_t*)params->kernel_buffer, |
271 &preamble->body_signature, data_key)) { | 298 &preamble->body_signature, data_key)) { |
| 299 debug("Kernel data verification failed.\n"); |
272 RSAPublicKeyFree(data_key); | 300 RSAPublicKeyFree(data_key); |
273 continue; | 301 continue; |
274 } | 302 } |
275 | 303 |
276 /* Done with the kernel signing key, so can free it now */ | 304 /* Done with the kernel signing key, so can free it now */ |
277 RSAPublicKeyFree(data_key); | 305 RSAPublicKeyFree(data_key); |
278 | 306 |
279 /* If we're still here, the kernel is valid. */ | 307 /* If we're still here, the kernel is valid. */ |
280 /* Save the first good partition we find; that's the one we'll boot */ | 308 /* Save the first good partition we find; that's the one we'll boot */ |
281 if (-1 == good_partition) { | 309 debug("Partiton is good.\n"); |
282 good_partition = gpt.current_kernel; | 310 good_partition = gpt.current_kernel; |
283 params->partition_number = gpt.current_kernel; | 311 params->partition_number = gpt.current_kernel; |
284 params->bootloader_address = preamble->bootloader_address; | 312 params->bootloader_address = preamble->bootloader_address; |
285 params->bootloader_size = preamble->bootloader_size; | 313 params->bootloader_size = preamble->bootloader_size; |
286 /* If we're in developer or recovery mode, there's no rollback | 314 /* If we're in developer or recovery mode, there's no rollback |
287 * protection, so we can stop at the first valid kernel. */ | 315 * protection, so we can stop at the first valid kernel. */ |
288 if (!is_normal) | 316 if (!is_normal) |
289 break; | 317 break; |
290 | 318 |
291 /* Otherwise, we're in normal boot mode, so we do care about | 319 /* Otherwise, we're in normal boot mode, so we do care about the |
292 * the key index in the TPM. If the good partition's key | 320 * key index in the TPM. If the good partition's key version is |
293 * version is the same as the tpm, then the TPM doesn't need | 321 * the same as the tpm, then the TPM doesn't need updating; we |
294 * updating; we can stop now. Otherwise, we'll check all the | 322 * can stop now. Otherwise, we'll check all the other headers |
295 * other headers to see if they contain a newer key. */ | 323 * to see if they contain a newer key. */ |
296 if (key_version == tpm_key_version && | 324 if (key_version == tpm_key_version && |
297 preamble->kernel_version == tpm_kernel_version) | 325 preamble->kernel_version == tpm_kernel_version) |
298 break; | 326 break; |
299 } | |
300 } /* while(GptNextKernelEntry) */ | 327 } /* while(GptNextKernelEntry) */ |
301 } while(0); | 328 } while(0); |
302 | 329 |
303 /* Free kernel buffer */ | 330 /* Free kernel buffer */ |
304 if (kbuf) | 331 if (kbuf) |
305 Free(kbuf); | 332 Free(kbuf); |
306 | 333 |
307 /* Write and free GPT data */ | 334 /* Write and free GPT data */ |
308 WriteAndFreeGptData(&gpt); | 335 WriteAndFreeGptData(&gpt); |
309 | 336 |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
344 /* Success! */ | 371 /* Success! */ |
345 return LOAD_KERNEL_SUCCESS; | 372 return LOAD_KERNEL_SUCCESS; |
346 } | 373 } |
347 | 374 |
348 // Handle error cases | 375 // Handle error cases |
349 if (found_partitions) | 376 if (found_partitions) |
350 return LOAD_KERNEL_INVALID; | 377 return LOAD_KERNEL_INVALID; |
351 else | 378 else |
352 return LOAD_KERNEL_NOT_FOUND; | 379 return LOAD_KERNEL_NOT_FOUND; |
353 } | 380 } |
OLD | NEW |