Add a tboot command line option that falls back to booting the kernel directly instead of performing a measured launch, if the previous measured launch failed. This acts as a failsafe and prevents the system from going into an endless reboot loop. Testing: Disable Vt-d on system. Boot without ignore_prev_err, and with ignore_prev_err=true. Verify system keeps trying to boot and resets on SENTER. Set ignore_prev_err=false. Verify tboot skips measured launch and transfers control directly to the kernel. Soft reset system and verify error is not cleared. Power-cycle system and verify TXT error is cleared. Signed-off-by: Sahil Rihan <sri...@fb.com> diff --git a/README b/README --- a/README +++ b/README @@ -272,6 +272,25 @@ It means tboot will use this algorithm to compute hash and use TPM2_PCR_Extend to extend it into PCRs. +o Recovering from measured launch failures. + When there's an error during SENTER, the system usually reboots. Since the underlying + cause is some sort of configuration error, the system can end up in a loop + rebooting endlessly after each attempted measured launch. In some environments it + make more sense to fall back to booting the kernel directly so that the system comes + up and is remotely accessible. After that the issue can be diagnosed and the system + power-cycled to clear the error. To enable this behavior a command line option can + be used: + ignore_prev_err=false|true // defaults to true + + The option defaults to true, which preserves the original behavior i.e. try a measured + launch even if the previous measured launch had errors. + + Setting the value to false will check if the previous measured launch was successful + by inspecting the TXT.ERRORCODE value. If measured launch failed, tboot will launch + the kernel directly without trying to perform a measured launch. + + Note: TXT.ERRORCODE is only cleared if the system is power cycled. A reboot is not + sufficient to clear the error code. PCR Usage: --------- diff --git a/include/tb_error.h b/include/tb_error.h --- a/include/tb_error.h +++ b/include/tb_error.h @@ -66,6 +66,7 @@ TB_ERR_FATAL, /* generic fatal error */ TB_ERR_NV_VERIFICATION_FAILED, /* NV failed to verify against policy */ + TB_ERR_PREV_TXT_ERROR, /* previous measured launch failed */ TB_ERR_MAX } tb_error_t; diff --git a/tboot/common/cmdline.c b/tboot/common/cmdline.c --- a/tboot/common/cmdline.c +++ b/tboot/common/cmdline.c @@ -83,7 +83,8 @@ { "min_ram", "0" }, /* size in bytes | 0 for no min */ { "call_racm", "false" }, /* true|false|check */ { "measure_nv", "false" }, /* true|false */ - { "extpol", "sha1" }, /* agile|embedded|sha1|sha256|sm3|... */ + { "extpol", "sha1" }, /* agile|embedded|sha1|sha256|sm3|... */ + { "ignore_prev_err", "true"}, /* true|false */ { NULL, NULL } }; static char g_tboot_param_values[ARRAY_SIZE(g_tboot_cmdline_options)][MAX_VALUE_LEN]; @@ -528,6 +529,15 @@ } } +bool get_tboot_ignore_prev_err(void) +{ + const char *ignore_prev_err = get_option_val(g_tboot_cmdline_options, + g_tboot_param_values, "ignore_prev_err"); + if ( ignore_prev_err == NULL || strcmp(ignore_prev_err, "true") == 0 ) + return true; + return false; +} + /* * linux kernel command line parsing */ diff --git a/tboot/common/policy.c b/tboot/common/policy.c --- a/tboot/common/policy.c +++ b/tboot/common/policy.c @@ -97,6 +97,7 @@ { TB_POLTYPE_CONT_NON_FATAL, TB_POLACT_CONTINUE, { {TB_ERR_FATAL, TB_POLACT_HALT}, + {TB_ERR_PREV_TXT_ERROR, TB_POLACT_UNMEASURED_LAUNCH}, {TB_ERR_TPM_NOT_READY, TB_POLACT_UNMEASURED_LAUNCH}, {TB_ERR_SMX_NOT_SUPPORTED, TB_POLACT_UNMEASURED_LAUNCH}, {TB_ERR_VMX_NOT_SUPPORTED, TB_POLACT_UNMEASURED_LAUNCH}, diff --git a/tboot/common/tb_error.c b/tboot/common/tb_error.c --- a/tboot/common/tb_error.c +++ b/tboot/common/tb_error.c @@ -114,6 +114,9 @@ case TB_ERR_NV_VERIFICATION_FAILED: printk(TBOOT_ERR"verifying nv against policy failed.\n"); break; + case TB_ERR_PREV_TXT_ERROR: + printk(TBOOT_ERR"previous measured launch had errors, skipping measured launch...\n"); + break; default: printk(TBOOT_ERR"unknown error (%d).\n", error); break; diff --git a/tboot/common/tboot.c b/tboot/common/tboot.c --- a/tboot/common/tboot.c +++ b/tboot/common/tboot.c @@ -414,7 +414,10 @@ apply_policy(err); /* print any errors on last boot, which must be from TXT launch */ - txt_get_error(); + txt_display_errors(); + if (txt_has_error() && get_tboot_ignore_prev_err() == false) { + apply_policy(TB_ERR_PREV_TXT_ERROR); + } /* need to verify that platform can perform measured launch */ err = verify_platform(); diff --git a/tboot/include/cmdline.h b/tboot/include/cmdline.h --- a/tboot/include/cmdline.h +++ b/tboot/include/cmdline.h @@ -54,6 +54,7 @@ extern bool get_tboot_call_racm_check(void); extern bool get_tboot_measure_nv(void); extern void get_tboot_extpol(void); +extern bool get_tboot_ignore_prev_err(void); /* for parse cmdline of linux kernel, say vga and mem */ extern void linux_parse_cmdline(const char *cmdline); diff --git a/tboot/include/txt/txt.h b/tboot/include/txt/txt.h --- a/tboot/include/txt/txt.h +++ b/tboot/include/txt/txt.h @@ -39,7 +39,8 @@ // #include <multiboot.h> extern bool txt_is_launched(void); -extern bool txt_get_error(void); +extern void txt_display_errors(void); +extern bool txt_has_error(void); extern void txt_get_racm_error(void); extern tb_error_t supports_txt(void); extern tb_error_t txt_verify_platform(void); diff --git a/tboot/txt/errors.c b/tboot/txt/errors.c --- a/tboot/txt/errors.c +++ b/tboot/txt/errors.c @@ -46,7 +46,7 @@ #include <txt/errorcode.h> -static void display_errors(void) +void txt_display_errors(void) { txt_errorcode_t err; txt_ests_t ests; @@ -58,7 +58,7 @@ * display TXT.ERRORODE error */ err = (txt_errorcode_t)read_pub_config_reg(TXTCR_ERRORCODE); - if (err._raw == 0 || err._raw == 0xc0000001 || err._raw == 0xc0000009) + if (txt_has_error() == false) printk(TBOOT_INFO"TXT.ERRORCODE: 0x%Lx\n", err._raw); else printk(TBOOT_ERR"TXT.ERRORCODE: 0x%Lx\n", err._raw); @@ -112,17 +112,16 @@ printk(TBOOT_ERR"TXT.E2STS: 0x%Lx\n", e2sts._raw); } -bool txt_get_error(void) +bool txt_has_error(void) { txt_errorcode_t err; - display_errors(); - err = (txt_errorcode_t)read_pub_config_reg(TXTCR_ERRORCODE); - if ( err.valid ) + if (err._raw == 0 || err._raw == 0xc0000001 || err._raw == 0xc0000009) { return false; - else + } else { return true; + } } #define CLASS_ACM_ENTRY 0x1
------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot _______________________________________________ tboot-devel mailing list tboot-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/tboot-devel