From: Gang W. <gan...@in...> - 2014-01-30 05:15:27
|
changeset ead7d32d544b in /hg/p/tboot/code details: http://hg.code.sf.net/p/tboot/code/code?cmd=changeset;node=ead7d32d544b description: Extend tboot policy supporting measuring TPM NV TPM NV measuring is defaultly disabled, need below cmdline option to enable: measure_nv=true When NV measuring is enabled, it will get all NV measuring policy entry from the tboot policy structure. Every NV policy entry will specify: nv_index: TPM NV index to measure and verify pcr: PCR to be extended with the NV measurement mod_num: Tell how to measure the nv = TB_POL_MOD_NUM_NV: hash then extend, no size limitation on NV index = TB_POL_MOD_NUM_NV_RAW: extend w/o hash, size should be exactly hash size hash_type: any - no verification needed; image - need verify per hashs list. hashs: hash list. optional. The nv_index to be measured must be defined with OWNERWRITE permission, otherwise the verification will fail, and nothing will be extended into pcr. Signed-off-by: Nehal Bandi <neh...@ci...> Signed-off-by: Gang Wei <gan...@in...> diffstat: include/tb_error.h | 2 + include/tb_policy.h | 31 +++++++++- tboot/common/cmdline.c | 11 +++ tboot/common/policy.c | 144 +++++++++++++++++++++++++++++++++++++++++++++++- tboot/common/tb_error.c | 3 + tboot/common/tboot.c | 7 ++ tboot/common/tpm.c | 66 ++++++++++++++++++++++ tboot/include/cmdline.h | 1 + tboot/include/tpm.h | 17 +++++ 9 files changed, 276 insertions(+), 6 deletions(-) diffs (truncated from 442 to 300 lines): diff -r 0f4d8c3d0b1f -r ead7d32d544b include/tb_error.h --- a/include/tb_error.h Wed Jan 29 23:27:39 2014 +0800 +++ b/include/tb_error.h Wed Jan 29 23:27:44 2014 +0800 @@ -64,6 +64,8 @@ failed */ TB_ERR_FATAL, /* generic fatal error */ + TB_ERR_NV_VERIFICATION_FAILED, /* NV failed to verify against + policy */ TB_ERR_MAX } tb_error_t; diff -r 0f4d8c3d0b1f -r ead7d32d544b include/tb_policy.h --- a/include/tb_policy.h Wed Jan 29 23:27:39 2014 +0800 +++ b/include/tb_policy.h Wed Jan 29 23:27:44 2014 +0800 @@ -60,7 +60,9 @@ #define TB_POL_MAX_MOD_NUM 127 /* largest supported module number */ #define TB_POL_MOD_NUM_ANY 129 /* matches any module number */ - /* (should be last entry) */ + /* (should be last entry of modules) */ +#define TB_POL_MOD_NUM_NV 130 /* indicate this is a nv index entry */ +#define TB_POL_MOD_NUM_NV_RAW 131 /* a nv entry verified by raw content */ #define TB_POL_MAX_PCR 23 /* largest supported PCR number */ #define TB_POL_PCR_NONE 255 /* don't extend measurement into a PCR */ @@ -74,7 +76,14 @@ uint8_t mod_num; /* 0-based or TB_POL_MOD_NUM_* */ uint8_t pcr; /* PCR number (0-23) or TB_POL_PCR_* */ uint8_t hash_type; /* TB_HTYPE_* */ - uint32_t reserved; + uint32_t nv_index; /* nv index to be measured, effective when */ + /* mod_num==TB_POL_MOD_NUM_{NV | NV_RAW} */ + /* mod_num: */ + /* TB_POL_MOD_NUM_NV_RAW: */ + /* check index size==hash size, */ + /* no hashing before verify and extend */ + /* TB_POL_MOD_NUM_NV: */ + /* hashing before verify and extend */ uint8_t num_hashes; tb_hash_t hashes[]; } tb_policy_entry_t; @@ -298,7 +307,9 @@ if ( print ) PRINT(TBOOT_DETA"\t policy entry[%d]:\n", i); if ( pol_entry->mod_num > TB_POL_MAX_MOD_NUM && - pol_entry->mod_num != TB_POL_MOD_NUM_ANY ) { + pol_entry->mod_num != TB_POL_MOD_NUM_ANY && + pol_entry->mod_num != TB_POL_MOD_NUM_NV && + pol_entry->mod_num != TB_POL_MOD_NUM_NV_RAW ) { if ( print ) PRINT(TBOOT_ERR"mod_num invalid (%u)\n", pol_entry->mod_num); return false; } @@ -306,7 +317,19 @@ if ( pol_entry->mod_num == TB_POL_MOD_NUM_ANY ) { if ( print ) PRINT(TBOOT_DETA"any\n"); } - else + else if ( pol_entry->mod_num == TB_POL_MOD_NUM_NV ) { + if ( print ) + PRINT(TBOOT_DETA"nv\n" + "\t\t nv_index: %08x\n", + pol_entry->nv_index); + } + else if ( pol_entry->mod_num == TB_POL_MOD_NUM_NV_RAW ) { + if ( print ) + PRINT(TBOOT_DETA"nv_raw\n" + "\t\t nv_index: %08x\n", + pol_entry->nv_index); + } + else if ( print ) PRINT(TBOOT_DETA"%u\n", pol_entry->mod_num); if ( pol_entry->pcr > TB_POL_MAX_PCR && diff -r 0f4d8c3d0b1f -r ead7d32d544b tboot/common/cmdline.c --- a/tboot/common/cmdline.c Wed Jan 29 23:27:39 2014 +0800 +++ b/tboot/common/cmdline.c Wed Jan 29 23:27:44 2014 +0800 @@ -75,6 +75,7 @@ { "pcr_map", "legacy" }, /* legacy|da */ { "min_ram", "0" }, /* size in bytes | 0 for no min */ { "call_racm", "false" }, /* true|false|check */ + { "measure_nv", "false" }, /* true|false */ { NULL, NULL } }; static char g_tboot_param_values[ARRAY_SIZE(g_tboot_cmdline_options)][MAX_VALUE_LEN]; @@ -483,6 +484,16 @@ return true; } +bool get_tboot_measure_nv(void) +{ + const char *measure_nv = get_option_val(g_tboot_cmdline_options, + g_tboot_param_values, "measure_nv"); + if ( measure_nv == NULL || strcmp(measure_nv, "true") != 0 ) + return false; + return true; +} + + /* * linux kernel command line parsing */ diff -r 0f4d8c3d0b1f -r ead7d32d544b tboot/common/policy.c --- a/tboot/common/policy.c Wed Jan 29 23:27:39 2014 +0800 +++ b/tboot/common/policy.c Wed Jan 29 23:27:44 2014 +0800 @@ -110,6 +110,7 @@ { TB_POLTYPE_CONT_VERIFY_FAIL, TB_POLACT_HALT, { {TB_ERR_MODULE_VERIFICATION_FAILED, TB_POLACT_CONTINUE}, + {TB_ERR_NV_VERIFICATION_FAILED, TB_POLACT_CONTINUE}, {TB_ERR_POLICY_NOT_PRESENT, TB_POLACT_CONTINUE}, {TB_ERR_POLICY_INVALID, TB_POLACT_CONTINUE}, {TB_ERR_NONE, TB_POLACT_CONTINUE}, @@ -135,7 +136,7 @@ version : 2, policy_type : TB_POLTYPE_CONT_NON_FATAL, policy_control : TB_POLCTL_EXTEND_PCR17, - num_entries : 2, + num_entries : 3, entries : { { /* mod 0 is extended to PCR 18 by default, so don't re-extend it */ mod_num : 0, @@ -148,6 +149,13 @@ pcr : 19, hash_type : TB_HTYPE_ANY, num_hashes : 0 + }, + { /* NV index for geo-tagging will be extended to PCR 22 */ + mod_num : TB_POL_MOD_NUM_NV_RAW, + pcr : 22, + hash_type : TB_HTYPE_ANY, + nv_index : 0x40000010, + num_hashes : 0 } } }; @@ -157,7 +165,7 @@ version : 2, policy_type : TB_POLTYPE_CONT_NON_FATAL, policy_control : TB_POLCTL_EXTEND_PCR17, - num_entries : 2, + num_entries : 3, entries : { { /* mod 0 is extended to PCR 17 by default, so don't re-extend it */ mod_num : 0, @@ -170,6 +178,13 @@ pcr : 17, hash_type : TB_HTYPE_ANY, num_hashes : 0 + }, + { /* NV index for geo-tagging will be extended to PCR 22 */ + mod_num : TB_POL_MOD_NUM_NV_RAW, + pcr : 22, + hash_type : TB_HTYPE_ANY, + nv_index : 0x40000010, + num_hashes : 0 } } }; @@ -612,6 +627,131 @@ printk(TBOOT_INFO"all modules are verified\n"); } +static int find_first_nvpolicy_entry(const tb_policy_t *policy) +{ + if ( policy == NULL ) { + PRINT(TBOOT_ERR"Error: policy pointer is NULL\n"); + return -1; + } + + for ( int i = 0; i < policy->num_entries; i++ ) { + tb_policy_entry_t *pol_entry = get_policy_entry(policy, i); + if ( pol_entry == NULL ) + return -1; + + if ( pol_entry->mod_num == TB_POL_MOD_NUM_NV || + pol_entry->mod_num == TB_POL_MOD_NUM_NV_RAW ) + return i; + } + + return -1; +} + +static int find_next_nvpolicy_entry(const tb_policy_t *policy, int i) +{ + if ( policy == NULL || i < 0 || i >= policy->num_entries ) + return -1; + + for ( i++; i < policy->num_entries; i++ ) { + tb_policy_entry_t *pol_entry = get_policy_entry(policy, i); + if ( pol_entry == NULL ) + return -1; + + if ( pol_entry->mod_num == TB_POL_MOD_NUM_NV || + pol_entry->mod_num == TB_POL_MOD_NUM_NV_RAW ) + return i; + } + + return -1; +} + +static uint8_t nv_buf[4096]; + +static tb_error_t verify_nvindex(tb_policy_entry_t *pol_entry, + uint8_t hash_alg) +{ + size_t nv_size = sizeof(nv_buf); + tb_hash_t digest; + uint32_t attribute; + + if ( pol_entry == NULL ) + return TB_ERR_NV_VERIFICATION_FAILED; + + printk(TBOOT_INFO"verifying nv index 0x%08X\n", pol_entry->nv_index); + + /* check nv attribute */ + if ( TPM_SUCCESS != tpm_get_nvindex_permission(0, pol_entry->nv_index, + &attribute) ) { + printk(TBOOT_ERR"\t :reading nv index permission failed\n"); + return TB_ERR_NV_VERIFICATION_FAILED; + } + if ( !(attribute & TPM_NV_PER_OWNERWRITE) ) { + printk(TBOOT_ERR"\t :nv index should be OWNERWRITE, bad permission\n"); + return TB_ERR_NV_VERIFICATION_FAILED; + } + + /* get nv content */ + memset(nv_buf, 0, sizeof(nv_buf)); + if ( !read_policy_from_tpm(pol_entry->nv_index, + nv_buf, &nv_size) ) { + printk(TBOOT_ERR"\t :reading nv index 0x%08X failed\n", + pol_entry->nv_index); + return TB_ERR_NV_VERIFICATION_FAILED; + } + + /* hash the buffer if needed */ + switch ( pol_entry->mod_num ) { + case TB_POL_MOD_NUM_NV: + if ( !hash_buffer((const uint8_t*)nv_buf, nv_size, &digest, + TB_HALG_SHA1) ) { + printk(TBOOT_ERR"\t :nv content hash failed\n"); + return TB_ERR_NV_VERIFICATION_FAILED; + } + break; + case TB_POL_MOD_NUM_NV_RAW: + if ( nv_size != sizeof(digest.sha1) ) { + printk(TBOOT_ERR"\t :raw nv with wrong size (%d), should be %d\n", + (int)nv_size, sizeof(digest.sha1)); + return TB_ERR_NV_VERIFICATION_FAILED; + } + memcpy(digest.sha1, nv_buf, nv_size); + break; + default: + printk(TBOOT_ERR"\t :bad mod number for NV measuring in policy entry: %d\n", + pol_entry->mod_num); + return TB_ERR_NV_VERIFICATION_FAILED; + } + + /* add new hash to list (unless it doesn't get put in a PCR) + we'll just drop it if the list is full, but that will mean S3 resume + PCRs won't match pre-S3 */ + if ( NUM_VL_ENTRIES >= MAX_VL_HASHES ) + printk(TBOOT_WARN"\t too many hashes to save\n"); + else if ( pol_entry->pcr != TB_POL_PCR_NONE ) { + VL_ENTRIES(NUM_VL_ENTRIES).pcr = pol_entry->pcr; + VL_ENTRIES(NUM_VL_ENTRIES++).hash = digest; + } + + /* verify nv content */ + if ( !is_hash_in_policy_entry(pol_entry, &digest, hash_alg) ) { + printk(TBOOT_ERR"\t verification failed\n"); + return TB_ERR_NV_VERIFICATION_FAILED; + } + + printk(TBOOT_DETA"\t OK : "); print_hash(&digest, hash_alg); + return TB_ERR_NONE; +} + +void verify_all_nvindices(void) +{ + /* go through nv policies in tb policy */ + for ( int i = find_first_nvpolicy_entry(g_policy); + i >= 0; + i = find_next_nvpolicy_entry(g_policy, i) ) { + tb_policy_entry_t *pol_entry = get_policy_entry(g_policy, i); + apply_policy(verify_nvindex(pol_entry, g_policy->hash_alg)); + } +} /* * Local variables: diff -r 0f4d8c3d0b1f -r ead7d32d544b tboot/common/tb_error.c --- a/tboot/common/tb_error.c Wed Jan 29 23:27:39 2014 +0800 +++ b/tboot/common/tb_error.c Wed Jan 29 23:27:44 2014 +0800 @@ -111,6 +111,9 @@ case TB_ERR_FATAL: printk(TBOOT_ERR"generic fatal error.\n"); break; + case TB_ERR_NV_VERIFICATION_FAILED: + printk(TBOOT_ERR"verifying nv against policy failed.\n"); |