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