xref: /aosp_15_r20/external/vboot_reference/firmware/2lib/2kernel.c (revision 8617a60d3594060b7ecbd21bc622a7c14f3cf2bc)
1 /* Copyright 2020 The ChromiumOS Authors
2  * Use of this source code is governed by a BSD-style license that can be
3  * found in the LICENSE file.
4  *
5  * Kernel selection, loading, verification, and booting.
6  */
7 
8 #include "2api.h"
9 #include "2common.h"
10 #include "2misc.h"
11 #include "2nvstorage.h"
12 #include "2rsa.h"
13 #include "2secdata.h"
14 
vb2api_is_developer_signed(struct vb2_context * ctx)15 int vb2api_is_developer_signed(struct vb2_context *ctx)
16 {
17 	struct vb2_shared_data *sd = vb2_get_sd(ctx);
18 
19 	if (!sd->kernel_key_offset || !sd->kernel_key_size) {
20 		VB2_DEBUG("ERROR: Cannot call this before kernel_phase1!\n");
21 		return 0;
22 	}
23 
24 	struct vb2_public_key key;
25 	if (vb2_unpack_key(&key, vb2_member_of(sd, sd->kernel_key_offset)))
26 		return 0;
27 
28 	/* This is a debugging aid, not a security-relevant feature. There's no
29 	   reason to hardcode the whole key or waste time computing a hash. Just
30 	   spot check the starting bytes of the pseudorandom part of the key. */
31 	uint32_t devkey_n0inv = ctx->flags & VB2_CONTEXT_RECOVERY_MODE ?
32 		0x18cebcf5 :	/*  recovery_key.vbpubk @0x24 */
33 		0xe0cd87d9;	/* kernel_subkey.vbpubk @0x24 */
34 
35 	if (key.n0inv == devkey_n0inv)
36 		return 1;
37 
38 	return 0;
39 }
40 
41 test_mockable
vb2api_kernel_phase1(struct vb2_context * ctx)42 vb2_error_t vb2api_kernel_phase1(struct vb2_context *ctx)
43 {
44 	struct vb2_shared_data *sd = vb2_get_sd(ctx);
45 	struct vb2_workbuf wb;
46 	struct vb2_packed_key *packed_key;
47 	uint32_t flags;
48 	vb2_error_t rv;
49 
50 	vb2_workbuf_from_ctx(ctx, &wb);
51 
52 	/*
53 	 * Init secdata_fwmp spaces. No need to init secdata_firmware or
54 	 * secdata_kernel, since they were already read during firmware
55 	 * verification.  Ignore errors in recovery mode.
56 	 */
57 	rv = vb2_secdata_fwmp_init(ctx);
58 	if (rv && !(ctx->flags & VB2_CONTEXT_RECOVERY_MODE)) {
59 		VB2_DEBUG("TPM: init secdata_fwmp returned %#x\n", rv);
60 		vb2api_fail(ctx, VB2_RECOVERY_SECDATA_FWMP_INIT, rv);
61 		return rv;
62 	}
63 
64 	/* Initialize experimental feature flags while in normal RW path. */
65 	if (!(ctx->flags & VB2_CONTEXT_RECOVERY_MODE)) {
66 		flags = vb2_secdata_kernel_get(ctx, VB2_SECDATA_KERNEL_FLAGS);
67 		flags &= ~VB2_SECDATA_KERNEL_FLAG_DIAGNOSTIC_UI_DISABLED;
68 		flags |= VB2_SECDATA_KERNEL_FLAG_HWCRYPTO_ALLOWED;
69 		vb2_secdata_kernel_set(ctx, VB2_SECDATA_KERNEL_FLAGS, flags);
70 	}
71 
72 	/* Read kernel version from secdata. */
73 	sd->kernel_version_secdata =
74 		vb2_secdata_kernel_get(ctx, VB2_SECDATA_KERNEL_VERSIONS);
75 
76 	vb2_fill_dev_boot_flags(ctx);
77 
78 	/* Find the key to use to verify the kernel keyblock */
79 	if ((ctx->flags & VB2_CONTEXT_RECOVERY_MODE)) {
80 		/* Load recovery key from GBB. */
81 		rv = vb2_gbb_read_recovery_key(ctx, &packed_key, NULL, &wb);
82 		if (rv) {
83 			if (ctx->boot_mode != VB2_BOOT_MODE_BROKEN_SCREEN)
84 				VB2_DIE("GBB read recovery key failed.\n");
85 			else
86 				/*
87 				 * If we're headed for the BROKEN screen,
88 				 * we won't need the recovery key.  Just
89 				 * short-circuit with success.
90 				 */
91 				return VB2_SUCCESS;
92 		}
93 	} else {
94 		/* Kernel subkey from firmware preamble */
95 		struct vb2_fw_preamble *pre;
96 
97 		/* Make sure we have a firmware preamble loaded */
98 		if (!sd->preamble_size)
99 			return VB2_ERROR_API_KPHASE1_PREAMBLE;
100 
101 		pre = (struct vb2_fw_preamble *)
102 			vb2_member_of(sd, sd->preamble_offset);
103 		packed_key = &pre->kernel_subkey;
104 	}
105 
106 	sd->kernel_key_offset = vb2_offset_of(sd, packed_key);
107 	sd->kernel_key_size = packed_key->key_offset + packed_key->key_size;
108 
109 	vb2_set_workbuf_used(ctx, vb2_offset_of(sd, wb.buf));
110 
111 	if (vb2api_is_developer_signed(ctx))
112 		VB2_DEBUG("This is developer-signed firmware.\n");
113 
114 	return VB2_SUCCESS;
115 }
116 
handle_battery_cutoff(struct vb2_context * ctx)117 static vb2_error_t handle_battery_cutoff(struct vb2_context *ctx)
118 {
119 	/*
120 	 * Check if we need to cut-off battery. This should be done after EC
121 	 * FW and auxfw are updated, and before the kernel is started.  This
122 	 * is to make sure all firmware is up-to-date before shipping (which
123 	 * is the typical use-case for cutoff).
124 	 */
125 	if (vb2_nv_get(ctx, VB2_NV_BATTERY_CUTOFF_REQUEST)) {
126 		VB2_DEBUG("Request to cut-off battery\n");
127 		vb2_nv_set(ctx, VB2_NV_BATTERY_CUTOFF_REQUEST, 0);
128 
129 		/* May lose power immediately, so commit our update now. */
130 		VB2_TRY(vb2ex_commit_data(ctx));
131 
132 		vb2ex_ec_battery_cutoff();
133 		return VB2_REQUEST_SHUTDOWN;
134 	}
135 
136 	return VB2_SUCCESS;
137 }
138 
vb2api_kernel_phase2(struct vb2_context * ctx)139 vb2_error_t vb2api_kernel_phase2(struct vb2_context *ctx)
140 {
141 	struct vb2_shared_data *sd = vb2_get_sd(ctx);
142 	vb2_gbb_flags_t gbb_flags = vb2api_gbb_get_flags(ctx);
143 
144 	VB2_DEBUG("GBB flags are %#x\n", gbb_flags);
145 
146 	/*
147 	 * Do EC and auxfw software sync unless we're in recovery mode. This
148 	 * has UI but it's just a single non-interactive WAIT screen.
149 	 */
150 	if (!(ctx->flags & VB2_CONTEXT_RECOVERY_MODE)) {
151 		VB2_TRY(vb2api_ec_sync(ctx));
152 		VB2_TRY(vb2api_auxfw_sync(ctx));
153 		VB2_TRY(handle_battery_cutoff(ctx));
154 	}
155 
156 	/*
157 	 * If in the broken screen, save the recovery reason as subcode.
158 	 * Otherwise, clear any leftover recovery requests or subcodes.
159 	 */
160 	vb2api_clear_recovery(ctx);
161 
162 	/*
163 	 * Clear the diagnostic request flag and commit nvdata to prevent
164 	 * booting back into diagnostic mode when a forced system reset occurs.
165 	 */
166 	if (vb2_nv_get(ctx, VB2_NV_DIAG_REQUEST)) {
167 		vb2_nv_set(ctx, VB2_NV_DIAG_REQUEST, 0);
168 		/*
169 		 * According to current FAFT design (firmware_MiniDiag), we
170 		 * need an AP reset after MiniDiag test items to preserve the
171 		 * CBMEM console logs. So we need to commit nvdata immediately
172 		 * to prevent booting back to VB2_BOOT_MODE_DIAGNOSTICS.
173 		 */
174 		vb2ex_commit_data(ctx);
175 	}
176 
177 	/* Select boot path */
178 	switch (ctx->boot_mode) {
179 	case VB2_BOOT_MODE_MANUAL_RECOVERY:
180 	case VB2_BOOT_MODE_BROKEN_SCREEN:
181 		/* If we're in recovery mode just to do memory retraining, all
182 		   we need to do is reboot. */
183 		if (sd->recovery_reason == VB2_RECOVERY_TRAIN_AND_REBOOT) {
184 			VB2_DEBUG("Reboot after retraining in recovery\n");
185 			return VB2_REQUEST_REBOOT;
186 		}
187 
188 		/*
189 		 * Need to commit nvdata changes immediately, since we will be
190 		 * entering either manual recovery UI or BROKEN screen shortly.
191 		 */
192 		vb2ex_commit_data(ctx);
193 		break;
194 	case VB2_BOOT_MODE_DIAGNOSTICS:
195 	case VB2_BOOT_MODE_DEVELOPER:
196 		break;
197 	case VB2_BOOT_MODE_NORMAL:
198 		if (vb2_nv_get(ctx, VB2_NV_DISPLAY_REQUEST)) {
199 			vb2_nv_set(ctx, VB2_NV_DISPLAY_REQUEST, 0);
200 			VB2_DEBUG("Normal mode: "
201 				  "reboot to unset display request\n");
202 			return VB2_REQUEST_REBOOT;
203 		}
204 		break;
205 	default:
206 		return VB2_ERROR_ESCAPE_NO_BOOT;
207 	}
208 
209 	return VB2_SUCCESS;
210 }
211 
update_kernel_version(struct vb2_context * ctx)212 static void update_kernel_version(struct vb2_context *ctx)
213 {
214 	struct vb2_shared_data *sd = vb2_get_sd(ctx);
215 	uint32_t max_rollforward =
216 		vb2_nv_get(ctx, VB2_NV_KERNEL_MAX_ROLLFORWARD);
217 
218 	VB2_DEBUG("Checking if TPM kernel version needs advancing\n");
219 
220 	/*
221 	 * Special case for when we're trying a slot with new firmware.
222 	 * Firmware updates also usually change the kernel key, which means
223 	 * that the new firmware can only boot a new kernel, and the old
224 	 * firmware in the previous slot can only boot the previous kernel.
225 	 *
226 	 * Don't roll-forward the kernel version, because we don't yet know if
227 	 * the new kernel will successfully boot.
228 	 */
229 	if (vb2_nv_get(ctx, VB2_NV_FW_RESULT) == VB2_FW_RESULT_TRYING) {
230 		VB2_DEBUG("Trying new FW; "
231 			  "skip kernel version roll-forward.\n");
232 		return;
233 	}
234 
235 	/*
236 	 * Limit kernel version rollforward if needed.  Can't limit kernel
237 	 * version to less than the version currently in the TPM.  That is,
238 	 * we're limiting rollforward, not allowing rollback.
239 	 */
240 	uint32_t original_kernel_version =
241 		vb2_secdata_kernel_get(ctx, VB2_SECDATA_KERNEL_VERSIONS);
242 
243 	if (max_rollforward < original_kernel_version)
244 		max_rollforward = original_kernel_version;
245 
246 	if (sd->kernel_version_secdata > max_rollforward) {
247 		VB2_DEBUG("Limiting TPM kernel version roll-forward "
248 			  "to %#x < %#x\n",
249 			  max_rollforward, sd->kernel_version_secdata);
250 
251 		sd->kernel_version_secdata = max_rollforward;
252 	}
253 
254 	if (sd->kernel_version_secdata > original_kernel_version) {
255 		vb2_secdata_kernel_set(ctx, VB2_SECDATA_KERNEL_VERSIONS,
256 				       sd->kernel_version_secdata);
257 	} else {
258 		sd->kernel_version_secdata = original_kernel_version;
259 	}
260 }
261 
vb2api_kernel_finalize(struct vb2_context * ctx)262 vb2_error_t vb2api_kernel_finalize(struct vb2_context *ctx)
263 {
264 	vb2_gbb_flags_t gbb_flags = vb2api_gbb_get_flags(ctx);
265 
266 	/*
267 	 * Disallow booting to kernel when NO_BOOT flag is set, except when
268 	 * GBB flag disables software sync.
269 	 */
270 	if (!(gbb_flags & VB2_GBB_FLAG_DISABLE_EC_SOFTWARE_SYNC)
271 	    && (ctx->flags & VB2_CONTEXT_EC_SYNC_SUPPORTED)
272 	    && (ctx->flags & VB2_CONTEXT_NO_BOOT)) {
273 		VB2_DEBUG("Blocking escape from NO_BOOT mode.\n");
274 		vb2api_fail(ctx, VB2_RECOVERY_ESCAPE_NO_BOOT, 0);
275 		return VB2_ERROR_ESCAPE_NO_BOOT;
276 	}
277 
278 	if (ctx->boot_mode == VB2_BOOT_MODE_NORMAL)
279 		update_kernel_version(ctx);
280 
281 	return VB2_SUCCESS;
282 }
283