Add usage documentation to sgx_check.py

This commit is contained in:
Frinzell, Aaron
2022-01-27 17:28:50 -06:00
committed by Nathaniel Mitchell
parent 28a5234170
commit f4f196b47f
+92 -61
View File
@@ -1,5 +1,5 @@
#CHIPSEC: Platform Security Assessment Framework
#Copyright (c) 2010-2021, Intel Corporation
#Copyright (c) 2010-2022, Intel Corporation
#
#This program is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public License
@@ -23,12 +23,47 @@
"""
Check SGX related configuration
Reference: SGX BWG, CDI/IBP#: 565432
Reference:
- SGX BWG, CDI/IBP#: 565432
Usage:
``chipsec_main -m common.sgx_check``
Examples:
>>> chipsec_main.py -m common.sgx_check
Registers used:
- IA32_FEATURE_CONTROL.SGX_GLOBAL_EN
- IA32_FEATURE_CONTROL.LOCK
- IA32_DEBUG_INTERFACE.ENABLE
- IA32_DEBUG_INTERFACE.LOCK
- MTRRCAP.PRMRR
- PRMRR_VALID_CONFIG
- PRMRR_PHYBASE.PRMRR_base_address_fields
- PRMRR_PHYBASE.PRMRR_MEMTYPE
- PRMRR_MASK.PRMRR_mask_bits
- PRMRR_MASK.PRMRR_VLD
- PRMRR_MASK.PRMRR_LOCK
- PRMRR_UNCORE_PHYBASE.PRMRR_base_address_fields
- PRMRR_UNCORE_MASK.PRMRR_mask_bits
- PRMRR_UNCORE_MASK.PRMRR_VLD
- PRMRR_UNCORE_MASK.PRMRR_LOCK
- BIOS_SE_SVN.PFAT_SE_SVN
- BIOS_SE_SVN.ANC_SE_SVN
- BIOS_SE_SVN.SCLEAN_SE_SVN
- BIOS_SE_SVN.SINIT_SE_SVN
- BIOS_SE_SVN_STATUS.LOCK
- SGX_DEBUG_MODE.SGX_DEBUG_MODE_STATUS_BIT
.. note::
- Will not run within the EFI Shell
"""
_MODULE_NAME = 'sgx_check'
from chipsec.module_common import BaseModule, ModuleResult, MTAG_HWCONFIG
from chipsec.defines import BIT0, BIT1, BIT2, BIT5, BIT6, BIT7, BIT8
from chipsec.defines import BIT0, BIT1, BIT2, BIT5, BIT6, BIT7, BIT8
TAGS = [MTAG_HWCONFIG]
@@ -40,23 +75,25 @@ class sgx_check(BaseModule):
def is_supported(self):
sgx_cpu_support = False
for tid in range(self.cs.msr.get_cpu_thread_count()):
status = self.helper.set_affinity(tid)
if status == -1:
if self.logger.VERBOSE:
self.logger.log("[*] Failed to set affinity to CPU{:d}".format(tid))
(_, r_ebx, _, _) = self.cs.cpu.cpuid(0x07, 0x00)
if (r_ebx & BIT2):
if self.logger.VERBOSE: self.logger.log("[*] CPU{:d}: does support SGX".format(tid))
sgx_cpu_support = True
else:
if self.logger.VERBOSE: self.logger.log("[*]CPU{:d}: does not support SGX".format(tid))
if self.cs.helper.is_efi():
self.logger.log_important('Currently this module cannot run within the EFI Shell. Exiting.')
else:
for tid in range(self.cs.msr.get_cpu_thread_count()):
status = self.helper.set_affinity(tid)
if status == -1:
self.logger.verbose_log("[*] Failed to set affinity to CPU{:d}".format(tid))
(_, r_ebx, _, _) = self.cs.cpu.cpuid(0x07, 0x00)
if (r_ebx & BIT2):
self.logger.verbose_log("[*] CPU{:d}: does support SGX".format(tid))
sgx_cpu_support = True
else:
self.logger.verbose_log("[*]CPU{:d}: does not support SGX".format(tid))
self.logger.log_important('SGX not supported. Skipping module.')
if not sgx_cpu_support:
self.res = ModuleResult.NOTAPPLICABLE
return sgx_cpu_support
def check_sgx_config(self):
self.logger.start_test("Check SGX feature support")
self.logger.log("[*] Test if CPU has support for SGX")
sgx_ok = False
@@ -69,20 +106,20 @@ class sgx_check(BaseModule):
if bios_feature_control_enable:
self.logger.log_good("Intel SGX is Enabled in BIOS")
else:
self.logger.log_warning( "Intel SGX is not enabled in BIOS" )
self.logger.log_important("Intel SGX is not enabled in BIOS")
self.res = ModuleResult.WARNING
self.logger.log("\n[*] Verifying IA32_FEATURE_CONTROL MSR is locked")
locked = True
for tid in range(self.cs.msr.get_cpu_thread_count()):
feature_cntl_lock = self.cs.get_control('Ia32FeatureControlLock', tid)
if self.logger.VERBOSE: self.logger.log("[*] cpu{:d}: IA32_Feature_Control Lock = {:d}".format(tid, feature_cntl_lock))
self.logger.verbose_log("[*] cpu{:d}: IA32_Feature_Control Lock = {:d}".format(tid, feature_cntl_lock))
if 0 == feature_cntl_lock:
locked = False
if locked:
self.logger.log_good("IA32_Feature_Control locked")
else:
self.logger.log_failed("IA32_Feature_Control is unlocked")
self.logger.log_bad("IA32_Feature_Control is unlocked")
self.res = ModuleResult.FAILED
# Verify that Protected Memory Range (PRM) is supported, MSR IA32_MTRRCAP (FEh) [12]=1
@@ -92,14 +129,14 @@ class sgx_check(BaseModule):
for tid in range(self.cs.msr.get_cpu_thread_count()):
mtrrcap = self.cs.read_register_field('MTRRCAP', 'PRMRR', False, tid)
if (0 == mtrrcap):
if self.logger.VERBOSE: self.logger.log("[*] CPU{:d} Protected Memory Range configuration is not supported".format(tid))
self.logger.verbose_log("[*] CPU{:d} Protected Memory Range configuration is not supported".format(tid))
else:
prmrr_enable = True
if self.logger.VERBOSE: self.logger.log("[*] CPU{:d} Protected Memory Range configuration is supported".format(tid))
self.logger.verbose_log("[*] CPU{:d} Protected Memory Range configuration is supported".format(tid))
if prmrr_enable:
self.logger.log_good( "Protected Memory Range configuration is supported" )
self.logger.log_good("Protected Memory Range configuration is supported")
else:
self.logger.log_failed( "Protected Memory Range configuration is not supported" )
self.logger.log_bad("Protected Memory Range configuration is not supported")
self.res - ModuleResult.FAILED
# Check PRMRR configurations on each core.
@@ -171,10 +208,10 @@ class sgx_check(BaseModule):
(prmrr_base_memtype != prmrr_base_memtype_new)):
prmrr_uniform = False
if not prmrr_uniform:
self.logger.log_failed( "PRMRR config is not uniform across all CPUs" )
self.logger.log_bad("PRMRR config is not uniform across all CPUs")
self.res = ModuleResult.FAILED
else:
self.logger.log_good( "PRMRR config is uniform across all CPUs" )
self.logger.log_good("PRMRR config is uniform across all CPUs")
prmrr_configs = []
# NB: BWG Provides only a list of 4 possible values, see item 5, section 2.1. So values e.g. 0x050 are prhibited, report error.
config_support = False
@@ -211,24 +248,24 @@ class sgx_check(BaseModule):
self.logger.log("[*] Verifying PRMR memory type is valid")
self.logger.log("[*] PRMRR memory type : 0x{:X}".format(prmrr_base_memtype))
if prmrr_base_memtype == 0x6:
self.logger.log_good( "PRMRR memory type is WB as expected" )
self.logger.log_good("PRMRR memory type is WB as expected")
else:
self.logger.log_failed( "Unexpected PRMRR memory type (not WB)" )
self.logger.log_bad("Unexpected PRMRR memory type (not WB)")
self.res = ModuleResult.FAILED
self.logger.log("[*] PRMRR mask address: 0x{:012X}".format(prmrr_mask))
self.logger.log("[*] Verifying PRMR address are valid")
self.logger.log("[*] PRMRR uncore mask valid: 0x{:d}".format(prmrr_uncore_mask_vld))
if prmrr_mask_vld == 0x1:
self.logger.log_good( "Mcheck marked PRMRR address as valid" )
self.logger.log_good("Mcheck marked PRMRR address as valid")
else:
self.logger.log_failed( "Mcheck marked PRMRR address as invalid" )
self.logger.log_bad("Mcheck marked PRMRR address as invalid")
self.res = ModuleResult.FAILED
self.logger.log("[*] Verifying if PRMR mask register is locked")
self.logger.log("[*] PRMRR mask lock: 0x{:X}".format(prmrr_mask_lock))
if prmrr_locked:
self.logger.log_good( "PRMRR MASK register is locked" )
self.logger.log_good("PRMRR MASK register is locked")
else:
self.logger.log_failed( "PRMRR MASK register is not locked" )
self.logger.log_bad("PRMRR MASK register is not locked")
self.res = ModuleResult.FAILED
if check_uncore_vals:
self.logger.log("[*] PRMRR uncore base address: 0x{:012X}".format(prmrr_uncore_base))
@@ -236,16 +273,16 @@ class sgx_check(BaseModule):
self.logger.log("[*] Verifying PRMR uncore address are valid")
self.logger.log("[*] PRMRR uncore mask valid: 0x{:X}".format(prmrr_uncore_mask_vld))
if prmrr_uncore_mask_vld == 0x1:
self.logger.log_good( "Mcheck marked uncore PRMRR address as valid" )
self.logger.log_good("Mcheck marked uncore PRMRR address as valid")
else:
self.logger.log_failed( "Mcheck marked uncore PRMRR address as invalid" )
self.logger.log_bad("Mcheck marked uncore PRMRR address as invalid")
self.res = ModuleResult.FAILED
self.logger.log("[*] Verifying if PRMR uncore mask register is locked")
self.logger.log("[*] PRMRR uncore mask lock: 0x{:X}".format(prmrr_uncore_mask_lock))
if prmrr_uncore_mask_lock == 0x1:
self.logger.log_good( "PMRR uncore MASK register is locked" )
self.logger.log_good("PMRR uncore MASK register is locked")
else:
self.logger.log_failed( "PMRR uncore MASK register is not locked" )
self.logger.log_bad("PMRR uncore MASK register is not locked")
self.res = ModuleResult.FAILED
if bios_feature_control_enable and locked:
@@ -255,23 +292,23 @@ class sgx_check(BaseModule):
for tid in range(self.cs.msr.get_cpu_thread_count()):
status = self.helper.set_affinity(tid)
if status == -1:
if self.logger.VERBOSE: self.logger.log("[*] Failed to set affinity to CPU{:d}".format(tid))
self.logger.verbose_log("[*] Failed to set affinity to CPU{:d}".format(tid))
(r_eax, r_ebx, r_ecx, r_edx) = self.cs.cpu.cpuid(0x012, 0x00)
if (r_eax & BIT0):
if self.logger.VERBOSE: self.logger.log("[*] CPU{:d} SGX-1 instructions are supported".format(tid))
self.logger.verbose_log("[*] CPU{:d} SGX-1 instructions are supported".format(tid))
sgx1_instr_support = True
else:
if self.logger.VERBOSE: self.logger.log("[*] CPU{:d} SGX-1 instructions are not supported".format(tid))
self.logger.verbose_log("[*] CPU{:d} SGX-1 instructions are not supported".format(tid))
if (r_eax & BIT1):
if self.logger.VERBOSE: self.logger.log("[*] CPU{:d} SGX-2 instructions are supported".format(tid))
self.logger.verbose_log("[*] CPU{:d} SGX-2 instructions are supported".format(tid))
sgx2_instr_support = True
else:
if self.logger.VERBOSE: self.logger.log("[*] CPU{:d} SGX-2 instructions are not supported".format(tid))
self.logger.verbose_log("[*] CPU{:d} SGX-2 instructions are not supported".format(tid))
if sgx1_instr_support:
self.logger.log_good("Intel SGX instructions are supported and available to use")
sgx_ok = True
else:
self.logger.log_failed("Intel SGX instructions are not supported on system")
self.logger.log_bad("Intel SGX instructions are not supported on system")
sgx_ok = False
if sgx2_instr_support:
self.logger.log("[*] SGX-2 instructions are supported")
@@ -284,11 +321,11 @@ class sgx_check(BaseModule):
if sgx_ok and prmrr_enable and prmrr_uniform:
self.logger.log_good("Intel SGX is available to use")
elif (not sgx_ok) and (not bios_feature_control_enable) and prmrr_enable and prmrr_uniform:
self.logger.log_warning("Intel SGX instructions disabled by firmware")
self.logger.log_important("Intel SGX instructions disabled by firmware")
if self.res == ModuleResult.PASSED:
self.res = ModuleResult.WARNING
else:
self.logger.log_failed("Intel SGX is not available to use")
self.logger.log_bad("Intel SGX is not available to use")
self.res = ModuleResult.FAILED
if self.cs.is_register_defined('BIOS_SE_SVN') and self.cs.is_register_defined('BIOS_SE_SVN_STATUS'):
@@ -312,40 +349,34 @@ class sgx_check(BaseModule):
self.logger.log("[*] Lock : {:d}".format(debug_lock))
if (1 == sgx_debug_status):
self.logger.log_failed("SGX debug mode is enabled")
self.logger.log_bad("SGX debug mode is enabled")
self.res = ModuleResult.FAILED
else:
self.logger.log_good("SGX debug mode is disabled")
if (0 == debug_enable):
self.logger.log_good("Silicon debug features are disabled")
else:
self.logger.log_failed("Silicon debug features are not disabled")
self.logger.log_bad("Silicon debug features are not disabled")
self.res = ModuleResult.FAILED
if (0 == debug_enable) and (1==sgx_debug_status):
self.logger.log_failed("Enabling sgx_debug without enabling debug mode in msr IA32_DEBUG_INTERFACE is not a valid configuration")
self.logger.log_bad("Enabling sgx_debug without enabling debug mode in msr IA32_DEBUG_INTERFACE is not a valid configuration")
self.res = ModuleResult.FAILED
if (1 == debug_lock):
self.logger.log_good("Silicon debug Feature Control register is locked")
else:
self.logger.log_failed("Silicon debug Feature Control register is not locked")
self.logger.log_bad("Silicon debug Feature Control register is not locked")
self.res = ModuleResult.FAILED
return self.res
def run(self, module_argv):
if self.cs.helper.is_efi():
self.logger.error( 'Currently this module cannot run within the EFI Shell. Exiting.' )
return ModuleResult.SKIPPED
self.logger.start_test("Check SGX feature support")
self.res = self.check_sgx_config()
if self.res == ModuleResult.PASSED:
self.logger.log_passed('All SGX checks passed')
elif self.res == ModuleResult.WARNING:
self.logger.log_warning('One or more SGX checks detected a warning')
else:
self.res = self.check_sgx_config()
if self.res == ModuleResult.PASSED:
self.logger.log_passed_check('All SGX checks passed')
elif self.res == ModuleResult.WARNING:
self.logger.log_warn_check('One or more SGX checks detected a warning')
elif self.res == ModuleResult.SKIPPED:
self.logger.log_skipped_check('SGX test is being skipped')
elif self.res == ModuleResult.NOTAPPLICABLE:
self.logger.log_not_applicable_check('SGX test is being skipped')
else:
self.logger.log_failed_check('One or more SGX checks failed')
return self.res
self.logger.log_failed('One or more SGX checks failed')
return self.res