1 /* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
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 <stddef.h>
7 #include <stdio.h>
8 #include <string.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <unistd.h>
12 #include <ctype.h>
13 
14 #include "host_common.h"
15 
16 #include "crossystem.h"
17 #include "crossystem_arch.h"
18 #include "utility.h"
19 #include "vboot_common.h"
20 #include "vboot_nvstorage.h"
21 #include "vboot_struct.h"
22 
23 /* Filename for kernel command line */
24 #define KERNEL_CMDLINE_PATH "/proc/cmdline"
25 
26 /* Fields that GetVdatString() can get */
27 typedef enum VdatStringField {
28   VDAT_STRING_TIMERS = 0,           /* Timer values */
29   VDAT_STRING_LOAD_FIRMWARE_DEBUG,  /* LoadFirmware() debug information */
30   VDAT_STRING_LOAD_KERNEL_DEBUG,    /* LoadKernel() debug information */
31   VDAT_STRING_MAINFW_ACT            /* Active main firmware */
32 } VdatStringField;
33 
34 
35 /* Fields that GetVdatInt() can get */
36 typedef enum VdatIntField {
37   VDAT_INT_FLAGS = 0,                /* Flags */
38   VDAT_INT_HEADER_VERSION,           /* Header version for VbSharedData */
39   VDAT_INT_DEVSW_BOOT,               /* Dev switch position at boot */
40   VDAT_INT_DEVSW_VIRTUAL,            /* Dev switch is virtual */
41   VDAT_INT_RECSW_BOOT,               /* Recovery switch position at boot */
42   VDAT_INT_HW_WPSW_BOOT,             /* Hardware WP switch position at boot */
43   VDAT_INT_SW_WPSW_BOOT,             /* Flash chip's WP setting at boot */
44 
45   VDAT_INT_FW_VERSION_TPM,           /* Current firmware version in TPM */
46   VDAT_INT_KERNEL_VERSION_TPM,       /* Current kernel version in TPM */
47   VDAT_INT_TRIED_FIRMWARE_B,         /* Tried firmware B due to fwb_tries */
48   VDAT_INT_KERNEL_KEY_VERIFIED,      /* Kernel key verified using
49                                       * signature, not just hash */
50   VDAT_INT_RECOVERY_REASON,          /* Recovery reason for current boot */
51   VDAT_INT_FW_BOOT2                  /* Firmware selection by vboot2 */
52 } VdatIntField;
53 
54 
55 /* Description of build options that may be specified on the
56  * kernel command line. */
57 typedef enum VbBuildOption {
58   VB_BUILD_OPTION_UNKNOWN,
59   VB_BUILD_OPTION_DEBUG,
60   VB_BUILD_OPTION_NODEBUG
61 } VbBuildOption;
62 
63 static const char *fw_results[] = {"unknown", "trying", "success", "failure"};
64 
65 /* Masks for kern_nv usage by kernel. */
66 #define KERN_NV_FWUPDATE_TRIES_MASK 0x0000000F
67 #define KERN_NV_BLOCK_DEVMODE_FLAG  0x00000010
68 /* If you want to use the remaining currently-unused bits in kern_nv
69  * for something kernel-y, define a new field (the way we did for
70  * fwupdate_tries).  Don't just modify kern_nv directly, because that
71  * makes it too easy to accidentally corrupt other sub-fields. */
72 #define KERN_NV_CURRENTLY_UNUSED    0xFFFFFFE0
73 
74 /* Return true if the FWID starts with the specified string. */
FwidStartsWith(const char * start)75 int FwidStartsWith(const char *start) {
76   char fwid[VB_MAX_STRING_PROPERTY];
77   if (!VbGetSystemPropertyString("fwid", fwid, sizeof(fwid)))
78     return 0;
79 
80   return 0 == strncmp(fwid, start, strlen(start));
81 }
82 
83 static int vnc_read;
84 
VbGetNvStorage(VbNvParam param)85 int VbGetNvStorage(VbNvParam param) {
86   uint32_t value;
87   int retval;
88   static VbNvContext cached_vnc;
89 
90   /* TODO: locking around NV access */
91   if (!vnc_read) {
92     if (0 != VbReadNvStorage(&cached_vnc))
93       return -1;
94     vnc_read = 1;
95   }
96 
97   if (0 != VbNvSetup(&cached_vnc))
98     return -1;
99   retval = VbNvGet(&cached_vnc, param, &value);
100   if (0 != VbNvTeardown(&cached_vnc))
101     return -1;
102   if (0 != retval)
103     return -1;
104 
105   /* TODO: If vnc.raw_changed, attempt to reopen NVRAM for write and
106    * save the new defaults.  If we're able to, log. */
107   /* TODO: release lock */
108 
109   return (int)value;
110 }
111 
112 
VbSetNvStorage(VbNvParam param,int value)113 int VbSetNvStorage(VbNvParam param, int value) {
114   VbNvContext vnc;
115   int retval = -1;
116   int i;
117 
118   if (0 != VbReadNvStorage(&vnc))
119     return -1;
120 
121   if (0 != VbNvSetup(&vnc))
122     goto VbSetNvCleanup;
123   i = VbNvSet(&vnc, param, (uint32_t)value);
124   if (0 != VbNvTeardown(&vnc))
125     goto VbSetNvCleanup;
126   if (0 != i)
127     goto VbSetNvCleanup;
128 
129   if (vnc.raw_changed) {
130     vnc_read = 0;
131     if (0 != VbWriteNvStorage(&vnc))
132       goto VbSetNvCleanup;
133   }
134 
135   /* Success */
136   retval = 0;
137 
138 VbSetNvCleanup:
139   /* TODO: release lock */
140   return retval;
141 }
142 
143 /*
144  * Set a param value, and try to flag it for persistent backup.
145  * It's okay if backup isn't supported. It's best-effort only.
146  */
VbSetNvStorage_WithBackup(VbNvParam param,int value)147 static int VbSetNvStorage_WithBackup(VbNvParam param, int value)
148 {
149   int retval;
150   retval = VbSetNvStorage(param, value);
151   if (!retval)
152     VbSetNvStorage(VBNV_BACKUP_NVRAM_REQUEST, 1);
153   return retval;
154 }
155 
156 /* Find what build/debug status is specified on the kernel command
157  * line, if any. */
VbScanBuildOption(void)158 static VbBuildOption VbScanBuildOption(void) {
159   FILE* f = NULL;
160   char buf[4096] = "";
161   char *t, *saveptr;
162   const char *delimiters = " \r\n";
163 
164   f = fopen(KERNEL_CMDLINE_PATH, "r");
165   if (NULL != f) {
166     if (NULL == fgets(buf, sizeof(buf), f))
167       buf[0] = 0;
168     fclose(f);
169   }
170   for (t = strtok_r(buf, delimiters, &saveptr); t;
171        t = strtok_r(NULL, delimiters, &saveptr)) {
172     if (0 == strcmp(t, "cros_debug"))
173       return VB_BUILD_OPTION_DEBUG;
174     else if (0 == strcmp(t, "cros_nodebug"))
175       return VB_BUILD_OPTION_NODEBUG;
176   }
177 
178   return VB_BUILD_OPTION_UNKNOWN;
179 }
180 
181 
182 /* Determine whether the running OS image was built for debugging.
183  * Returns 1 if yes, 0 if no or indeterminate. */
VbGetDebugBuild(void)184 int VbGetDebugBuild(void) {
185   return VB_BUILD_OPTION_DEBUG == VbScanBuildOption();
186 }
187 
188 
189 /* Determine whether OS-level debugging should be allowed.
190  * Returns 1 if yes, 0 if no or indeterminate. */
VbGetCrosDebug(void)191 int VbGetCrosDebug(void) {
192   /* If the currently running system specifies its debug status, use
193    * that in preference to other indicators. */
194   VbBuildOption option = VbScanBuildOption();
195   if (VB_BUILD_OPTION_DEBUG == option) {
196       return 1;
197   } else if (VB_BUILD_OPTION_NODEBUG == option) {
198       return 0;
199   }
200 
201   /* Command line is silent; allow debug if the dev switch is on. */
202   if (1 == VbGetSystemPropertyInt("devsw_boot"))
203     return 1;
204 
205   /* All other cases disallow debug. */
206   return 0;
207 }
208 
209 
GetVdatLoadFirmwareDebug(char * dest,int size,const VbSharedDataHeader * sh)210 char* GetVdatLoadFirmwareDebug(char* dest, int size,
211                                const VbSharedDataHeader* sh) {
212   snprintf(dest, size,
213            "Check A result=%d\n"
214            "Check B result=%d\n"
215            "Firmware index booted=0x%02x\n"
216            "TPM combined version at start=0x%08x\n"
217            "Lowest combined version from firmware=0x%08x\n",
218            sh->check_fw_a_result,
219            sh->check_fw_b_result,
220            sh->firmware_index,
221            sh->fw_version_tpm_start,
222            sh->fw_version_lowest);
223   return dest;
224 }
225 
226 
227 #define TRUNCATED "\n(truncated)\n"
228 
GetVdatLoadKernelDebug(char * dest,int size,const VbSharedDataHeader * sh)229 char* GetVdatLoadKernelDebug(char* dest, int size,
230                              const VbSharedDataHeader* sh) {
231   int used = 0;
232   int first_call_tracked = 0;
233   int call;
234 
235   /* Make sure we have space for truncation warning */
236   if (size < strlen(TRUNCATED) + 1)
237     return NULL;
238   size -= strlen(TRUNCATED) + 1;
239 
240   used += snprintf(
241       dest + used, size - used,
242       "Calls to LoadKernel()=%d\n",
243       sh->lk_call_count);
244   if (used > size)
245     goto LoadKernelDebugExit;
246 
247   /* Report on the last calls */
248   if (sh->lk_call_count > VBSD_MAX_KERNEL_CALLS)
249     first_call_tracked = sh->lk_call_count - VBSD_MAX_KERNEL_CALLS;
250   for (call = first_call_tracked; call < sh->lk_call_count; call++) {
251     const VbSharedDataKernelCall* shc =
252         sh->lk_calls + (call & (VBSD_MAX_KERNEL_CALLS - 1));
253     int first_part_tracked = 0;
254     int part;
255 
256     used += snprintf(
257         dest + used, size - used,
258         "Call %d:\n"
259         "  Boot flags=0x%02x\n"
260         "  Boot mode=%d\n"
261         "  Test error=%d\n"
262         "  Return code=%d\n"
263         "  Debug flags=0x%02x\n"
264         "  Drive sectors=%" PRIu64 "\n"
265         "  Sector size=%d\n"
266         "  Check result=%d\n"
267         "  Kernel partitions found=%d\n",
268         call + 1,
269         shc->boot_flags,
270         shc->boot_mode,
271         shc->test_error_num,
272         shc->return_code,
273         shc->flags,
274         shc->sector_count,
275         shc->sector_size,
276         shc->check_result,
277         shc->kernel_parts_found);
278     if (used > size)
279       goto LoadKernelDebugExit;
280 
281     /* If we found too many partitions, only prints ones where the
282      * structure has info. */
283     if (shc->kernel_parts_found > VBSD_MAX_KERNEL_PARTS)
284       first_part_tracked = shc->kernel_parts_found - VBSD_MAX_KERNEL_PARTS;
285 
286     /* Report on the partitions checked */
287     for (part = first_part_tracked; part < shc->kernel_parts_found; part++) {
288       const VbSharedDataKernelPart* shp =
289           shc->parts + (part & (VBSD_MAX_KERNEL_PARTS - 1));
290 
291       used += snprintf(
292           dest + used, size - used,
293           "  Kernel %d:\n"
294           "    GPT index=%d\n"
295           "    Start sector=%" PRIu64 "\n"
296           "    Sector count=%" PRIu64 "\n"
297           "    Combined version=0x%08x\n"
298           "    Check result=%d\n"
299           "    Debug flags=0x%02x\n",
300           part + 1,
301           shp->gpt_index,
302           shp->sector_start,
303           shp->sector_count,
304           shp->combined_version,
305           shp->check_result,
306           shp->flags);
307       if (used > size)
308         goto LoadKernelDebugExit;
309     }
310   }
311 
312 LoadKernelDebugExit:
313 
314   /* Warn if data was truncated; we left space for this above. */
315   if (used > size)
316     strcat(dest, TRUNCATED);
317 
318   return dest;
319 }
320 
321 
GetVdatString(char * dest,int size,VdatStringField field)322 char* GetVdatString(char* dest, int size, VdatStringField field)
323 {
324   VbSharedDataHeader* sh = VbSharedDataRead();
325   char* value = dest;
326 
327   if (!sh)
328     return NULL;
329 
330   switch (field) {
331     case VDAT_STRING_TIMERS:
332       snprintf(dest, size,
333                "LFS=%" PRIu64 ",%" PRIu64
334                " LF=%" PRIu64 ",%" PRIu64
335                " LK=%" PRIu64 ",%" PRIu64,
336                sh->timer_vb_init_enter,
337                sh->timer_vb_init_exit,
338                sh->timer_vb_select_firmware_enter,
339                sh->timer_vb_select_firmware_exit,
340                sh->timer_vb_select_and_load_kernel_enter,
341                sh->timer_vb_select_and_load_kernel_exit);
342       break;
343 
344     case VDAT_STRING_LOAD_FIRMWARE_DEBUG:
345       value = GetVdatLoadFirmwareDebug(dest, size, sh);
346       break;
347 
348     case VDAT_STRING_LOAD_KERNEL_DEBUG:
349       value = GetVdatLoadKernelDebug(dest, size, sh);
350       break;
351 
352     case VDAT_STRING_MAINFW_ACT:
353       switch(sh->firmware_index) {
354         case 0:
355           StrCopy(dest, "A", size);
356           break;
357         case 1:
358           StrCopy(dest, "B", size);
359           break;
360         case 0xFF:
361           StrCopy(dest, "recovery", size);
362           break;
363         default:
364           value = NULL;
365       }
366       break;
367 
368     default:
369       value = NULL;
370       break;
371   }
372 
373   free(sh);
374   return value;
375 }
376 
377 
GetVdatInt(VdatIntField field)378 int GetVdatInt(VdatIntField field) {
379   VbSharedDataHeader* sh = VbSharedDataRead();
380   int value = -1;
381 
382   if (!sh)
383     return -1;
384 
385   /* Fields supported in version 1 */
386   switch (field) {
387     case VDAT_INT_FLAGS:
388       value = (int)sh->flags;
389       break;
390     case VDAT_INT_HEADER_VERSION:
391       value = sh->struct_version;
392       break;
393     case VDAT_INT_TRIED_FIRMWARE_B:
394       value = (sh->flags & VBSD_FWB_TRIED ? 1 : 0);
395       break;
396     case VDAT_INT_KERNEL_KEY_VERIFIED:
397       value = (sh->flags & VBSD_KERNEL_KEY_VERIFIED ? 1 : 0);
398       break;
399     case VDAT_INT_FW_VERSION_TPM:
400       value = (int)sh->fw_version_tpm;
401       break;
402     case VDAT_INT_KERNEL_VERSION_TPM:
403       value = (int)sh->kernel_version_tpm;
404       break;
405     case VDAT_INT_FW_BOOT2:
406       value = (sh->flags & VBSD_BOOT_FIRMWARE_VBOOT2 ? 1 : 0);
407     default:
408       break;
409   }
410 
411   /* Fields added in struct version 2 */
412   if (sh->struct_version >= 2) {
413     switch(field) {
414       case VDAT_INT_DEVSW_BOOT:
415         value = (sh->flags & VBSD_BOOT_DEV_SWITCH_ON ? 1 : 0);
416         break;
417       case VDAT_INT_DEVSW_VIRTUAL:
418         value = (sh->flags & VBSD_HONOR_VIRT_DEV_SWITCH ? 1 : 0);
419         break;
420       case VDAT_INT_RECSW_BOOT:
421         value = (sh->flags & VBSD_BOOT_REC_SWITCH_ON ? 1 : 0);
422         break;
423       case VDAT_INT_HW_WPSW_BOOT:
424         value = (sh->flags & VBSD_BOOT_FIRMWARE_WP_ENABLED ? 1 : 0);
425         break;
426       case VDAT_INT_SW_WPSW_BOOT:
427         value = (sh->flags & VBSD_BOOT_FIRMWARE_SW_WP_ENABLED ? 1 : 0);
428         break;
429       case VDAT_INT_RECOVERY_REASON:
430         value = sh->recovery_reason;
431         break;
432       default:
433         break;
434     }
435   }
436 
437   free(sh);
438   return value;
439 }
440 
441 /* Return version of VbSharedData struct or -1 if not found. */
VbSharedDataVersion(void)442 int VbSharedDataVersion(void) {
443   return GetVdatInt(VDAT_INT_HEADER_VERSION);
444 }
445 
VbGetSystemPropertyInt(const char * name)446 int VbGetSystemPropertyInt(const char* name) {
447   int value = -1;
448 
449   /* Check architecture-dependent properties first */
450   value = VbGetArchPropertyInt(name);
451   if (-1 != value)
452     return value;
453 
454   /* NV storage values */
455   else if (!strcasecmp(name,"kern_nv")) {
456     value = VbGetNvStorage(VBNV_KERNEL_FIELD);
457   } else if (!strcasecmp(name,"nvram_cleared")) {
458     value = VbGetNvStorage(VBNV_KERNEL_SETTINGS_RESET);
459   } else if (!strcasecmp(name,"recovery_request")) {
460     value = VbGetNvStorage(VBNV_RECOVERY_REQUEST);
461   } else if (!strcasecmp(name,"dbg_reset")) {
462     value = VbGetNvStorage(VBNV_DEBUG_RESET_MODE);
463   } else if (!strcasecmp(name,"disable_dev_request")) {
464     value = VbGetNvStorage(VBNV_DISABLE_DEV_REQUEST);
465   } else if (!strcasecmp(name,"clear_tpm_owner_request")) {
466     value = VbGetNvStorage(VBNV_CLEAR_TPM_OWNER_REQUEST);
467   } else if (!strcasecmp(name,"clear_tpm_owner_done")) {
468     value = VbGetNvStorage(VBNV_CLEAR_TPM_OWNER_DONE);
469   } else if (!strcasecmp(name,"fwb_tries")) {
470     value = VbGetNvStorage(VBNV_TRY_B_COUNT);
471   } else if (!strcasecmp(name,"fw_vboot2")) {
472     value = GetVdatInt(VDAT_INT_FW_BOOT2);
473   } else if (!strcasecmp(name,"fw_try_count")) {
474     value = VbGetNvStorage(VBNV_FW_TRY_COUNT);
475   } else if (!strcasecmp(name,"fwupdate_tries")) {
476     value = VbGetNvStorage(VBNV_KERNEL_FIELD);
477     if (value != -1)
478       value &= KERN_NV_FWUPDATE_TRIES_MASK;
479   } else if (!strcasecmp(name,"block_devmode")) {
480     value = VbGetNvStorage(VBNV_KERNEL_FIELD);
481     if (value != -1) {
482       value &= KERN_NV_BLOCK_DEVMODE_FLAG;
483       value = !!value;
484     }
485   } else if (!strcasecmp(name,"loc_idx")) {
486     value = VbGetNvStorage(VBNV_LOCALIZATION_INDEX);
487   } else if (!strcasecmp(name,"backup_nvram_request")) {
488     value = VbGetNvStorage(VBNV_BACKUP_NVRAM_REQUEST);
489   } else if (!strcasecmp(name,"dev_boot_usb")) {
490     value = VbGetNvStorage(VBNV_DEV_BOOT_USB);
491   } else if (!strcasecmp(name,"dev_boot_legacy")) {
492     value = VbGetNvStorage(VBNV_DEV_BOOT_LEGACY);
493   } else if (!strcasecmp(name,"dev_boot_signed_only")) {
494     value = VbGetNvStorage(VBNV_DEV_BOOT_SIGNED_ONLY);
495   } else if (!strcasecmp(name,"oprom_needed")) {
496     value = VbGetNvStorage(VBNV_OPROM_NEEDED);
497   } else if (!strcasecmp(name,"recovery_subcode")) {
498     value = VbGetNvStorage(VBNV_RECOVERY_SUBCODE);
499   }
500   /* Other parameters */
501   else if (!strcasecmp(name,"cros_debug")) {
502     value = VbGetCrosDebug();
503   } else if (!strcasecmp(name,"debug_build")) {
504     value = VbGetDebugBuild();
505   } else if (!strcasecmp(name,"devsw_boot")) {
506     value = GetVdatInt(VDAT_INT_DEVSW_BOOT);
507   } else if (!strcasecmp(name,"devsw_virtual")) {
508     value = GetVdatInt(VDAT_INT_DEVSW_VIRTUAL);
509   } else if (!strcasecmp(name, "recoverysw_boot")) {
510     value = GetVdatInt(VDAT_INT_RECSW_BOOT);
511   } else if (!strcasecmp(name, "wpsw_boot")) {
512     value = GetVdatInt(VDAT_INT_HW_WPSW_BOOT);
513   } else if (!strcasecmp(name, "sw_wpsw_boot")) {
514     value = GetVdatInt(VDAT_INT_SW_WPSW_BOOT);
515   } else if (!strcasecmp(name,"vdat_flags")) {
516     value = GetVdatInt(VDAT_INT_FLAGS);
517   } else if (!strcasecmp(name,"tpm_fwver")) {
518     value = GetVdatInt(VDAT_INT_FW_VERSION_TPM);
519   } else if (!strcasecmp(name,"tpm_kernver")) {
520     value = GetVdatInt(VDAT_INT_KERNEL_VERSION_TPM);
521   } else if (!strcasecmp(name,"tried_fwb")) {
522     value = GetVdatInt(VDAT_INT_TRIED_FIRMWARE_B);
523   } else if (!strcasecmp(name,"recovery_reason")) {
524     value = GetVdatInt(VDAT_INT_RECOVERY_REASON);
525   }
526 
527   return value;
528 }
529 
530 
VbGetSystemPropertyString(const char * name,char * dest,size_t size)531 const char* VbGetSystemPropertyString(const char* name, char* dest,
532                                       size_t size) {
533   static const char unknown_string[] = "unknown";
534 
535   /* Check architecture-dependent properties first */
536   if (VbGetArchPropertyString(name, dest, size))
537     return dest;
538 
539   if (!strcasecmp(name,"kernkey_vfy")) {
540     switch(GetVdatInt(VDAT_INT_KERNEL_KEY_VERIFIED)) {
541       case 0:
542         return "hash";
543       case 1:
544         return "sig";
545       default:
546         return NULL;
547     }
548   } else if (!strcasecmp(name, "mainfw_act")) {
549     return GetVdatString(dest, size, VDAT_STRING_MAINFW_ACT);
550   } else if (!strcasecmp(name, "vdat_timers")) {
551     return GetVdatString(dest, size, VDAT_STRING_TIMERS);
552   } else if (!strcasecmp(name, "vdat_lfdebug")) {
553     return GetVdatString(dest, size, VDAT_STRING_LOAD_FIRMWARE_DEBUG);
554   } else if (!strcasecmp(name, "vdat_lkdebug")) {
555     return GetVdatString(dest, size, VDAT_STRING_LOAD_KERNEL_DEBUG);
556   } else if (!strcasecmp(name, "ddr_type")) {
557     return unknown_string;
558   } else if (!strcasecmp(name, "fw_try_next")) {
559     return VbGetNvStorage(VBNV_FW_TRY_NEXT) ? "B" : "A";
560   } else if (!strcasecmp(name, "fw_tried")) {
561     return VbGetNvStorage(VBNV_FW_TRIED) ? "B" : "A";
562   } else if (!strcasecmp(name, "fw_result")) {
563     int v = VbGetNvStorage(VBNV_FW_RESULT);
564     if (v < ARRAY_SIZE(fw_results))
565       return fw_results[v];
566     else
567       return "unknown";
568   } else if (!strcasecmp(name, "fw_prev_tried")) {
569     return VbGetNvStorage(VBNV_FW_PREV_TRIED) ? "B" : "A";
570   } else if (!strcasecmp(name, "fw_prev_result")) {
571     int v = VbGetNvStorage(VBNV_FW_PREV_RESULT);
572     if (v < ARRAY_SIZE(fw_results))
573       return fw_results[v];
574     else
575       return "unknown";
576   }
577 
578   return NULL;
579 }
580 
581 
VbSetSystemPropertyInt(const char * name,int value)582 int VbSetSystemPropertyInt(const char* name, int value) {
583   /* Check architecture-dependent properties first */
584 
585   if (0 == VbSetArchPropertyInt(name, value))
586     return 0;
587 
588   /* NV storage values */
589   if (!strcasecmp(name,"nvram_cleared")) {
590     /* Can only clear this flag; it's set inside the NV storage library. */
591     return VbSetNvStorage(VBNV_KERNEL_SETTINGS_RESET, 0);
592   } else if (!strcasecmp(name,"recovery_request")) {
593     return VbSetNvStorage(VBNV_RECOVERY_REQUEST, value);
594   } else if (!strcasecmp(name,"recovery_subcode")) {
595     return VbSetNvStorage(VBNV_RECOVERY_SUBCODE, value);
596   } else if (!strcasecmp(name,"dbg_reset")) {
597     return VbSetNvStorage(VBNV_DEBUG_RESET_MODE, value);
598   } else if (!strcasecmp(name,"disable_dev_request")) {
599     return VbSetNvStorage(VBNV_DISABLE_DEV_REQUEST, value);
600   } else if (!strcasecmp(name,"clear_tpm_owner_request")) {
601     return VbSetNvStorage(VBNV_CLEAR_TPM_OWNER_REQUEST, value);
602   } else if (!strcasecmp(name,"clear_tpm_owner_done")) {
603     /* Can only clear this flag; it's set by firmware. */
604     return VbSetNvStorage(VBNV_CLEAR_TPM_OWNER_DONE, 0);
605   } else if (!strcasecmp(name,"fwb_tries")) {
606     return VbSetNvStorage(VBNV_TRY_B_COUNT, value);
607   } else if (!strcasecmp(name,"fw_try_count")) {
608     return VbSetNvStorage(VBNV_FW_TRY_COUNT, value);
609   } else if (!strcasecmp(name,"oprom_needed")) {
610     return VbSetNvStorage(VBNV_OPROM_NEEDED, value);
611   } else if (!strcasecmp(name,"backup_nvram_request")) {
612       /* Best-effort only, since it requires firmware and TPM support. */
613     return VbSetNvStorage(VBNV_BACKUP_NVRAM_REQUEST, value);
614   } else if (!strcasecmp(name,"fwupdate_tries")) {
615     int kern_nv = VbGetNvStorage(VBNV_KERNEL_FIELD);
616     if (kern_nv == -1)
617       return -1;
618     kern_nv &= ~KERN_NV_FWUPDATE_TRIES_MASK;
619     kern_nv |= (value & KERN_NV_FWUPDATE_TRIES_MASK);
620     return VbSetNvStorage_WithBackup(VBNV_KERNEL_FIELD, kern_nv);
621   } else if (!strcasecmp(name,"block_devmode")) {
622     int kern_nv = VbGetNvStorage(VBNV_KERNEL_FIELD);
623     if (kern_nv == -1)
624       return -1;
625     kern_nv &= ~KERN_NV_BLOCK_DEVMODE_FLAG;
626     if (value)
627 	kern_nv |= KERN_NV_BLOCK_DEVMODE_FLAG;
628     return VbSetNvStorage_WithBackup(VBNV_KERNEL_FIELD, kern_nv);
629   } else if (!strcasecmp(name,"loc_idx")) {
630     return VbSetNvStorage_WithBackup(VBNV_LOCALIZATION_INDEX, value);
631   } else if (!strcasecmp(name,"dev_boot_usb")) {
632     return VbSetNvStorage_WithBackup(VBNV_DEV_BOOT_USB, value);
633   } else if (!strcasecmp(name,"dev_boot_legacy")) {
634     return VbSetNvStorage_WithBackup(VBNV_DEV_BOOT_LEGACY, value);
635   } else if (!strcasecmp(name,"dev_boot_signed_only")) {
636     return VbSetNvStorage_WithBackup(VBNV_DEV_BOOT_SIGNED_ONLY, value);
637   }
638 
639   return -1;
640 }
641 
642 
VbSetSystemPropertyString(const char * name,const char * value)643 int VbSetSystemPropertyString(const char* name, const char* value) {
644   /* Chain to architecture-dependent properties */
645   if (0 == VbSetArchPropertyString(name, value))
646     return 0;
647 
648   if (!strcasecmp(name, "fw_try_next")) {
649     if (!strcasecmp(value, "A"))
650       return VbSetNvStorage(VBNV_FW_TRY_NEXT, 0);
651     else if (!strcasecmp(value, "B"))
652       return VbSetNvStorage(VBNV_FW_TRY_NEXT, 1);
653     else
654       return -1;
655 
656   } else if (!strcasecmp(name, "fw_result")) {
657     int i;
658 
659     for (i = 0; i < ARRAY_SIZE(fw_results); i++) {
660       if (!strcasecmp(value, fw_results[i]))
661 	return VbSetNvStorage(VBNV_FW_RESULT, i);
662     }
663     return -1;
664   }
665 
666   return -1;
667 }
668