/* Copyright 2020 The Chromium OS Authors. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. * * Kernel selection, loading, verification, and booting. */ #include "2common.h" #include "2kernel.h" #include "2misc.h" #include "2nvstorage.h" #include "2rsa.h" #include "2secdata.h" #include "vb2_common.h" #include "vboot_kernel.h" /** * Reset any NVRAM requests. * * @param ctx Vboot context * @return 1 if a reboot is required, 0 otherwise. */ static int vb2_reset_nv_requests(struct vb2_context *ctx) { int need_reboot = 0; if (vb2_nv_get(ctx, VB2_NV_DISPLAY_REQUEST)) { VB2_DEBUG("Unset display request (undo display init)\n"); vb2_nv_set(ctx, VB2_NV_DISPLAY_REQUEST, 0); need_reboot = 1; } if (vb2_nv_get(ctx, VB2_NV_DIAG_REQUEST)) { VB2_DEBUG("Unset diagnostic request (undo display init)\n"); vb2_nv_set(ctx, VB2_NV_DIAG_REQUEST, 0); need_reboot = 1; } return need_reboot; } vb2_error_t vb2_normal_boot(struct vb2_context *ctx) { struct vb2_shared_data *sd = vb2_get_sd(ctx); uint32_t max_rollforward = vb2_nv_get(ctx, VB2_NV_KERNEL_MAX_ROLLFORWARD); /* Boot from fixed disk only */ VB2_DEBUG("Entering\n"); if (vb2_reset_nv_requests(ctx)) { VB2_DEBUG("Normal mode: reboot to reset NVRAM requests\n"); return VB2_REQUEST_REBOOT; } vb2_error_t rv = VbTryLoadKernel(ctx, VB_DISK_FLAG_FIXED); VB2_DEBUG("Checking if TPM kernel version needs advancing\n"); /* * Special case for when we're trying a slot with new firmware. * Firmware updates also usually change the kernel key, which means * that the new firmware can only boot a new kernel, and the old * firmware in the previous slot can only boot the previous kernel. * * Don't roll-forward the kernel version, because we don't yet know if * the new kernel will successfully boot. */ if (vb2_nv_get(ctx, VB2_NV_FW_RESULT) == VB2_FW_RESULT_TRYING) { VB2_DEBUG("Trying new FW; skip kernel version roll-forward.\n"); return rv; } /* * Limit kernel version rollforward if needed. Can't limit kernel * version to less than the version currently in the TPM. That is, * we're limiting rollforward, not allowing rollback. */ if (max_rollforward < sd->kernel_version_secdata) max_rollforward = sd->kernel_version_secdata; if (sd->kernel_version > max_rollforward) { VB2_DEBUG("Limiting TPM kernel version roll-forward " "to %#x < %#x\n", max_rollforward, sd->kernel_version); sd->kernel_version = max_rollforward; } if (sd->kernel_version > sd->kernel_version_secdata) { vb2_secdata_kernel_set(ctx, VB2_SECDATA_KERNEL_VERSIONS, sd->kernel_version); } return rv; } int vb2api_is_developer_signed(struct vb2_context *ctx) { struct vb2_shared_data *sd = vb2_get_sd(ctx); if (!sd->kernel_key_offset || !sd->kernel_key_size) { VB2_DEBUG("ERROR: Cannot call this before kernel_phase1!\n"); return 0; } struct vb2_public_key key; if (vb2_unpack_key(&key, vb2_member_of(sd, sd->kernel_key_offset))) return 0; /* This is a debugging aid, not a security-relevant feature. There's no reason to hardcode the whole key or waste time computing a hash. Just spot check the starting bytes of the pseudorandom part of the key. */ uint32_t devkey_n0inv = ctx->flags & VB2_CONTEXT_RECOVERY_MODE ? 0x18cebcf5 : /* recovery_key.vbpubk @0x24 */ 0xe0cd87d9; /* kernel_subkey.vbpubk @0x24 */ if (key.n0inv == devkey_n0inv) return 1; return 0; } vb2_error_t vb2api_kernel_phase1(struct vb2_context *ctx) { struct vb2_shared_data *sd = vb2_get_sd(ctx); struct vb2_workbuf wb; struct vb2_packed_key *packed_key; uint32_t secdata_flags; vb2_error_t rv; vb2_workbuf_from_ctx(ctx, &wb); /* * Init secdata_fwmp spaces. No need to init secdata_firmware or * secdata_kernel, since they were already read during firmware * verification. Ignore errors in recovery mode. */ rv = vb2_secdata_fwmp_init(ctx); if (rv && !(ctx->flags & VB2_CONTEXT_RECOVERY_MODE)) { VB2_DEBUG("TPM: init secdata_fwmp returned %#x\n", rv); vb2api_fail(ctx, VB2_RECOVERY_SECDATA_FWMP_INIT, rv); return rv; } /* Enable phone recovery while disabling the UI */ secdata_flags = vb2_secdata_kernel_get(ctx, VB2_SECDATA_KERNEL_FLAGS); secdata_flags &= ~VB2_SECDATA_KERNEL_FLAG_PHONE_RECOVERY_DISABLED; secdata_flags |= VB2_SECDATA_KERNEL_FLAG_PHONE_RECOVERY_UI_DISABLED; vb2_secdata_kernel_set(ctx, VB2_SECDATA_KERNEL_FLAGS, secdata_flags); /* Read kernel version from secdata. */ sd->kernel_version_secdata = vb2_secdata_kernel_get(ctx, VB2_SECDATA_KERNEL_VERSIONS); sd->kernel_version = sd->kernel_version_secdata; /* Find the key to use to verify the kernel keyblock */ if ((ctx->flags & VB2_CONTEXT_RECOVERY_MODE)) { /* Load recovery key from GBB. */ rv = vb2_gbb_read_recovery_key(ctx, &packed_key, NULL, &wb); if (rv) { if (vb2_allow_recovery(ctx)) VB2_DIE("GBB read recovery key failed.\n"); else /* * If we're headed for the BROKEN screen, * we won't need the recovery key. Just * short-circuit with success. */ return VB2_SUCCESS; } } else { /* Kernel subkey from firmware preamble */ struct vb2_fw_preamble *pre; /* Make sure we have a firmware preamble loaded */ if (!sd->preamble_size) return VB2_ERROR_API_KPHASE1_PREAMBLE; pre = (struct vb2_fw_preamble *) vb2_member_of(sd, sd->preamble_offset); packed_key = &pre->kernel_subkey; } sd->kernel_key_offset = vb2_offset_of(sd, packed_key); sd->kernel_key_size = packed_key->key_offset + packed_key->key_size; vb2_set_workbuf_used(ctx, vb2_offset_of(sd, wb.buf)); if (vb2api_is_developer_signed(ctx)) VB2_DEBUG("This is developer-signed firmware.\n"); return VB2_SUCCESS; }