• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2012 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 
6 #include <ctype.h>
7 #include <fcntl.h>
8 #include <stddef.h>
9 #include <stdio.h>
10 #include <string.h>
11 #include <sys/file.h>
12 #include <unistd.h>
13 
14 #include "2api.h"
15 #include "2common.h"
16 #include "2nvstorage.h"
17 #include "2sysincludes.h"
18 #include "chromeos_config.h"
19 #include "crossystem_arch.h"
20 #include "crossystem.h"
21 #include "crossystem_vbnv.h"
22 #include "host_common.h"
23 #include "flashrom.h"
24 #include "subprocess.h"
25 #include "vboot_struct.h"
26 
27 /* Filename for crossystem lock */
28 #define CROSSYSTEM_LOCK_PATH (CROSSYSTEM_LOCK_DIR "/crossystem.lock")
29 
30 /* Filename for kernel command line */
31 #define KERNEL_CMDLINE_PATH "/proc/cmdline"
32 
33 /* Filename for the tpm_clear_request executable. */
34 #define TPM_CLEAR_REQUEST_EXEC_NAME "/usr/sbin/tpm_clear_request"
35 
36 /* Fields that GetVdatString() can get */
37 typedef enum VdatStringField {
38 	VDAT_STRING_DEPRECATED_TIMERS = 0,  /* Timer values */
39 	VDAT_STRING_LOAD_FIRMWARE_DEBUG,  /* LoadFirmware() debug info */
40 	VDAT_STRING_DEPRECATED_LOAD_KERNEL_DEBUG,  /* vb2api_load_kernel()
41 						      debug info */
42 	VDAT_STRING_MAINFW_ACT  /* Active main firmware */
43 } VdatStringField;
44 
45 
46 /* Fields that GetVdatInt() can get */
47 typedef enum VdatIntField {
48 	VDAT_INT_FLAGS = 0,           /* Flags */
49 	VDAT_INT_HEADER_VERSION,      /* Header version for VbSharedData */
50 	VDAT_INT_DEVSW_BOOT,          /* Dev switch position at boot */
51 	VDAT_INT_RECSW_BOOT,          /* Recovery switch position at boot */
52 	VDAT_INT_HW_WPSW_BOOT,        /* Hardware WP switch position at boot */
53 
54 	VDAT_INT_FW_VERSION_TPM,      /* Current firmware version in TPM */
55 	VDAT_INT_KERNEL_VERSION_TPM,  /* Current kernel version in TPM */
56 	VDAT_INT_KERNEL_KEY_VERIFIED, /* Kernel key verified using
57 				       * signature, not just hash */
58 	VDAT_INT_RECOVERY_REASON,     /* Recovery reason for current boot */
59 	VDAT_INT_FW_BOOT2,            /* Firmware selection by vboot2 */
60 	VDAT_INT_FW_VERSION_ACT,      /* Current active firmware version */
61 	VDAT_INT_KERNEL_VERSION_ACT,  /* Current active kernel version */
62 } VdatIntField;
63 
64 
65 /* Description of build options that may be specified on the
66  * kernel command line. */
67 typedef enum VbBuildOption {
68 	VB_BUILD_OPTION_UNKNOWN,
69 	VB_BUILD_OPTION_DEBUG,
70 	VB_BUILD_OPTION_NODEBUG
71 } VbBuildOption;
72 
73 static const char *fw_results[] = {"unknown", "trying", "success", "failure"};
74 static const char *default_boot[] = {"disk", "usb", "altfw"};
75 
76 /* Masks for kern_nv usage by kernel. */
77 #define KERN_NV_FWUPDATE_TRIES_MASK 0x000F
78 #define KERN_NV_BLOCK_DEVMODE_FLAG  0x0010
79 #define KERN_NV_TPM_ATTACK_FLAG     0x0020
80 /* If you want to use the remaining currently-unused bits in kern_nv
81  * for something kernel-y, define a new field (the way we did for
82  * fwupdate_tries).  Don't just modify kern_nv directly, because that
83  * makes it too easy to accidentally corrupt other sub-fields. */
84 #define KERN_NV_CURRENTLY_UNUSED    0xFFC0
85 
86 /* Return true if the FWID starts with the specified string. */
FwidStartsWith(const char * start)87 int FwidStartsWith(const char *start)
88 {
89 	char fwid[VB_MAX_STRING_PROPERTY];
90 	if (VbGetSystemPropertyString("fwid", fwid, sizeof(fwid)) != 0)
91 		return 0;
92 
93 	return 0 == strncmp(fwid, start, strlen(start));
94 }
95 
96 /* Acquire the lock for crossystem SetSystemProperty call. */
AcquireCrossystemLock(void)97 static int AcquireCrossystemLock(void)
98 {
99 	int lock_fd;
100 
101 	lock_fd = open(CROSSYSTEM_LOCK_PATH, O_RDWR | O_CREAT, 0600);
102 	if (lock_fd < 0)
103 		return -1;
104 
105 	if (flock(lock_fd, LOCK_EX) < 0)
106 		return -1;
107 
108 	return lock_fd;
109 }
110 
111 /* Release the lock for crossystem SetSystemProperty call. */
ReleaseCrossystemLock(int lock_fd)112 static int ReleaseCrossystemLock(int lock_fd)
113 {
114 	if (flock(lock_fd, F_UNLCK) < 0)
115 		return -1;
116 
117 	close(lock_fd);
118 
119 	return 0;
120 }
121 
122 /* Check if system FW type is equivalent to a given name */
CheckFwType(const char * name)123 static bool CheckFwType(const char *name)
124 {
125 	char fwtype_buf[VB_MAX_STRING_PROPERTY];
126 	int fwtype_ret;
127 
128 	fwtype_ret = VbGetSystemPropertyString("mainfw_type",
129 		fwtype_buf, sizeof(fwtype_buf));
130 
131 	if (fwtype_ret == 0 && !strcasecmp(fwtype_buf, name))
132 		return true;
133 
134 	return false;
135 }
136 
get_fake_context(void)137 static struct vb2_context *get_fake_context(void)
138 {
139 	static uint8_t fake_workbuf[sizeof(struct vb2_shared_data) + 16]
140 		__attribute__((aligned(VB2_WORKBUF_ALIGN)));
141 	static struct vb2_context *fake_ctx;
142 
143 	if (fake_ctx)
144 		return fake_ctx;
145 
146 	vb2api_init(fake_workbuf, sizeof(fake_workbuf), &fake_ctx);
147 
148 	return fake_ctx;
149 }
150 
151 static int vnc_read;
152 
vb2_get_nv_storage(enum vb2_nv_param param)153 int vb2_get_nv_storage(enum vb2_nv_param param)
154 {
155 	VbSharedDataHeader* sh = VbSharedDataRead();
156 	struct vb2_context *ctx = get_fake_context();
157 
158 	if (!sh)
159 		return -1;
160 
161 	/* TODO: locking around NV access */
162 	if (!vnc_read) {
163 		if (sh && sh->flags & VBSD_NVDATA_V2)
164 			ctx->flags |= VB2_CONTEXT_NVDATA_V2;
165 		if (0 != vb2_read_nv_storage(ctx)) {
166 			free(sh);
167 			return -1;
168 		}
169 		vb2_nv_init(ctx);
170 
171 		/* TODO: If vnc.raw_changed, attempt to reopen NVRAM for write
172 		 * and save the new defaults.  If we're able to, log. */
173 
174 		vnc_read = 1;
175 	}
176 
177 	free(sh);
178 	return (int)vb2_nv_get(ctx, param);
179 }
180 
vb2_set_nv_storage(enum vb2_nv_param param,int value)181 int vb2_set_nv_storage(enum vb2_nv_param param, int value)
182 {
183 	VbSharedDataHeader* sh = VbSharedDataRead();
184 	struct vb2_context *ctx = get_fake_context();
185 
186 	if (!sh)
187 		return -1;
188 
189 	/* TODO: locking around NV access */
190 	if (sh && sh->flags & VBSD_NVDATA_V2)
191 		ctx->flags |= VB2_CONTEXT_NVDATA_V2;
192 	if (0 != vb2_read_nv_storage(ctx)) {
193 		free(sh);
194 		return -1;
195 	}
196 	vb2_nv_init(ctx);
197 	vb2_nv_set(ctx, param, (uint32_t)value);
198 
199 	if (ctx->flags & VB2_CONTEXT_NVDATA_CHANGED) {
200 		vnc_read = 0;
201 		if (0 != vb2_write_nv_storage(ctx)) {
202 			free(sh);
203 			return -1;
204 		}
205 		ctx->flags &= ~VB2_CONTEXT_NVDATA_CHANGED;
206 	}
207 
208 	/* Success */
209 	free(sh);
210 	return 0;
211 }
212 
213 /*
214  * Set a param value, and try to flag it for persistent backup.  It's okay if
215  * backup isn't supported (which it isn't, in current designs). It's
216  * best-effort only.
217  */
vb2_set_nv_storage_with_backup(enum vb2_nv_param param,int value)218 static int vb2_set_nv_storage_with_backup(enum vb2_nv_param param, int value)
219 {
220 	int retval;
221 	retval = vb2_set_nv_storage(param, value);
222 	if (!retval)
223 		vb2_set_nv_storage(VB2_NV_BACKUP_NVRAM_REQUEST, 1);
224 	return retval;
225 }
226 
227 /* Find what build/debug status is specified on the kernel command
228  * line, if any. */
VbScanBuildOption(void)229 static VbBuildOption VbScanBuildOption(void)
230 {
231 	FILE* f = NULL;
232 	char buf[4096] = "";
233 	char *t, *saveptr;
234 	const char *delimiters = " \r\n";
235 
236 	f = fopen(KERNEL_CMDLINE_PATH, "r");
237 	if (NULL != f) {
238 		if (NULL == fgets(buf, sizeof(buf), f))
239 			buf[0] = 0;
240 		fclose(f);
241 	}
242 	for (t = strtok_r(buf, delimiters, &saveptr); t;
243 	     t = strtok_r(NULL, delimiters, &saveptr)) {
244 		if (0 == strcmp(t, "cros_debug"))
245 			return VB_BUILD_OPTION_DEBUG;
246 		else if (0 == strcmp(t, "cros_nodebug"))
247 			return VB_BUILD_OPTION_NODEBUG;
248 	}
249 
250 	return VB_BUILD_OPTION_UNKNOWN;
251 }
252 
253 /* Determine whether the running OS image was built for debugging.
254  * Returns 1 if yes, 0 if no or indeterminate. */
VbGetDebugBuild(void)255 static vb2_error_t VbGetDebugBuild(void)
256 {
257 	return VB_BUILD_OPTION_DEBUG == VbScanBuildOption();
258 }
259 
260 /* Determine whether OS-level debugging should be allowed.
261  * Returns 1 if yes, 0 if no or indeterminate. */
VbGetCrosDebug(void)262 static int VbGetCrosDebug(void)
263 {
264 	/* If the currently running system specifies its debug status, use
265 	 * that in preference to other indicators. */
266 	VbBuildOption option = VbScanBuildOption();
267 	if (VB_BUILD_OPTION_DEBUG == option) {
268 		return 1;
269 	} else if (VB_BUILD_OPTION_NODEBUG == option) {
270 		return 0;
271 	}
272 
273 	/* Command line is silent; allow debug if this was a developer boot.
274 	 * NOTE: This should intentionally never be true in recovery mode,
275 	 * since the recovery initramfs is supposed to remain trusted even when
276 	 * the developer switch is on. */
277 	if (CheckFwType("developer"))
278 		return 1;
279 
280 	/* All other cases disallow debug. */
281 	return 0;
282 }
283 
GetVdatLoadFirmwareDebug(char * dest,int size,const VbSharedDataHeader * sh)284 static int GetVdatLoadFirmwareDebug(char *dest, int size,
285 				    const VbSharedDataHeader *sh)
286 {
287 	snprintf(dest, size,
288 		 "Check A result=%d\n"
289 		 "Check B result=%d\n"
290 		 "Firmware index booted=0x%02x\n"
291 		 "Active firmware version=0x%08x\n"
292 		 "Firmware version in TPM =0x%08x\n"
293 		 "Lowest combined version from firmware=0x%08x\n",
294 		 sh->check_fw_a_result,
295 		 sh->check_fw_b_result,
296 		 sh->firmware_index,
297 		 sh->fw_version_act,
298 		 sh->fw_version_tpm,
299 		 sh->fw_version_lowest);
300 	return 0;
301 }
302 
GetVdatString(char * dest,int size,VdatStringField field)303 static int GetVdatString(char *dest, int size, VdatStringField field)
304 {
305 	VbSharedDataHeader *sh = VbSharedDataRead();
306 	int value = 0;
307 
308 	if (!sh)
309 		return -1;
310 
311 	switch (field) {
312 		case VDAT_STRING_LOAD_FIRMWARE_DEBUG:
313 			value = GetVdatLoadFirmwareDebug(dest, size, sh);
314 			break;
315 
316 		case VDAT_STRING_MAINFW_ACT:
317 			switch(sh->firmware_index) {
318 				case 0:
319 					StrCopy(dest, "A", size);
320 					break;
321 				case 1:
322 					StrCopy(dest, "B", size);
323 					break;
324 				case 0xFF:
325 					StrCopy(dest, "recovery", size);
326 					break;
327 				default:
328 					value = -1;
329 			}
330 			break;
331 
332 		default:
333 			value = -1;
334 			break;
335 	}
336 
337 	free(sh);
338 	return value;
339 }
340 
FwidMajorVersion(void)341 static int FwidMajorVersion(void)
342 {
343 	char fwid[VB_MAX_STRING_PROPERTY];
344 	int version;
345 
346 	if (VbGetSystemPropertyString("fwid", fwid, sizeof(fwid)) != 0)
347 		return -1;
348 
349 	if (sscanf(fwid, "%*[^.].%d", &version) != 1 || version <= 0) {
350 		fprintf(stderr, "WARNING: Cannot parse major version from %s\n",
351 			fwid);
352 		return -1;
353 	}
354 
355 	return version;
356 }
357 
GetVdatInt(VdatIntField field)358 static int GetVdatInt(VdatIntField field)
359 {
360 	VbSharedDataHeader* sh = VbSharedDataRead();
361 	int value = -1;
362 
363 	if (!sh)
364 		return -1;
365 
366 	/* Fields supported in version 1 */
367 	switch (field) {
368 		case VDAT_INT_FLAGS:
369 			value = (int)sh->flags;
370 			break;
371 		case VDAT_INT_HEADER_VERSION:
372 			value = sh->struct_version;
373 			break;
374 		case VDAT_INT_KERNEL_KEY_VERIFIED:
375 			value = (sh->flags & VBSD_KERNEL_KEY_VERIFIED ? 1 : 0);
376 			break;
377 		case VDAT_INT_FW_VERSION_TPM:
378 			/* b/269204332#comment5: Before CL:2054270 and CL:2056343,
379 			   fw_version_tpm was always 0. */
380 			if (sh->struct_version <= 2 && FwidMajorVersion() < 12935)
381 				value = (int)sh->fw_version_act;
382 			else
383 				value = (int)sh->fw_version_tpm;
384 			break;
385 		case VDAT_INT_KERNEL_VERSION_TPM:
386 			value = (int)sh->kernel_version_tpm;
387 			break;
388 		case VDAT_INT_FW_BOOT2:
389 			value = (sh->flags & VBSD_BOOT_FIRMWARE_VBOOT2 ? 1 : 0);
390 			break;
391 		case VDAT_INT_FW_VERSION_ACT:
392 			value = (int)sh->fw_version_act;
393 			break;
394 		default:
395 			break;
396 	}
397 
398 	/* Fields added in struct version 2 */
399 	if (sh->struct_version >= 2) {
400 		switch(field) {
401 			case VDAT_INT_DEVSW_BOOT:
402 				value = (sh->flags &
403 					 VBSD_BOOT_DEV_SWITCH_ON ? 1 : 0);
404 				break;
405 			case VDAT_INT_RECSW_BOOT:
406 				value = (sh->flags &
407 					 VBSD_BOOT_REC_SWITCH_ON ? 1 : 0);
408 				break;
409 			case VDAT_INT_HW_WPSW_BOOT:
410 				value = (sh->flags &
411 					 VBSD_BOOT_FIRMWARE_WP_ENABLED ? 1 : 0);
412 				break;
413 			case VDAT_INT_RECOVERY_REASON:
414 				value = sh->recovery_reason;
415 				break;
416 			default:
417 				break;
418 		}
419 	}
420 
421 	/* Fields added in struct version 3 */
422 	if (sh->struct_version >= 3) {
423 		switch(field) {
424 			case VDAT_INT_KERNEL_VERSION_ACT:
425 				value = (int)sh->kernel_version_act;
426 				break;
427 			default:
428 				break;
429 		}
430 	}
431 
432 	free(sh);
433 	return value;
434 }
435 
436 /* Return version of VbSharedData struct or -1 if not found. */
VbSharedDataVersion(void)437 int VbSharedDataVersion(void)
438 {
439 	return GetVdatInt(VDAT_INT_HEADER_VERSION);
440 }
441 
VbGetSystemPropertyInt(const char * name)442 int VbGetSystemPropertyInt(const char *name)
443 {
444 	int value = -1;
445 
446 	/* Check architecture-dependent properties first */
447 	value = VbGetArchPropertyInt(name);
448 	if (-1 != value)
449 		return value;
450 
451 	/* NV storage values */
452 	else if (!strcasecmp(name,"kern_nv")) {
453 		value = vb2_get_nv_storage(VB2_NV_KERNEL_FIELD);
454 	} else if (!strcasecmp(name,"nvram_cleared")) {
455 		value = vb2_get_nv_storage(VB2_NV_KERNEL_SETTINGS_RESET);
456 	} else if (!strcasecmp(name,"recovery_request")) {
457 		value = vb2_get_nv_storage(VB2_NV_RECOVERY_REQUEST);
458 	} else if (!strcasecmp(name,"diagnostic_request")) {
459 		value = vb2_get_nv_storage(VB2_NV_DIAG_REQUEST);
460 	} else if (!strcasecmp(name,"dbg_reset")) {
461 		value = vb2_get_nv_storage(VB2_NV_DEBUG_RESET_MODE);
462 	} else if (!strcasecmp(name,"disable_dev_request")) {
463 		value = vb2_get_nv_storage(VB2_NV_DISABLE_DEV_REQUEST);
464 	} else if (!strcasecmp(name,"clear_tpm_owner_request")) {
465 		if (EXTERNAL_TPM_CLEAR_REQUEST && CheckFwType("nonchrome")) {
466 			const char *const argv[] = {
467 				TPM_CLEAR_REQUEST_EXEC_NAME,
468 				NULL,
469 			};
470 			value = subprocess_run(argv, &subprocess_null, &subprocess_null,
471 					       &subprocess_null);
472 		} else {
473 			value = vb2_get_nv_storage(VB2_NV_CLEAR_TPM_OWNER_REQUEST);
474 		}
475 	} else if (!strcasecmp(name,"clear_tpm_owner_done")) {
476 		value = vb2_get_nv_storage(VB2_NV_CLEAR_TPM_OWNER_DONE);
477 	} else if (!strcasecmp(name,"tpm_rebooted")) {
478 		value = vb2_get_nv_storage(VB2_NV_TPM_REQUESTED_REBOOT);
479 	} else if (!strcasecmp(name,"fw_try_count")) {
480 		value = vb2_get_nv_storage(VB2_NV_TRY_COUNT);
481 	} else if (!strcasecmp(name,"fw_vboot2")) {
482 		value = GetVdatInt(VDAT_INT_FW_BOOT2);
483 	} else if (!strcasecmp(name,"fwupdate_tries")) {
484 		value = vb2_get_nv_storage(VB2_NV_KERNEL_FIELD);
485 		if (value != -1)
486 			value &= KERN_NV_FWUPDATE_TRIES_MASK;
487 	} else if (!strcasecmp(name,"block_devmode")) {
488 		value = vb2_get_nv_storage(VB2_NV_KERNEL_FIELD);
489 		if (value != -1) {
490 			value &= KERN_NV_BLOCK_DEVMODE_FLAG;
491 			value = !!value;
492 		}
493 	} else if (!strcasecmp(name,"tpm_attack")) {
494 		value = vb2_get_nv_storage(VB2_NV_KERNEL_FIELD);
495 		if (value != -1) {
496 			value &= KERN_NV_TPM_ATTACK_FLAG;
497 			value = !!value;
498 		}
499 	} else if (!strcasecmp(name,"loc_idx")) {
500 		value = vb2_get_nv_storage(VB2_NV_LOCALIZATION_INDEX);
501 	} else if (!strcasecmp(name,"backup_nvram_request")) {
502 		value = vb2_get_nv_storage(VB2_NV_BACKUP_NVRAM_REQUEST);
503 	} else if (!strcasecmp(name,"dev_boot_usb")) {
504 		value = vb2_get_nv_storage(VB2_NV_DEV_BOOT_EXTERNAL);
505 	} else if (!strcasecmp(name,"dev_boot_altfw") ||
506 		   !strcasecmp(name,"dev_boot_legacy")) {
507 		value = vb2_get_nv_storage(VB2_NV_DEV_BOOT_ALTFW);
508 	} else if (!strcasecmp(name,"dev_boot_signed_only")) {
509 		value = vb2_get_nv_storage(VB2_NV_DEV_BOOT_SIGNED_ONLY);
510 	} else if (!strcasecmp(name,"dev_enable_udc")) {
511 		value = vb2_get_nv_storage(VB2_NV_DEV_ENABLE_UDC);
512 	} else if (!strcasecmp(name,"display_request")) {
513 		value = vb2_get_nv_storage(VB2_NV_DISPLAY_REQUEST);
514 	} else if (!strcasecmp(name,"recovery_subcode")) {
515 		value = vb2_get_nv_storage(VB2_NV_RECOVERY_SUBCODE);
516 	} else if (!strcasecmp(name,"wipeout_request")) {
517 		value = vb2_get_nv_storage(VB2_NV_REQ_WIPEOUT);
518 	} else if (!strcasecmp(name,"kernel_max_rollforward")) {
519 		value = vb2_get_nv_storage(VB2_NV_KERNEL_MAX_ROLLFORWARD);
520 	}
521 	/* Other parameters */
522 	else if (!strcasecmp(name,"cros_debug")) {
523 		value = VbGetCrosDebug();
524 	} else if (!strcasecmp(name,"debug_build")) {
525 		value = VbGetDebugBuild();
526 	} else if (!strcasecmp(name,"devsw_boot")) {
527 		value = GetVdatInt(VDAT_INT_DEVSW_BOOT);
528 	} else if (!strcasecmp(name, "recoverysw_boot")) {
529 		value = GetVdatInt(VDAT_INT_RECSW_BOOT);
530 	} else if (!strcasecmp(name, "wpsw_cur")) {
531 		/* Use "write-protect at boot" as a fallback value. */
532 		value = GetVdatInt(VDAT_INT_HW_WPSW_BOOT);
533 		fprintf(stderr,
534 			"Fallback to WPSW_BOOT (%d), which may be invalid\n",
535 			value);
536 	} else if (!strcasecmp(name,"vdat_flags")) {
537 		value = GetVdatInt(VDAT_INT_FLAGS);
538 	} else if (!strcasecmp(name,"tpm_fwver")) {
539 		value = GetVdatInt(VDAT_INT_FW_VERSION_TPM);
540 	} else if (!strcasecmp(name,"tpm_kernver")) {
541 		value = GetVdatInt(VDAT_INT_KERNEL_VERSION_TPM);
542 	} else if (!strcasecmp(name,"act_fwver")) {
543 		value = GetVdatInt(VDAT_INT_FW_VERSION_ACT);
544 	} else if (!strcasecmp(name,"act_kernver")) {
545 		value = GetVdatInt(VDAT_INT_KERNEL_VERSION_ACT);
546 	} else if (!strcasecmp(name,"recovery_reason")) {
547 		value = GetVdatInt(VDAT_INT_RECOVERY_REASON);
548 	} else if (!strcasecmp(name, "boot_on_ac_detect")) {
549 		value = vb2_get_nv_storage(VB2_NV_BOOT_ON_AC_DETECT);
550 	} else if (!strcasecmp(name, "try_ro_sync")) {
551 		value = vb2_get_nv_storage(VB2_NV_TRY_RO_SYNC);
552 	} else if (!strcasecmp(name, "battery_cutoff_request")) {
553 		value = vb2_get_nv_storage(VB2_NV_BATTERY_CUTOFF_REQUEST);
554 	} else if (!strcasecmp(name, "inside_vm")) {
555 		/* Detect if the host is a VM. If there is no HWID and the
556 		 * firmware type is "nonchrome", then assume it is a VM. If
557 		 * HWID is present, it is a baremetal Chrome OS machine. Other
558 		 * cases are errors. */
559 		char hwid[VB_MAX_STRING_PROPERTY];
560 		if (VbGetSystemPropertyString("hwid", hwid,
561 					      sizeof(hwid)) != 0) {
562 			char fwtype_buf[VB_MAX_STRING_PROPERTY];
563 			int fwtype_ret = VbGetSystemPropertyString(
564 				"mainfw_type", fwtype_buf, sizeof(fwtype_buf));
565 			if (fwtype_ret == 0 &&
566 			    !strcasecmp(fwtype_buf, "nonchrome")) {
567 				value = 1;
568 			}
569 		} else {
570 			value = 0;
571 		}
572 	} else if (!strcasecmp(name, "post_ec_sync_delay")) {
573 		value = vb2_get_nv_storage(VB2_NV_POST_EC_SYNC_DELAY);
574 	}
575 
576 	return value;
577 }
578 
VbGetSystemPropertyString(const char * name,char * dest,size_t size)579 int VbGetSystemPropertyString(const char *name, char *dest, size_t size)
580 {
581 	if (dest == NULL || size == 0)
582 	{
583 		fprintf(stderr, "invalid dest buffer\n");
584 		return -1;
585 	}
586 	/* Check for HWID override via cros_config */
587 	if (!strcasecmp(name, "hwid")) {
588 		char *hwid_override;
589 
590 		if (chromeos_config_get_string("/", "hwid-override",
591 					       &hwid_override) == VB2_SUCCESS) {
592 			StrCopy(dest, hwid_override, size);
593 			free(hwid_override);
594 			return 0;
595 		}
596 	}
597 
598 	/* Check architecture-dependent properties */
599 	if (VbGetArchPropertyString(name, dest, size))
600 		return 0;
601 
602 	if (!strcasecmp(name,"kernkey_vfy")) {
603 		switch(GetVdatInt(VDAT_INT_KERNEL_KEY_VERIFIED)) {
604 			case 0:
605 				StrCopy(dest, "hash", size);
606 				return 0;
607 			case 1:
608 				StrCopy(dest, "sig", size);
609 				return 0;
610 			default:
611 				return -1;
612 		}
613 	} else if (!strcasecmp(name, "mainfw_act")) {
614 		return GetVdatString(dest, size, VDAT_STRING_MAINFW_ACT);
615 	} else if (!strcasecmp(name, "vdat_lfdebug")) {
616 		return GetVdatString(dest, size,
617 				VDAT_STRING_LOAD_FIRMWARE_DEBUG);
618 	} else if (!strcasecmp(name, "fw_try_next")) {
619 		StrCopy(dest,
620 			vb2_get_nv_storage(VB2_NV_TRY_NEXT) ? "B" : "A",
621 			size);
622 		return 0;
623 	} else if (!strcasecmp(name, "fw_tried")) {
624 		StrCopy(dest,
625 			vb2_get_nv_storage(VB2_NV_FW_TRIED) ? "B" : "A",
626 			size);
627 		return 0;
628 	} else if (!strcasecmp(name, "fw_result")) {
629 		int v = vb2_get_nv_storage(VB2_NV_FW_RESULT);
630 		if (v < ARRAY_SIZE(fw_results))
631 			StrCopy(dest, fw_results[v], size);
632 		else
633 			StrCopy(dest, "unknown", size);
634 		return 0;
635 	} else if (!strcasecmp(name, "fw_prev_tried")) {
636 		StrCopy(dest,
637 			vb2_get_nv_storage(VB2_NV_FW_PREV_TRIED) ? "B" : "A",
638 			size);
639 		return 0;
640 	} else if (!strcasecmp(name, "fw_prev_result")) {
641 		int v = vb2_get_nv_storage(VB2_NV_FW_PREV_RESULT);
642 		if (v < ARRAY_SIZE(fw_results))
643 			StrCopy(dest, fw_results[v], size);
644 		else
645 			StrCopy(dest, "unknown", size);
646 		return 0;
647 	} else if (!strcasecmp(name,"dev_default_boot")) {
648 		int v = vb2_get_nv_storage(VB2_NV_DEV_DEFAULT_BOOT);
649 		if (v < ARRAY_SIZE(default_boot))
650 			StrCopy(dest, default_boot[v], size);
651 		else
652 			StrCopy(dest, "unknown", size);
653 		return 0;
654 	} else if (!strcasecmp(name, "minios_priority")) {
655 		StrCopy(dest,
656 			vb2_get_nv_storage(VB2_NV_MINIOS_PRIORITY) ?"B" : "A",
657 			size);
658 		return 0;
659 	}
660 
661 	return -1;
662 }
663 
VbSetSystemPropertyIntInternal(const char * name,int value)664 static int VbSetSystemPropertyIntInternal(const char *name, int value)
665 {
666 	/* Check architecture-dependent properties first */
667 
668 	if (0 == VbSetArchPropertyInt(name, value))
669 		return 0;
670 
671 	/* NV storage values */
672 	if (!strcasecmp(name,"nvram_cleared")) {
673 		/* Can only clear this flag; it's set inside the NV storage
674 		 * library. */
675 		return vb2_set_nv_storage(VB2_NV_KERNEL_SETTINGS_RESET, 0);
676 	} else if (!strcasecmp(name,"recovery_request")) {
677 		return vb2_set_nv_storage(VB2_NV_RECOVERY_REQUEST, value);
678 	} else if (!strcasecmp(name,"diagnostic_request")) {
679 		return vb2_set_nv_storage(VB2_NV_DIAG_REQUEST, value);
680 	} else if (!strcasecmp(name,"recovery_subcode")) {
681 		return vb2_set_nv_storage(VB2_NV_RECOVERY_SUBCODE, value);
682 	} else if (!strcasecmp(name,"dbg_reset")) {
683 		return vb2_set_nv_storage(VB2_NV_DEBUG_RESET_MODE, value);
684 	} else if (!strcasecmp(name,"disable_dev_request")) {
685 		return vb2_set_nv_storage(VB2_NV_DISABLE_DEV_REQUEST, value);
686 	} else if (!strcasecmp(name,"clear_tpm_owner_request")) {
687 		if (EXTERNAL_TPM_CLEAR_REQUEST && CheckFwType("nonchrome")) {
688 			const char *const argv[] = {
689 				TPM_CLEAR_REQUEST_EXEC_NAME,
690 				value ? "1" : "0",
691 				NULL,
692 			};
693 			return subprocess_run(argv, &subprocess_null, &subprocess_null,
694 					      &subprocess_null);
695 		} else {
696 			return vb2_set_nv_storage(
697 				VB2_NV_CLEAR_TPM_OWNER_REQUEST, value);
698 		}
699 	} else if (!strcasecmp(name,"clear_tpm_owner_done")) {
700 		/* Can only clear this flag; it's set by firmware. */
701 		return vb2_set_nv_storage(VB2_NV_CLEAR_TPM_OWNER_DONE, 0);
702 	} else if (!strcasecmp(name,"fw_try_count")) {
703 		return vb2_set_nv_storage(VB2_NV_TRY_COUNT, value);
704 	} else if (!strcasecmp(name,"display_request")) {
705 		return vb2_set_nv_storage(VB2_NV_DISPLAY_REQUEST, value);
706 	} else if (!strcasecmp(name,"wipeout_request")) {
707 		/* Can only clear this flag, set only by firmware. */
708 		return vb2_set_nv_storage(VB2_NV_REQ_WIPEOUT, 0);
709 	} else if (!strcasecmp(name,"backup_nvram_request")) {
710 		/* Best-effort only, since it requires firmware and TPM
711 		 * support. */
712 		return vb2_set_nv_storage(VB2_NV_BACKUP_NVRAM_REQUEST, value);
713 	} else if (!strcasecmp(name,"fwupdate_tries")) {
714 		int kern_nv = vb2_get_nv_storage(VB2_NV_KERNEL_FIELD);
715 		if (kern_nv == -1)
716 			return -1;
717 		kern_nv &= ~KERN_NV_FWUPDATE_TRIES_MASK;
718 		kern_nv |= (value & KERN_NV_FWUPDATE_TRIES_MASK);
719 		return vb2_set_nv_storage_with_backup(
720 			VB2_NV_KERNEL_FIELD, kern_nv);
721 	} else if (!strcasecmp(name,"block_devmode")) {
722 		int kern_nv = vb2_get_nv_storage(VB2_NV_KERNEL_FIELD);
723 		if (kern_nv == -1)
724 			return -1;
725 		kern_nv &= ~KERN_NV_BLOCK_DEVMODE_FLAG;
726 		if (value)
727 			kern_nv |= KERN_NV_BLOCK_DEVMODE_FLAG;
728 		return vb2_set_nv_storage_with_backup(
729 			VB2_NV_KERNEL_FIELD, kern_nv);
730 	} else if (!strcasecmp(name,"tpm_attack")) {
731 		/* This value should only be read and cleared, but we allow
732 		 * setting it to 1 for testing. */
733 		int kern_nv = vb2_get_nv_storage(VB2_NV_KERNEL_FIELD);
734 		if (kern_nv == -1)
735 			return -1;
736 		kern_nv &= ~KERN_NV_TPM_ATTACK_FLAG;
737 		if (value)
738 			kern_nv |= KERN_NV_TPM_ATTACK_FLAG;
739 		return vb2_set_nv_storage_with_backup(
740 			VB2_NV_KERNEL_FIELD, kern_nv);
741 	} else if (!strcasecmp(name,"loc_idx")) {
742 		return vb2_set_nv_storage_with_backup(
743 			VB2_NV_LOCALIZATION_INDEX, value);
744 	} else if (!strcasecmp(name,"dev_boot_usb")) {
745 		return vb2_set_nv_storage_with_backup(
746 			VB2_NV_DEV_BOOT_EXTERNAL, value);
747 	} else if (!strcasecmp(name,"dev_boot_altfw") ||
748 		   !strcasecmp(name,"dev_boot_legacy")) {
749 		return vb2_set_nv_storage_with_backup(
750 			VB2_NV_DEV_BOOT_ALTFW, value);
751 	} else if (!strcasecmp(name,"dev_boot_signed_only")) {
752 		return vb2_set_nv_storage_with_backup(
753 			VB2_NV_DEV_BOOT_SIGNED_ONLY, value);
754 	} else if (!strcasecmp(name, "dev_enable_udc")) {
755 		return vb2_set_nv_storage_with_backup(
756 			VB2_NV_DEV_ENABLE_UDC, value);
757 	} else if (!strcasecmp(name, "boot_on_ac_detect")) {
758 		return vb2_set_nv_storage_with_backup(
759 			VB2_NV_BOOT_ON_AC_DETECT, value);
760 	} else if (!strcasecmp(name, "try_ro_sync")) {
761 		return vb2_set_nv_storage_with_backup(
762 			VB2_NV_TRY_RO_SYNC, value);
763 	} else if (!strcasecmp(name, "battery_cutoff_request")) {
764 		return vb2_set_nv_storage(VB2_NV_BATTERY_CUTOFF_REQUEST, value);
765 	} else if (!strcasecmp(name,"kernel_max_rollforward")) {
766 		return vb2_set_nv_storage(VB2_NV_KERNEL_MAX_ROLLFORWARD, value);
767 	} else if (!strcasecmp(name, "post_ec_sync_delay")) {
768 		return vb2_set_nv_storage(VB2_NV_POST_EC_SYNC_DELAY, value);
769 	}
770 
771 	return -1;
772 }
773 
VbSetSystemPropertyInt(const char * name,int value)774 int VbSetSystemPropertyInt(const char *name, int value)
775 {
776 	int result = -1;
777 	int lock_fd;
778 
779 	lock_fd = AcquireCrossystemLock();
780 	if (lock_fd < 0)
781 		return -1;
782 
783 	result = VbSetSystemPropertyIntInternal(name, value);
784 
785 	if (ReleaseCrossystemLock(lock_fd) < 0)
786 		return -1;
787 
788 	return result;
789 }
790 
VbSetSystemPropertyStringInternal(const char * name,const char * value)791 static int VbSetSystemPropertyStringInternal(const char *name,
792 					     const char *value)
793 {
794 	/* Chain to architecture-dependent properties */
795 	if (0 == VbSetArchPropertyString(name, value))
796 		return 0;
797 
798 	if (!strcasecmp(name, "fw_try_next")) {
799 		if (!strcasecmp(value, "A"))
800 			return vb2_set_nv_storage(VB2_NV_TRY_NEXT, 0);
801 		else if (!strcasecmp(value, "B"))
802 			return vb2_set_nv_storage(VB2_NV_TRY_NEXT, 1);
803 		else
804 			return -1;
805 	} else if (!strcasecmp(name, "minios_priority")) {
806 		if (!strcasecmp(value, "A"))
807 			return vb2_set_nv_storage(VB2_NV_MINIOS_PRIORITY, 0);
808 		else if (!strcasecmp(value, "B"))
809 			return vb2_set_nv_storage(VB2_NV_MINIOS_PRIORITY, 1);
810 		else
811 			return -1;
812 	} else if (!strcasecmp(name, "fw_result")) {
813 		int i;
814 
815 		for (i = 0; i < ARRAY_SIZE(fw_results); i++) {
816 			if (!strcasecmp(value, fw_results[i]))
817 				return vb2_set_nv_storage(VB2_NV_FW_RESULT, i);
818 		}
819 		return -1;
820 	} else if (!strcasecmp(name, "dev_default_boot")) {
821 		int i;
822 
823 		/* "legacy" term deprecated in favour of "altfw"
824 		   (see: b/179458327) */
825 		if (!strcasecmp(value, "legacy")) {
826 			fprintf(stderr,
827 				"!!!\n"
828 				"!!! PLEASE USE 'altfw' INSTEAD OF 'legacy'\n"
829 				"!!!\n");
830 			value = "altfw";
831 		}
832 
833 		for (i = 0; i < ARRAY_SIZE(default_boot); i++) {
834 			if (!strcasecmp(value, default_boot[i]))
835 				return vb2_set_nv_storage(
836 					VB2_NV_DEV_DEFAULT_BOOT, i);
837 		}
838 		return -1;
839 	}
840 
841 	return -1;
842 }
843 
VbSetSystemPropertyString(const char * name,const char * value)844 int VbSetSystemPropertyString(const char *name, const char *value)
845 {
846 	int result = -1;
847 	int lock_fd;
848 
849 	lock_fd = AcquireCrossystemLock();
850 	if (lock_fd < 0)
851 		return -1;
852 
853 	result = VbSetSystemPropertyStringInternal(name, value);
854 
855 	if (ReleaseCrossystemLock(lock_fd) < 0)
856 		return -1;
857 
858 	return result;
859 }
860 
861 /**
862  * Get index of the last valid VBNV entry.
863  *
864  * @param buf		Pointer to the buffer containing VBNV entries.
865  * @param buf_sz	Size of the buffer.
866  * @param vbnv_size	The size of a single VBNV entry for this device.
867  *
868  * @return The index of the last valid VBNV entry found by binary search,
869  * or -1 if not found. When the FMAP region is corrupted (used entries occurring
870  * after blank ones), the returned index may not point to the last VBNV
871  * entry.
872  */
vb2_nv_index(const uint8_t * buf,uint32_t buf_sz,int vbnv_size)873 static int vb2_nv_index(const uint8_t *buf, uint32_t buf_sz, int vbnv_size)
874 {
875 	int used_below, blank_above;
876 	uint8_t blank[VB2_NVDATA_SIZE_V2];
877 
878 	/* The size of the buffer should be an even multiple of the
879 	   VBNV size. */
880 	if (buf_sz % vbnv_size != 0) {
881 		VB2_DIE("The VBNV in flash (%u bytes) is not an even multiple "
882 			"of the VBNV size (%u bytes).  This is likely a "
883 			"firmware bug.\n", buf_sz, vbnv_size);
884 	}
885 
886 	memset(blank, 0xff, sizeof(blank));
887 
888 	/* To match the searching algorithm in firmware, perform binary search
889 	   instead of linear search to find the last used index. */
890 	used_below = 0;
891 	blank_above = buf_sz / vbnv_size;
892 	while (used_below + 1 < blank_above) {
893 		int mid = (used_below + blank_above) / 2;
894 		if (!memcmp(blank, &buf[mid * vbnv_size], vbnv_size))
895 			blank_above = mid;
896 		else
897 			used_below = mid;
898 	}
899 
900 	/* Check the all blank case. */
901 	if (used_below == 0 &&
902 	    !memcmp(blank, &buf[used_below * vbnv_size], vbnv_size)) {
903 		fprintf(stderr, "VBNV is uninitialized.\n");
904 		return -1;
905 	}
906 
907 	return used_below;
908 }
909 
910 /**
911  * Check whether the VBNV entries are corrupted.
912  *
913  * @param buf		Pointer to the buffer containing VBNV entries.
914  * @param buf_sz	Size of the buffer.
915  * @param vbnv_size	The size of a single VBNV entry for this device.
916  *
917  * @return True if there are used entries occurring after blank ones, or false
918  * otherwise.
919  */
is_corrupted(const uint8_t * buf,uint32_t buf_sz,int vbnv_size)920 static bool is_corrupted(const uint8_t *buf, uint32_t buf_sz, int vbnv_size)
921 {
922 	uint8_t blank[VB2_NVDATA_SIZE_V2];
923 	bool found_blank = false;
924 
925 	memset(blank, 0xff, sizeof(blank));
926 
927 	for (int i = 0; i < buf_sz / vbnv_size; i++) {
928 		if (!memcmp(blank, &buf[i * vbnv_size], vbnv_size))
929 			found_blank = true;
930 		else if (found_blank)
931 			return true;
932 	}
933 
934 	return false;
935 }
936 
937 #define VBNV_FMAP_REGION "RW_NVRAM"
938 
vb2_read_nv_storage_flashrom(struct vb2_context * ctx)939 int vb2_read_nv_storage_flashrom(struct vb2_context *ctx)
940 {
941 	int index;
942 	int vbnv_size = vb2_nv_get_size(ctx);
943 
944 	struct firmware_image image = {
945 		.programmer = FLASHROM_PROGRAMMER_INTERNAL_AP,
946 	};
947 	if (flashrom_read(&image, VBNV_FMAP_REGION))
948 		return -1;
949 
950 	index = vb2_nv_index(image.data, image.size, vbnv_size);
951 	if (index < 0) {
952 		free(image.data);
953 		return -1;
954 	}
955 
956 	memcpy(ctx->nvdata, &image.data[index * vbnv_size], vbnv_size);
957 	free(image.data);
958 	return 0;
959 }
960 
vb2_write_nv_storage_flashrom(struct vb2_context * ctx)961 int vb2_write_nv_storage_flashrom(struct vb2_context *ctx)
962 {
963 	int rv = 0;
964 	int index;
965 	bool corrupted;
966 	int vbnv_size = vb2_nv_get_size(ctx);
967 
968 	struct firmware_image image = {
969 		.programmer = FLASHROM_PROGRAMMER_INTERNAL_AP,
970 	};
971 	if (flashrom_read(&image, VBNV_FMAP_REGION))
972 		return -1;
973 
974 	index = vb2_nv_index(image.data, image.size, vbnv_size) + 1;
975 	corrupted = is_corrupted(image.data, image.size, vbnv_size);
976 
977 	if (corrupted || index * vbnv_size == image.size) {
978 		/* VBNV is corrupted or full.  Erase and write at beginning. */
979 		if (corrupted)
980 			fprintf(stderr, "VBNV is corrupted; erasing %s\n",
981 				VBNV_FMAP_REGION);
982 		memset(image.data, 0xff, image.size);
983 		index = 0;
984 	}
985 
986 	memcpy(&image.data[index * vbnv_size], ctx->nvdata, vbnv_size);
987 	if (flashrom_write(&image, VBNV_FMAP_REGION)) {
988 		rv = -1;
989 		goto exit;
990 	}
991 
992  exit:
993 	free(image.data);
994 	return rv;
995 }
996