summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2011-07-26 16:26:59 -0700
committerRandall Spangler <rspangler@chromium.org>2011-07-27 10:16:14 -0700
commit99275128b44a8de53c5c72987148c8d0bffc0689 (patch)
tree5d45a608f0517ab871395e8d3c35f4edf0a8afef
parent57e91f713f7e647e79ecdf7a6de878f638661e05 (diff)
downloadvboot-99275128b44a8de53c5c72987148c8d0bffc0689.tar.gz
If trying firmware B and found invalid kernel, just reboot
When we're trying a new firmware B with a new kernel subkey, if it can't find any kernels there may still be a kernel which the old firmware A likes. So instead of going to recovery mode, just reboot so we fall back to firmware A. If firmware A doesn't find any valid kernels we'll still go to recovery mode. BUG=chrome-os-partner:1657 TEST=manual: Do a firmware+OS update which involves kernel subkey rotation. After installing the new firmware but before rebooting into the new OS, corrupt the new kernel so that it'll fail validation. Then reboot. On previous firmware, this would go to recovery mode. Now it should simply reboot and be back in firmware A / kernel A. Change-Id: I12796f428fd6969ea5ef36f39c4f58cb0a2bff0d Reviewed-on: http://gerrit.chromium.org/gerrit/4770 Reviewed-by: Gaurav Shah <gauravsh@chromium.org> Tested-by: Randall Spangler <rspangler@chromium.org>
-rw-r--r--firmware/lib/vboot_api_kernel.c29
1 files changed, 24 insertions, 5 deletions
diff --git a/firmware/lib/vboot_api_kernel.c b/firmware/lib/vboot_api_kernel.c
index 692e3b08..5331526c 100644
--- a/firmware/lib/vboot_api_kernel.c
+++ b/firmware/lib/vboot_api_kernel.c
@@ -625,11 +625,30 @@ VbError_t VbSelectAndLoadKernel(VbCommonParams* cparams,
/* Normal boot */
retval = VbBootNormal(cparams, &p);
- /* See if we need to update the TPM. */
- if (!((1 == shared->firmware_index) && (shared->flags & VBSD_FWB_TRIED))) {
- /* We don't advance the TPM if we're trying a new firmware B, because
- * that firmware may have a key change and roll forward the TPM too
- * soon. */
+ if ((1 == shared->firmware_index) && (shared->flags & VBSD_FWB_TRIED)) {
+ /* Special cases for when we're trying a new firmware B. These are
+ * needed because firmware updates also usually change the kernel key,
+ * which means that the B firmware can only boot a new kernel, and the
+ * old firmware in A can only boot the previous kernel. */
+
+ /* Don't advance the TPM if we're trying a new firmware B, because we
+ * don't yet know if the new kernel will successfully boot. We still
+ * want to be able to fall back to the previous firmware+kernel if the
+ * new firmware+kernel fails. */
+
+ /* If we found only invalid kernels, reboot and try again. This allows
+ * us to fall back to the previous firmware+kernel instead of giving up
+ * and going to recovery mode right away. We'll still go to recovery
+ * mode if we run out of tries and the old firmware can't find a kernel
+ * it likes. */
+ if (VBERROR_INVALID_KERNEL_FOUND == retval) {
+ VBDEBUG(("Trying firmware B, and only found invalid kernels.\n"));
+ VbSetRecoveryRequest(VBNV_RECOVERY_NOT_REQUESTED);
+ goto VbSelectAndLoadKernel_exit;
+ }
+ } else {
+ /* Not trying a new firmware B. */
+ /* See if we need to update the TPM. */
VBDEBUG(("Checking if TPM kernel version needs advancing\n"));
if (shared->kernel_version_tpm > shared->kernel_version_tpm_start) {
tpm_status = RollbackKernelWrite(shared->kernel_version_tpm);