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 the dev switch is on. */
274 if (1 == VbGetSystemPropertyInt("devsw_boot"))
275 return 1;
276
277 /* All other cases disallow debug. */
278 return 0;
279 }
280
GetVdatLoadFirmwareDebug(char * dest,int size,const VbSharedDataHeader * sh)281 static int GetVdatLoadFirmwareDebug(char *dest, int size,
282 const VbSharedDataHeader *sh)
283 {
284 snprintf(dest, size,
285 "Check A result=%d\n"
286 "Check B result=%d\n"
287 "Firmware index booted=0x%02x\n"
288 "Active firmware version=0x%08x\n"
289 "Firmware version in TPM =0x%08x\n"
290 "Lowest combined version from firmware=0x%08x\n",
291 sh->check_fw_a_result,
292 sh->check_fw_b_result,
293 sh->firmware_index,
294 sh->fw_version_act,
295 sh->fw_version_tpm,
296 sh->fw_version_lowest);
297 return 0;
298 }
299
GetVdatString(char * dest,int size,VdatStringField field)300 static int GetVdatString(char *dest, int size, VdatStringField field)
301 {
302 VbSharedDataHeader *sh = VbSharedDataRead();
303 int value = 0;
304
305 if (!sh)
306 return -1;
307
308 switch (field) {
309 case VDAT_STRING_LOAD_FIRMWARE_DEBUG:
310 value = GetVdatLoadFirmwareDebug(dest, size, sh);
311 break;
312
313 case VDAT_STRING_MAINFW_ACT:
314 switch(sh->firmware_index) {
315 case 0:
316 StrCopy(dest, "A", size);
317 break;
318 case 1:
319 StrCopy(dest, "B", size);
320 break;
321 case 0xFF:
322 StrCopy(dest, "recovery", size);
323 break;
324 default:
325 value = -1;
326 }
327 break;
328
329 default:
330 value = -1;
331 break;
332 }
333
334 free(sh);
335 return value;
336 }
337
FwidMajorVersion(void)338 static int FwidMajorVersion(void)
339 {
340 char fwid[VB_MAX_STRING_PROPERTY];
341 int version;
342
343 if (VbGetSystemPropertyString("fwid", fwid, sizeof(fwid)) != 0)
344 return -1;
345
346 if (sscanf(fwid, "%*[^.].%d", &version) != 1 || version <= 0) {
347 fprintf(stderr, "WARNING: Cannot parse major version from %s\n",
348 fwid);
349 return -1;
350 }
351
352 return version;
353 }
354
GetVdatInt(VdatIntField field)355 static int GetVdatInt(VdatIntField field)
356 {
357 VbSharedDataHeader* sh = VbSharedDataRead();
358 int value = -1;
359
360 if (!sh)
361 return -1;
362
363 /* Fields supported in version 1 */
364 switch (field) {
365 case VDAT_INT_FLAGS:
366 value = (int)sh->flags;
367 break;
368 case VDAT_INT_HEADER_VERSION:
369 value = sh->struct_version;
370 break;
371 case VDAT_INT_KERNEL_KEY_VERIFIED:
372 value = (sh->flags & VBSD_KERNEL_KEY_VERIFIED ? 1 : 0);
373 break;
374 case VDAT_INT_FW_VERSION_TPM:
375 /* b/269204332#comment5: Before CL:2054270 and CL:2056343,
376 fw_version_tpm was always 0. */
377 if (sh->struct_version <= 2 && FwidMajorVersion() < 12935)
378 value = (int)sh->fw_version_act;
379 else
380 value = (int)sh->fw_version_tpm;
381 break;
382 case VDAT_INT_KERNEL_VERSION_TPM:
383 value = (int)sh->kernel_version_tpm;
384 break;
385 case VDAT_INT_FW_BOOT2:
386 value = (sh->flags & VBSD_BOOT_FIRMWARE_VBOOT2 ? 1 : 0);
387 break;
388 case VDAT_INT_FW_VERSION_ACT:
389 value = (int)sh->fw_version_act;
390 break;
391 default:
392 break;
393 }
394
395 /* Fields added in struct version 2 */
396 if (sh->struct_version >= 2) {
397 switch(field) {
398 case VDAT_INT_DEVSW_BOOT:
399 value = (sh->flags &
400 VBSD_BOOT_DEV_SWITCH_ON ? 1 : 0);
401 break;
402 case VDAT_INT_RECSW_BOOT:
403 value = (sh->flags &
404 VBSD_BOOT_REC_SWITCH_ON ? 1 : 0);
405 break;
406 case VDAT_INT_HW_WPSW_BOOT:
407 value = (sh->flags &
408 VBSD_BOOT_FIRMWARE_WP_ENABLED ? 1 : 0);
409 break;
410 case VDAT_INT_RECOVERY_REASON:
411 value = sh->recovery_reason;
412 break;
413 default:
414 break;
415 }
416 }
417
418 /* Fields added in struct version 3 */
419 if (sh->struct_version >= 3) {
420 switch(field) {
421 case VDAT_INT_KERNEL_VERSION_ACT:
422 value = (int)sh->kernel_version_act;
423 break;
424 default:
425 break;
426 }
427 }
428
429 free(sh);
430 return value;
431 }
432
433 /* Return version of VbSharedData struct or -1 if not found. */
VbSharedDataVersion(void)434 int VbSharedDataVersion(void)
435 {
436 return GetVdatInt(VDAT_INT_HEADER_VERSION);
437 }
438
VbGetSystemPropertyInt(const char * name)439 int VbGetSystemPropertyInt(const char *name)
440 {
441 int value = -1;
442
443 /* Check architecture-dependent properties first */
444 value = VbGetArchPropertyInt(name);
445 if (-1 != value)
446 return value;
447
448 /* NV storage values */
449 else if (!strcasecmp(name,"kern_nv")) {
450 value = vb2_get_nv_storage(VB2_NV_KERNEL_FIELD);
451 } else if (!strcasecmp(name,"nvram_cleared")) {
452 value = vb2_get_nv_storage(VB2_NV_KERNEL_SETTINGS_RESET);
453 } else if (!strcasecmp(name,"recovery_request")) {
454 value = vb2_get_nv_storage(VB2_NV_RECOVERY_REQUEST);
455 } else if (!strcasecmp(name,"diagnostic_request")) {
456 value = vb2_get_nv_storage(VB2_NV_DIAG_REQUEST);
457 } else if (!strcasecmp(name,"dbg_reset")) {
458 value = vb2_get_nv_storage(VB2_NV_DEBUG_RESET_MODE);
459 } else if (!strcasecmp(name,"disable_dev_request")) {
460 value = vb2_get_nv_storage(VB2_NV_DISABLE_DEV_REQUEST);
461 } else if (!strcasecmp(name,"clear_tpm_owner_request")) {
462 if (EXTERNAL_TPM_CLEAR_REQUEST && CheckFwType("nonchrome")) {
463 const char *const argv[] = {
464 TPM_CLEAR_REQUEST_EXEC_NAME,
465 NULL,
466 };
467 value = subprocess_run(argv, &subprocess_null, &subprocess_null,
468 &subprocess_null);
469 } else {
470 value = vb2_get_nv_storage(VB2_NV_CLEAR_TPM_OWNER_REQUEST);
471 }
472 } else if (!strcasecmp(name,"clear_tpm_owner_done")) {
473 value = vb2_get_nv_storage(VB2_NV_CLEAR_TPM_OWNER_DONE);
474 } else if (!strcasecmp(name,"tpm_rebooted")) {
475 value = vb2_get_nv_storage(VB2_NV_TPM_REQUESTED_REBOOT);
476 } else if (!strcasecmp(name,"fw_try_count")) {
477 value = vb2_get_nv_storage(VB2_NV_TRY_COUNT);
478 } else if (!strcasecmp(name,"fw_vboot2")) {
479 value = GetVdatInt(VDAT_INT_FW_BOOT2);
480 } else if (!strcasecmp(name,"fwupdate_tries")) {
481 value = vb2_get_nv_storage(VB2_NV_KERNEL_FIELD);
482 if (value != -1)
483 value &= KERN_NV_FWUPDATE_TRIES_MASK;
484 } else if (!strcasecmp(name,"block_devmode")) {
485 value = vb2_get_nv_storage(VB2_NV_KERNEL_FIELD);
486 if (value != -1) {
487 value &= KERN_NV_BLOCK_DEVMODE_FLAG;
488 value = !!value;
489 }
490 } else if (!strcasecmp(name,"tpm_attack")) {
491 value = vb2_get_nv_storage(VB2_NV_KERNEL_FIELD);
492 if (value != -1) {
493 value &= KERN_NV_TPM_ATTACK_FLAG;
494 value = !!value;
495 }
496 } else if (!strcasecmp(name,"loc_idx")) {
497 value = vb2_get_nv_storage(VB2_NV_LOCALIZATION_INDEX);
498 } else if (!strcasecmp(name,"backup_nvram_request")) {
499 value = vb2_get_nv_storage(VB2_NV_BACKUP_NVRAM_REQUEST);
500 } else if (!strcasecmp(name,"dev_boot_usb")) {
501 value = vb2_get_nv_storage(VB2_NV_DEV_BOOT_EXTERNAL);
502 } else if (!strcasecmp(name,"dev_boot_altfw") ||
503 !strcasecmp(name,"dev_boot_legacy")) {
504 value = vb2_get_nv_storage(VB2_NV_DEV_BOOT_ALTFW);
505 } else if (!strcasecmp(name,"dev_boot_signed_only")) {
506 value = vb2_get_nv_storage(VB2_NV_DEV_BOOT_SIGNED_ONLY);
507 } else if (!strcasecmp(name,"dev_enable_udc")) {
508 value = vb2_get_nv_storage(VB2_NV_DEV_ENABLE_UDC);
509 } else if (!strcasecmp(name,"display_request")) {
510 value = vb2_get_nv_storage(VB2_NV_DISPLAY_REQUEST);
511 } else if (!strcasecmp(name,"recovery_subcode")) {
512 value = vb2_get_nv_storage(VB2_NV_RECOVERY_SUBCODE);
513 } else if (!strcasecmp(name,"wipeout_request")) {
514 value = vb2_get_nv_storage(VB2_NV_REQ_WIPEOUT);
515 } else if (!strcasecmp(name,"kernel_max_rollforward")) {
516 value = vb2_get_nv_storage(VB2_NV_KERNEL_MAX_ROLLFORWARD);
517 }
518 /* Other parameters */
519 else if (!strcasecmp(name,"cros_debug")) {
520 value = VbGetCrosDebug();
521 } else if (!strcasecmp(name,"debug_build")) {
522 value = VbGetDebugBuild();
523 } else if (!strcasecmp(name,"devsw_boot")) {
524 value = GetVdatInt(VDAT_INT_DEVSW_BOOT);
525 } else if (!strcasecmp(name, "recoverysw_boot")) {
526 value = GetVdatInt(VDAT_INT_RECSW_BOOT);
527 } else if (!strcasecmp(name, "wpsw_cur")) {
528 /* Use "write-protect at boot" as a fallback value. */
529 value = GetVdatInt(VDAT_INT_HW_WPSW_BOOT);
530 fprintf(stderr,
531 "Fallback to WPSW_BOOT (%d), which may be invalid\n",
532 value);
533 } else if (!strcasecmp(name,"vdat_flags")) {
534 value = GetVdatInt(VDAT_INT_FLAGS);
535 } else if (!strcasecmp(name,"tpm_fwver")) {
536 value = GetVdatInt(VDAT_INT_FW_VERSION_TPM);
537 } else if (!strcasecmp(name,"tpm_kernver")) {
538 value = GetVdatInt(VDAT_INT_KERNEL_VERSION_TPM);
539 } else if (!strcasecmp(name,"act_fwver")) {
540 value = GetVdatInt(VDAT_INT_FW_VERSION_ACT);
541 } else if (!strcasecmp(name,"act_kernver")) {
542 value = GetVdatInt(VDAT_INT_KERNEL_VERSION_ACT);
543 } else if (!strcasecmp(name,"recovery_reason")) {
544 value = GetVdatInt(VDAT_INT_RECOVERY_REASON);
545 } else if (!strcasecmp(name, "boot_on_ac_detect")) {
546 value = vb2_get_nv_storage(VB2_NV_BOOT_ON_AC_DETECT);
547 } else if (!strcasecmp(name, "try_ro_sync")) {
548 value = vb2_get_nv_storage(VB2_NV_TRY_RO_SYNC);
549 } else if (!strcasecmp(name, "battery_cutoff_request")) {
550 value = vb2_get_nv_storage(VB2_NV_BATTERY_CUTOFF_REQUEST);
551 } else if (!strcasecmp(name, "inside_vm")) {
552 /* Detect if the host is a VM. If there is no HWID and the
553 * firmware type is "nonchrome", then assume it is a VM. If
554 * HWID is present, it is a baremetal Chrome OS machine. Other
555 * cases are errors. */
556 char hwid[VB_MAX_STRING_PROPERTY];
557 if (VbGetSystemPropertyString("hwid", hwid,
558 sizeof(hwid)) != 0) {
559 char fwtype_buf[VB_MAX_STRING_PROPERTY];
560 int fwtype_ret = VbGetSystemPropertyString(
561 "mainfw_type", fwtype_buf, sizeof(fwtype_buf));
562 if (fwtype_ret == 0 &&
563 !strcasecmp(fwtype_buf, "nonchrome")) {
564 value = 1;
565 }
566 } else {
567 value = 0;
568 }
569 } else if (!strcasecmp(name, "post_ec_sync_delay")) {
570 value = vb2_get_nv_storage(VB2_NV_POST_EC_SYNC_DELAY);
571 }
572
573 return value;
574 }
575
VbGetSystemPropertyString(const char * name,char * dest,size_t size)576 int VbGetSystemPropertyString(const char *name, char *dest, size_t size)
577 {
578 if (dest == NULL || size == 0)
579 {
580 fprintf(stderr, "invalid dest buffer\n");
581 return -1;
582 }
583 /* Check for HWID override via cros_config */
584 if (!strcasecmp(name, "hwid")) {
585 char *hwid_override;
586
587 if (chromeos_config_get_string("/", "hwid-override",
588 &hwid_override) == VB2_SUCCESS) {
589 StrCopy(dest, hwid_override, size);
590 free(hwid_override);
591 return 0;
592 }
593 }
594
595 /* Check architecture-dependent properties */
596 if (VbGetArchPropertyString(name, dest, size))
597 return 0;
598
599 if (!strcasecmp(name,"kernkey_vfy")) {
600 switch(GetVdatInt(VDAT_INT_KERNEL_KEY_VERIFIED)) {
601 case 0:
602 StrCopy(dest, "hash", size);
603 return 0;
604 case 1:
605 StrCopy(dest, "sig", size);
606 return 0;
607 default:
608 return -1;
609 }
610 } else if (!strcasecmp(name, "mainfw_act")) {
611 return GetVdatString(dest, size, VDAT_STRING_MAINFW_ACT);
612 } else if (!strcasecmp(name, "vdat_lfdebug")) {
613 return GetVdatString(dest, size,
614 VDAT_STRING_LOAD_FIRMWARE_DEBUG);
615 } else if (!strcasecmp(name, "fw_try_next")) {
616 StrCopy(dest,
617 vb2_get_nv_storage(VB2_NV_TRY_NEXT) ? "B" : "A",
618 size);
619 return 0;
620 } else if (!strcasecmp(name, "fw_tried")) {
621 StrCopy(dest,
622 vb2_get_nv_storage(VB2_NV_FW_TRIED) ? "B" : "A",
623 size);
624 return 0;
625 } else if (!strcasecmp(name, "fw_result")) {
626 int v = vb2_get_nv_storage(VB2_NV_FW_RESULT);
627 if (v < ARRAY_SIZE(fw_results))
628 StrCopy(dest, fw_results[v], size);
629 else
630 StrCopy(dest, "unknown", size);
631 return 0;
632 } else if (!strcasecmp(name, "fw_prev_tried")) {
633 StrCopy(dest,
634 vb2_get_nv_storage(VB2_NV_FW_PREV_TRIED) ? "B" : "A",
635 size);
636 return 0;
637 } else if (!strcasecmp(name, "fw_prev_result")) {
638 int v = vb2_get_nv_storage(VB2_NV_FW_PREV_RESULT);
639 if (v < ARRAY_SIZE(fw_results))
640 StrCopy(dest, fw_results[v], size);
641 else
642 StrCopy(dest, "unknown", size);
643 return 0;
644 } else if (!strcasecmp(name,"dev_default_boot")) {
645 int v = vb2_get_nv_storage(VB2_NV_DEV_DEFAULT_BOOT);
646 if (v < ARRAY_SIZE(default_boot))
647 StrCopy(dest, default_boot[v], size);
648 else
649 StrCopy(dest, "unknown", size);
650 return 0;
651 } else if (!strcasecmp(name, "minios_priority")) {
652 StrCopy(dest,
653 vb2_get_nv_storage(VB2_NV_MINIOS_PRIORITY) ?"B" : "A",
654 size);
655 return 0;
656 }
657
658 return -1;
659 }
660
VbSetSystemPropertyIntInternal(const char * name,int value)661 static int VbSetSystemPropertyIntInternal(const char *name, int value)
662 {
663 /* Check architecture-dependent properties first */
664
665 if (0 == VbSetArchPropertyInt(name, value))
666 return 0;
667
668 /* NV storage values */
669 if (!strcasecmp(name,"nvram_cleared")) {
670 /* Can only clear this flag; it's set inside the NV storage
671 * library. */
672 return vb2_set_nv_storage(VB2_NV_KERNEL_SETTINGS_RESET, 0);
673 } else if (!strcasecmp(name,"recovery_request")) {
674 return vb2_set_nv_storage(VB2_NV_RECOVERY_REQUEST, value);
675 } else if (!strcasecmp(name,"diagnostic_request")) {
676 return vb2_set_nv_storage(VB2_NV_DIAG_REQUEST, value);
677 } else if (!strcasecmp(name,"recovery_subcode")) {
678 return vb2_set_nv_storage(VB2_NV_RECOVERY_SUBCODE, value);
679 } else if (!strcasecmp(name,"dbg_reset")) {
680 return vb2_set_nv_storage(VB2_NV_DEBUG_RESET_MODE, value);
681 } else if (!strcasecmp(name,"disable_dev_request")) {
682 return vb2_set_nv_storage(VB2_NV_DISABLE_DEV_REQUEST, value);
683 } else if (!strcasecmp(name,"clear_tpm_owner_request")) {
684 if (EXTERNAL_TPM_CLEAR_REQUEST && CheckFwType("nonchrome")) {
685 const char *const argv[] = {
686 TPM_CLEAR_REQUEST_EXEC_NAME,
687 value ? "1" : "0",
688 NULL,
689 };
690 return subprocess_run(argv, &subprocess_null, &subprocess_null,
691 &subprocess_null);
692 } else {
693 return vb2_set_nv_storage(
694 VB2_NV_CLEAR_TPM_OWNER_REQUEST, value);
695 }
696 } else if (!strcasecmp(name,"clear_tpm_owner_done")) {
697 /* Can only clear this flag; it's set by firmware. */
698 return vb2_set_nv_storage(VB2_NV_CLEAR_TPM_OWNER_DONE, 0);
699 } else if (!strcasecmp(name,"fw_try_count")) {
700 return vb2_set_nv_storage(VB2_NV_TRY_COUNT, value);
701 } else if (!strcasecmp(name,"display_request")) {
702 return vb2_set_nv_storage(VB2_NV_DISPLAY_REQUEST, value);
703 } else if (!strcasecmp(name,"wipeout_request")) {
704 /* Can only clear this flag, set only by firmware. */
705 return vb2_set_nv_storage(VB2_NV_REQ_WIPEOUT, 0);
706 } else if (!strcasecmp(name,"backup_nvram_request")) {
707 /* Best-effort only, since it requires firmware and TPM
708 * support. */
709 return vb2_set_nv_storage(VB2_NV_BACKUP_NVRAM_REQUEST, value);
710 } else if (!strcasecmp(name,"fwupdate_tries")) {
711 int kern_nv = vb2_get_nv_storage(VB2_NV_KERNEL_FIELD);
712 if (kern_nv == -1)
713 return -1;
714 kern_nv &= ~KERN_NV_FWUPDATE_TRIES_MASK;
715 kern_nv |= (value & KERN_NV_FWUPDATE_TRIES_MASK);
716 return vb2_set_nv_storage_with_backup(
717 VB2_NV_KERNEL_FIELD, kern_nv);
718 } else if (!strcasecmp(name,"block_devmode")) {
719 int kern_nv = vb2_get_nv_storage(VB2_NV_KERNEL_FIELD);
720 if (kern_nv == -1)
721 return -1;
722 kern_nv &= ~KERN_NV_BLOCK_DEVMODE_FLAG;
723 if (value)
724 kern_nv |= KERN_NV_BLOCK_DEVMODE_FLAG;
725 return vb2_set_nv_storage_with_backup(
726 VB2_NV_KERNEL_FIELD, kern_nv);
727 } else if (!strcasecmp(name,"tpm_attack")) {
728 /* This value should only be read and cleared, but we allow
729 * setting it to 1 for testing. */
730 int kern_nv = vb2_get_nv_storage(VB2_NV_KERNEL_FIELD);
731 if (kern_nv == -1)
732 return -1;
733 kern_nv &= ~KERN_NV_TPM_ATTACK_FLAG;
734 if (value)
735 kern_nv |= KERN_NV_TPM_ATTACK_FLAG;
736 return vb2_set_nv_storage_with_backup(
737 VB2_NV_KERNEL_FIELD, kern_nv);
738 } else if (!strcasecmp(name,"loc_idx")) {
739 return vb2_set_nv_storage_with_backup(
740 VB2_NV_LOCALIZATION_INDEX, value);
741 } else if (!strcasecmp(name,"dev_boot_usb")) {
742 return vb2_set_nv_storage_with_backup(
743 VB2_NV_DEV_BOOT_EXTERNAL, value);
744 } else if (!strcasecmp(name,"dev_boot_altfw") ||
745 !strcasecmp(name,"dev_boot_legacy")) {
746 return vb2_set_nv_storage_with_backup(
747 VB2_NV_DEV_BOOT_ALTFW, value);
748 } else if (!strcasecmp(name,"dev_boot_signed_only")) {
749 return vb2_set_nv_storage_with_backup(
750 VB2_NV_DEV_BOOT_SIGNED_ONLY, value);
751 } else if (!strcasecmp(name, "dev_enable_udc")) {
752 return vb2_set_nv_storage_with_backup(
753 VB2_NV_DEV_ENABLE_UDC, value);
754 } else if (!strcasecmp(name, "boot_on_ac_detect")) {
755 return vb2_set_nv_storage_with_backup(
756 VB2_NV_BOOT_ON_AC_DETECT, value);
757 } else if (!strcasecmp(name, "try_ro_sync")) {
758 return vb2_set_nv_storage_with_backup(
759 VB2_NV_TRY_RO_SYNC, value);
760 } else if (!strcasecmp(name, "battery_cutoff_request")) {
761 return vb2_set_nv_storage(VB2_NV_BATTERY_CUTOFF_REQUEST, value);
762 } else if (!strcasecmp(name,"kernel_max_rollforward")) {
763 return vb2_set_nv_storage(VB2_NV_KERNEL_MAX_ROLLFORWARD, value);
764 } else if (!strcasecmp(name, "post_ec_sync_delay")) {
765 return vb2_set_nv_storage(VB2_NV_POST_EC_SYNC_DELAY, value);
766 }
767
768 return -1;
769 }
770
VbSetSystemPropertyInt(const char * name,int value)771 int VbSetSystemPropertyInt(const char *name, int value)
772 {
773 int result = -1;
774 int lock_fd;
775
776 lock_fd = AcquireCrossystemLock();
777 if (lock_fd < 0)
778 return -1;
779
780 result = VbSetSystemPropertyIntInternal(name, value);
781
782 if (ReleaseCrossystemLock(lock_fd) < 0)
783 return -1;
784
785 return result;
786 }
787
VbSetSystemPropertyStringInternal(const char * name,const char * value)788 static int VbSetSystemPropertyStringInternal(const char *name,
789 const char *value)
790 {
791 /* Chain to architecture-dependent properties */
792 if (0 == VbSetArchPropertyString(name, value))
793 return 0;
794
795 if (!strcasecmp(name, "fw_try_next")) {
796 if (!strcasecmp(value, "A"))
797 return vb2_set_nv_storage(VB2_NV_TRY_NEXT, 0);
798 else if (!strcasecmp(value, "B"))
799 return vb2_set_nv_storage(VB2_NV_TRY_NEXT, 1);
800 else
801 return -1;
802 } else if (!strcasecmp(name, "minios_priority")) {
803 if (!strcasecmp(value, "A"))
804 return vb2_set_nv_storage(VB2_NV_MINIOS_PRIORITY, 0);
805 else if (!strcasecmp(value, "B"))
806 return vb2_set_nv_storage(VB2_NV_MINIOS_PRIORITY, 1);
807 else
808 return -1;
809 } else if (!strcasecmp(name, "fw_result")) {
810 int i;
811
812 for (i = 0; i < ARRAY_SIZE(fw_results); i++) {
813 if (!strcasecmp(value, fw_results[i]))
814 return vb2_set_nv_storage(VB2_NV_FW_RESULT, i);
815 }
816 return -1;
817 } else if (!strcasecmp(name, "dev_default_boot")) {
818 int i;
819
820 /* "legacy" term deprecated in favour of "altfw"
821 (see: b/179458327) */
822 if (!strcasecmp(value, "legacy")) {
823 fprintf(stderr,
824 "!!!\n"
825 "!!! PLEASE USE 'altfw' INSTEAD OF 'legacy'\n"
826 "!!!\n");
827 value = "altfw";
828 }
829
830 for (i = 0; i < ARRAY_SIZE(default_boot); i++) {
831 if (!strcasecmp(value, default_boot[i]))
832 return vb2_set_nv_storage(
833 VB2_NV_DEV_DEFAULT_BOOT, i);
834 }
835 return -1;
836 }
837
838 return -1;
839 }
840
VbSetSystemPropertyString(const char * name,const char * value)841 int VbSetSystemPropertyString(const char *name, const char *value)
842 {
843 int result = -1;
844 int lock_fd;
845
846 lock_fd = AcquireCrossystemLock();
847 if (lock_fd < 0)
848 return -1;
849
850 result = VbSetSystemPropertyStringInternal(name, value);
851
852 if (ReleaseCrossystemLock(lock_fd) < 0)
853 return -1;
854
855 return result;
856 }
857
858 /**
859 * Get index of the last valid VBNV entry.
860 *
861 * @param buf Pointer to the buffer containing VBNV entries.
862 * @param buf_sz Size of the buffer.
863 * @param vbnv_size The size of a single VBNV entry for this device.
864 *
865 * @return The index of the last valid VBNV entry found by binary search,
866 * or -1 if not found. When the FMAP region is corrupted (used entries occurring
867 * after blank ones), the returned index may not point to the last VBNV
868 * entry.
869 */
vb2_nv_index(const uint8_t * buf,uint32_t buf_sz,int vbnv_size)870 static int vb2_nv_index(const uint8_t *buf, uint32_t buf_sz, int vbnv_size)
871 {
872 int used_below, blank_above;
873 uint8_t blank[VB2_NVDATA_SIZE_V2];
874
875 /* The size of the buffer should be an even multiple of the
876 VBNV size. */
877 if (buf_sz % vbnv_size != 0) {
878 VB2_DIE("The VBNV in flash (%u bytes) is not an even multiple "
879 "of the VBNV size (%u bytes). This is likely a "
880 "firmware bug.\n", buf_sz, vbnv_size);
881 }
882
883 memset(blank, 0xff, sizeof(blank));
884
885 /* To match the searching algorithm in firmware, perform binary search
886 instead of linear search to find the last used index. */
887 used_below = 0;
888 blank_above = buf_sz / vbnv_size;
889 while (used_below + 1 < blank_above) {
890 int mid = (used_below + blank_above) / 2;
891 if (!memcmp(blank, &buf[mid * vbnv_size], vbnv_size))
892 blank_above = mid;
893 else
894 used_below = mid;
895 }
896
897 /* Check the all blank case. */
898 if (used_below == 0 &&
899 !memcmp(blank, &buf[used_below * vbnv_size], vbnv_size)) {
900 fprintf(stderr, "VBNV is uninitialized.\n");
901 return -1;
902 }
903
904 return used_below;
905 }
906
907 /**
908 * Check whether the VBNV entries are corrupted.
909 *
910 * @param buf Pointer to the buffer containing VBNV entries.
911 * @param buf_sz Size of the buffer.
912 * @param vbnv_size The size of a single VBNV entry for this device.
913 *
914 * @return True if there are used entries occurring after blank ones, or false
915 * otherwise.
916 */
is_corrupted(const uint8_t * buf,uint32_t buf_sz,int vbnv_size)917 static bool is_corrupted(const uint8_t *buf, uint32_t buf_sz, int vbnv_size)
918 {
919 uint8_t blank[VB2_NVDATA_SIZE_V2];
920 bool found_blank = false;
921
922 memset(blank, 0xff, sizeof(blank));
923
924 for (int i = 0; i < buf_sz / vbnv_size; i++) {
925 if (!memcmp(blank, &buf[i * vbnv_size], vbnv_size))
926 found_blank = true;
927 else if (found_blank)
928 return true;
929 }
930
931 return false;
932 }
933
934 #define VBNV_FMAP_REGION "RW_NVRAM"
935
vb2_read_nv_storage_flashrom(struct vb2_context * ctx)936 int vb2_read_nv_storage_flashrom(struct vb2_context *ctx)
937 {
938 int index;
939 int vbnv_size = vb2_nv_get_size(ctx);
940
941 struct firmware_image image = {
942 .programmer = FLASHROM_PROGRAMMER_INTERNAL_AP,
943 };
944 if (flashrom_read(&image, VBNV_FMAP_REGION))
945 return -1;
946
947 index = vb2_nv_index(image.data, image.size, vbnv_size);
948 if (index < 0) {
949 free(image.data);
950 return -1;
951 }
952
953 memcpy(ctx->nvdata, &image.data[index * vbnv_size], vbnv_size);
954 free(image.data);
955 return 0;
956 }
957
vb2_write_nv_storage_flashrom(struct vb2_context * ctx)958 int vb2_write_nv_storage_flashrom(struct vb2_context *ctx)
959 {
960 int rv = 0;
961 int index;
962 bool corrupted;
963 int vbnv_size = vb2_nv_get_size(ctx);
964
965 struct firmware_image image = {
966 .programmer = FLASHROM_PROGRAMMER_INTERNAL_AP,
967 };
968 if (flashrom_read(&image, VBNV_FMAP_REGION))
969 return -1;
970
971 index = vb2_nv_index(image.data, image.size, vbnv_size) + 1;
972 corrupted = is_corrupted(image.data, image.size, vbnv_size);
973
974 if (corrupted || index * vbnv_size == image.size) {
975 /* VBNV is corrupted or full. Erase and write at beginning. */
976 if (corrupted)
977 fprintf(stderr, "VBNV is corrupted; erasing %s\n",
978 VBNV_FMAP_REGION);
979 memset(image.data, 0xff, image.size);
980 index = 0;
981 }
982
983 memcpy(&image.data[index * vbnv_size], ctx->nvdata, vbnv_size);
984 if (flashrom_write(&image, VBNV_FMAP_REGION)) {
985 rv = -1;
986 goto exit;
987 }
988
989 exit:
990 free(image.data);
991 return rv;
992 }
993