Version 1.2.3

- new VMM hypercall interface support (Xen and HyperV hypercall formats)
- Windows only
- new paging hierarchy dump/parsing (paging HAL component and
chipsec_util cpu pt)
- new EPT paging hierarchy dump/parsing (chipsec_util vmm ept)
- new VT-d paging hierarchy dump/parsing (chipsec_util iommu pt)
- new support of Embedded Controller (EC) access (ec HAL component and
chipsec_util ec)
- new support of TPM 1.2 access (tpm HAL component)
- new support of Message Bus access on Atom SoC (msgbus HAL component
and chipsec_util msgbus) - Linux only
- parsing RAW UEFI images
- updated smbus and SPD HAL components to use XML config
- merged cpuid into cpu HAL component (use chipsec_util cpu cpuid)
- new module: tools.vmm.vbox.vbox_crash_apicbase
- udated modules: common.bios_ts, common.uefi.s3bootscript, remap
- added template config file smm_config.ini for tools.smm.smm_ptr SMI
fuzzer
- added template config file te.cfg for tools.secureboot.te tool
This commit is contained in:
c7zero
2016-06-30 23:06:41 -07:00
parent c681defd37
commit dabccd36c0
41 changed files with 2895 additions and 590 deletions
+38 -23
View File
@@ -1,6 +1,6 @@
#!/usr/local/bin/python
#CHIPSEC: Platform Security Assessment Framework
#Copyright (c) 2010-2015, Intel Corporation
#Copyright (c) 2010-2016, Intel Corporation
#
#This program is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public License
@@ -18,8 +18,8 @@
#Contact information:
#chipsec@intel.com
#
# -------------------------------------------------------------------------------
#
@@ -46,9 +46,8 @@ from chipsec.hal.physmem import Memory
from chipsec.hal.msr import Msr
from chipsec.hal.ucode import Ucode
from chipsec.hal.io import PortIO
#from chipsec.hal.cr import CrRegs
from chipsec.hal.cpuid import CpuID
#from chipsec.hal.mmio import *
#from chipsec.hal.cpuid import CpuID
from chipsec.hal.msgbus import MsgBus
import chipsec.hal.cpu
import chipsec.hal.mmio as mmio
@@ -65,8 +64,6 @@ import traceback
#try: import importlib
#except ImportError: _importlib = False
#
class RegisterType:
PCICFG = 'pcicfg'
@@ -75,6 +72,7 @@ class RegisterType:
MSR = 'msr'
PORTIO = 'io'
IOBAR = 'iobar'
MSGBUS = 'msgbus'
##################################################################################
@@ -94,6 +92,7 @@ CHIPSET_ID_QRK = 8
CHIPSET_ID_AVN = 9
CHIPSET_ID_HSX = 10
CHIPSET_ID_SKL = 11
CHIPSET_ID_BSW = 12
CHIPSET_CODE_COMMON = 'COMMON'
CHIPSET_CODE_UNKNOWN = ''
@@ -109,10 +108,11 @@ CHIPSET_CODE_QRK = 'QRK'
CHIPSET_CODE_AVN = 'AVN'
CHIPSET_CODE_HSX = 'HSX'
CHIPSET_CODE_SKL = 'SKL'
CHIPSET_CODE_BSW = 'BSW'
CHIPSET_FAMILY_XEON = [CHIPSET_ID_JKT,CHIPSET_ID_IVT,CHIPSET_ID_HSX]
CHIPSET_FAMILY_CORE = [CHIPSET_ID_SNB,CHIPSET_ID_IVB,CHIPSET_ID_HSW,CHIPSET_ID_BDW,CHIPSET_ID_SKL]
CHIPSET_FAMILY_ATOM = [CHIPSET_ID_BYT,CHIPSET_ID_AVN]
CHIPSET_FAMILY_ATOM = [CHIPSET_ID_BYT,CHIPSET_ID_AVN,CHIPSET_CODE_BSW]
CHIPSET_FAMILY_QUARK = [CHIPSET_ID_QRK]
@@ -150,8 +150,8 @@ Chipset_Dictionary = {
0x0A08 : {'name' : 'Haswell', 'id' : CHIPSET_ID_HSW , 'code' : CHIPSET_CODE_HSW, 'longname' : '4th Generation Core Processor (Haswell U/Y)' },
# 5th Generation Core Processor Family (Broadwell)
0x1600 : {'name' : 'Broadwell', 'id' : CHIPSET_ID_BDW , 'code' : 'BDW', 'longname' : 'Desktop 5th Generation Core Processor (Broadwell CPU / Wildcat Point PCH)' },
0x1604 : {'name' : 'Broadwell', 'id' : CHIPSET_ID_BDW , 'code' : 'BDW', 'longname' : 'Mobile 5th Generation Core Processor (Broadwell M/H / Wildcat Point PCH)' },
0x1600 : {'name' : 'Broadwell', 'id' : CHIPSET_ID_BDW , 'code' : CHIPSET_CODE_BDW, 'longname' : 'Desktop 5th Generation Core Processor (Broadwell CPU / Wildcat Point PCH)' },
0x1604 : {'name' : 'Broadwell', 'id' : CHIPSET_ID_BDW , 'code' : CHIPSET_CODE_BDW, 'longname' : 'Mobile 5th Generation Core Processor (Broadwell M/H / Wildcat Point PCH)' },
# 6th Generation Core Processor Family (Skylake)
0x1904 : {'name' : 'Skylake', 'id' : CHIPSET_ID_SKL , 'code' : CHIPSET_CODE_SKL, 'longname' : 'Mobile 6th Generation Core Processor (Skylake U)' },
@@ -213,7 +213,6 @@ class DeviceNotFoundError (RuntimeError):
class Chipset:
def __init__(self, helper=None):
if logger().VERBOSE: logger().log("[Chipset] __init__")
if helper is None:
self.helper = OsHelper()
else:
@@ -237,7 +236,8 @@ class Chipset:
self.io = PortIO ( self )
self.cpu = chipsec.hal.cpu.CPU( self )
#self.cr = CrRegs ( self )
self.cpuid = CpuID ( self )
#self.cpuid = CpuID ( self )
self.msgbus = MsgBus ( self )
#
# All HAL components which use above 'basic primitive' HAL components
# should be instantiated in modules/utilcmd with an instance of chipset
@@ -273,6 +273,7 @@ class Chipset:
self.code = data_dict['code'].lower()
self.longname = data_dict['longname']
self.id = data_dict['id']
else:
_unknown_platform = True
self.longname = 'UnknownPlatform'
@@ -512,8 +513,11 @@ def read_register( _cs, reg_name, cpu_thread=0 ):
size = int(reg['size'],16)
reg_value = _cs.io._read_port( port, size )
elif RegisterType.IOBAR == rtype:
iobar = chipsec.hal.iobar.iobar( _cs )
reg_value = iobar.read_IO_BAR_reg( reg['bar'], int(reg['offset'],16), int(reg['size'],16) )
_iobar = chipsec.hal.iobar.iobar( _cs )
reg_value = _iobar.read_IO_BAR_reg( reg['bar'], int(reg['offset'],16), int(reg['size'],16) )
elif RegisterType.MSGBUS == rtype:
reg_value = _cs.msgbus.message_reg_read( int(reg['port'],16), int(reg['offset'],16) )
return reg_value
def write_register( _cs, reg_name, reg_value, cpu_thread=0 ):
@@ -539,13 +543,15 @@ def write_register( _cs, reg_name, reg_value, cpu_thread=0 ):
eax = (reg_value & 0xFFFFFFFF)
edx = ((reg_value >> 32) & 0xFFFFFFFF)
_cs.msr.write_msr( cpu_thread, int(reg['msr'],16), eax, edx )
elif RegisterType.PORT == rtype:
elif RegisterType.PORTIO == rtype:
port = int(reg['port'],16)
size = int(reg['size'],16)
_cs.io._write_port( port, reg_value, size )
elif RegisterType.IOBAR == rtype:
iobar = chipsec.hal.iobar( _cs )
iobar.write_IO_BAR_reg( reg['bar'], int(reg['offset'],16), reg_value )
_iobar = chipsec.hal.iobar.iobar( _cs )
_iobar.write_IO_BAR_reg( reg['bar'], int(reg['offset'],16), int(reg['size'],16), reg_value )
elif RegisterType.MSGBUS == rtype:
_cs.msgbus.message_reg_write( int(reg['port'],16), int(reg['offset'],16), reg_value )
def read_register_dict( _cs, reg_name):
reg_value = read_register( _cs, reg_name)
@@ -568,21 +574,22 @@ def get_register_field( _cs, reg_name, reg_value, field_name, preserve_field_pos
if preserve_field_position: return reg_value & (field_mask << field_bit)
else: return (reg_value >> field_bit) & field_mask
def set_register_field( _cs, reg_name, reg_value, field_name, field_value ):
def set_register_field( _cs, reg_name, reg_value, field_name, field_value, preserve_field_position=False ):
field_attrs = get_register_def( _cs, reg_name )['FIELDS'][field_name]
field_bit = int(field_attrs['bit'])
field_mask = (1 << int(field_attrs['size'])) - 1
reg_value &= ~(field_mask << field_bit)
reg_value |= ((field_value & field_mask) << field_bit)
reg_value &= ~(field_mask << field_bit) # keep other fields
if preserve_field_position: reg_value |= (field_value & (field_mask << field_bit))
else: reg_value |= ((field_value & field_mask) << field_bit)
return reg_value
def read_register_field( _cs, reg_name, field_name, preserve_field_position=False, cpu_thread=0 ):
reg_value = read_register( _cs, reg_name )
return get_register_field( _cs, reg_name, reg_value, field_name, preserve_field_position )
def write_register_field( _cs, reg_name, field_name, field_value, cpu_thread=0 ):
def write_register_field( _cs, reg_name, field_name, field_value, preserve_field_position=False, cpu_thread=0 ):
reg_value = read_register( _cs, reg_name, cpu_thread )
reg_value_new = set_register_field( _cs, reg_name, reg_value, field_name, field_value )
reg_value_new = set_register_field( _cs, reg_name, reg_value, field_name, field_value, preserve_field_position )
#logger().log("set register %s (0x%x) field %s = 0x%x ==> 0x%x" % (reg_name, reg_value, field_name, field_value, reg_value_new))
return write_register( _cs, reg_name, reg_value_new, cpu_thread )
@@ -632,6 +639,8 @@ def print_register( _cs, reg_name, reg_val ):
reg_str = "[*] %s = %s << %s (I/O port 0x%X)" % (reg_name, reg_val_str, reg['desc'], int(reg['port'],16))
elif RegisterType.IOBAR == rtype:
reg_str = "[*] %s = %s << %s (I/O %s + 0x%X)" % (reg_name, reg_val_str, reg['desc'], reg['bar'], int(reg['offset'],16))
elif RegisterType.MSGBUS == rtype:
reg_str = "[*] %s = %s << %s (msgbus port 0x%X, off 0x%X)" % (reg_name, reg_val_str, reg['desc'], int(reg['port'],16), int(reg['offset'],16))
reg_str += _register_fields_str( reg, reg_val )
logger().log( reg_str )
@@ -653,6 +662,12 @@ def set_control( _cs, control_name, control_value, cpu_thread=0 ):
field = control['field']
return chipsec.chipset.write_register_field( _cs, reg, field, control_value, cpu_thread )
def is_control_defined( _cs, control_name ):
try:
return (_cs.Cfg.CONTROLS[ control_name ] is not None)
except KeyError:
return False
_chipset = None
+24 -3
View File
@@ -1,6 +1,6 @@
#!/usr/local/bin/python
#CHIPSEC: Platform Security Assessment Framework
#Copyright (c) 2010-2015, Intel Corporation
#Copyright (c) 2010-2016, Intel Corporation
#
#This program is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public License
@@ -32,6 +32,7 @@
# __chipsec/defines.py__ - common defines
__version__ = '1.0'
import struct
BIT0 = 0x0001
BIT1 = 0x0002
@@ -98,10 +99,15 @@ BIT61 = 0x2000000000000000
BIT62 = 0x4000000000000000
BIT63 = 0x8000000000000000
BOUNDARY_1KB = 0x400
BOUNDARY_2KB = 0x800
BOUNDARY_4KB = 0x1000
BOUNDARY_1MB = 0x100000
BOUNDARY_2MB = 0x200000
BOUNDARY_4MB = 0x400000
BOUNDARY_8MB = 0x800000
BOUNDARY_16MB = 0x1000000
BOUNDARY_32MB = 0x2000000
BOUNDARY_64MB = 0x4000000
BOUNDARY_128MB = 0x8000000
BOUNDARY_256MB = 0x10000000
@@ -117,7 +123,13 @@ ALIGNED_64MB = 0x3FFFFFF
ALIGNED_128MB = 0x7FFFFFF
ALIGNED_256MB = 0xFFFFFFF
def scan_single_bit_mask(self,mask):
MASK_8b = 0xFF
MASK_16b = 0xFFFF
MASK_32b = 0xFFFFFFFF
MASK_64b = 0xFFFFFFFFFFFFFFFF
def scan_single_bit_mask(mask):
for bit in range(0,7):
if mask>>bit == 1:
return bit
@@ -129,3 +141,12 @@ COMPRESSION_TYPE_NONE = 0
COMPRESSION_TYPE_TIANO = 1
COMPRESSION_TYPE_LZMA = 2
COMPRESSION_TYPES = [COMPRESSION_TYPE_NONE, COMPRESSION_TYPE_TIANO, COMPRESSION_TYPE_LZMA]
def DB(val):
return struct.pack('<B', val)
def DW(value):
return struct.pack('<H', val)
def DD(val):
return struct.pack('<L', val)
def DQ(val):
return struct.pack('<Q', val)
+75 -69
View File
@@ -18,8 +18,8 @@
#Contact information:
#chipsec@intel.com
#
# -------------------------------------------------------------------------------
@@ -38,7 +38,7 @@ __version__ = '0.1'
import struct
import sys
from collections import defaultdict
from collections import defaultdict
from collections import namedtuple
from chipsec.logger import *
@@ -111,6 +111,8 @@ ACPI_TABLE_SIG_PCCT = 'PCCT'
ACPI_TABLE_SIG_MSDM = 'MSDM'
ACPI_TABLE_SIG_BATB = 'BATB'
ACPI_TABLE_SIG_BGRT = 'BGRT'
ACPI_TABLE_SIG_LPIT = 'LPIT'
ACPI_TABLE_SIG_ASPT = 'ASPT'
ACPI_TABLES = {
ACPI_TABLE_SIG_ROOT: chipsec.hal.acpi_tables.ACPI_TABLE,
@@ -148,7 +150,9 @@ ACPI_TABLES = {
ACPI_TABLE_SIG_PCCT: chipsec.hal.acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_MSDM: chipsec.hal.acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_BATB: chipsec.hal.acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_BGRT: chipsec.hal.acpi_tables.ACPI_TABLE
ACPI_TABLE_SIG_BGRT: chipsec.hal.acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_LPIT: chipsec.hal.acpi_tables.ACPI_TABLE,
ACPI_TABLE_SIG_ASPT: chipsec.hal.acpi_tables.ACPI_TABLE
}
########################################################################################################
@@ -222,13 +226,13 @@ class ACPI:
rsdp_buf = self.cs.mem.read_physical_mem( rsdp_pa, ACPI_RSDP_EXT_SIZE)
rsdp = RSDP(rsdp_buf)
return rsdp
#
# Check RSDP in Extended BIOS Data Area
#
def _find_RSDP_in_EBDA(self):
rsdp_pa = None
rsdp = None
def _find_RSDP_in_EBDA(self):
rsdp_pa = None
rsdp = None
if logger().HAL: logger().log( "[acpi] searching RSDP in EBDA.." )
ebda_ptr_addr = 0x40E
ebda_addr = struct.unpack('<H', self.cs.mem.read_physical_mem( ebda_ptr_addr, 2 ))[0] << 4
@@ -239,57 +243,57 @@ class ACPI:
rsdp_pa = ebda_addr + pos
rsdp = self.read_RSDP(rsdp_pa)
if rsdp.is_RSDP_valid():
logger().log( "[acpi] found RSDP in EBDA at: 0x%016X" % rsdp_pa )
if logger().HAL: logger().log( "[acpi] found RSDP in EBDA at: 0x%016X" % rsdp_pa )
else:
rsdp_pa = None
return rsdp, rsdp_pa
return rsdp, rsdp_pa
#
# Search RSDP in legacy BIOS E/F segments (0xE0000 - 0xFFFFF)
#
def _find_RSDP_in_legacy_BIOS_segments(self):
rsdp_pa = None
rsdp = None
def _find_RSDP_in_legacy_BIOS_segments(self):
rsdp_pa = None
rsdp = None
membuf = self.cs.mem.read_physical_mem( 0xE0000, 0x20000 )
pos = membuf.find( ACPI_RSDP_SIG )
if -1 != pos:
rsdp_pa = 0xE0000 + pos
rsdp = self.read_RSDP(rsdp_pa)
if rsdp.is_RSDP_valid():
logger().log( "[acpi] found RSDP in BIOS E/F segments: 0x%016X" % rsdp_pa )
if logger().HAL: logger().log( "[acpi] found RSDP in BIOS E/F segments: 0x%016X" % rsdp_pa )
else:
rsdp_pa = None
return rsdp, rsdp_pa
return rsdp, rsdp_pa
#
# Search for RSDP in the EFI memory (EFI Configuration Table)
#
def _find_RSDP_in_EFI_config_table(self):
rsdp_pa = None
rsdp = None
def _find_RSDP_in_EFI_config_table(self):
rsdp_pa = None
rsdp = None
if logger().HAL: logger().log( '[acpi] searching RSDP pointers in EFI Configuration Table..' )
(isFound,ect_pa,ect,ect_buf) = self.uefi.find_EFI_Configuration_Table()
if isFound:
if RSDP_GUID_ACPI2_0 in ect.VendorTables:
rsdp_pa = ect.VendorTables[ RSDP_GUID_ACPI2_0 ]
logger().log( '[acpi] ACPI 2.0+ RSDP {%s} in EFI Config Table: 0x%016X' % (RSDP_GUID_ACPI2_0,rsdp_pa) )
if logger().HAL: logger().log( '[acpi] ACPI 2.0+ RSDP {%s} in EFI Config Table: 0x%016X' % (RSDP_GUID_ACPI2_0,rsdp_pa) )
elif RSDP_GUID_ACPI1_0 in ect.VendorTables:
rsdp_pa = ect.VendorTables[ RSDP_GUID_ACPI1_0 ]
logger().log( '[acpi] ACPI 1.0 RSDP {%s} in EFI Config Table: 0x%016X' % (RSDP_GUID_ACPI1_0,rsdp_pa) )
if logger().HAL: logger().log( '[acpi] ACPI 1.0 RSDP {%s} in EFI Config Table: 0x%016X' % (RSDP_GUID_ACPI1_0,rsdp_pa) )
rsdp = self.read_RSDP(rsdp_pa)
if rsdp.is_RSDP_valid():
logger().log( "[acpi] found RSDP in EFI Config Table: 0x%016X" % rsdp_pa )
if logger().HAL: logger().log( "[acpi] found RSDP in EFI Config Table: 0x%016X" % rsdp_pa )
else:
rsdp_pa = None
return rsdp, rsdp_pa
#
# Search for RSDP in all EFI memory
#
def _find_RSDP_in_EFI(self):
rsdp_pa = None
rsdp = None
return rsdp, rsdp_pa
#
# Search for RSDP in all EFI memory
#
def _find_RSDP_in_EFI(self):
rsdp_pa = None
rsdp = None
if logger().HAL: logger().log( "[acpi] searching all EFI memory for RSDP (this may take a minute).." )
CHUNK_SZ = 1024*1024 # 1MB
(smram_base, smram_limit, smram_size) = self.cs.cpu.get_SMRAM()
@@ -302,29 +306,31 @@ class ACPI:
if logger().VERBOSE: logger().log( "[acpi] found '%s' signature at 0x%016X. Checking if valid RSDP.." % (ACPI_RSDP_SIG,rsdp_pa) )
rsdp = self.read_RSDP(rsdp_pa)
if rsdp.is_RSDP_valid():
logger().log( "[acpi] found RSDP in EFI memory: 0x%016X" % rsdp_pa )
if logger().HAL: logger().log( "[acpi] found RSDP in EFI memory: 0x%016X" % rsdp_pa )
break
pa -= CHUNK_SZ
return rsdp, rsdp_pa
return rsdp, rsdp_pa
#
# Searches for Root System Description Pointer (RSDP) in various locations for legacy/EFI systems
#
def find_RSDP( self ):
rsdp, rsdp_pa = self._find_RSDP_in_EBDA()
if rsdp_pa is None:
rsdp, rsdp_pa = self._find_RSDP_in_legacy_BIOS_segments()
if rsdp_pa is None:
rsdp, rsdp_pa = self._find_RSDP_in_EFI_config_table()
if rsdp_pa is None:
rsdp, rsdp_pa = self._find_RSDP_in_EFI()
if rsdp_pa is not None: logger().log( rsdp )
rsdp, rsdp_pa = self._find_RSDP_in_EBDA()
if rsdp_pa is None:
rsdp, rsdp_pa = self._find_RSDP_in_legacy_BIOS_segments()
if rsdp_pa is None:
rsdp, rsdp_pa = self._find_RSDP_in_EFI_config_table()
if rsdp_pa is None:
rsdp, rsdp_pa = self._find_RSDP_in_EFI()
if rsdp_pa is not None:
if logger().HAL: logger().log( rsdp )
return (rsdp_pa, rsdp)
#
# Retrieves System Description Table (RSDT or XSDT) either from RSDP or using OS API
#
@@ -339,12 +345,12 @@ class ACPI:
is_xsdt = True
else:
return (False,None,None,None)
logger().log( "[acpi] found %s at PA: 0x%016X" % ('XSDT' if is_xsdt else 'RSDT', sdt_pa) )
if logger().HAL: logger().log( "[acpi] found %s at PA: 0x%016X" % ('XSDT' if is_xsdt else 'RSDT', sdt_pa) )
sdt_header_buf = self.cs.mem.read_physical_mem( sdt_pa, ACPI_TABLE_HEADER_SIZE )
sdt_header = self._parse_table_header( sdt_header_buf )
sdt_buf = self.cs.mem.read_physical_mem( sdt_pa, sdt_header.Length )
else:
logger().log( "[acpi] reading RSDT/XSDT using OS API.." )
if logger().HAL: logger().log( "[acpi] reading RSDT/XSDT using OS API.." )
(sdt_buf, is_xsdt) = self.cs.helper.get_ACPI_SDT()
sdt_header = self._parse_table_header( sdt_buf[ :ACPI_TABLE_HEADER_SIZE] )
@@ -363,14 +369,14 @@ class ACPI:
(is_xsdt,sdt_pa,sdt,sdt_header) = self.get_SDT()
# cache RSDT/XSDT in the list of ACPI tables
if sdt_pa is not None: self.tableList[ sdt_header.Signature ].append(sdt_pa)
if sdt_pa is not None: self.tableList[ sdt_header.Signature ].append(sdt_pa)
# cache other ACPI tables in the list
for a in sdt.Entries:
_sig = self.cs.mem.read_physical_mem( a, ACPI_TABLE_SIG_SIZE )
if _sig not in ACPI_TABLES.keys():
logger().warn( 'Unknown ACPI table signature: %s' % _sig )
self.tableList[ _sig ].append(a)
self.tableList[ _sig ].append(a)
return self.tableList
@@ -389,46 +395,46 @@ class ACPI:
else:
if logger().HAL: logger().log( "[acpi] Found the following ACPI tables:" )
for tableName in sorted(self.tableList.keys()):
logger().log( " - %s: %s" % (tableName, ", ".join([("0x%016X" % addr) for addr in self.tableList[tableName]])) )
logger().log( " - %s: %s" % (tableName, ", ".join([("0x%016X" % addr) for addr in self.tableList[tableName]])) )
#
# Retrieves contents of ACPI table from memory or from file
#
def get_parse_ACPI_table( self, name, isfile = False ):
acpi_tables = self.get_ACPI_table(name, isfile)
return [self._parse_table( name, table_header_blob, table_blob ) for (table_header_blob, table_blob) in acpi_tables if table_header_blob is not None]
acpi_tables = self.get_ACPI_table(name, isfile)
return [self._parse_table( name, table_header_blob, table_blob ) for (table_header_blob, table_blob) in acpi_tables if table_header_blob is not None]
def get_ACPI_table( self, name, isfile = False ):
acpi_tables_data = []
if isfile:
acpi_tables_data.append(chipsec.file.read_file( name ))
else:
for table_address in self.tableList[name]:
acpi_tables_data = []
if isfile:
acpi_tables_data.append(chipsec.file.read_file( name ))
else:
for table_address in self.tableList[name]:
t_data = None
t_size = self.cs.mem.read_physical_mem_dword( table_address + 4 )
t_data = self.cs.mem.read_physical_mem( table_address, t_size )
acpi_tables_data.append( t_data )
acpi_tables = []
for t_data in acpi_tables_data:
acpi_tables_data.append( t_data )
acpi_tables = []
for t_data in acpi_tables_data:
table_header_blob = None
table_blob = None
if t_data is not None:
if t_data is not None:
table_header_blob = t_data[ : ACPI_TABLE_HEADER_SIZE ]
table_blob = t_data[ ACPI_TABLE_HEADER_SIZE : ]
acpi_tables.append((table_header_blob, table_blob))
return acpi_tables
acpi_tables.append((table_header_blob, table_blob))
return acpi_tables
#
# Dumps contents of ACPI table
#
def dump_ACPI_table( self, name, isfile = False ):
acpi_tables = self.get_parse_ACPI_table( name, isfile )
for acpi_table in acpi_tables:
acpi_tables = self.get_parse_ACPI_table( name, isfile )
for acpi_table in acpi_tables:
(table_header,table,table_header_blob,table_blob) = acpi_table
logger().log( "==================================================================" )
logger().log( "ACPI Table: %s" % name )
+30 -8
View File
@@ -1,6 +1,6 @@
#!/usr/local/bin/python
#CHIPSEC: Platform Security Assessment Framework
#Copyright (c) 2010-2015, Intel Corporation
#Copyright (c) 2010-2016, Intel Corporation
#
#This program is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public License
@@ -60,18 +60,18 @@ class CPU:
def read_cr(self, cpu_thread_id, cr_number ):
value = self.helper.read_cr( cpu_thread_id, cr_number )
if logger().HAL: logger().log( "[cpu%d] read CR%d: value = 0x%08X" % (cpu_thread_id, cr_number, value) )
if logger().VERBOSE: logger().log( "[cpu%d] read CR%d: value = 0x%08X" % (cpu_thread_id, cr_number, value) )
return value
def write_cr(self, cpu_thread_id, cr_number, value ):
if logger().HAL: logger().log( "[cpu%d] write CR%d: value = 0x%08X" % (cpu_thread_id, cr_number, value) )
if logger().VERBOSE: logger().log( "[cpu%d] write CR%d: value = 0x%08X" % (cpu_thread_id, cr_number, value) )
status = self.helper.write_cr( cpu_thread_id, cr_number, value )
return status
def cpuid(self, eax, ecx ):
if logger().HAL: logger().log( "[cpu] CPUID in : EAX=0x%08X, ECX=0x%08X" % (eax, ecx) )
(eax, ebx, ecx, edx) = self.cs.cpuid.cpuid( eax, ecx )
if logger().HAL: logger().log( "[cpu] CPUID out: EAX=0x%08X, EBX=0x%08X, ECX=0x%08X, EDX=0x%08X" % (eax, ebx, ecx, edx) )
if logger().VERBOSE: logger().log( "[cpu] CPUID in : EAX=0x%08X, ECX=0x%08X" % (eax, ecx) )
(eax, ebx, ecx, edx) = self.helper.cpuid( eax, ecx )
if logger().VERBOSE: logger().log( "[cpu] CPUID out: EAX=0x%08X, EBX=0x%08X, ECX=0x%08X, EDX=0x%08X" % (eax, ebx, ecx, edx) )
return (eax, ebx, ecx, edx)
# Using CPUID we can determine if Hyper-Threading is enabled in the CPU
@@ -99,7 +99,7 @@ class CPU:
def get_number_threads_from_APIC_table(self):
_acpi = chipsec.hal.acpi.ACPI( self.cs )
dACPIID = {}
(table_header,APIC_object,table_header_blob,table_blob) = _acpi.get_parse_ACPI_table( chipsec.hal.acpi.ACPI_TABLE_SIG_APIC )[0]
(table_header,APIC_object,table_header_blob,table_blob) = _acpi.get_parse_ACPI_table( chipsec.hal.acpi.ACPI_TABLE_SIG_APIC )
for structure in APIC_object.apic_structs:
if 0x00 == structure.Type:
if dACPIID.has_key( structure.APICID ) == False:
@@ -153,7 +153,9 @@ class CPU:
# Returns SMRAM base from either SMRR MSR or TSEG PCIe config register
#
def get_SMRAM( self ):
smram_base = None
smram_base = None
smram_limit = None
smram_size = 0
try:
(smram_base, smram_limit, smram_size) = self.get_SMRR_SMRAM()
except:
@@ -175,3 +177,23 @@ class CPU:
smrr = chipsec.chipset.get_register_field( self.cs, 'MTRRCAP', mtrrcap_msr_reg, 'SMRR' )
return (1 == smrr)
#
# Dump CPU page tables at specified physical base of paging-directory hierarchy (CR3)
#
def dump_page_tables( self, cr3, pt_fname=None ):
_orig_logname = logger().LOG_FILE_NAME
hpt = chipsec.hal.paging.c_ia32e_page_tables( self.cs )
if logger().HAL: logger().log( '[cpu] dumping paging hierarchy at physical base (CR3) = 0x%08X...' % cr3 )
if pt_fname is None: pt_fname = ('pt_%08X' % cr3)
logger().set_log_file( pt_fname )
hpt.read_pt_and_show_status( pt_fname, 'PT', cr3 )
logger().set_log_file( _orig_logname )
if hpt.failure: logger().error( 'could not dump page tables' )
def dump_page_tables_all( self ):
for tid in range(self.cs.msr.get_cpu_thread_count()):
cr3 = self.read_cr( tid, 3 )
if logger().HAL: logger().log( '[cpu%d] found paging hierarchy base (CR3): 0x%08X' % (tid,cr3) )
self.dump_page_tables( cr3 )
+178
View File
@@ -0,0 +1,178 @@
#!/usr/local/bin/python
#CHIPSEC: Platform Security Assessment Framework
#Copyright (c) 2010-2016, Intel Corporation
#
#This program is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public License
#as published by the Free Software Foundation; Version 2.
#
#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with this program; if not, write to the Free Software
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
#Contact information:
#chipsec@intel.com
#
# -------------------------------------------------------------------------------
#
# CHIPSEC: Platform Hardware Security Assessment Framework
#
# -------------------------------------------------------------------------------
"""
Access to Embedded Controller (EC)
Usage:
>>> write_command( command )
>>> write_data( data )
>>> read_data()
>>> read_memory( offset )
>>> write_memory( offset, data )
>>> read_memory_extended( word_offset )
>>> write_memory_extended( word_offset, data )
>>> read_range( start_offset, size )
>>> write_range( start_offset, buffer )
"""
from chipsec.logger import *
from chipsec.cfg.common import *
#
# Embedded Controller ACPI ports
#
IO_PORT_EC_DATA = 0x62
IO_PORT_EC_COMMAND = 0x66
IO_PORT_EC_STATUS = 0x66
IO_PORT_EC_INDEX = 0x380
IO_PORT_EC_INDEX_ADDRH = (IO_PORT_EC_INDEX + 0x1)
IO_PORT_EC_INDEX_ADDRL = (IO_PORT_EC_INDEX + 0x2)
IO_PORT_EC_INDEX_DATA = (IO_PORT_EC_INDEX + 0x3)
EC_STS_OBF = 0x01 # EC Output buffer full
EC_STS_IBF = 0x02 # EC Input buffer empty
#
# Embedded Controller ACPI commands
# These commands should be submitted to EC ACPI I/O ports
#
EC_COMMAND_ACPI_READ = 0x080 # Read EC ACPI memory
EC_COMMAND_ACPI_WRITE = 0x081 # Write EC ACPI memory
EC_COMMAND_ACPI_LOCK = 0x082 # Lock EC for burst use
EC_COMMAND_ACPI_UNLOCK = 0x083 # Unlock EC from burst use
EC_COMMAND_ACPI_QUERY = 0x084 # Query EC event
EC_COMMAND_ACPI_READ_EXT = 0x0F0 # Read EC ACPI extended memory
EC_COMMAND_ACPI_WRITE_EXT = 0x0F1 # Write EC ACPI extended memory
class EC:
def __init__( self, cs ):
self.cs = cs
#
# EC ACPI memory access
#
# Wait for EC input buffer empty
def _wait_ec_inbuf_empty( self ):
to = 1000
while (self.cs.io.read_port_byte(IO_PORT_EC_STATUS) & EC_STS_IBF) and to: to = to - 1
return True
# Wait for EC output buffer full
def _wait_ec_outbuf_full( self ):
to = 1000
while not ( self.cs.io.read_port_byte(IO_PORT_EC_STATUS) & EC_STS_OBF ) and to: to = to - 1
return True
def write_command( self, command ):
self._wait_ec_inbuf_empty()
return self.cs.io.write_port_byte( IO_PORT_EC_COMMAND, command )
def write_data( self, data ):
self._wait_ec_inbuf_empty()
return self.cs.io.write_port_byte( IO_PORT_EC_DATA, data )
def read_data( self ):
if not self._wait_ec_outbuf_full(): return None
return self.cs.io.read_port_byte( IO_PORT_EC_DATA )
def read_memory( self, offset ):
self.write_command( EC_COMMAND_ACPI_READ )
self.write_data( offset )
return self.read_data()
def write_memory( self, offset, data ):
self.write_command( EC_COMMAND_ACPI_WRITE )
self.write_data( offset )
return self.write_data( data )
def read_memory_extended( self, word_offset ):
self.write_command( EC_COMMAND_ACPI_READ )
self.write_data( 0x2 )
self.write_data( word_offset & 0xFF )
self.write_command( EC_COMMAND_ACPI_READ_EXT )
self.write_data( word_offset >> 8 )
return self.read_data()
def write_memory_extended( self, word_offset, data ):
self.write_command( EC_COMMAND_ACPI_WRITE )
self.write_data( 0x2 )
self.write_data( word_offset & 0xFF )
self.write_command( EC_COMMAND_ACPI_WRITE_EXT )
self.write_data( word_offset >> 8 )
return self.write_data( data )
def read_range( self, start_offset, size ):
buffer = [chr(0xFF)]*size
#self.write_command( EC_COMMAND_ACPI_READ )
for i in range (size):
#self.write_data( start_offset + i )
#buffer[i] = chr( self.read_data() )
if start_offset + i < 0x100:
buffer[i] = chr( self.read_memory( start_offset + i ) )
else:
buffer[i] = chr( self.read_memory_extended( start_offset + i ) )
if logger().VERBOSE:
logger().log( "[ec] read EC memory from offset %X size %X:" % (start_offset, size) )
print_buffer( buffer )
return buffer
def write_range( self, start_offset, buffer ):
size = len(buffer)
for i in range(size):
self.write_memory( start_offset + i, ord(buffer[i]) )
if logger().VERBOSE:
logger().log( "[ec] write EC memory to offset %X size %X:" % (start_offset, size) )
print_buffer( buffer )
return True
#
# EC Intex I/O access
#
def read_idx( self, offset ):
self.cs.io.write_port_byte( IO_PORT_EC_INDEX_ADDRL, offset & 0xFF )
self.cs.io.write_port_byte( IO_PORT_EC_INDEX_ADDRH, (offset>>8) & 0xFF )
value = self.cs.io.read_port_byte( IO_PORT_EC_INDEX_DATA )
if logger().HAL: logger().log( "[ec] index read: offset 0x%02X > 0x%02X:" % (offset, value) )
return value
def write_idx( self, offset, value ):
if logger().HAL: logger().log( "[ec] index write: offset 0x%02X < 0x%02X:" % (offset, value) )
self.cs.io.write_port_byte( IO_PORT_EC_INDEX_ADDRL, offset & 0xFF )
self.cs.io.write_port_byte( IO_PORT_EC_INDEX_ADDRH, (offset>>8) & 0xFF )
self.cs.io.write_port_byte( IO_PORT_EC_INDEX_DATA, value & 0xFF )
return True
+2 -1
View File
@@ -1,5 +1,5 @@
#CHIPSEC: Platform Security Assessment Framework
#Copyright (c) 2010-2015, Intel Corporation
#Copyright (c) 2010-2016, Intel Corporation
#
#This program is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public License
@@ -26,6 +26,7 @@ Base for HAL Components
import chipsec.logger
import chipsec.chipset
import chipsec.defines
class HALBase( object ):
def __init__(self):
+3 -3
View File
@@ -1,6 +1,6 @@
#!/usr/local/bin/python
#CHIPSEC: Platform Security Assessment Framework
#Copyright (c) 2010-2015, Intel Corporation
#Copyright (c) 2010-2016, Intel Corporation
#
#This program is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public License
@@ -104,7 +104,7 @@ class iobar:
# Read I/O register from I/O range defined by I/O BAR name
#
def read_IO_BAR_reg( self, bar_name, offset, size ):
if logger().VERBOSE: logger().log('[iobar] read %s + %u (%u)' % (bar_name, offset, size))
if logger().VERBOSE: logger().log('[iobar] read %s + 0x%X (%u)' % (bar_name, offset, size))
(bar_base,bar_size) = self.get_IO_BAR_base_address( bar_name )
io_port = bar_base + offset
if offset > bar_size: logger().warn( 'offset 0x%X is ouside %s size (0x%X)' % (offset,bar_name,size) )
@@ -117,7 +117,7 @@ class iobar:
#
def write_IO_BAR_reg( self, bar_name, offset, size, value ):
(bar_base,bar_size) = self.get_IO_BAR_base_address( bar_name )
if logger().VERBOSE: logger().log( '[iobar] write IO reg 0x%X from %s (0x%X): 0x%X' % (bar_name,bar_base,offset,value) )
if logger().VERBOSE: logger().log( '[iobar] write %s + 0x%X (%u): 0x%X' % (bar_name,offset,size,value) )
io_port = bar_base + offset
if offset > bar_size: logger().warn( 'offset 0x%X is ouside %s size (0x%X)' % (offset,bar_name,size) )
return self.cs.io._write_port( io_port, value, size )
+35 -2
View File
@@ -1,6 +1,6 @@
#!/usr/local/bin/python
#CHIPSEC: Platform Security Assessment Framework
#Copyright (c) 2010-2015, Intel Corporation
#Copyright (c) 2010-2016, Intel Corporation
#
#This program is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public License
@@ -30,6 +30,7 @@ from chipsec.logger import *
import chipsec.hal.iobar
import chipsec.hal.mmio
import chipsec.hal.paging
IOMMU_ENGINE_DEFAULT = 'VTD'
IOMMU_ENGINE_GFX = 'GFXVTD'
@@ -90,7 +91,7 @@ class iommu:
logger().log( "Engine enabled : %d" % enabled )
te = self.is_IOMMU_Translation_Enabled( iommu_engine )
logger().log( "Translation enabled : %d" % te )
rtaddr_rta = chipsec.chipset.read_register_field( self.cs, vtd + '_RTADDR', 'RTA' )
rtaddr_rta = chipsec.chipset.read_register_field( self.cs, vtd + '_RTADDR', 'RTA', True )
logger().log( "Root Table Address : 0x%016X" % rtaddr_rta )
irta = chipsec.chipset.read_register_field( self.cs, vtd + '_IRTA', 'IRTA' )
logger().log( "Interrupt Remapping Table : 0x%016X" % irta )
@@ -116,6 +117,38 @@ class iommu:
chipsec.chipset.print_register( self.cs, vtd + '_ECAP', ecap_reg )
logger().log( '' )
def dump_IOMMU_page_tables( self, iommu_engine ):
vtd = IOMMU_ENGINES[ iommu_engine ]
te = self.is_IOMMU_Translation_Enabled( iommu_engine )
logger().log( "[iommu] Translation enabled : %d" % te )
rtaddr_reg = chipsec.chipset.read_register( self.cs, vtd + '_RTADDR' )
rtaddr_rta = chipsec.chipset.get_register_field( self.cs, vtd + '_RTADDR', rtaddr_reg, 'RTA', True )
rtaddr_rtt = chipsec.chipset.get_register_field( self.cs, vtd + '_RTADDR', rtaddr_reg, 'RTT' )
#rtaddr_rta = chipsec.chipset.read_register_field( self.cs, vtd + '_RTADDR', 'RTA', True )
#rtaddr_rtt = chipsec.chipset.read_register_field( self.cs, vtd + '_RTADDR', 'RTT' )
logger().log( "[iommu] Root Table Address/Type: 0x%016X/%X" % (rtaddr_rta,rtaddr_rtt) )
ecap_reg = chipsec.chipset.read_register( self.cs, vtd + '_ECAP' )
ecs = chipsec.chipset.get_register_field( self.cs, vtd + '_ECAP', ecap_reg, 'ECS' )
pasid = chipsec.chipset.get_register_field( self.cs, vtd + '_ECAP', ecap_reg, 'PASID' )
logger().log( '[iommu] PASID / ECS : %x / %x' % (pasid, ecs))
if 0xFFFFFFFFFFFFFFFF != rtaddr_reg:
if te:
logger().log( '[iommu] dumping VT-d page table hierarchy at 0x%016X (vtd_context_%08x)..' % (rtaddr_rta,rtaddr_rta) )
paging_vtd = chipsec.hal.paging.c_vtd_page_tables( self.cs )
paging_vtd.read_vtd_context('vtd_context_%08x' % rtaddr_rta, rtaddr_rta)
logger().log( '[iommu] total VTd domains: %d' % len(paging_vtd.domains))
for domain in paging_vtd.domains:
paging_vtd.read_pt_and_show_status('vtd_%08x' % domain, 'VTd', domain)
#if paging_vtd.failure: logger().error( "couldn't dump VT-d page tables" )
else:
logger().log( "[iommu] translation via VT-d engine '%s' is not enabled" % iommu_engine )
else:
logger().error( "cannot access VT-d registers" )
def dump_IOMMU_status( self, iommu_engine ):
vtd = IOMMU_ENGINES[ iommu_engine ]
logger().log( "==================================================================" )
+204
View File
@@ -0,0 +1,204 @@
#!/usr/local/bin/python
#CHIPSEC: Platform Security Assessment Framework
#Copyright (c) 2010-2016, Intel Corporation
#
#This program is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public License
#as published by the Free Software Foundation; Version 2.
#
#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with this program; if not, write to the Free Software
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
#Contact information:
#chipsec@intel.com
#
# -------------------------------------------------------------------------------
#
# CHIPSEC: Platform Hardware Security Assessment Framework
# (c) 2010-2016 Intel Corporation
#
# -------------------------------------------------------------------------------
"""
Access to message bus (IOSF sideband) interface registers on Intel SoCs
References:
- Intel(R) Atom(TM) Processor E3800 Product Family Datasheet, May 2016, Revision 4.0
http://www.intel.com/content/www/us/en/embedded/products/bay-trail/atom-e3800-family-datasheet.html (sections 3.6 and 13.4.6 - 13.4.8)
- Intel(R) Atom(TM) Processor D2000 and N2000 Series Datasheet, Volume 2, July 2012, Revision 003
http://www.intel.com/content/dam/doc/datasheet/atom-d2000-n2000-vol-2-datasheet.pdf (section 1.10.2)
usage:
>>> msgbus_reg_read( port, register )
>>> msgbus_reg_write( port, register, data )
>>> msgbus_read_message( port, register, opcode )
>>> msgbus_write_message( port, register, opcode, data )
>>> msgbus_send_message( port, register, opcode, data )
"""
__version__ = '1.0'
import struct
import sys
import os.path
import chipsec.chipset
from chipsec.logger import logger
#
# IOSF Message bus message opcodes
# Reference: http://lxr.free-electrons.com/source/arch/x86/include/asm/iosf_mbi.h
#
class MessageBusOpcode:
MB_OPCODE_MMIO_READ = 0x00
MB_OPCODE_MMIO_WRITE = 0x01
MB_OPCODE_IO_READ = 0x02
MB_OPCODE_IO_WRITE = 0x03
MB_OPCODE_CFG_READ = 0x04
MB_OPCODE_CFG_WRITE = 0x05
MB_OPCODE_CR_READ = 0x06
MB_OPCODE_CR_WRITE = 0x07
MB_OPCODE_REG_READ = 0x10
MB_OPCODE_REG_WRITE = 0x11
MB_OPCODE_ESRAM_READ = 0x12
MB_OPCODE_ESRAM_WRITE = 0x13
#
# IOSF Message bus unit ports
# Reference: http://lxr.free-electrons.com/source/arch/x86/include/asm/iosf_mbi.h
# @TODO: move these to per-platform XML config?
#
class MessageBusPort_Atom:
UNIT_AUNIT = 0x00
UNIT_SMC = 0x01
UNIT_CPU = 0x02
UNIT_BUNIT = 0x03
UNIT_PMC = 0x04
UNIT_GFX = 0x06
UNIT_SMI = 0x0C
UNIT_USB = 0x43
UNIT_SATA = 0xA3
UNIT_PCIE = 0xA6
class MessageBusPort_Quark:
UNIT_HBA = 0x00
UNIT_HB = 0x03
UNIT_RMU = 0x04
UNIT_MM = 0x05
UNIT_SOC = 0x31
def MB_MESSAGE_MCR( _cs, port, reg, opcode ):
mcr = 0x0
mcr = chipsec.chipset.set_register_field( _cs, 'MSG_CTRL_REG', mcr, 'MESSAGE_WR_BYTE_ENABLES', 0xF )
mcr = chipsec.chipset.set_register_field( _cs, 'MSG_CTRL_REG', mcr, 'MESSAGE_ADDRESS_OFFSET', reg )
mcr = chipsec.chipset.set_register_field( _cs, 'MSG_CTRL_REG', mcr, 'MESSAGE_PORT', port )
mcr = chipsec.chipset.set_register_field( _cs, 'MSG_CTRL_REG', mcr, 'MESSAGE_OPCODE', opcode )
return mcr
def MB_MESSAGE_MCRX( _cs, reg ):
mcrx = 0x0
mcrx = chipsec.chipset.set_register_field( _cs, 'MSG_CTRL_REG_EXT', mcrx, 'MESSAGE_ADDRESS_OFFSET_EXT', reg, preserve_field_position=True )
return mcrx
def MB_MESSAGE_MDR( _cs, data ):
mdr = 0x0
mdr = chipsec.chipset.set_register_field( _cs, 'MSG_DATA_REG', mdr, 'MESSAGE_DATA', data )
return mdr
class MsgBusRuntimeError (RuntimeError):
pass
class MsgBus:
def __init__( self, cs ):
self.helper = cs.helper
self.cs = cs
#
# Issues read message on the message bus
#
def msgbus_read_message( self, port, register, opcode ):
mcr = MB_MESSAGE_MCR (self.cs, port, register, opcode)
mcrx = MB_MESSAGE_MCRX(self.cs, register)
if logger().HAL: logger().log( "[msgbus] read: port 0x%02X + 0x%08X (op = 0x%02X)" % (port, register, opcode) )
if logger().VERBOSE: logger().log( "[msgbus] MCR = 0x%08X, MCRX = 0x%08X" % (mcr, mcrx) )
mdr_out = self.helper.msgbus_send_read_message( mcr, mcrx )
if logger().HAL: logger().log( "[msgbus] < 0x%08X" % mdr_out )
return mdr_out
#
# Issues write message on the message bus
#
def msgbus_write_message( self, port, register, opcode, data ):
mcr = MB_MESSAGE_MCR (self.cs, port, register, opcode)
mcrx = MB_MESSAGE_MCRX(self.cs, register)
mdr = MB_MESSAGE_MDR (self.cs, data)
if logger().HAL: logger().log( "[msgbus] write: port 0x%02X + 0x%08X (op = 0x%02X) < data = 0x%08X" % (port, register, opcode, data) )
if logger().VERBOSE: logger().log( "[msgbus] MCR = 0x%08X, MCRX = 0x%08X, MDR = 0x%08X" % (mcr, mcrx, mdr) )
return self.helper.msgbus_send_write_message( mcr, mcrx, mdr )
#
# Issues generic message on the message bus
#
def msgbus_send_message( self, port, register, opcode, data=None ):
mcr = MB_MESSAGE_MCR(self.cs, port, register, opcode)
mcrx = MB_MESSAGE_MCRX(self.cs, register)
mdr = None if data is None else MB_MESSAGE_MDR(self.cs, data)
if logger().HAL:
logger().log( "[msgbus] message: port 0x%02X + 0x%08X (op = 0x%02X)" % (port, register, opcode) )
if data is not None: logger().log( "[msgbus] data = 0x%08X" % data )
if logger().VERBOSE: logger().log( "[msgbus] MCR = 0x%08X, MCRX = 0x%08X, MDR = 0x%08X" % (mcr, mcrx, mdr) )
mdr_out = self.helper.msgbus_send_message( mcr, mcrx, mdr )
if logger().HAL: logger().log( "[msgbus] < 0x%08X" % mdr_out )
return mdr_out
#
# Message bus register read/write
#
def msgbus_reg_read( self, port, register ):
return self.msgbus_read_message( port, register, MessageBusOpcode.MB_OPCODE_REG_READ )
def msgbus_reg_write( self, port, register, data ):
return self.msgbus_write_message( port, register, MessageBusOpcode.MB_OPCODE_REG_WRITE, data )
"""
# py implementation of msgbus -- doesn't seem to work properly becaise it's not atomic
def msgbus_send_message( self, port, register, opcode, data=None ):
if logger().HAL:
logger().log( "[msgbus] message - port: 0x%02X, reg: 0x%08X (op: 0x%02X)" % (port, register, opcode) )
if data is not None: logger().log( "[msgbus] message - data: 0x%08X" % data )
if (register & 0xFFFFFF00):
# write extended register address (bits [31:08]) to Message Control Register Extension (MCRX)
chipsec.chipset.write_register_field( self.cs, 'MSG_CTRL_REG_EXT', 'MESSAGE_ADDRESS_OFFSET_EXT', register, preserve_field_position=True )
res = None
# write data to Message Data Register (MDR) for writes
if data is not None: chipsec.chipset.write_register( self.cs, 'MSG_DATA_REG', data )
# write message (byte enables, address bits [08:00], port and opcode) to Message Control Register (MCR)
chipsec.chipset.write_register( self.cs, 'MSG_CTRL_REG', MB_MESSAGE(self.cs, port, register, opcode) )
# read the data from Message Data Register (MDR) for reads
if data is None: res = chipsec.chipset.read_register( self.cs, 'MSG_DATA_REG' )
return res
"""
+604
View File
@@ -0,0 +1,604 @@
#!/usr/local/bin/python
#CHIPSEC: Platform Security Assessment Framework
#Copyright (c) 2010-2016, Intel Corporation
#
#This program is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public License
#as published by the Free Software Foundation; Version 2.
#
#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with this program; if not, write to the Free Software
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
#Contact information:
#chipsec@intel.com
#
# -------------------------------------------------------------------------------
#
# CHIPSEC: Platform Hardware Security Assessment Framework
# (c) 2010-2016 Intel Corporation
#
# -------------------------------------------------------------------------------
## \addtogroup hal
# chipsec/hal/paging.py
# ====================
# x64/IA-64 Paging functionality including x86 page tables, Extended Page Tables (EPT) and VT-d page tables
#
# ~~~
import os
import sys
import time
import struct
import chipsec.defines
from chipsec.logger import logger
ADDR_MASK = chipsec.defines.MASK_64b
MAXPHYADDR = 0x000FFFFFFFFFF000
SIZE_4KB = chipsec.defines.BOUNDARY_4KB
SIZE_2MB = chipsec.defines.BOUNDARY_2MB
SIZE_1GB = chipsec.defines.BOUNDARY_1GB
ADDR_4KB = 0xFFFFFFFFFFFFF000 & MAXPHYADDR
ADDR_2MB = 0xFFFFFFFFFFE00000 & MAXPHYADDR
ADDR_1GB = 0xFFFFFFFFC0000000 & MAXPHYADDR
class InvalidMemoryAddress (RuntimeError):
pass
class c_translation(object):
def __init__(self):
self.translation = {}
def is_translation_exist(self, addr, mask, size):
return ((addr & mask) in self.translation) and (self.translation[addr & mask]['size'] == size)
def get_translation(self, addr):
if len(self.translation) == 0:
return addr
ADDR_4KB = 0xFFFFFFFFFFFFF000
ADDR_2MB = 0xFFFFFFFFFFE00000
ADDR_1GB = 0xFFFFFFFFC0000000
if self.is_translation_exist(addr, ADDR_4KB, '4KB'):
result = self.translation[addr & ADDR_4KB]['addr'] | (addr & ~ADDR_4KB)
elif self.is_translation_exist(addr, ADDR_2MB, '2MB'):
result = self.translation[addr & ADDR_2MB]['addr'] | (addr & ~ADDR_2MB)
elif self.is_translation_exist(addr, ADDR_1GB, '1GB'):
result = self.translation[addr & ADDR_1GB]['addr'] | (addr & ~ADDR_1GB)
else:
result = None
return result
def get_pages_by_physaddr(self, addr):
SIZE = {'4KB': ADDR_4KB, '2MB': ADDR_2MB, '1GB': ADDR_1GB}
result = []
for i in self.translation.keys():
page = self.translation[i]
size = SIZE[page['size']]
if (page['addr'] & size) == (addr & size):
result.append(page)
return result
def get_address_space(self):
total = 0
mem_range = self.get_mem_range()
for i in mem_range:
total += i[1] - i[0]
return total
def get_mem_range(self, noattr=False):
SIZE = {'4KB': SIZE_4KB, '2MB': SIZE_2MB, '1GB': SIZE_1GB}
perm = {self.translation[a]['addr']:self.translation[a] for a in self.translation.keys()}
mem_range = []
for addr in sorted(perm.keys()):
attr = perm[addr]['attr']
size = SIZE[perm[addr]['size']]
if noattr:
attr = ''
if (mem_range == []):
mem_range += [[addr, addr + size, attr]]
elif (mem_range[-1][1] == addr) and (mem_range[-1][2] == attr):
mem_range[-1][1] += size
else:
mem_range += [[addr, addr + size, attr]]
return mem_range
def add_page(self, virt, phys, size, attr):
if size not in ['4KB', '2MB', '4MB', '1GB']:
raise Exception('Invalid size!')
self.translation[virt] = {'addr': phys, 'size': size, 'attr': attr}
return
def del_page(self, addr):
if addr in self.translation:
del self.translation[addr]
return
def expand_pages(self, exp_size):
SIZE = {'1GB': '2MB', '2MB': '4KB'}
for virt in self.translation.keys():
size = self.translation[virt]['size']
attr = self.translation[virt]['attr']
phys = self.translation[virt]['addr']
pgsize = (1<<12) if size == '2MB' else (1<<20)
if size == exp_size:
for i in xrange(512):
self.add_page(virt + i*pgsize, phys + i*pgsize, SIZE[exp_size], attr)
return
class c_reverse_translation(object):
def __init__(self, translation):
self.reverse_translation = {}
for virt in translation.keys():
phys = translation[virt]['addr']
size = translation[virt]['size']
attr = translation[virt]['attr']
if phys not in self.reverse_translation:
self.reverse_translation[phys] = []
self.reverse_translation[phys].append({'addr': virt, 'size': size, 'attr': attr})
def get_reverse_translation(self, addr):
ADDR_4KB = 0xFFFFFFFFFFFFF000
addr &= ADDR_4KB
return self.reverse_translation[addr] if addr in self.reverse_translation else []
class c_paging_memory_access(object):
def __init__(self, cs):
self.cs = cs
def readmem(self, name, addr, size = 4096):
return self.cs.mem.read_physical_mem(addr, size)
class c_paging_with_2nd_level_translation(c_paging_memory_access):
def __init__(self, cs):
c_paging_memory_access.__init__(self, cs)
self.translation_level2 = c_translation()
def readmem(self, name, addr, size = 4096):
phys = self.translation_level2.get_translation(addr)
if phys != addr:
name += '_0x%08x' % phys
return super(c_paging_with_2nd_level_translation, self).readmem(name, phys, size)
class c_paging(c_paging_with_2nd_level_translation, c_translation):
def __init__(self, cs):
c_paging_with_2nd_level_translation.__init__(self, cs)
c_translation.__init__(self)
# variables
self.did = 0
self.out = sys.stdout
self.name = ''
self.pt = {}
self.pointer = None
self.failure = False
self.canonical_msb = 47
def get_canonical(self, va):
canonical_mask = (ADDR_MASK << (self.canonical_msb + 1)) & ADDR_MASK
canonical_va = (va | canonical_mask) if (va >> self.canonical_msb) & 0x1 else va
return canonical_va
def get_field(self, entry, desc):
return (entry >> desc['offset']) & desc['mask']
def set_field(self, value, desc):
return (value & desc['mask']) << desc['offset']
def read_entries(self, info, addr, size = 8):
data = self.readmem('%s_%s_0x%08x' % (self.name, info, addr), addr, 0x1000)
entries = struct.unpack('<512Q', data)
if size == 16:
entries = [[entries[i], entries[i + 1]] for i in xrange(0, 512, 2)]
same = True
for i in xrange(len(entries)):
same = same and (entries[0] == entries[i])
if same:
return [entries[0]]
return entries
def print_info(self, name):
logger().log('\n %s physical address ranges:' % name)
mem_range = self.get_mem_range()
for index in xrange(len(mem_range)):
i = mem_range[index]
logger().log(' 0x%013x - 0x%013x %8d %s' % (i[0], i[1] - 1, (i[1] - i[0]) >> 12, i[2]))
logger().log('\n %s pages:' % name)
for i in sorted(self.pt.keys()):
logger().log(' 0x%013x %s' % (i, self.pt[i]))
logger().log('\n')
logger().log(' %s size: %d KB, address space: %d MB' % (name, len(self.pt.keys()) * 4, self.get_address_space() >> 20))
return
def check_misconfig(self, addr_list):
addr_list = [x & MAXPHYADDR for x in addr_list]
mem_range = self.get_mem_range()
for addr in addr_list:
for i in xrange(len(mem_range)):
if (mem_range[i][0] <= addr) and (addr < mem_range[i][1]):
print ('*** WARNING: PAGE TABLES MISCONFIGURATION 0x%013x' % addr)
return
def save_configuration(self, path):
cfg = open(path, 'w')
try:
cfg.write(str(self.translation_level2.translation) + '\n')
cfg.write(str(self.translation) + '\n')
cfg.write(str(self.pt))
finally:
cfg.close()
return
def load_configuration(self, path):
cfg = open(path, 'r')
try:
self.translation_level2.translation = eval(cfg.readline())
self.translation = eval(cfg.readline())
self.pt = eval(cfg.readline())
finally:
cfg.close()
return
def read_pt_and_show_status(self, path, name, ptr):
#txt = open(path, 'w')
try:
if logger().HAL: logger().log( '[paging] reading %s page tables at 0x%016X ...' % (name, ptr) )
#self.out = txt
self.read_page_tables(ptr)
self.print_info('[paging] %s page tables' % name)
#self.out = sys.stdout
self.failure = False
if logger().HAL: logger().log( '[paging] size: %d KB, address space: %d MB' % (len(self.pt.keys()) * 4, self.get_address_space() >> 20) )
except InvalidMemoryAddress:
self.translation_level2.translation = {}
self.translation = {}
self.pt = {}
self.failure = True
logger().error( ' ERROR: Invalid %s Page Tables!' % name )
#finally:
# #txt.close()
return
class c_4level_page_tables(c_paging):
def __init__(self, cs):
c_paging.__init__(self, cs)
# constants
self.PHYSICAL_ADDR_NAME = ''
self.PML4_INDX = {'mask': 0x1FF, 'offset': 39}
self.PDPT_INDX = {'mask': 0x1FF, 'offset': 30}
self.PD_INDX = {'mask': 0x1FF, 'offset': 21}
self.PT_INDX = {'mask': 0x1FF, 'offset': 12}
self.PT_NAME = ['EPTP', 'PML4E', 'PDPTE', 'PDE', 'PTE']
self.PT_SIZE = ['', '', '1GB', '2MB', '4KB']
def get_virt_addr(self, pml4e_index, pdpte_index = 0, pde_index = 0, pte_index = 0):
ofs1 = self.set_field(pml4e_index, self.PML4_INDX)
ofs2 = self.set_field(pdpte_index, self.PDPT_INDX)
ofs3 = self.set_field(pde_index, self.PD_INDX)
ofs4 = self.set_field(pte_index, self.PT_INDX)
return (ofs1 | ofs2 | ofs3 | ofs4)
def print_entry(self, lvl, pa, va = 0, perm = ''):
canonical_va = self.get_canonical(va)
info = ' %s%6s: %013X' % (' ' *lvl, self.PT_NAME[lvl], pa)
if perm <> '':
size = self.PT_SIZE[lvl]
info += ' - %s PAGE %s' % (size, perm)
info = info.ljust(64)
if pa == va:
info += '1:1 mapping'
else:
info += '%s: %013X' % (self.PHYSICAL_ADDR_NAME, canonical_va)
self.add_page(canonical_va, pa, size, perm)
logger().log(info)
return
def read_page_tables(self, ptr):
addr = ptr & ADDR_4KB
self.pointer = addr
self.pt = {addr: 'pml4'}
self.translation = {}
self.print_entry(0, addr)
self.read_pml4(addr)
return
def read_pml4(self, addr):
pml4 = self.read_entries('pml4', addr)
for pml4e_index in xrange(len(pml4)):
pml4e = pml4[pml4e_index]
if self.is_present(pml4e):
addr = pml4e & ADDR_4KB
self.pt[addr] = 'pdpt'
self.print_entry(1, addr)
self.read_pdpt(addr, pml4e_index)
return
def read_pdpt(self, addr, pml4e_index):
pdpt = self.read_entries('pdpt', addr)
for pdpte_index in xrange(len(pdpt)):
pdpte = pdpt[pdpte_index]
if self.is_present(pdpte):
if self.is_bigpage(pdpte):
virt = self.get_virt_addr(pml4e_index, pdpte_index)
phys = pdpte & ADDR_1GB
self.print_entry(2, phys, virt, self.get_attr(pdpte))
else:
addr = pdpte & ADDR_4KB
self.pt[addr] = 'pd'
self.print_entry(2, addr)
self.read_pd(addr, pml4e_index, pdpte_index)
return
def read_pd(self, addr, pml4e_index, pdpte_index):
pd = self.read_entries('pd', addr)
for pde_index in xrange(len(pd)):
pde = pd[pde_index]
if self.is_present(pde):
if self.is_bigpage(pde):
virt = self.get_virt_addr(pml4e_index, pdpte_index, pde_index)
phys = pde & ADDR_2MB
self.print_entry(3, phys, virt, self.get_attr(pde))
else:
addr = pde & ADDR_4KB
self.pt[addr] = 'pt'
self.print_entry(3, addr)
self.read_pt(addr, pml4e_index, pdpte_index, pde_index)
return
def read_pt(self, addr, pml4e_index, pdpte_index, pde_index):
pt = self.read_entries('pt', addr)
for pte_index in xrange(len(pt)):
pte = pt[pte_index]
if self.is_present(pte):
virt = self.get_virt_addr(pml4e_index, pdpte_index, pde_index, pte_index)
phys = pte & ADDR_4KB
self.print_entry(4, phys, virt, self.get_attr(pte))
return
def read_entry_by_virt_addr(self, virt):
if self.pointer == None:
raise Exception('Page Table pointer is undefined!')
addr = self.pointer
pml4 = self.read_entries('pml4', addr)
pml4e = pml4[self.get_field(virt, self.PML4_INDX)]
if self.is_present(pml4e):
addr = pml4e & ADDR_4KB
pdpt = self.read_entries('pdpt', addr)
pdpte = pdpt[self.get_field(virt, self.PDPT_INDX)]
if self.is_present(pdpte):
if self.is_bigpage(pdpte):
addr = (pdpte & ADDR_1GB) | (virt & ~ADDR_1GB)
return {'addr': addr, 'attr': self.get_attr(pdpte), 'size': '1GB'}
else:
addr = pdpte & ADDR_4KB
pd = self.read_entries('pd', addr)
pde = pd[self.get_field(virt, self.PD_INDX)]
if self.is_present(pde):
if self.is_bigpage(pde):
addr = (pde & ADDR_2MB) | (virt & ~ADDR_2MB)
return {'addr': addr, 'attr': self.get_attr(pde), 'size': '2MB'}
else:
addr = pde & ADDR_4KB
pt = self.read_entries('pt', addr)
pte = pt[self.get_field(virt, self.PT_INDX)]
if self.is_present(pte):
addr = (pte & ADDR_4KB) | (virt & ~ADDR_4KB)
return {'addr': addr, 'attr': self.get_attr(pte), 'size': '4KB'}
return None
class c_ia32e_page_tables(c_4level_page_tables):
def __init__(self, cs):
c_4level_page_tables.__init__(self, cs)
# constants
self.PHYSICAL_ADDR_NAME = 'VA'
self.PT_NAME = ['CR3P', 'PML4E', 'PDPTE', 'PDE', 'PTE']
self.P = {'mask': 0x1, 'offset': 0}
self.RW = {'mask': 0x1, 'offset': 1}
self.US = {'mask': 0x1, 'offset': 2}
self.BIGPAGE = {'mask': 0x1, 'offset': 7}
def is_present(self, entry):
return self.get_field(entry, self.P) <> 0
def is_bigpage(self, entry):
return self.get_field(entry, self.BIGPAGE) <> 0
def get_attr(self, entry):
RW_DESC = ['R', 'W']
US_DESC = ['S', 'U']
return RW_DESC[self.get_field(entry, self.RW)] + ' ' + US_DESC[self.get_field(entry, self.US)]
class c_pae_page_tables(c_ia32e_page_tables):
def __init__(self):
c_ia32e_page_tables.__init__(self)
# constants
self.PML4_INDX = {'mask': 0x000, 'offset': 39}
self.PDPT_INDX = {'mask': 0x003, 'offset': 30}
self.PT_NAME = ['', 'CR3', 'PDPTE', 'PDE', 'PTE']
def read_page_tables(self, ptr):
addr = ptr & ADDR_4KB
self.pointer = addr
self.pt = {addr: 'pdpt'}
self.translation = {}
self.print_entry(1, addr)
self.read_pdpt(addr)
return
def read_pml4(self, addr):
raise Exception('PAE Page tables have no PML4!')
return
def read_pdpt(self, addr):
pdpt = self.read_entries('pdpt', addr)
for pdpte_index in xrange(4):
pdpte = pdpt[pdpte_index]
if self.is_present(pdpte):
if self.is_bigpage(pdpte):
virt = self.get_virt_addr(0, pdpte_index)
phys = pdpte & ADDR_1GB
self.print_entry(2, phys, virt, self.get_attr(pdpte))
else:
addr = pdpte & ADDR_4KB
self.pt[addr] = 'pd'
self.print_entry(2, addr)
self.read_pd(addr, 0, pdpte_index)
return
class c_extended_page_tables(c_4level_page_tables):
def __init__(self, cs):
c_4level_page_tables.__init__(self, cs)
# constants
self.PHYSICAL_ADDR_NAME = 'GPA'
self.XWR = {'mask': 0x7, 'offset': 0}
self.MEM_TYPE = {'mask': 0x7, 'offset': 3}
self.BIGPAGE = {'mask': 0x1, 'offset': 7}
self.canonical_msb = 63
def is_present(self, entry):
return self.get_field(entry, self.XWR) <> 0
def is_bigpage(self, entry):
return self.get_field(entry, self.BIGPAGE) <> 0
def get_attr(self, entry):
XWR_DESC = ['---', '--R', '-W-', '-WR', 'X--', 'X-R', 'XW-', 'XWR']
MEM_DESC = ['UC', 'WC', '02', '03', 'WT', 'WP', 'WB', 'UC-']
return XWR_DESC[self.get_field(entry, self.XWR)] + ' ' + MEM_DESC[self.get_field(entry, self.MEM_TYPE)]
def read_pt_and_show_status(self, path, name, ptr):
super(c_extended_page_tables, self).read_pt_and_show_status(path, name, ptr)
self.check_misconfig(self.pt)
return
def map_bigpage_1G(self, virt, i):
if self.pointer == None:
raise Exception('Page Table pointer is undefined!')
addr = self.pointer
pml4 = self.read_entries('pml4', addr)
pml4e = pml4[self.get_field(virt, self.PML4_INDX)]
if self.is_present(pml4e):
addr = pml4e & ADDR_4KB
pdpt = self.read_entries('pdpt', addr)
new_entry = struct.pack('<Q', ((pdpt[i] | 0x87) & ~ADDR_4KB) | (i << 30))
self.cs.mem.write_physical_mem(addr + i*8, 8, new_entry)
return None
class c_vtd_page_tables(c_extended_page_tables):
def __init__(self, cs):
c_extended_page_tables.__init__(self, cs)
# constants
self.DID_BUS = {'mask': 0xFF, 'offset': 8}
self.DID_DEV = {'mask': 0x1F, 'offset': 3}
self.DID_FUN = {'mask': 0x07, 'offset': 0}
self.RE_LO_P = {'mask': 0x01, 'offset': 0}
self.CE_HI_AW = {'mask': 0x07, 'offset': 0}
self.CE_HI_AVAIL = {'mask': 0x0F, 'offset': 3}
self.CE_HI_DID = {'mask': 0xFF, 'offset': 8}
self.CE_LO_P = {'mask': 0x01, 'offset': 0}
self.CE_LO_FPD = {'mask': 0x01, 'offset': 1}
self.CE_LO_T = {'mask': 0x03, 'offset': 2}
# variables
self.context = {}
self.domains = {}
self.cpt = {}
def read_vtd_context(self, path, ptr):
txt = open(path, 'w')
try:
self.out = txt
addr = ptr & ADDR_4KB
self.context = {}
self.domains = {}
self.cpt = {addr: 'root'}
self.read_re(addr)
if len(self.domains) != 0:
logger().log('[paging] VT-d domains:')
for domain in sorted(self.domains.keys()):
logger().log(' 0x%016x ' % domain)
logger().log('[paging] total VT-d domains: %d\n' % len(self.domains))
logger().log('[paging] VT-d context entries:')
for source_id in sorted(self.context.keys()):
self.print_context_entry(source_id, self.context[source_id])
logger().log('[paging] VT-d context pages:')
for i in sorted(self.cpt.keys()):
logger().log(' 0x%013x %s' % (i, self.cpt[i]))
finally:
txt.close()
return
def read_re(self, addr):
re = self.read_entries('re', addr, 16)
for ree_index in xrange(len(re)):
ree_lo = re[ree_index][0]
ree_hi = re[ree_index][1]
if self.get_field(ree_lo, self.RE_LO_P):
addr = ree_lo & ADDR_4KB
self.read_ce(addr, ree_index)
self.cpt[addr] = 'context'
return
def read_ce(self, addr, ree_index):
ce = self.read_entries('ce', addr, 16)
for cee_index in xrange(len(ce)):
cee_lo = ce[cee_index][0]
cee_hi = ce[cee_index][1]
if self.get_field(cee_lo, self.CE_LO_P):
source_id = (ree_index << 8) | cee_index
self.context[source_id] = [cee_lo, cee_hi]
if self.get_field(cee_lo, self.CE_LO_T) in (0, 1):
slptptr = cee_lo & MAXPHYADDR
self.domains[slptptr] = 1
return
def print_context_entry(self, source_id, cee):
if self.get_field(cee[0], self.CE_LO_P):
info = (
self.get_field(source_id, self.DID_BUS),
self.get_field(source_id, self.DID_DEV),
self.get_field(source_id, self.DID_FUN),
self.get_field(cee[1], self.CE_HI_DID),
self.get_field(cee[1], self.CE_HI_AVAIL),
self.get_field(cee[1], self.CE_HI_AW),
self.get_field(cee[0], self.CE_LO_T),
self.get_field(cee[0], self.CE_LO_FPD),
cee[0] & MAXPHYADDR
)
logger().log(' %02X:%02X.%X DID: %02X AVAIL: %X AW: %X T: %X FPD: %X SLPTPTR: %016X' % info)
return
def read_page_tables(self, ptr):
logger().log(' Page Tables for domain 0x%013x: ' % ptr)
super(c_vtd_page_tables, self).read_page_tables(ptr)
return
def read_pt_and_show_status(self, path, name, ptr):
super(c_vtd_page_tables, self).read_pt_and_show_status(path, name, ptr)
self.check_misconfig(self.cpt)
return
+26 -104
View File
@@ -1,6 +1,6 @@
#!/usr/local/bin/python
#CHIPSEC: Platform Security Assessment Framework
#Copyright (c) 2010-2015, Intel Corporation
#Copyright (c) 2010-2016, Intel Corporation
#
#This program is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public License
@@ -71,156 +71,78 @@ class Memory:
# Reading physical memory
def read_physical_mem( self, phys_address, length ):
if logger().VERBOSE: logger().log("[mem] 0x%016X"%phys_address)
if logger().HAL: logger().log("[mem] 0x%016X"%phys_address)
return self.helper.read_physical_mem( phys_address, length )
def read_physical_mem_dword( self, phys_address ):
out_buf = self.read_physical_mem( phys_address, 4 )
value = struct.unpack( '=I', out_buf )[0]
if logger().VERBOSE:
logger().log( '[mem] dword at PA = 0x%016X: 0x%08X' % (phys_address, value) )
if logger().HAL: logger().log( '[mem] dword at PA = 0x%016X: 0x%08X' % (phys_address, value) )
return value
def read_physical_mem_word( self, phys_address ):
out_buf = self.read_physical_mem( phys_address, 2 )
value = struct.unpack( '=H', out_buf )[0]
if logger().VERBOSE:
logger().log( '[mem] word at PA = 0x%016X: 0x%04X' % (phys_address, value) )
if logger().HAL: logger().log( '[mem] word at PA = 0x%016X: 0x%04X' % (phys_address, value) )
return value
def read_physical_mem_byte( self, phys_address ):
out_buf = self.read_physical_mem( phys_address, 1 )
value = struct.unpack( '=B', out_buf )[0]
if logger().VERBOSE:
logger().log( '[mem] byte at PA = 0x%016X: 0x%02X' % (phys_address, value) )
if logger().HAL: logger().log( '[mem] byte at PA = 0x%016X: 0x%02X' % (phys_address, value) )
return value
# Writing physical memory
def write_physical_mem( self, phys_address, length, buf ):
if logger().VERBOSE:
if logger().HAL:
logger().log( '[mem] buffer len = 0x%X to PA = 0x%016X' % (length, phys_address) )
print_buffer( buf )
return self.helper.write_physical_mem( phys_address, length, buf )
def write_physical_mem_dword( self, phys_address, dword_value ):
if logger().VERBOSE:
logger().log( '[mem] dword to PA = 0x%016X <- 0x%08X' % (phys_address, dword_value) )
if logger().HAL: logger().log( '[mem] dword to PA = 0x%016X <- 0x%08X' % (phys_address, dword_value) )
return self.write_physical_mem( phys_address, 4, struct.pack( 'I', dword_value ) )
def write_physical_mem_word( self, phys_address, word_value ):
if logger().VERBOSE:
logger().log( '[mem] word to PA = 0x%016X <- 0x%04X' % (phys_address, word_value) )
if logger().HAL: logger().log( '[mem] word to PA = 0x%016X <- 0x%04X' % (phys_address, word_value) )
return self.write_physical_mem( phys_address, 2, struct.pack( 'H', word_value ) )
def write_physical_mem_byte( self, phys_address, byte_value ):
if logger().VERBOSE:
logger().log( '[mem] byte to PA = 0x%016X <- 0x%02X' % (phys_address, byte_value) )
if logger().HAL: logger().log( '[mem] byte to PA = 0x%016X <- 0x%02X' % (phys_address, byte_value) )
return self.write_physical_mem( phys_address, 1, struct.pack( 'B', byte_value ) )
# Allocate physical memory buffer
def alloc_physical_mem( self, length, max_phys_address=0xFFFFFFFFFFFFFFFF ):
(va, pa) = self.helper.alloc_physical_mem( length, max_phys_address )
if logger().VERBOSE: logger().log( '[mem] Allocated: PA = 0x%016X, VA = 0x%016X' % (pa, va) )
if logger().HAL: logger().log( '[mem] Allocated: PA = 0x%016X, VA = 0x%016X' % (pa, va) )
return (va, pa)
def va2pa( self, va ):
(pa, error_code) = self.helper.va2pa( va )
if logger().VERBOSE: logger().log( '[mem] VA (0x%016X) -> PA (0x%016X)' % (va, pa) )
if logger().HAL: logger().log( '[mem] VA (0x%016X) -> PA (0x%016X)' % (va, pa) )
if error_code:
logger().log( '[mem] Looks like VA (0x%016X) not mapped' % (va) )
return
return pa
# Map physical address to virtual
####################################################################################
#
# DEPRECATED
# Physical memory API using 64b Physical Address split into 32b High and Low parts
#
####################################################################################
def map_io_space(self, pa, length, cache_type):
va = self.helper.map_io_space(pa, length, cache_type)
if logger().HAL: logger().log( '[mem] Mapped: PA = 0x%016X, VA = 0x%016X' % (pa, va) )
return va
def read_phys_mem_64( self, phys_address_hi, phys_address_lo, length ):
out_buf = self.helper.read_phys_mem( phys_address_hi, phys_address_lo, length )
return out_buf
# Free physical memory buffer
def read_phys_mem_dword_64(self, phys_address_hi, phys_address_lo ):
out_buf = self.read_phys_mem_64( phys_address_hi, phys_address_lo, 4 )
try:
value = struct.unpack( 'L', out_buf.raw )[0]
except:
raise MemoryAccessError, "read_phys_mem did not return hex dword"
if logger().VERBOSE:
logger().log( '[mem] dword at PA = 0x%08X_%08X: 0x%08X' % (phys_address_hi, phys_address_lo, value) )
return value
def free_physical_mem(self, pa):
self.helper.free_physical_mem(pa)
if logger().HAL: logger().log( '[mem] Deallocated : PA = 0x%016X' % pa )
return
def read_phys_mem_word_64(self, phys_address_hi, phys_address_lo ):
out_buf = self.read_phys_mem_64( phys_address_hi, phys_address_lo, 2 )
try:
value = struct.unpack( 'H', out_buf.raw )[0]
except:
raise MemoryAccessError, "read_phys_mem did not return hex word"
if logger().VERBOSE:
logger().log( '[mem] word at PA = 0x%08X_%08X: 0x%04X' % (phys_address_hi, phys_address_lo, value) )
return value
def read_phys_mem_byte_64(self, phys_address_hi, phys_address_lo ):
out_buf = self.read_phys_mem_64( phys_address_hi, phys_address_lo, 1 )
try:
value = struct.unpack( 'B', out_buf.raw )[0]
except:
raise MemoryAccessError, "read_phys_mem did not return 1 Byte"
if logger().VERBOSE:
logger().log( '[mem] byte at PA = 0x%08X_%08X: 0x%02X' % (phys_address_hi, phys_address_lo, value) )
return value
def write_phys_mem_64( self, phys_address_hi, phys_address_lo, length, buf ):
return self.helper.write_phys_mem( phys_address_hi, phys_address_lo, length, buf )
def write_phys_mem_dword_64( self, phys_address_hi, phys_address_lo, dword_value ):
if logger().VERBOSE:
logger().log( '[mem] dword to PA = 0x%08X_%08X <- 0x%08X' % (phys_address_hi, phys_address_lo, dword_value) )
return self.write_phys_mem_64( phys_address_hi, phys_address_lo, 4, struct.pack( 'I', dword_value ) )
def write_phys_mem_word_64( self, phys_address_hi, phys_address_lo, word_value ):
if logger().VERBOSE:
logger().log( '[mem] word to PA = 0x%08X_%08X <- 0x%04X' % (phys_address_hi, phys_address_lo, word_value) )
return self.write_phys_mem_64( phys_address_hi, phys_address_lo, 2, struct.pack( 'H', word_value ) )
def write_phys_mem_byte_64( self, phys_address_hi, phys_address_lo, byte_value ):
if logger().VERBOSE:
logger().log( '[mem] byte to PA = 0x%08X_%08X <- 0x%02X' % (phys_address_hi, phys_address_lo, byte_value) )
return self.write_phys_mem_64( phys_address_hi, phys_address_lo, 1, struct.pack( 'B', byte_value ) )
####################################################################################
#
# DEPRECATED
# Physical memory API using 32b Physical Address
#
####################################################################################
def read_phys_mem_byte(self, phys_address ):
return self.read_phys_mem_byte_64( 0, phys_address )
def read_phys_mem_word(self, phys_address ):
return self.read_phys_mem_word_64( 0, phys_address )
def read_phys_mem_dword(self, phys_address ):
return self.read_phys_mem_dword_64( 0, phys_address )
def read_phys_mem(self, phys_address, length ):
return self.read_phys_mem_64( 0, phys_address, length )
def write_phys_mem_byte( self, phys_address, byte_value ):
return self.write_phys_mem_byte_64( 0, phys_address, byte_value )
def write_phys_mem_word( self, phys_address, word_value ):
return self.write_phys_mem_word_64( 0, phys_address, word_value )
def write_phys_mem_dword( self, phys_address, dword_value ):
return self.write_phys_mem_dword_64( 0, phys_address, dword_value )
def write_phys_mem(self, phys_address, length, buf ):
return self.write_phys_mem_64( 0, phys_address, length, buf )
def set_mem_bit(self, addr, bit):
addr += bit >> 3
byte = self.read_physical_mem_byte(addr)
self.write_physical_mem_byte(addr, (byte | (0x1 << (bit & 0x7))))
return byte
+120 -64
View File
@@ -1,6 +1,6 @@
#!/usr/local/bin/python
#CHIPSEC: Platform Security Assessment Framework
#Copyright (c) 2010-2015, Intel Corporation
#Copyright (c) 2010-2016, Intel Corporation
#
#This program is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public License
@@ -24,7 +24,6 @@
# -------------------------------------------------------------------------------
#
# CHIPSEC: Platform Hardware Security Assessment Framework
# (c) 2010-2012 Intel Corporation
#
# -------------------------------------------------------------------------------
@@ -33,14 +32,33 @@ Access to SMBus Controller
"""
from chipsec.logger import *
#from chipsec.cfg.common import *
import chipsec.hal.iobar
SMBUS_COMMAND_QUICK = 0
SMBUS_COMMAND_BYTE = 1
SMBUS_COMMAND_BYTE_DATA = 2
SMBUS_COMMAND_WORD_DATA = 3
SMBUS_COMMAND_PROCESS_CALL = 4
SMBUS_COMMAND_BLOCK = 5
SMBUS_COMMAND_I2C_READ = 6
SMBUS_COMMAND_BLOCK_PROCESS = 7
SMBUS_POLL_COUNT = 1000
SMBUS_COMMAND_WRITE = 0
SMBUS_COMMAND_READ = 1
class SMBus:
def __init__( self, cs ):
self.cs = cs
self.iobar = chipsec.hal.iobar.iobar( self.cs )
self.smb_reg_status = 'SMBUS_HST_STS'
self.smb_reg_command = 'SMBUS_HST_CMD'
self.smb_reg_address = 'SMBUS_HST_SLVA'
self.smb_reg_control = 'SMBUS_HST_CNT'
self.smb_reg_data0 = 'SMBUS_HST_D0'
self.smb_reg_data1 = 'SMBUS_HST_D1'
def get_SMBus_Base_Address( self ):
if self.iobar.is_IO_BAR_defined( 'SMBUS_BASE' ):
@@ -66,7 +84,7 @@ class SMBus:
def is_SMBus_supported( self ):
(did,vid) = self.cs.get_DeviceVendorID( 'SMBUS' )
if logger().VERBOSE: logger().log( "[*] SMBus Controller (DID,VID) = (0x%04X,0x%04X)" % (did,vid) )
if logger().VERBOSE: logger().log( "[smbus] SMBus Controller (DID,VID) = (0x%04X,0x%04X)" % (did,vid) )
if (0x8086 == vid): return True
else:
logger().error( "Unknown SMBus Controller (DID,VID) = (0x%04X,0x%04X)" % (did,vid) )
@@ -87,82 +105,120 @@ class SMBus:
if 0 == (cmd & 0x1): chipsec.chipset.write_register( self.cs, 'SMBUS_CMD', (cmd|0x1) )
def _wait_for_cycle( self, smbus_io_base ):
# wait for cycle to complete
#while True:
for i in range(1000):
sts = self.cs.io.read_port_byte( smbus_io_base )
if (sts & 0x02): break
elif (sts & 0x04):
if logger().VERBOSE: logger().error( "SMBus cycle failed: Device error" )
elif (sts & 0x08):
if logger().VERBOSE: logger().error( "SMBus cycle failed: Bus Error" )
elif (sts & 0x10):
if logger().VERBOSE: logger().error( "SMBus cycle failed: Unknown Error" )
return ((sts & 0x02) > 0)
#
# SMBus commands
#
def _read_byte( self, smbus_io_base, target_address, offset ):
self.cs.io.write_port_byte( smbus_io_base + 0x0, 0xFF ) # Clear status bits
##self.cs.io.write_port_byte( smbus_io_base + 0x1, 0x1F )
#for i in range(100):
# self.cs.io.write_port_byte( smbus_io_base + 0x0, 0xFF ) # Clear status bits
# sts = self.cs.io.read_port_byte( smbus_io_base )
# if (0 == (sts & 0x9F)): break
#if (sts & 0x9F):
# logger().error( "SMBus is not ready for whatever reason" )
# return 0xFF
# waits for SMBus to become ready
def _is_smbus_ready( self ):
for i in range(SMBUS_POLL_COUNT):
#time.sleep( SMBUS_POLL_SLEEP_INTERVAL )
busy = chipsec.chipset.read_register_field( self.cs, self.smb_reg_status, 'BUSY' )
if 0 == busy: return True
return (0 == busy)
self.cs.io.write_port_byte( smbus_io_base + 0x4, (target_address | 0x1) ) # Byte Read from SMBus device at target_address
self.cs.io.write_port_byte( smbus_io_base + 0x3, offset ) # Byte offset
self.cs.io.write_port_byte( smbus_io_base + 0x2, 0x48 ) # Send command
# wait for cycle to complete
if not self._wait_for_cycle( smbus_io_base ): return 0xFF
# read the data
value = self.cs.io.read_port_byte( smbus_io_base + 0x5 )
# Clear status bits
self.cs.io.write_port_byte( smbus_io_base + 0x0, 0xFF )
return value
def _write_byte( self, smbus_io_base, target_address, offset, value ):
self.cs.io.write_port_byte( smbus_io_base + 0x0, 0xFF ) # Clear status bits
self.cs.io.write_port_byte( smbus_io_base + 0x4, target_address ) # Byte Write to SMBus device at target_address
self.cs.io.write_port_byte( smbus_io_base + 0x3, offset ) # Byte offset
self.cs.io.write_port_byte( smbus_io_base + 0x5, value ) # Byte data to write
self.cs.io.write_port_byte( smbus_io_base + 0x2, 0x48 ) # Send command
# wait for cycle to complete
if not self._wait_for_cycle( smbus_io_base ): return False
# Clear status bits
self.cs.io.write_port_byte( smbus_io_base + 0x0, 0xFF )
return True
# waits for SMBus transaction to complete
def _wait_for_cycle( self ):
for i in range(SMBUS_POLL_COUNT):
#time.sleep( SMBUS_POLL_SLEEP_INTERVAL )
sts = chipsec.chipset.read_register( self.cs, self.smb_reg_status )
busy = chipsec.chipset.get_register_field( self.cs, self.smb_reg_status, sts, 'BUSY' )
failed = chipsec.chipset.get_register_field( self.cs, self.smb_reg_status, sts, 'FAILED' )
if 0 == busy:
#if logger().VERBOSE:
# intr = chipsec.chipset.get_register_field( self.cs, self.smb_reg_status, sts, 'INTR' )
# logger().log( "[smbus]: INTR = %d" % intr )
break
elif 1 == failed:
#kill = 0
#if chipsec.chipset.register_has_field( self.cs, self.smb_reg_control, 'KILL' ):
# kill = chipsec.chipset.read_register_field( self.cs, self.smb_reg_control, 'KILL' )
if logger().HAL: logger().error( "SMBus transaction failed (FAILED/ERROR bit = 1)" )
return False
else:
if chipsec.chipset.register_has_field( self.cs, self.smb_reg_status, 'DEV_ERR' ):
if 1 == chipsec.chipset.get_register_field( self.cs, self.smb_reg_status, sts, 'DEV_ERR' ):
if logger().HAL: logger().error( "SMBus device error (invalid cmd, unclaimed cycle or time-out error)" )
return False
if chipsec.chipset.register_has_field( self.cs, self.smb_reg_status, 'BUS_ERR' ):
if 1 == chipsec.chipset.get_register_field( self.cs, self.smb_reg_status, sts, 'BUS_ERR' ):
if logger().HAL: logger().error( "SMBus bus error" )
return False
return (0 == busy)
def read_byte( self, target_address, offset ):
smbus_io_base = self.get_SMBus_Base_Address()
value = self._read_byte( smbus_io_base, target_address, offset )
# clear status bits
chipsec.chipset.write_register( self.cs, self.smb_reg_status, 0xFF )
# SMBus txn RW direction = Read, SMBus slave address = target_address
hst_sa = 0x0
hst_sa = chipsec.chipset.set_register_field( self.cs, self.smb_reg_address, hst_sa, 'RW', SMBUS_COMMAND_READ )
hst_sa = chipsec.chipset.set_register_field( self.cs, self.smb_reg_address, hst_sa, 'Address', target_address, True )
chipsec.chipset.write_register( self.cs, self.smb_reg_address, hst_sa )
# command data = byte offset (bus txn address)
chipsec.chipset.write_register_field( self.cs, self.smb_reg_command, 'DataOffset', offset )
# command = Byte Data
#if chipsec.chipset.register_has_field( self.cs, self.smb_reg_control, 'SMB_CMD' ):
chipsec.chipset.write_register_field( self.cs, self.smb_reg_control, 'SMB_CMD', SMBUS_COMMAND_BYTE_DATA )
# send SMBus txn
chipsec.chipset.write_register_field( self.cs, self.smb_reg_control, 'START', 1 )
# wait for cycle to complete
if not self._wait_for_cycle(): return 0xFF
# read the data
value = chipsec.chipset.read_register_field( self.cs, self.smb_reg_data0, 'Data' )
# clear status bits
chipsec.chipset.write_register( self.cs, self.smb_reg_status, 0xFF )
# clear address/offset registers
#chipsec.chipset.write_register( self.cs, self.smb_reg_address, 0x0 )
#chipsec.chipset.write_register( self.cs, self.smb_reg_command, 0x0 )
if logger().VERBOSE: logger().log( "[smbus] read device %X off %X = %X" % (target_address, offset, value) )
return value
def write_byte( self, target_address, offset, value ):
smbus_io_base = self.get_SMBus_Base_Address()
sts = self._write_byte( smbus_io_base, target_address, offset, value )
# clear status bits
chipsec.chipset.write_register( self.cs, self.smb_reg_status, 0xFF )
# SMBus txn RW direction = Write, SMBus slave address = target_address
hst_sa = 0x0
hst_sa = chipsec.chipset.set_register_field( self.cs, self.smb_reg_address, hst_sa, 'RW', SMBUS_COMMAND_WRITE )
hst_sa = chipsec.chipset.set_register_field( self.cs, self.smb_reg_address, hst_sa, 'Address', target_address, True )
chipsec.chipset.write_register( self.cs, self.smb_reg_address, hst_sa )
# command data = byte offset (bus txn address)
chipsec.chipset.write_register_field( self.cs, self.smb_reg_command, 'DataOffset', offset )
# write the data
chipsec.chipset.write_register_field( self.cs, self.smb_reg_data0, 'Data', value )
# command = Byte Data
#if chipsec.chipset.register_has_field( self.cs, self.smb_reg_control, 'SMB_CMD' ):
chipsec.chipset.write_register_field( self.cs, self.smb_reg_control, 'SMB_CMD', SMBUS_COMMAND_BYTE_DATA )
# send SMBus txn
chipsec.chipset.write_register_field( self.cs, self.smb_reg_control, 'START', 1 )
# wait for cycle to complete
if not self._wait_for_cycle(): return False
# clear status bits
chipsec.chipset.write_register( self.cs, self.smb_reg_status, 0xFF )
# clear address/offset registers
#chipsec.chipset.write_register( self.cs, self.smb_reg_address, 0x0 )
#chipsec.chipset.write_register( self.cs, self.smb_reg_command, 0x0 )
if logger().VERBOSE: logger().log( "[smbus] write to device %X off %X = %X" % (target_address, offset, value) )
return sts
return True
def read_range( self, target_address, start_offset, size ):
buffer = [chr(0xFF)]*size
smbus_io_base = self.get_SMBus_Base_Address()
for i in range (size):
buffer[i] = chr( self._read_byte( smbus_io_base, target_address, start_offset + i ) )
if logger().VERBOSE:
logger().log( "[smbus] read device %X from offset %X size %X:" % (target_address, start_offset, size) )
print_buffer( buffer )
buffer[i] = chr( self.read_byte( target_address, start_offset + i ) )
if logger().HAL:
logger().log( "[smbus] reading %u bytes from device 0x%X at offset %X" % (size, target_address, start_offset) )
#print_buffer( buffer )
return buffer
def write_range( self, target_address, start_offset, buffer ):
size = len(buffer)
smbus_io_base = self.get_SMBus_Base_Address()
for i in range(size):
self._write_byte( smbus_io_base, target_address, start_offset + i, ord(buffer[i]) )
if logger().VERBOSE:
logger().log( "[smbus] write device %X to offset %X size %X:" % (target_address, start_offset, size) )
print_buffer( buffer )
self.write_byte( target_address, start_offset + i, ord(buffer[i]) )
if logger().HAL:
logger().log( "[smbus] writing %u bytes to device 0x%X at offset %X" % (size, target_address, start_offset) )
#print_buffer( buffer )
return True
+10 -4
View File
@@ -1,6 +1,6 @@
#!/usr/local/bin/python
#CHIPSEC: Platform Security Assessment Framework
#Copyright (c) 2010-2015, Intel Corporation
#Copyright (c) 2010-2016, Intel Corporation
#
#This program is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public License
@@ -309,10 +309,16 @@ class SPD:
return self.smbus.write_byte( device, offset, value )
def read_range( self, start_offset, size, device=SPD_SMBUS_ADDRESS ):
return self.smbus.read_range( device, start_offset, size )
buffer = [chr(0xFF)]*size
for i in range (size):
buffer[i] = chr( self.read_byte( start_offset + i, device ) )
return buffer
def write_range( self, start_offset, buffer, device=SPD_SMBUS_ADDRESS ):
return self.smbus.write_range( device, start_offset, buffer )
size = len(buffer)
for i in range(size):
self.write_byte( start_offset + i, ord(buffer[i]), device )
return True
def dump( self, device=SPD_SMBUS_ADDRESS ):
buf = self.read_range( 0, 0x100, device )
@@ -383,7 +389,7 @@ class SPD:
def decode( self, device=SPD_SMBUS_ADDRESS ):
spd = None
device_type = self.getDRAMDeviceType( device )
spd_buffer = ''.join(self.dump())
spd_buffer = ''.join(self.dump( device ))
if DRAM_DEVICE_TYPE_DDR == device_type:
spd = SPD_DDR ( *struct.unpack_from( SPD_DDR_FORMAT, spd_buffer ) )
+26 -71
View File
@@ -1,6 +1,6 @@
#!/usr/local/bin/python
#CHIPSEC: Platform Security Assessment Framework
#Copyright (c) 2010-2015, Intel Corporation
#Copyright (c) 2010-2016, Intel Corporation
#
#This program is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public License
@@ -44,11 +44,10 @@ usage:
If you want to change logic to read SPI Flash in 4 byte chunks:
SPI_READ_WRITE_MAX_DBC = 4
SPI write cycles operate on 4 byte chunks (not optimized yet)
@TBD: SPI write cycles operate on 4 byte chunks (not optimized yet)
Approximate performance (on 2 core HT Sandy Bridge CPU 2.6GHz):
SPI read: ~25 sec per 1MB (DBC=64)
SPI write: ~140 sec per 1MB (DBC=4)
Approximate performance (on 2-core SMT Intel Core i5-4300U (Haswell) CPU 1.9GHz):
SPI read: ~7 sec per 1MB (with DBC=64)
"""
__version__ = '1.0'
@@ -57,6 +56,7 @@ import struct
import sys
import time
import chipsec.defines
import chipsec.chipset
from chipsec.file import *
from chipsec.hal.hal_base import HALBase
@@ -309,7 +309,7 @@ class SPI:
logger().log( "BFPREG = %08X:" % bfpreg )
logger().log( " Base : %08X" % ((bfpreg & Cfg.PCH_RCBA_SPI_FREGx_BASE_MASK) << 12) )
logger().log( " Limit : %08X" % ((bfpreg & Cfg.PCH_RCBA_SPI_FREGx_LIMIT_MASK) >> 4) )
logger().log( " Shadowed BIOS Select: %d" % ((bfpreg & Cfg.BIT31)>>31) )
logger().log( " Shadowed BIOS Select: %d" % ((bfpreg & chipsec.defines.BIT31)>>31) )
def display_SPI_Ranges_Access_Permissions( self ):
@@ -386,74 +386,29 @@ class SPI:
if logger().VERBOSE: self.display_BIOS_write_protection()
ble = chipsec.chipset.get_control( self.cs, 'BiosLockEnable' )
bioswe = chipsec.chipset.get_control( self.cs, 'BiosWriteEnable' )
if ble and (not bioswe):
if logger().HAL: logger().log( "[spi] BIOS write protection is enabled" )
return False
elif bioswe:
if logger().HAL: logger().log( "[spi] BIOS write protection is not enabled" )
return True
else:
if logger().HAL: logger().log( "[spi] BIOS write protection is enabled but not locked. Disabling.." )
smmbwp = chipsec.chipset.get_control( self.cs, 'SmmBiosWriteProtection' )
# @TODO: hack - update to use write_register_field
reg_value = chipsec.chipset.read_register( self.cs, 'BC' )
reg_value |= 0x1
chipsec.chipset.write_register( self.cs, 'BC', reg_value )
if smmbwp == 1:
if logger().HAL: logger().log( "[spi] SMM BIOS write protection (SmmBiosWriteProtection) is enabled" )
if bioswe == 1:
if logger().HAL: logger().log( "[spi] BIOS write protection (BiosWriteEnable) is not enabled" )
return True
elif ble == 0:
if logger().HAL: logger().log( "[spi] BIOS write protection is enabled but not locked. Disabling.." )
else: # bioswe == 0 and ble == 1
if logger().HAL: logger().log( "[spi] BIOS write protection is enabled. Attempting to disable.." )
# Set BiosWriteEnable control bit
chipsec.chipset.set_control( self.cs, 'BiosWriteEnable', 1 )
# read BiosWriteEnable back to check if BIOS writes are enabled
bioswe = chipsec.chipset.get_control( self.cs, 'BiosWriteEnable' )
if logger().VERBOSE: self.display_BIOS_write_protection()
if logger().HAL: logger().log_important( "BIOS write protection is %s" % ('disabled' if bioswe else 'still enabled') )
return bioswe
if logger().HAL: logger().log_important( "BIOS write protection is %s (BiosWriteEnable = %d)" % ('disabled' if bioswe else 'still enabled', bioswe) )
"""
def get_BIOS_Control_fallback( self ):
#
# BIOS Control (BC) 0:31:0 PCIe CFG register
#
reg_value = self.cs.pci.read_byte( 0, 31, 0, Cfg.LPC_BC_REG_OFF )
BcRegister = Cfg.LPC_BC_REG( reg_value, (reg_value>>5)&0x1, (reg_value>>4)&0x1, (reg_value>>2)&0x3, (reg_value>>1)&0x1, reg_value&0x1 )
return (BcRegister, reg_value)
def get_BIOS_Control( self ):
if chipsec.chipset.is_register_defined( self.cs, 'BC' ):
reg_value = chipsec.chipset.read_register( self.cs, 'BC' )
BcRegister = Cfg.LPC_BC_REG( reg_value, \
chipsec.chipset.get_register_field(self.cs, 'BC', reg_value, 'SMM_BWP'), \
chipsec.chipset.get_register_field(self.cs, 'BC', reg_value, 'TSS'), \
chipsec.chipset.get_register_field(self.cs, 'BC', reg_value, 'SRC'), \
chipsec.chipset.get_register_field(self.cs, 'BC', reg_value, 'BLE'), \
chipsec.chipset.get_register_field(self.cs, 'BC', reg_value, 'BIOSWE') )
return (BcRegister, reg_value)
else:
if logger().HAL: logger().error( "Could not locate the definition of 'BIOS Control' register. Using hardcoded location (results may be incorrect).." )
return self.get_BIOS_Control_fallback()
def disable_BIOS_write_protection_OLD( self ):
(BcRegister, reg_value) = self.get_BIOS_Control()
if logger().VERBOSE: logger().log( BcRegister )
if BcRegister.BLE and (not BcRegister.BIOSWE):
logger().log( "[spi] BIOS write protection enabled" )
return False
elif BcRegister.BIOSWE:
logger().log( "[spi] BIOS write protection not enabled" )
return True
else:
logger().log( "[spi] BIOS write protection enabled but not locked. Disabling.." )
reg_value |= 0x1
chipsec.chipset.write_register( self.cs, 'BC', reg_value )
(BcRegister, reg_value) = self.get_BIOS_Control()
if logger().VERBOSE: logger().log( BcRegister )
if BcRegister.BIOSWE:
logger().log_important( "BIOS write protection is disabled" )
return True
else:
return False
"""
return (bioswe==1)
##############################################################################################################
@@ -552,7 +507,7 @@ class SPI:
n = data_byte_count / dbc
r = data_byte_count % dbc
if logger().UTIL_TRACE or logger().VERBOSE:
if logger().UTIL_TRACE or logger().DEBUG:
logger().log( "[spi] reading 0x%x bytes from SPI at FLA = 0x%X (in %d 0x%x-byte chunks + 0x%x-byte remainder)" % (data_byte_count, spi_fla, n, dbc, r) )
cycle_done = self._wait_SPI_flash_cycle_done()
@@ -561,7 +516,7 @@ class SPI:
return None
for i in range(n):
if logger().UTIL_TRACE or logger().VERBOSE:
if logger().DEBUG:
logger().log( "[spi] reading chunk %d of 0x%x bytes from 0x%X" % (i, dbc, spi_fla + i*dbc) )
if not self._send_spi_cycle( HSFCTL_READ_CYCLE, dbc-1, spi_fla + i*dbc ):
logger().error( "SPI flash read failed" )
@@ -573,7 +528,7 @@ class SPI:
buf += [ chr((dword_value>>(8*j))&0xff) for j in range(4) ]
#buf += tuple( struct.pack("I", dword_value) )
if (0 != r):
if logger().UTIL_TRACE or logger().VERBOSE:
if logger().DEBUG:
logger().log( "[spi] reading remaining 0x%x bytes from 0x%X" % (r, spi_fla + n*dbc) )
if not self._send_spi_cycle( HSFCTL_READ_CYCLE, r-1, spi_fla + n*dbc ):
logger().error( "SPI flash read failed" )
+3 -3
View File
@@ -1,6 +1,6 @@
#!/usr/local/bin/python
#CHIPSEC: Platform Security Assessment Framework
#Copyright (c) 2010-2015, Intel Corporation
#Copyright (c) 2010-2016, Intel Corporation
#
#This program is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public License
@@ -134,7 +134,7 @@ def parse_uefi_section( _uefi, data, Size, offset, polarity, parent_offset, pare
if efi_file != None:
os.rename(os.path.join(parent_path, efi_file), os.path.join(parent_path, ui_string))
efi_file = None
if (SecType in (EFI_SECTION_COMPRESSION, EFI_SECTION_GUID_DEFINED, EFI_SECTION_FIRMWARE_VOLUME_IMAGE)):
if (SecType in (EFI_SECTION_COMPRESSION, EFI_SECTION_GUID_DEFINED, EFI_SECTION_FIRMWARE_VOLUME_IMAGE, EFI_SECTION_RAW)):
section_dir_path = "%s.dir" % section_path
os.makedirs( section_dir_path )
if (SecType == EFI_SECTION_COMPRESSION):
@@ -161,7 +161,7 @@ def parse_uefi_section( _uefi, data, Size, offset, polarity, parent_offset, pare
#else:
# write_file( os.path.join(section_dir_path, "%s-%04X" % (sguid, Attributes)), SecBody[DataOffset:] )
pass
elif (SecType == EFI_SECTION_FIRMWARE_VOLUME_IMAGE):
elif (SecType == EFI_SECTION_FIRMWARE_VOLUME_IMAGE or SecType == EFI_SECTION_RAW):
parse_uefi_region(_uefi, SecBody[SecHeaderSize:], section_dir_path)
sec_offset, next_sec_offset, SecName, SecType, SecBody, SecHeaderSize = NextFwFileSection(data, Size, next_sec_offset, polarity)
secn = secn + 1
+469
View File
@@ -0,0 +1,469 @@
#CHIPSEC: Platform Security Assessment Framework
#Copyright (c) 2010-2016, Intel Corporation
#
#This program is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public License
#as published by the Free Software Foundation; Version 2.
#
#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with this program; if not, write to the Free Software
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
#Contact information:
#chipsec@intel.com
#
"""
Trusted Platform Module (TPM) HAL component
https://trustedcomputinggroup.org
"""
__version__ = '0.1'
import struct
import sys
import time
from collections import namedtuple
from chipsec.logger import *
from chipsec.file import *
import chipsec.hal.tpm12_commands
class TpmRuntimeError (RuntimeError):
pass
COMMANDREADY = 0x40
TPMGO = 0x20
HEADERSIZE = 0x0A
HEADERFORMAT = '>HII'
BEENSEIZED = 0x10
REQUESTUSE = 0x2
ACTIVELOCALITY = 0x20
DATAAVAIL = 0x10
TPM_DATAFIFO = 0x0024
TPM_STS = 0x0018
TPM_DIDVID = 0x0F00
TPM_ACCESS = 0x0000
TPM_RID = 0x0F04
TPM_INTCAP = 0x0014
TPM_INTENABLE = 0x0008
STATUS = {
0x00:"Success",
0x01:"ERROR: Authentication Failed",
0x02:"ERROR: The index to a PCR, DIR or other register is incorrect",
0x03:"ERROR: One or more parameter is bad",
0x04:"ERROR: An operation completed successfully but the auditing of that operation failed",
0x05:"ERROR: The clear disable flag is set and all clear operations now require physical access",
0x06:"ERROR: The TPM is deactivated",
0x07:"ERROR: The TPM is disabled",
0x08:"ERROR: The target command has been disabled",
0x09:"ERROR: The operation failed",
0x0A:"ERROR: The ordinal was unknown or inconsistent",
0x0B:"ERROR: The ability to install an owner is disabled",
0x0C:"ERROR: The key handle can not be interpreted",
0x0D:"ERROR: The key handle points to an invalid key",
0x0E:"ERROR: Unacceptable encryption scheme",
0x0F:"ERROR: Migration authorization failed",
0x10:"ERROR: PCR information could not be interpreted",
0x11:"ERROR: No room to load key",
0x12:"ERROR: There is no SRK set",
0x13:"ERROR: An encrypted blob is invalid or was not created by this TPM",
0x14:"ERROR: There is already an Owner",
0x15:"ERROR: The TPM has insufficient internal resources to perform the requested action",
0x16:"ERROR: A random string was too short",
0x17:"ERROR: The TPM does not have the space to perform the operation",
0x18:"ERROR: The named PCR value does not match the current PCR value.",
0x19:"ERROR: The paramSize argument to the command has the incorrect value",
0x1A:"ERROR: There is no existing SHA-1 thread.",
0x1B:"ERROR: The calculation is unable to proceed because the existing SHA-1 thread has already encountered an error",
0x1C:"ERROR: Self-test has failed and the TPM has shut-down",
0x1D:"ERROR: The authorization for the second key in a 2 key function failed authorization",
0x1E:"ERROR: The tag value sent to for a command is invalid",
0x1F:"ERROR: An IO error occurred transmitting information to the TPM",
0x20:"ERROR: The encryption process had a problem",
0x21:"ERROR: The decryption process did not complete",
0x22:"ERROR: An invalid handle was used",
0x23:"ERROR: The TPM does not a EK installed",
0x24:"ERROR: The usage of a key is not allowed",
0x25:"ERROR: The submitted entity type is not allowed",
0x26:"ERROR: The command was received in the wrong sequence relative to TPM_Init and a subsequent TPM_Startup",
0x27:"ERROR: Signed data cannot include additional DER information",
0x28:"ERROR: The key properties in TPM_KEY_PARMs are not supported by this TPM",
0x29:"ERROR: The migration properties of this key are incorrect",
0x2A:"ERROR: The signature or encryption scheme for this key is incorrect or not permitted in this situation",
0x2B:"ERROR: The size of the data (or blob) parameter is bad or inconsistent with the referenced key",
0x2C:"ERROR: A parameter is bad",
0x2D:"ERROR: Either the physicalPresence or physicalPresenceLock bits have the wrong value",
0x2E:"ERROR: The TPM cannot perform this version of the capability",
0x2F:"ERROR: The TPM does not allow for wrapped transport sessions",
0x30:"ERROR: TPM audit construction failed and the underlying command was returning a failure code also",
0x31:"ERROR: TPM audit construction failed and the underlying command was returning success",
0x32:"ERROR: Attempt to reset a PCR register that does not have the resettable attribute",
0x33:"ERROR: Attempt to reset a PCR register that requires locality and locality modifier not part of command transport",
0x34:"ERROR: Make identity blob not properly typed",
0x35:"ERROR: When saving context identified resource type does not match actual resource",
0x36:"ERROR: The TPM is attempting to execute a command only available when in FIPS mode",
0x37:"ERROR: The command is attempting to use an invalid family ID",
0x38:"ERROR: The permission to manipulate the NV storage is not available",
0x39:"ERROR: The operation requires a signed command",
0x3A:"ERROR: Wrong operation to load an NV key",
0x3B:"ERROR: NV_LoadKey blob requires both owner and blob authorization",
0x3C:"ERROR: The NV area is locked and not writeable",
0x3D:"ERROR: The locality is incorrect for the attempted operation",
0x3E:"ERROR: The NV area is read only and can?t be written to",
0x3F:"ERROR: There is no protection on the write to the NV area",
0x40:"ERROR: The family count value does not match",
0x41:"ERROR: The NV area has already been written to",
0x42:"ERROR: The NV area attributes conflict",
0x43:"ERROR: The structure tag and version are invalid or inconsistent",
0x44:"ERROR: The key is under control of the TPM Owner and can only be evicted by the TPM Owner",
0x45:"ERROR: The counter handle is incorrect",
0x46:"ERROR: The write is not a complete write of the area",
0x47:"ERROR: The gap between saved context counts is too large",
0x48:"ERROR: The maximum number of NV writes without an owner has been exceeded",
0x49:"ERROR: No operator AuthData value is set",
0x4A:"ERROR: The resource pointed to by context is not loaded",
0x4B:"ERROR: The delegate administration is locked",
0x4C:"ERROR: Attempt to manage a family other then the delegated family",
0x4D:"ERROR: Delegation table management not enabled",
0x4E:"ERROR: There was a command executed outside of an exclusive transport session",
0x4F:"ERROR: Attempt to context save a owner evict controlled key",
0x50:"ERROR: The DAA command has no resources available to execute the command",
0x51:"ERROR: The consistency check on DAA parameter inputData0 has failed",
0x52:"ERROR: The consistency check on DAA parameter inputData1 has failed",
0x53:"ERROR: The consistency check on DAA_issuerSettings has failed",
0x54:"ERROR: The consistency check on DAA_tpmSpecific has failed",
0x55:"ERROR: The atomic process indicated by the submitted DAA command is not the expected process",
0x56:"ERROR: The issuer's validity check has detected an inconsistency",
0x57:"ERROR: The consistency check on w has failed",
0x58:"ERROR: The handle is incorrect",
0x59:"ERROR: Delegation is not correct",
0x5A:"ERROR: The context blob is invalid",
0x5B:"ERROR: Too many contexts held by the TPM",
0x5C:"ERROR: Migration authority signature validation failure",
0x5D:"ERROR: Migration destination not authenticated",
0x5E:"ERROR: Migration source incorrect",
0x5F:"ERROR: Incorrect migration authority",
0x60:"ERROR: TBD",
0x61:"ERROR: Attempt to revoke the EK and the EK is not revocable",
0x62:"ERROR: Bad signature of CMK ticket",
0x63:"ERROR: There is no room in the context list for additional contexts",
0x800:"NON-FATAL ERROR: The TPM is too busy to respond to the command immediately, but the command could be resubmitted at a later time",
0x801:"NON-FATAL ERROR: TPM_ContinueSelfTest has not been run.",
0x802:"NON-FATAL ERROR: The TPM is currently executing the actions of TPM_ContinueSelfTest because the ordinal required resources that have not been tested",
0x803:"NON-FATAL ERROR: The TPM is defending against dictionary attacks and is in some time-out period."
}
LOCALITY = {
'0':0x0000,
'1':0x1000,
'2':0x2000,
'3':0x3000,
'4':0x4000
}
COMMANDS = {
"pcrread" : chipsec.hal.tpm12_commands.pcrread,
"nvread" : chipsec.hal.tpm12_commands.nvread,
"startup" : chipsec.hal.tpm12_commands.startup,
"continueselftest" : chipsec.hal.tpm12_commands.continueselftest,
"forceclear" : chipsec.hal.tpm12_commands.forceclear
}
class TPM_RESPONSE_HEADER( namedtuple('TPM_RESPONSE_HEADER', 'ResponseTag DataSize ReturnCode') ):
__slots__ = ()
def __str__(self):
_str = """----------------------------------------------------------------
TPM response header
----------------------------------------------------------------
Response TAG: 0x%x
Data Size : 0x%x
Return Code : 0x%x
""" % ( self.ResponseTag, self.DataSize, self.ReturnCode )
_str += "\t"
try:
_str += STATUS[self.ReturnCode]
except:
_str += "Invalid return code"
_str += "\n"
return _str
class TPM():
def __init__( self, cs ):
self.cs = cs
self.helper = cs.helper
self.TPM_BASE = int(self.cs.Cfg.MEMORY_RANGES["TPM"]["address"], 16)
def command( self, commandName, locality, command_argv ):
"""
Send command to the TPM and receive data
"""
try:
Locality = LOCALITY[locality]
except:
logger().log_bad("Invalid locality value\n")
return
requestedUse = False
#
# Request locality use if needed
#
access_address = self.TPM_BASE | Locality | TPM_ACCESS
if self.helper.read_mmio_reg( access_address, 4 ) == BEENSEIZED:
self.helper.write_mmio_reg( access_address, 4, REQUESTUSE )
requestedUse = True
#
# Build command (big endian) and send/receive
#
( command, size ) = COMMANDS[commandName]( command_argv )
self._send_command( Locality, command, size )
( header, data, header_blob, data_blob ) = self._read_response( Locality )
logger().log( header )
print_buffer( str(data_blob) )
logger().log( '\n' )
#
# Release locality if needed
#
if requestedUse==True:
self.helper.write_mmio_reg( access_address, 4, BEENSEIZED )
self.helper.write_mmio_reg( access_address, 1, ACTIVELOCALITY )
def _send_command( self, Locality, command, size ):
"""
Send a command to the TPM using the locality specified
"""
count = 0
datafifo_address = self.TPM_BASE | Locality | TPM_DATAFIFO
sts_address = self.TPM_BASE | Locality| TPM_STS
access_address = self.TPM_BASE | Locality| TPM_ACCESS
self.helper.write_mmio_reg( access_address, 1, REQUESTUSE )
#
# Set status to command ready
#
sts_value = self.helper.read_mmio_reg( sts_address, 1 )
while ( 0 == ( sts_value & COMMANDREADY ) ):
self.helper.write_mmio_reg( sts_address, 1, COMMANDREADY )
sts_value = self.helper.read_mmio_reg( sts_address, 1 )
while count < size:
sts_value = self.helper.read_mmio_reg( sts_address, 4 )
burst_count = ( ( sts_value>>8 ) & 0xFFFFFF )
burst_index = 0
while ( burst_index < burst_count ) and ( count < size ):
self.helper.write_mmio_reg( datafifo_address, 1, struct.unpack("=B", command[count])[0] )
count += 1
burst_index += 0x1
self.helper.write_mmio_reg( sts_address, 1, TPMGO )
def _read_response(self, Locality):
"""
Read the TPM's response using the specified locality
"""
count = 0
header = ""
header_blob = bytearray()
data = ""
data_blob = bytearray()
#
# Build FIFO address
#
datafifo_address = self.TPM_BASE | Locality | TPM_DATAFIFO
access_address = self.TPM_BASE | Locality| TPM_ACCESS
sts_address = self.TPM_BASE | Locality| TPM_STS
sts_value = self.helper.read_mmio_reg( sts_address, 1 )
data_avail = bin( sts_value & ( 1<<4 ) )[2]
#
# Read data available
#
# watchdog?
while data_avail == '0':
sts_value = self.helper.read_mmio_reg( sts_address, 1 )
self.helper.write_mmio_reg( sts_address, 1, DATAAVAIL )
data_avail = bin( sts_value & ( 1<<4 ) )[2]
while count < HEADERSIZE:
sts_value = self.helper.read_mmio_reg( sts_address, 4 )
burst_count = ( ( sts_value>>8 ) & 0xFFFFFF )
burst_index = 0
while ( burst_index < burst_count ) and ( count < HEADERSIZE ):
header_blob.append(self.helper.read_mmio_reg( datafifo_address, 1 ))
count += 1
burst_index += 0x1
header = TPM_RESPONSE_HEADER( *struct.unpack_from( HEADERFORMAT, header_blob ) )
count = 0
if header.DataSize > 10 and header.ReturnCode == 0:
length = header.DataSize - HEADERSIZE
while count < length:
sts_value = self.helper.read_mmio_reg( sts_address, 4 )
burst_count = ( ( sts_value>>8 ) & 0xFFFFFF )
burst_index = 0
while ( burst_index < burst_count ) and ( count < length ):
data_blob.append( self.helper.read_mmio_reg( datafifo_address, 1 ) )
count += 1
burst_index += 0x1
return ( header, data, header_blob, data_blob )
def dump_access( self, locality ):
"""
View the contents of the register used to gain ownership of the TPM
"""
try:
Locality = LOCALITY[locality]
except:
logger().log_bad("Invalid locality value\n")
return
access_address = self.TPM_BASE | Locality| TPM_ACCESS
access_value = self.helper.read_mmio_reg( access_address, 1 )
logger().log( "================================================================" )
logger().log( " TPM Access" )
logger().log( "================================================================" )
logger().log( "\ttpmRegValidSts : 0x%s" % bin( access_value & ( 1<<7 ) )[2] )
logger().log( "\treserved : 0x%s" % bin( access_value & ( 1<<6 ) )[2] )
logger().log( "\tactiveLocality : 0x%s" % bin( access_value & ( 1<<5 ) )[2] )
logger().log( "\tbeenSeized : 0x%s" % bin( access_value & ( 1<<4 ) )[2] )
logger().log( "\tSeize : 0x%s" % bin( access_value & ( 1<<3 ) )[2] )
logger().log( "\tpendingRequest : 0x%s" % bin( access_value & ( 1<<2 ) )[2] )
logger().log( "\trequestUse : 0x%s" % bin( access_value & ( 1<<1 ) )[2] )
logger().log( "\ttpmEstablishment: 0x%s" % bin( access_value & ( 1<<0 ) )[2] )
def dump_status( self, locality ):
"""
View general status details
"""
try:
Locality = LOCALITY[locality]
except:
logger().log_bad("Invalid locality value\n")
return
sts_address = self.TPM_BASE | Locality| TPM_STS
sts_value = self.helper.read_mmio_reg( sts_address, 4 )
logger().log( "================================================================" )
logger().log( " TPM Status" )
logger().log( "================================================================" )
logger().log( "\tburstCount : 0x%x" % ( ( sts_value>>8 ) & 0xFFFFFF ) )
logger().log( "\tstsValid : 0x%s" % bin( sts_value & ( 1<<7 ) )[2] )
logger().log( "\tcommandReady : 0x%s" % bin( sts_value & ( 1<<6 ) )[2] )
logger().log( "\ttpmGo : 0x%s" % bin( sts_value & ( 1<<5 ) )[2] )
logger().log( "\tdataAvail : 0x%s" % bin( sts_value & ( 1<<4 ) )[2] )
logger().log( "\tExpect : 0x%s" % bin( sts_value & ( 1<<3 ) )[2] )
logger().log( "\tReserved : 0x%s" % bin( sts_value & ( 1<<2 ) )[2] )
logger().log( "\tresponseRetry: 0x%s" % bin( sts_value & ( 1<<1 ) )[2] )
logger().log( "\tReserved : 0x%s" % bin( sts_value & ( 1<<0 ) )[2] )
def dump_didvid( self, locality ):
"""
TPM's Vendor and Device ID
"""
try:
Locality = LOCALITY[locality]
except:
logger().log_bad("Invalid locality value\n")
return
didvid_address = self.TPM_BASE | Locality| TPM_DIDVID
didvid_value = self.helper.read_mmio_reg( didvid_address, 4 )
logger().log( "================================================================" )
logger().log( " TPM DID VID" )
logger().log( "================================================================" )
logger().log( "\tdid: 0x%x" % ( ( didvid_value>>16 ) & 0xFFFF ) )
logger().log( "\tvid: 0x%x" % ( didvid_value & 0xFFFF) )
def dump_rid( self, locality ):
"""
TPM's Revision ID
"""
try:
Locality = LOCALITY[locality]
except:
logger().log_bad("Invalid locality value\n")
return
rid_address = self.TPM_BASE | Locality| TPM_RID
rid_value = self.helper.read_mmio_reg( rid_address, 1 )
logger().log( "================================================================" )
logger().log( " TPM RID" )
logger().log( "================================================================" )
logger().log( "\trid: 0x%x" % rid_value )
def dump_intcap( self, locality ):
"""
Provides information of which interrupts that particular TPM supports
"""
try:
Locality = LOCALITY[locality]
except:
logger().log_bad("Invalid locality value\n")
return
intcap_address = self.TPM_BASE | Locality| TPM_INTCAP
intcap_value = self.helper.read_mmio_reg( intcap_address, 4 )
logger().log( "================================================================" )
logger().log( " TPM INTF CAPABILITY" )
logger().log( "================================================================" )
logger().log( "\tReserved : 0x%x" % ( ( intcap_value>>8 ) & 0xFFFFFE ) )
logger().log( "\tBurstCountStatic : 0x%s" % bin( intcap_value & ( 1<<8 ) )[2] )
logger().log( "\tCommandReadyIntSupport : 0x%s" % bin( intcap_value & ( 1<<7 ) )[2] )
logger().log( "\tInterruptEdgeFalling : 0x%s" % bin( intcap_value & ( 1<<6 ) )[2] )
logger().log( "\tInterruptEdgeRising : 0x%s" % bin( intcap_value & ( 1<<5 ) )[2] )
logger().log( "\tInterruptLevelLow : 0x%s" % bin( intcap_value & ( 1<<4 ) )[2] )
logger().log( "\tInterruptLevelHigh : 0x%s" % bin( intcap_value & ( 1<<3 ) )[2] )
logger().log( "\tLocalityChangeIntSupport: 0x%s" % bin( intcap_value & ( 1<<2 ) )[2] )
logger().log( "\tstsValidIntSupport : 0x%s" % bin( intcap_value & ( 1<<1 ) )[2] )
logger().log( "\tdataAvailIntSupport : 0x%s" % bin( intcap_value & ( 1<<0 ) )[2] )
def dump_intenable( self, locality ):
"""
View the contents of the register used to enable specific interrupts
"""
polType = { 0:"High Level", 1:"Low Level", 2:"Rising edge", 3:"Failing edge" }
try:
Locality = LOCALITY[locality]
except:
logger().log_bad("Invalid locality value\n")
return
intenable_address = self.TPM_BASE | Locality| TPM_INTENABLE
intenable_value = self.helper.read_mmio_reg( intenable_address, 4 )
logger().log( "================================================================" )
logger().log( " TPM INT ENABLE" )
logger().log( "================================================================" )
logger().log( "\tglobalIntEnable : 0x%s" % bin( intenable_value & ( 1<<31 ) )[2] )
logger().log( "\tReserved : 0x%x" % ( (intenable_value>>8) & 0x7FFFFF00 ) )
logger().log( "\tcommandReadyEnable : 0x%s" % bin( intenable_value & ( 1<<7 ) )[2] )
logger().log( "\tReserved : 0x%x" % ( (intenable_value>>5) & 0x3 ) )
type = ( ( intenable_value>>3 ) & 0x3 )
logger().log( "\ttypePolarity : 0x%x %s" % ( type, polType[type] ) )
logger().log( "\tlocalityChangeIntEnable: 0x%s" % bin( intenable_value & ( 1<<2 ) )[2] )
logger().log( "\tstsValidIntEnable : 0x%s" % bin( intenable_value & ( 1<<1 ) )[2] )
logger().log( "\tdataAvailIntEnable : 0x%s" % bin( intenable_value & ( 1<<0 ) )[2] )
+185
View File
@@ -0,0 +1,185 @@
#CHIPSEC: Platform Security Assessment Framework
#Copyright (c) 2010-2016, Intel Corporation
#
#This program is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public License
#as published by the Free Software Foundation; Version 2.
#
#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with this program; if not, write to the Free Software
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
#Contact information:
#chipsec@intel.com
#
"""
Definition for TPMv1.2 commands to use with TPM HAL
TCG PC Client TPM Specification
TCG TPM v1.2 Specification
"""
import struct
from chipsec.logger import *
COMMAND_FORMAT = "=HIIIII"
TPM_TAG_RQU_COMMAND = 0xc100
TPM_TAG_RQU_AUTH1_COMMAND = 0xc200
TPM_TAG_RQU_AUTH2_COMMAND = 0xC300
TPM_TAG_RSP_COMMAND = 0xC400
TPM_TAG_RSP_AUTH1_COMMAND = 0xC500
TPM_TAG_RSP_AUTH2_COMMAND = 0xC600
TPM_ORD_CONTINUESELFTEST = 0x53000000
TPM_ORD_FORCECLEAR = 0x5D000000
TPM_ORD_GETCAPABILITY = 0x65000000
TPM_ORD_NV_DEFINESPACE = 0xCC000000
TPM_ORD_NV_READVALUE = 0xCF000000
TPM_ORD_NV_WRITEVALUE = 0xCD000000
TPM_ORD_PCRREAD = 0x15000000
TPM_ORD_PHYSICALDISABLE = 0x70000000
TPM_ORD_PHYSICALENABLE = 0x6F000000
TPM_ORD_PHYSICALSETDEACTIVATED = 0x72000000
TPM_ORD_STARTUP = 0x99000000
TPM_ORD_SAVESTATE = 0x98000000
TSC_ORD_PHYSICALPRESENCE = 0x0A000040
TSC_ORD_RESETESTABLISHMENTBIT = 0x0B000040
STARTUP = {
1:0x0100,
2:0x0200,
3:0x0300
}
PCR= {
0 :0x00000000,
1 :0x01000000,
2 :0x02000000,
3 :0x03000000,
4 :0x04000000,
5 :0x05000000,
6 :0x06000000,
7 :0x07000000,
8 :0x08000000,
9 :0x09000000,
10:0x0a000000,
11:0x0b000000,
12:0x0c000000,
13:0x0d000000,
14:0x0e000000,
15:0x0f000000,
16:0x10000000,
17:0x11000000,
18:0x12000000,
19:0x13000000,
20:0x14000000,
21:0x15000000,
22:0x16000000,
23:0x17000000,
24:0x18000000,
25:0x19000000,
26:0x1a000000,
27:0x1b000000,
28:0x1c000000,
29:0x1d000000,
30:0x1e000000
}
def pcrread( command_argv ):
"""
The TPM_PCRRead operation provides non-cryptographic reporting of the contents of a named PCR
"""
Size = 0x0E000000
try:
Pcr = PCR[int(command_argv[0])]
except:
logger().log_bad("Invalid PCR value\n")
return
command = struct.pack( COMMAND_FORMAT, TPM_TAG_RQU_COMMAND, Size, TPM_ORD_PCRREAD, Pcr, 0, 0 )
size = Size >> 0x18
return ( command, size )
def nvread( command_argv ):
"""
Read a value from the NV store
Index, Offset, Size
"""
Size = 0x18000000
command = struct.pack( COMMAND_FORMAT, TPM_TAG_RQU_COMMAND, Size, TPM_ORD_NV_READVALUE, int(command_argv[0], 16), int(command_argv[1], 16), int(command_argv[2], 16) )
size = Size >> 0x18
return ( command, size )
def startup( command_argv ):
"""
Execute a tpm_startup command. TPM_Startup is always preceded by TPM_Init, which is the physical indication (a system wide reset) that TPM initialization is necessary
Type of Startup to be used:
1: TPM_ST_CLEAR
2: TPM_ST_STATE
3: TPM_ST_DEACTIVATED
"""
try:
startupType = STARTUP[int(command_argv[0])]
except:
logger().log_bad("Invalid startup type option value\n")
return
Size = 0x0E000000
command = struct.pack( COMMAND_FORMAT, TPM_TAG_RQU_COMMAND, Size, TPM_ORD_STARTUP, startupType, 0, 0 )
size = Size >> 0x18
return ( command, size )
def continueselftest( command_argv ):
"""
TPM_ContinueSelfTest informs the TPM that it should complete self-test of all TPM functions. The TPM may return success immediately and then perform the self-test, or it may perform the self-test and then return success or failure.
"""
Size = 0x0A000000
command = struct.pack( COMMAND_FORMAT, TPM_TAG_RQU_COMMAND, Size, TPM_ORD_CONTINUESELFTEST, 0, 0, 0 )
size = Size >> 0x18
return ( command, size )
def getcap( command_argv ):
"""
Returns current information regarding the TPM
CapArea - Capabilities Area
SubCapSize - Size of SubCapabilities
SubCap - Subcapabilities
"""
Size = 0x18000000
command = struct.pack( COMMAND_FORMAT, TPM_TAG_RQU_COMMAND, Size, TPM_ORD_GETCAPABILITY, int(command_argv[0], 16), int(command_argv[1], 16), int(command_argv[2], 16) )
size = Size >> 0x18
return ( command, size )
def forceclear( command_argv ):
Size = 0x0A000000
command = struct.pack( COMMAND_FORMAT, TPM_TAG_RQU_COMMAND, Size, TPM_ORD_FORCECLEAR, 0, 0, 0 )
size = Size >> 0x18
return ( command, size )
+17 -16
View File
@@ -1,6 +1,6 @@
#!/usr/local/bin/python
#CHIPSEC: Platform Security Assessment Framework
#Copyright (c) 2010-2015, Intel Corporation
#Copyright (c) 2010-2016, Intel Corporation
#
#This program is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public License
@@ -68,6 +68,8 @@ def parse_script( script, log_script=False ):
while (off < len_s) and (entry_type != S3BootScriptOpcode.EFI_BOOT_SCRIPT_TERMINATE_OPCODE):
entry_type,s3script_entry = parse_s3bootscript_entry( script_type, script, off, log_script )
# couldn't parse the next entry - return what has been parsed so far
if s3script_entry is None: return s3_boot_script_entries
s3_boot_script_entries.append( s3script_entry )
off += s3script_entry.length
@@ -443,7 +445,7 @@ NVRAM: EFI Variable Store
# Decode the S3 Resume Boot-Script into a sequence of operations/opcodes
#
# @TODO: should be dumping memory contents in a loop until end opcode is found or id'ing actual size
script_buffer = self.helper.read_physical_mem( bootscript_pa, 0x100000 )
script_buffer = self.helper.read_physical_mem( bootscript_pa, 0x200000 )
if logger().HAL: logger().log( '[uefi] Decoding S3 Resume Boot-Script..' )
script_entries = parse_script( script_buffer, log_script )
parsed_scripts[ bootscript_pa ] = script_entries
@@ -466,23 +468,22 @@ NVRAM: EFI Variable Store
print_buffer( var )
return var
def set_EFI_variable( self, name, guid, var, attrs=None ):
if logger().UTIL_TRACE or logger().VERBOSE:
def set_EFI_variable( self, name, guid, var, datasize=None, attrs=None ):
if logger().HAL:
logger().log( '[uefi] writing EFI variable %s:%s %s' % (guid, name, '' if attrs is None else ('(attributes = %s)' % attrs)) )
#print_buffer( var )
return self.helper.set_EFI_variable( name, guid, var, attrs )
def set_EFI_variable_from_file( self, name, guid, filename, attrs=None ):
return self.helper.set_EFI_variable( name, guid, var, datasize, attrs )
def set_EFI_variable_from_file( self, name, guid, filename, datasize=None, attrs=None ):
if filename is None:
logger().error( 'File with EFI variable is not specified' )
return False
var = read_file( filename )
return self.set_EFI_variable( name, guid, var, attrs )
return self.set_EFI_variable( name, guid, var, datasize, attrs )
def delete_EFI_variable( self, name, guid, attrs=None ):
if logger().UTIL_TRACE or logger().VERBOSE:
logger().log( '[uefi] deleting EFI variable %s:%s %s' % (guid, name, '' if attrs is None else ('(attributes = %s)' % attrs)) )
return self.helper.set_EFI_variable( name, guid, None, attrs )
def delete_EFI_variable( self, name, guid ):
if logger().HAL: logger().log( '[uefi] deleting EFI variable %s:%s' % (guid, name) )
return self.helper.delete_EFI_variable( name, guid )
######################################################################
@@ -555,16 +556,16 @@ NVRAM: EFI Variable Store
(isFound,est_pa,est_header,est,est_buf) = self.find_EFI_System_Table()
if isFound and est is not None:
if 0 != est.BootServices:
logger().log( "[uefi] UEFI appears to be in Boot mode" )
if logger().HAL: logger().log( "[uefi] UEFI appears to be in Boot mode" )
ect_pa = est.ConfigurationTable
else:
logger().log( "[uefi] UEFI appears to be in Runtime mode" )
if logger().HAL: logger().log( "[uefi] UEFI appears to be in Runtime mode" )
ect_pa = self.cs.mem.va2pa( est.ConfigurationTable )
if not ect_pa:
print "[uefi] Cann't find UEFI ConfigurationTable"
logger().error( "Can't find UEFI ConfigurationTable" )
return (None,ect_pa,ect,ect_buf)
logger().log( "[uefi] EFI Configuration Table (%d entries): VA = 0x%016X, PA = 0x%016X" % (est.NumberOfTableEntries,est.ConfigurationTable,ect_pa) )
if logger().HAL: logger().log( "[uefi] EFI Configuration Table (%d entries): VA = 0x%016X, PA = 0x%016X" % (est.NumberOfTableEntries,est.ConfigurationTable,ect_pa) )
found = (ect_pa is not None)
if found:
+2 -2
View File
@@ -1,6 +1,6 @@
#!/usr/local/bin/python
#CHIPSEC: Platform Security Assessment Framework
#Copyright (c) 2010-2015, Intel Corporation
#Copyright (c) 2010-2016, Intel Corporation
#
#This program is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public License
@@ -551,7 +551,7 @@ def NextFwFile(FvImage, FvLength, fof, polarity):
next_offset = None
res = None
update_or_deleted = False
if (fof + file_header_size) < FvLength:
if (fof + file_header_size) <= len(FvImage[fof:]):
fheader = FvImage[fof:fof+file_header_size]
Name0, Name1, Name2, Name3, IntegrityCheck, Type, Attributes, Size, State = struct.unpack(EFI_FFS_FILE_HEADER, fheader)
fsize = get_3b_size(Size);
+18 -4
View File
@@ -18,8 +18,8 @@
#Contact information:
#chipsec@intel.com
#
# -------------------------------------------------------------------------------
#
@@ -253,6 +253,10 @@ NVAR_NVRAM_FS_FILE = "CEF5B9A3-476D-497F-9FDC-E98143E0422C"
def getNVstore_NVAR( nvram_buf ):
l = (-1, -1, None)
FvOffset, FsGuid, FvLength, FvAttributes, FvHeaderLength, FvChecksum, ExtHeaderOffset, FvImage, CalcSum = NextFwVolume(nvram_buf)
if (FvOffset >= len(nvram_buf)):
return l
if (FvOffset + FvLength) > len(nvram_buf):
FvLength = len(nvram_buf) - FvOffset
while FvOffset != None:
polarity = bit_set(FvAttributes, EFI_FVB2_ERASE_POLARITY)
cur_offset, next_offset, Name, Type, Attributes, State, Checksum, Size, FileImage, HeaderSize, UD, fCalcSum = NextFwFile(FvImage, FvLength, FvHeaderLength, polarity)
@@ -951,9 +955,15 @@ def parse_s3bootscript_entry( s3bootscript_type, script, off, log_script=False )
opcode = None
entry_data = None
remaining_len = len(script[off:])
if S3BootScriptType.EFI_BOOT_SCRIPT_TYPE_EDKCOMPAT == s3bootscript_type:
fhdr = '<HB'
hdr_length = struct.calcsize(fhdr)
if remaining_len < hdr_length:
if logger().VERBOSE: logger().warn( 'the script should have at least 0x%X bytes to parse next entry' % hdr_length )
return (0,None)
opcode, entry_length = struct.unpack( fhdr, script[ off : off + hdr_length ] )
if S3BootScriptOpcode_EdkCompat.EFI_BOOT_SCRIPT_TERMINATE_OPCODE == opcode:
entry_length = hdr_length
@@ -961,7 +971,7 @@ def parse_s3bootscript_entry( s3bootscript_type, script, off, log_script=False )
if entry_length > MAX_S3_BOOTSCRIPT_ENTRY_LENGTH:
logger().error( '[uefi] Unrecognized S3 boot script format (entry length = 0x%X)' % entry_length )
return None
return (0,None)
s3script_entry = S3BOOTSCRIPT_ENTRY( s3bootscript_type, entry_index, off, entry_length, entry_data )
@@ -970,6 +980,10 @@ def parse_s3bootscript_entry( s3bootscript_type, script, off, log_script=False )
fhdr = '<II'
hdr_length = struct.calcsize(fhdr)
f = fhdr + 'B'
if remaining_len < (hdr_length + 1):
if logger().VERBOSE: logger().warn( 'the script should have at least 0x%X bytes to parse next entry' % (hdr_length+1) )
return (0,None)
entry_index, entry_length, opcode = struct.unpack(f, script[ off : off + hdr_length + 1 ])
if S3BootScriptOpcode_MDE.EFI_BOOT_SCRIPT_TERMINATE_OPCODE == opcode:
entry_length = hdr_length + 1
@@ -978,7 +992,7 @@ def parse_s3bootscript_entry( s3bootscript_type, script, off, log_script=False )
if entry_length > MAX_S3_BOOTSCRIPT_ENTRY_LENGTH:
logger().error( '[uefi] Unrecognized S3 boot script format (entry length = 0x%X)' % entry_length )
return None
return (0,None)
s3script_entry = S3BOOTSCRIPT_ENTRY( s3bootscript_type, entry_index, off, entry_length, entry_data )
s3script_entry.header_length = hdr_length
+108
View File
@@ -0,0 +1,108 @@
#!/usr/local/bin/python
#CHIPSEC: Platform Security Assessment Framework
#Copyright (c) 2010-2016, Intel Corporation
#
#This program is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public License
#as published by the Free Software Foundation; Version 2.
#
#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with this program; if not, write to the Free Software
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
#Contact information:
#chipsec@intel.com
#
# -------------------------------------------------------------------------------
#
# CHIPSEC: Platform Hardware Security Assessment Framework
# (c) 2010-2016 Intel Corporation
#
# -------------------------------------------------------------------------------
## \addtogroup hal
# chipsec/hal/vmm.py
# ====================
# VMM specific functionality
# 1. Hypercall interfaces
# 2. Second-level Address Translation (SLAT)
# 3. ..
#
# ~~~
__version__ = '1.0'
import struct
import sys
import os.path
from chipsec.logger import logger
class VMMRuntimeError (RuntimeError):
pass
class VMM:
def __init__( self, cs ):
self.cs = cs
self.helper = cs.helper
self.output = ''
(self.membuf0_va, self.membuf0_pa) = (0, 0)
(self.membuf1_va, self.membuf1_pa) = (0, 0)
def __del__(self):
if self.membuf0_va <> 0:
#self.helper.free_physical_mem(self.membuf0_va)
(self.membuf0_va, self.membuf0_pa) = (0, 0)
(self.membuf1_va, self.membuf1_pa) = (0, 0)
def init(self):
(self.membuf0_va, self.membuf0_pa) = self.cs.mem.alloc_physical_mem(0x2000, 0xFFFFFFFFFFFFFFFF)
(self.membuf1_va, self.membuf1_pa) = (self.membuf0_va + 0x1000, self.membuf0_pa + 0x1000)
if self.membuf0_va == 0:
logger().log( "[vmm] Could not allocate memory!")
raise
# Generic hypercall interface
def hypercall(self, rax, rbx, rcx, rdx, rdi, rsi, r8=0, r9=0, r10=0, r11=0, xmm_buffer=0):
return self.helper.hypercall(rcx, rdx, r8, r9, r10, r11, rax, rbx, rdi, rsi, xmm_buffer)
# Hypervisor-specific hypercall interfaces
def hypercall64_five_args(self, vector, arg1=0, arg2=0, arg3=0, arg4=0, arg5=0):
return self.helper.hypercall(0, arg3, arg5, 0, arg4, 0, vector, 0, arg1, arg2)
def hypercall64_memory_based(self, hypervisor_input_value, parameters, size = 0):
self.cs.mem.write_physical_mem(self.membuf0_pa, len(parameters[:0x1000]), parameters[:0x1000])
regs = self.helper.hypercall(hypervisor_input_value & ~0x00010000, self.membuf0_pa, self.membuf1_pa)
self.output = self.helper.read_physical_mem(self.membuf1_pa, size) if size > 0 else ''
return regs
def hypercall64_fast(self, hypervisor_input_value, param0 = 0, param1 = 0):
return self.helper.hypercall(hypervisor_input_value | 0x00010000, param0, param1)
def hypercall64_extended_fast(self, hypervisor_input_value, parameter_block):
(param0, param1, xmm_regs) = struct.unpack('<QQ96s', parameter_block)
self.cs.mem.write_physical_mem(self.membuf0_pa, 0x60, xmm_regs)
return self.helper.hypercall(hypervisor_input_value | 0x00010000, param0, param1, 0, 0, 0, 0, 0, 0, 0, self.membuf0_va)
#
# Dump EPT page tables at specified physical base (EPT pointer)
#
def dump_EPT_page_tables( self, eptp, pt_fname=None ):
_orig_logname = logger().LOG_FILE_NAME
paging_ept = chipsec.hal.paging.c_extended_page_tables( self.cs )
if logger().HAL: logger().log( '[vmm] dumping EPT paging hierarchy at EPTP 0x%08X...' % eptp )
if pt_fname is None: pt_fname = ('ept_%08X' % eptp)
logger().set_log_file( pt_fname )
paging_ept.read_pt_and_show_status( pt_fname, 'EPT', eptp )
logger().set_log_file( _orig_logname )
if paging_ept.failure: logger().error( 'could not dump EPT page tables' )
+24 -10
View File
@@ -223,22 +223,19 @@ class EfiHelper(Helper):
(status, data, attrs) = self.get_EFI_variable_full(name, guidstr)
return data
def set_EFI_variable(self, name, guidstr, data, attrs=0x7):
def set_EFI_variable(self, name, guidstr, data, datasize=None, attrs=0x7):
guid = uuid.UUID(guidstr)
if not attrs: attrs = int(7)
if not data:
size = 0
data = '\0'*4
else: size = len(data)
if data is None: data = '\0'*4
if datasize is None: datasize = len(data)
(Status, DataSize, guidbytes) = edk2.SetVariable(unicode(name), guid.bytes, int(attrs), data, size)
(Status, datasize, guidbytes) = edk2.SetVariable(unicode(name), guid.bytes, int(attrs), data, datasize)
return Status
def delete_EFI_variable(self, name, guid):
return self.set_EFI_variable(name, guid, "")
return self.set_EFI_variable(name, guid, None, 0)
def list_EFI_variables(self):
@@ -290,6 +287,23 @@ class EfiHelper(Helper):
logger().error( "[efi] ACPI is not supported yet" )
return 0
#
# IOSF Message Bus access
#
def msgbus_send_read_message( self, mcr, mcrx ):
logger().error( "[efi] Message Bus is not supported yet" )
return None
def msgbus_send_write_message( self, mcr, mcrx, mdr ):
logger().error( "[efi] Message Bus is not supported yet" )
return None
def msgbus_send_message( self, mcr, mcrx, mdr=None ):
logger().error( "[efi] Message Bus is not supported yet" )
return None
def get_threads_count ( self ):
logger().log_warning( "EFI helper hasn't implemented get_threads_count yet" )
#print "OsHelper for %s does not support get_threads_count from OS API"%self.os_system.lower()
@@ -302,8 +316,8 @@ class EfiHelper(Helper):
def alloc_phys_mem( self, length, max_pa ):
# temporary WA using malloc
va = edk2.allocphysmem(length, max_pa)
pa = self.va2pa(va[0])
return (va[0], pa)
pa = self.va2pa(va)
return (va, pa)
def get_descriptor_table( self, cpu_thread_id, desc_table_code ):
logger().log_warning("EFI helper has not implemented get_descriptor_table yet")
+28 -8
View File
@@ -174,6 +174,10 @@ class OsHelper:
return self.helper.alloc_phys_mem( length, (max_pa_hi<<32|max_pa_lo) )
def va2pa( self, va ):
return self.helper.va2pa( va )
def map_io_space(self, physical_address, length, cache_type):
return self.helper.map_io_space(physical_address, length, cache_type)
def free_physical_mem(self, physical_address):
return self.helper.free_phys_mem(physical_address)
#
# read/write mmio
@@ -244,8 +248,11 @@ class OsHelper:
def get_EFI_variable( self, name, guid ):
return self.helper.get_EFI_variable( name, guid )
def set_EFI_variable( self, name, guid, var, attrs=None ):
return self.helper.set_EFI_variable( name, guid, var, attrs )
def set_EFI_variable( self, name, guid, data, datasize=None, attrs=None ):
return self.helper.set_EFI_variable( name, guid, data, datasize, attrs )
def delete_EFI_variable( self, name, guid ):
return self.helper.delete_EFI_variable( name, guid )
def list_EFI_variables( self ):
return self.helper.list_EFI_variables()
@@ -259,18 +266,25 @@ class OsHelper:
def get_ACPI_table_list(self):
return self.helper.get_ACPI_table_list()
#
# Hypervisor
#
def do_hypercall( self, vector, arg1=0, arg2=0, arg3=0, arg4=0, arg5=0, use_peach=0 ):
return self.helper.do_hypercall( vector, arg1, arg2, arg3, arg4, arg5, use_peach)
#
# CPUID
#
def cpuid( self, eax, ecx ):
return self.helper.cpuid( eax, ecx )
#
# IOSF Message Bus access
#
def msgbus_send_read_message( self, mcr, mcrx ):
return self.helper.msgbus_send_read_message( mcr, mcrx )
def msgbus_send_write_message( self, mcr, mcrx, mdr ):
return self.helper.msgbus_send_write_message( mcr, mcrx, mdr )
def msgbus_send_message( self, mcr, mcrx, mdr ):
return self.helper.msgbus_send_message( mcr, mcrx, mdr )
#
# Affinity
#
@@ -292,6 +306,12 @@ class OsHelper:
def send_sw_smi( self, cpu_thread_id, SMI_code_data, _rax, _rbx, _rcx, _rdx, _rsi, _rdi ):
return self.helper.send_sw_smi( cpu_thread_id, SMI_code_data, _rax, _rbx, _rcx, _rdx, _rsi, _rdi )
#
# Hypercall
#
def hypercall( self, rcx=0, rdx=0, r8=0, r9=0, r10=0, r11=0, rax=0, rbx=0, rdi=0, rsi=0, xmm_buffer=0 ):
return self.helper.hypercall( rcx, rdx, r8, r9, r10, r11, rax, rbx, rdi, rsi, xmm_buffer )
#
# File system
#
+66 -8
View File
@@ -1,6 +1,6 @@
#!/usr/local/bin/python
#CHIPSEC: Platform Security Assessment Framework
#Copyright (c) 2010-2015, Intel Corporation
#Copyright (c) 2010-2016, Intel Corporation
#
#This program is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public License
@@ -116,8 +116,6 @@ READ_PCI_CFG_REGISTER = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x807, METHOD_BUF
WRITE_PCI_CFG_REGISTER = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x808, METHOD_BUFFERED, CHIPSEC_CTL_ACCESS)
IOCTL_READ_PHYSMEM = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x809, METHOD_BUFFERED, CHIPSEC_CTL_ACCESS)
IOCTL_WRITE_PHYSMEM = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80a, METHOD_BUFFERED, CHIPSEC_CTL_ACCESS)
IOCTL_ALLOC_PHYSMEM = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x812, METHOD_BUFFERED, CHIPSEC_CTL_ACCESS)
IOCTL_GET_PHYSADDR = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x815, METHOD_BUFFERED, CHIPSEC_CTL_ACCESS)
IOCTL_LOAD_UCODE_PATCH = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80b, METHOD_BUFFERED, CHIPSEC_CTL_ACCESS)
IOCTL_WRMSR = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80c, METHOD_BUFFERED, CHIPSEC_CTL_ACCESS)
IOCTL_RDMSR = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80d, METHOD_BUFFERED, CHIPSEC_CTL_ACCESS)
@@ -125,9 +123,15 @@ IOCTL_READ_IO_PORT = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80e, METHOD_BUF
IOCTL_WRITE_IO_PORT = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80f, METHOD_BUFFERED, CHIPSEC_CTL_ACCESS)
IOCTL_GET_CPU_DESCRIPTOR_TABLE = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x810, METHOD_BUFFERED, CHIPSEC_CTL_ACCESS)
IOCTL_SWSMI = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x811, METHOD_BUFFERED, CHIPSEC_CTL_ACCESS)
IOCTL_ALLOC_PHYSMEM = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x812, METHOD_BUFFERED, CHIPSEC_CTL_ACCESS)
IOCTL_CPUID = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x813, METHOD_BUFFERED, CHIPSEC_CTL_ACCESS)
IOCTL_HYPERCALL = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x814, METHOD_BUFFERED, CHIPSEC_CTL_ACCESS)
IOCTL_GET_PHYSADDR = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x815, METHOD_BUFFERED, CHIPSEC_CTL_ACCESS)
IOCTL_MAP_IO_SPACE = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x816, METHOD_BUFFERED, CHIPSEC_CTL_ACCESS)
IOCTL_FREE_PHYSMEM = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x817, METHOD_BUFFERED, CHIPSEC_CTL_ACCESS)
IOCTL_WRCR = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x818, METHOD_BUFFERED, CHIPSEC_CTL_ACCESS)
IOCTL_RDCR = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x819, METHOD_BUFFERED, CHIPSEC_CTL_ACCESS)
IOCTL_MSGBUS_SEND_MESSAGE = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x820, METHOD_BUFFERED, CHIPSEC_CTL_ACCESS)
#
# NT Errors
@@ -273,7 +277,7 @@ class Win32Helper(Helper):
try:
self.NtEnumerateSystemEnvironmentValuesEx = windll.ntdll.NtEnumerateSystemEnvironmentValuesEx
self.NtEnumerateSystemEnvironmentValuesEx.restype = c_uint
self.NtEnumerateSystemEnvironmentValuesEx.restype = c_int
self.NtEnumerateSystemEnvironmentValuesEx.argtypes = [c_int, c_void_p, c_void_p]
except AttributeError, msg:
logger().warn( "NtEnumerateSystemEnvironmentValuesEx function doesn't seem to exist" )
@@ -608,6 +612,41 @@ class Win32Helper(Helper):
pa = struct.unpack( 'Q', out_buf )[0]
return (pa,error_code)
#
# HYPERCALL
#
def hypercall( self, rcx, rdx, r8, r9, r10, r11, rax, rbx, rdi, rsi, xmm_buffer ):
if self.os_machine == 'AMD64':
arg_type = 'Q'
out_length = 8
else:
arg_type = 'D'
out_length = 4
out_buf = (c_char * out_length)()
in_buf = struct.pack( '<11' + arg_type, rcx, rdx, r8, r9, r10, r11, rax, rbx, rdi, rsi, xmm_buffer )
out_buf = self._ioctl( IOCTL_HYPERCALL, in_buf, out_length )
return struct.unpack( '<' + arg_type, out_buf )[0]
#
# MAP_IO_SPACE
#
def map_io_space( self, physical_address, length, cache_type ):
out_length = 8
out_buf = (c_char * out_length)()
in_buf = struct.pack( '<3Q', physical_address, length, cache_type )
out_buf = self._ioctl( IOCTL_MAP_IO_SPACE, in_buf, out_length )
virtual_address = struct.unpack( '<Q', out_buf )[0]
return virtual_address
#
# FREE_PHYS_MEM
#
def free_phys_mem( self, physical_address ):
out_length = 8
out_buf = (c_char * out_length)()
in_buf = struct.pack( '<Q', physical_address )
out_buf = self._ioctl( IOCTL_FREE_PHYSMEM, in_buf, out_length )
return
def read_msr( self, cpu_thread_id, msr_addr ):
(eax,edx) = (0,0)
@@ -735,10 +774,10 @@ class Win32Helper(Helper):
(status, data, attributes) = self.get_EFI_variable_full( name, guid, attrs )
return data
def set_EFI_variable( self, name, guid, var, attrs=None ):
var_len = 0
if var is None: var = bytes(0)
else: var_len = len(var)
def set_EFI_variable( self, name, guid, data, datasize, attrs ):
var = bytes(0) if data is None else data
var_len = len(var) if datasize is None else datasize
if attrs is None:
if self.SetFirmwareEnvironmentVariable is not None:
if logger().HAL: logger().log( "[helper] -> SetFirmwareEnvironmentVariable( name='%s', GUID='%s', length=0x%X ).." % (name, "{%s}" % guid, var_len) )
@@ -755,6 +794,9 @@ class Win32Helper(Helper):
#raise WinError(errno.EIO, "Unable to set EFI variable")
return status
def delete_EFI_variable(self, name, guid):
return self.set_EFI_variable( name, guid, None, datasize=0, attrs=None )
def list_EFI_variables( self, infcls=2 ):
if logger().VERBOSE: logger().log( '[helper] -> NtEnumerateSystemEnvironmentValuesEx( infcls=%d )..' % infcls )
efi_vars = create_string_buffer( EFI_VAR_MAX_BUFFER_SIZE )
@@ -856,6 +898,22 @@ class Win32Helper(Helper):
return tBuffer[:retVal], xsdt
#
# IOSF Message Bus access
#
def msgbus_send_read_message( self, mcr, mcrx ):
logger().error( "[helper] Message Bus is not supported yet" )
return None
def msgbus_send_write_message( self, mcr, mcrx, mdr ):
logger().error( "[helper] Message Bus is not supported yet" )
return None
def msgbus_send_message( self, mcr, mcrx, mdr=None ):
logger().error( "[helper] Message Bus is not supported yet" )
return None
#
# File system
#
+23 -46
View File
@@ -1,5 +1,5 @@
#CHIPSEC: Platform Security Assessment Framework
#Copyright (c) 2010-2015, Intel Corporation
#Copyright (c) 2010-2016, Intel Corporation
#
#This program is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public License
@@ -21,9 +21,9 @@
"""
`BIOS Boot Hijacking and VMware Vulnerabilities Digging <http://powerofcommunity.net/poc2007/sunbing.pdf>`_ - Sun Bing
Checks for BIOS Interface Lock including Top Swap Mode
Checks for BIOS Top Swap Mode
`BIOS Boot Hijacking and VMware Vulnerabilities Digging <http://powerofcommunity.net/poc2007/sunbing.pdf>`_ - Sun Bing
"""
from chipsec.module_common import *
@@ -34,62 +34,39 @@ class bios_ts(chipsec.module_common.BaseModule):
BaseModule.__init__(self)
def is_supported(self):
if not chipsec.chipset.is_register_defined( self.cs, 'GCS' ):
self.logger.error( "Couldn't find definition of required configuration registers (GCS)... skipping" )
return False
if not chipsec.chipset.register_has_field( self.cs, 'GCS', 'BILD'):
self.logger.error( "Couldn't locate 'BIOS Interface Lock Down' bit in the configuration for the BUC register... skipping" )
return False
#return (self.cs.get_chipset_id() not in chipsec.chipset.CHIPSET_FAMILY_ATOM)
return True
def check_top_swap_mode(self):
def check_bios_iface_lock(self):
self.logger.start_test( "BIOS Interface Lock (including Top Swap Mode)" )
self.logger.start_test( "BIOS Interface Lock and Top Swap Mode" )
if not chipsec.chipset.is_register_defined( self.cs, 'BC' ):
self.logger.warn("Couldn't locate the 'BC' register definition")
bild = 0
if chipsec.chipset.is_control_defined( self.cs, 'BiosInterfaceLockDown' ):
bild = chipsec.chipset.get_control( self.cs, 'BiosInterfaceLockDown' )
self.logger.log( "[*] BiosInterfaceLockDown (BILD) control = %d" % bild )
else:
bc_reg = chipsec.chipset.read_register( self.cs, 'BC' )
chipsec.chipset.print_register( self.cs, 'BC', bc_reg )
if not chipsec.chipset.register_has_field( self.cs, 'BC', 'TSS' ):
self.logger.warn( "Couldn't locate 'TSS' bit in the 'BC' register definition" )
else:
tss = chipsec.chipset.get_register_field( self.cs, 'BC', bc_reg, 'TSS' )
self.logger.log( "[*] BIOS Top Swap mode is %s" % ('enabled' if (1==tss) else 'disabled') )
if not chipsec.chipset.is_register_defined( self.cs, 'BUC' ):
self.logger.warn( "Couldn't locate the 'BUC' register definition" )
else:
buc_reg = chipsec.chipset.read_register( self.cs, 'BUC' )
chipsec.chipset.print_register( self.cs, 'BUC', buc_reg )
if not chipsec.chipset.register_has_field( self.cs, 'BUC', 'TS' ):
self.logger.warn( "Couldn't locate 'TS' bit in the 'BUC' register definition" )
else:
ts = chipsec.chipset.get_register_field( self.cs, 'BUC', buc_reg, 'TS' )
self.logger.log( "[*] RTC version of TS = %x" % ts )
if not chipsec.chipset.is_register_defined( self.cs, 'GCS' ):
self.logger.error( "Couldn't locate required 'GCS' register definition" )
self.logger.error( "BiosInterfaceLockDown (BILD) control is not defined" )
return ModuleResult.ERROR
gcs_reg = chipsec.chipset.read_register( self.cs, 'GCS' )
chipsec.chipset.print_register( self.cs, 'GCS', gcs_reg )
if not chipsec.chipset.register_has_field( self.cs, 'GCS', 'BILD' ):
self.logger.error( "Couldn't locate 'BILD' bit in the 'GCS' register definition" )
return ModuleResult.ERROR
bild = chipsec.chipset.get_register_field( self.cs, 'GCS', gcs_reg, 'BILD' )
self.logger.log( '' )
if chipsec.chipset.is_control_defined( self.cs, 'TopSwapStatus' ):
tss = chipsec.chipset.get_control( self.cs, 'TopSwapStatus' )
self.logger.log( "[*] BIOS Top Swap mode is %s (TSS = %d)" % ('enabled' if (1==tss) else 'disabled', tss) )
if chipsec.chipset.is_control_defined( self.cs, 'TopSwap' ):
ts = chipsec.chipset.get_control( self.cs, 'TopSwap' )
self.logger.log( "[*] RTC TopSwap control (TS) = %x" % ts )
if 0 == bild:
res = ModuleResult.FAILED
self.logger.log_failed_check( "BIOS Interface is not locked (including Top Swap Mode)" )
return ModuleResult.FAILED
else:
res = ModuleResult.PASSED
self.logger.log_passed_check( "BIOS Interface is locked (including Top Swap Mode)" )
return ModuleResult.PASSED
return res
# --------------------------------------------------------------------------
# run( module_argv )
# Required function: run here all tests from this module
# --------------------------------------------------------------------------
def run(self, module_argv ):
return self.check_top_swap_mode()
return self.check_bios_iface_lock()
@@ -1,5 +1,5 @@
#CHIPSEC: Platform Security Assessment Framework
#Copyright (c) 2010-2015, Intel Corporation
#Copyright (c) 2010-2016, Intel Corporation
#
#This program is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public License
@@ -138,7 +138,8 @@ class s3bootscript(BaseModule):
else:
found,bootscript_PAs = self._uefi.find_s3_bootscript()
if not found:
self.logger.log_good( "S3 Boot-Script wasn't found in EFI variables (BIOS may still be using some other mechanism to locate it)" )
self.logger.log_good( "Didn't find any S3 boot-scripts in EFI variables" )
self.logger.log_warn_check( "S3 Boot-Script was not found. Firmware may be using other ways to store/locate it" )
return ModuleResult.WARNING
self.logger.log_important( 'Found %d S3 boot-script(s) in EFI variables' % len(bootscript_PAs) )
@@ -165,7 +166,7 @@ class s3bootscript(BaseModule):
else:
# BOOTSCRIPT_INSIDE_SMRAM
status = ModuleResult.WARNING
self.logger.log( "S3 Boot-Script is inside SMRAM. The script is protected but Dispatch opcodes cannot be inspected" )
self.logger.log_warn_check( "S3 Boot-Script is inside SMRAM. The script is protected but Dispatch opcodes cannot be inspected" )
self.logger.log_important( "Additional testing of the S3 boot-script can be done using tools.uefi.s3script_modify" )
@@ -183,14 +184,15 @@ class s3bootscript(BaseModule):
script_pa = int(module_argv[0],16)
self.logger.log( '[*] Using manually assigned S3 Boot-Script table base: 0x%016X' % script_pa )
(self.smrambase, self.smramlimit, self.smramsize) = self.cs.cpu.get_SMRAM()
self.logger.log( '[*] SMRAM: Base = 0x%016X, Limit = 0x%016X, Size = 0x%08X' % (self.smrambase, self.smramlimit, self.smramsize) )
if self.smrambase is not None and self.smramlimit is not None:
self.logger.log( '[*] SMRAM: Base = 0x%016X, Limit = 0x%016X, Size = 0x%08X' % (self.smrambase, self.smramlimit, self.smramsize) )
try:
if script_pa is not None: return self.check_s3_bootscripts( script_pa )
else: return self.check_s3_bootscripts( )
except:
logger().error("The module was not able to recognize the S3 resume boot script on this platform.")
if logger().VERBOSE: raise
self.logger.error("The module was not able to recognize the S3 resume boot script on this platform.")
if self.logger.VERBOSE: raise
return ModuleResult.ERROR
+7 -7
View File
@@ -17,8 +17,8 @@
#Contact information:
#chipsec@intel.com
#
"""
`Preventing & Detecting Xen Hypervisor Subversions <http://www.invisiblethingslab.com/resources/bh08/part2-full.pdf>`_ by Joanna Rutkowska & Rafal Wojtczuk
@@ -83,7 +83,7 @@ class remap(BaseModule):
self.logger.log( "[*] Top Of Upper Memory: 0x%016X" % touud )
self.logger.log( "[*] Remap Limit Address: 0x%016X" % (remaplimit|0xFFFFF) )
self.logger.log( "[*] Remap Base Address : 0x%016X" % remapbase )
self.logger.log( "[*] 4GB : 0x%016X" % self.cs.Cfg.BIT32 )
self.logger.log( "[*] 4GB : 0x%016X" % chipsec.defines.BIT32 )
self.logger.log( "[*] Top Of Low Memory : 0x%016X" % tolud )
self.logger.log( "[*] TSEG (SMRAM) Base : 0x%016X\n" % tsegmb )
@@ -100,10 +100,10 @@ class remap(BaseModule):
if ok: self.logger.log_good( " Remap window configuration is correct: REMAPBASE <= REMAPLIMIT < TOUUD" )
else: self.logger.log_bad( " Remap window configuration is not correct" )
ok = (0 == tolud & self.cs.Cfg.ALIGNED_1MB) and \
(0 == touud & self.cs.Cfg.ALIGNED_1MB) and \
(0 == remapbase & self.cs.Cfg.ALIGNED_1MB) and \
(0 == remaplimit & self.cs.Cfg.ALIGNED_1MB)
ok = (0 == tolud & chipsec.defines.ALIGNED_1MB) and \
(0 == touud & chipsec.defines.ALIGNED_1MB) and \
(0 == remapbase & chipsec.defines.ALIGNED_1MB) and \
(0 == remaplimit & chipsec.defines.ALIGNED_1MB)
remap_ok = remap_ok and ok
if ok: self.logger.log_good( " All addresses are 1MB aligned" )
else: self.logger.log_bad( " Not all addresses are 1MB aligned" )
@@ -0,0 +1 @@
EFI\Boot\Shell.efi
@@ -0,0 +1,14 @@
Name=SMI_name
Desc=custom_description
SMI_code=*
SMI_data=*
RAX=PTR
RBX=PTR
RCX=PTR
RDX=PTR
RSI=PTR
RDI=PTR
PTR_OFFSET=0x10
SIG=4141
SIG_OFFSET=0x0
@@ -1,5 +1,5 @@
#CHIPSEC: Platform Security Assessment Framework
#Copyright (c) 2010-2015, Intel Corporation
#Copyright (c) 2010-2016, 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,32 +23,54 @@
"""
.. note:: This module will attempt to modify the S3 Boot Script on the platform. Doing this could cause the platform to malfunction. Use with care!
Usage:
Replacing existing opcode:
chipsec_main.py -m tools.uefi.s3script_modify -a replace_op,<reg_opcode>,<address>,<value>
<reg_opcode> = pci_wr|mmio_wr|io_wr|pci_rw|mmio_rw|io_rw
chipsec_main.py -m tools.uefi.s3script_modify -a replace_op,mem[,<address>,<value>]
chipsec_main.py -m tools.uefi.s3script_modify -a replace_op,dispatch
chipsec_main.py -m tools.uefi.s3script_modify -a replace_op,dispatch_ep
Adding new opcode:
chipsec_main.py -m tools.uefi.s3script_modify -a add_op,<reg_opcode>,<address>,<value>,<width>
<reg_opcode> = pci_wr|mmio_wr|io_wr
chipsec_main.py -m tools.uefi.s3script_modify -a add_op,dispatch[,<entrypoint>]
Examples:
``chipsec_main.py -m tools.uefi.s3script_modify -a <reg_opcode>,<address>,<value>``
``chipsec_main.py -m tools.uefi.s3script_modify -a replace_op,<reg_opcode>,<address>,<value>``
<reg_opcode> = pci_wr|mmio_wr|io_wr|pci_rw|mmio_rw|io_rw
The option will look for a script opcode that writes to PCI config, MMIO or I/O
registers and modify the opcode to write the given value to the register with
the given address.
After executing this, if the system is vulnerable to boot script modification,
the hardware configuration will have changed according to given <reg_opcode>.
``chipsec_main.py -m tools.uefi.s3script_modify -a mem``
``chipsec_main.py -m tools.uefi.s3script_modify -a replace_op,mem``
The option will look for a script opcode that writes to memory and
modify the opcode to write the given value to the given address.
By default this test will allocate memory and write write 0xB007B007 that location.
After executing this, if the system is vulnerable to boot script modification, you
should find the given value in the allocated memory location.
``chipsec_main.py -m tools.uefi.s3script_modify -a dispatch``
The modify_dispatch option will look for a dispatch opcode in the script and
``chipsec_main.py -m tools.uefi.s3script_modify -a replace_op,dispatch``
The option will look for a dispatch opcode in the script and
modify the opcode to point to a different entry point. The new entry point will
contain a HLT instruction.
After executing this, if the system is vulnerable to boot script modification,
the system should hang on resume from S3.
``chipsec_main.py -m tools.uefi.s3script_modify -a dispatch_ep``
The modify_dispatch_ep option will look for a dispatch opcode in the script and
``chipsec_main.py -m tools.uefi.s3script_modify -a replace_op,dispatch_ep``
The option will look for a dispatch opcode in the script and
will modify memory at the entry point for that opcode. The modified instructions
will contain a HLT instruction.
After executing this, if the system is vulnerable to dispatch opcode entry point
modification, the system should hang on resume from S3.
``chipsec_main.py -m tools.uefi.s3script_modify -a add_op,<reg_opcode>,<address>,<value>,<width>``
<reg_opcode> = pci_wr|mmio_wr|io_wr
The option will add a new opcode which writes to PCI config, MMIO or I/O
registers with specified values.
``chipsec_main.py -m tools.uefi.s3script_modify -a add_op,dispatch``
The option will add a new DISPATCH opcode to the script with entry point to
either existing or newly allocated memory.
"""
examples_str = """ Examples:
@@ -1,5 +1,5 @@
#CHIPSEC: Platform Security Assessment Framework
#Copyright (c) 2010-2015, Intel Corporation
#Copyright (c) 2010-2016, Intel Corporation
#
#This program is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public License
@@ -74,12 +74,12 @@ class cpuid_fuzz (BaseModule):
self.logger.log( "[*] CPUID EAX: 0x%08X" % eax )
if _FUZZ_ECX_RANDOM:
ecx = random.randint( 0, 0xFFFFFFFF )
(r_eax, r_ebx, r_ecx, r_edx) = self.cs.cpuid.cpuid( eax, ecx )
(r_eax, r_ebx, r_ecx, r_edx) = self.cs.cpu.cpuid( eax, ecx )
else:
for ecx in range( _MAX_ECX ):
logger.log( " > ECX: 0x%08X" % ecx )
if _FLUSH_LOG_EACH_ITER: self.logger.flush()
(r_eax, r_ebx, r_ecx, r_edx) = self.cs.cpuid.cpuid( eax, ecx )
(r_eax, r_ebx, r_ecx, r_edx) = self.cs.cpu.cpuid( eax, ecx )
if _LOG_OUT_RESULTS: logger.log( " Out: EAX=0x%08X, EBX=0x%08X, ECX=0x%08X, EDX=0x%08X" % (r_eax,r_ebx,r_ecx,r_edx) )
it += 1
return True
@@ -1,5 +1,5 @@
#CHIPSEC: Platform Security Assessment Framework
#Copyright (c) 2010-2015, Intel Corporation
#Copyright (c) 2010-2016, Intel Corporation
#
#This program is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public License
@@ -173,7 +173,7 @@ def fuzz_pcie_device( b, d, f ):
if CALC_MMIO_SIZE:
size = get_mmio_range_size( b, d, f, bar_off )
logger.log( "[*] + 0x%02X (%X): MMIO BAR at 0x%016X (64-bit? %d) with size: 0x%08X. Fuzzing.." % (bar_off,bar_reg,bar,is64bit,size) )
if ACTIVE_RANGE and size > 0x1000: #Vbox GT MMIO size = 0x02000000
if ACTIVE_RANGE and size > 0x1000:
list = []
list = find_active_range(bar, size)
if len(list) > 0:
@@ -0,0 +1,21 @@
#CHIPSEC: Platform Security Assessment Framework
#Copyright (c) 2010-2016, Intel Corporation
#
#This program is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public License
#as published by the Free Software Foundation; Version 2.
#
#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with this program; if not, write to the Free Software
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
#Contact information:
#chipsec@intel.com
#
@@ -0,0 +1,51 @@
#CHIPSEC: Platform Security Assessment Framework
#Copyright (c) 2010-2016, Intel Corporation
#
#This program is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public License
#as published by the Free Software Foundation; Version 2.
#
#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with this program; if not, write to the Free Software
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
#Contact information:
#chipsec@intel.com
#
"""
PoC test for Host OS Crash when writing to IA32_APIC_BASE MSR (Oracle VirtualBox CVE-2015-0377)
http://www.oracle.com/technetwork/topics/security/cpujan2015-1972971.html
Usage:
``chipsec_main.py -i -m tools.vmm.vbox_crash_apicbase``
"""
from chipsec.module_common import *
_MODULE_NAME = 'vbox_crash_apicbase'
class vbox_crash_apicbase (BaseModule):
def run( self, module_argv ):
self.logger.start_test( "Host OS Crash due to IA32_APIC_BASE (Oracle VirtualBox CVE-2015-0377)" )
tid = 0
#(eax, edx) = self.cs.msr.read_msr( tid, 0x1B )
#self.cs.msr.write_msr( tid, 0x1B, eax, 0xDEADBEEF )
apicbase_msr = chipsec.chipset.read_register( self.cs, 'IA32_APIC_BASE', tid )
chipsec.chipset.print_register( self.cs, 'IA32_APIC_BASE', apicbase_msr )
apicbase_msr = 0xDEADBEEF00000000 | (apicbase_msr & 0xFFFFFFFF)
self.logger.log( "[*] writing 0x%016X to IA32_APIC_BASE MSR.." % apicbase_msr )
chipsec.chipset.write_register( self.cs, 'IA32_APIC_BASE', apicbase_msr, tid )
# If we are here, then we are fine ;)
self.logger.log_passed_check( "VMM/Host OS didn't crash (not vulnerable)" )
return ModuleResult.PASSED
+71 -25
View File
@@ -38,12 +38,16 @@ class CPUCommand(BaseCommand):
"""
>>> chipsec_util cpu info
>>> chipsec_util cpu cr <cpu_id> <cr_number> [value]
>>> chipsec_util cpu cpuid <eax> [ecx]
>>> chipsec_util cpu pt [paging_base_cr3]
Examples:
>>> chipsec_util cpu info
>>> chipsec_util cpu cr 0 0
>>> chipsec_util cpu cr 0 4 0x0
>>> chipsec_util cpu cpuid 40000000
>>> chipsec_util cpu pt
"""
def requires_driver(self):
@@ -59,44 +63,86 @@ class CPUCommand(BaseCommand):
op = self.argv[2]
t = time.time()
try:
_cpu = chipsec.hal.cpu.CPU(self.cs)
except chipsec.hal.cpu.CPURuntimeError, msg:
print msg
return
if 'info' == op:
self.logger.log( "[CHIPSEC] CPU information:" )
ht = _cpu.is_HT_active()
threads_per_core = _cpu.get_number_logical_processor_per_core()
threads_per_pkg = _cpu.get_number_logical_processor_per_package()
cores_per_pkg = _cpu.get_number_physical_processor_per_package()
threads_count = _cpu.get_number_threads_from_APIC_table()
sockets_count = _cpu.get_number_sockets_from_APIC_table()
ht = self.cs.cpu.is_HT_active()
threads_per_core = self.cs.cpu.get_number_logical_processor_per_core()
threads_per_pkg = self.cs.cpu.get_number_logical_processor_per_package()
cores_per_pkg = self.cs.cpu.get_number_physical_processor_per_package()
self.logger.log( " Hyper-Threading : %s" % ('Enabled' if ht else 'Disabled') )
self.logger.log( " CPU cores per package : %d" % cores_per_pkg )
self.logger.log( " CPU threads per core : %d" % threads_per_core )
self.logger.log( " CPU threads per package : %d" % threads_per_pkg )
self.logger.log( " Number of sockets : %d" % sockets_count )
self.logger.log( " Number of CPU threads : %d" % threads_count )
try:
threads_count = self.cs.cpu.get_number_threads_from_APIC_table()
sockets_count = self.cs.cpu.get_number_sockets_from_APIC_table()
self.logger.log( " Number of sockets : %d" % sockets_count )
self.logger.log( " Number of CPU threads : %d" % threads_count )
except:
pass
elif 'cr' == op:
if len(self.argv) < 5:
if len(self.argv) > 5:
cpu_thread_id = int(self.argv[3],10)
cr_number = int(self.argv[4],16)
value = int(self.argv[5], 16)
self.logger.log( "[CHIPSEC] CPU%d: write CR%d <- 0x%08X" % (cpu_thread_id, cr_number, value) )
self.cs.cpu.write_cr( cpu_thread_id, cr_number, value )
return True
elif len(self.argv) > 4:
cpu_thread_id = int(self.argv[3],10)
cr_number = int(self.argv[4],16)
value = self.cs.cpu.read_cr( cpu_thread_id, cr_number )
self.logger.log( "[CHIPSEC] CPU%d: read CR%d -> 0x%08X" % (cpu_thread_id, cr_number, value) )
return value
else:
for tid in range(self.cs.msr.get_cpu_thread_count()):
cr0 = self.cs.cpu.read_cr( tid, 0 )
cr2 = self.cs.cpu.read_cr( tid, 2 )
cr3 = self.cs.cpu.read_cr( tid, 3 )
cr4 = self.cs.cpu.read_cr( tid, 4 )
cr8 = self.cs.cpu.read_cr( tid, 8 )
self.logger.log( "[CHIPSEC][cpu%d] x86 Control Registers:" % tid )
self.logger.log( " CR0: 0x%016X" % cr0 )
self.logger.log( " CR2: 0x%016X" % cr2 )
self.logger.log( " CR3: 0x%016X" % cr3 )
self.logger.log( " CR4: 0x%016X" % cr4 )
self.logger.log( " CR8: 0x%016X" % cr8 )
elif 'cpuid' == op:
if len(self.argv) < 4:
print CPUCommand.__doc__
return
cpu_thread_id = int(self.argv[3],10)
cr_number = int(self.argv[4],16)
eax = int(self.argv[3],16)
ecx = int(self.argv[4],16) if 5 == len(self.argv) else 0
if len(self.argv) > 5:
value = int(self.argv[5], 16)
self.logger.log( "[CHIPSEC] CPU: %d write CR%d <- 0x%08X" % (cpu_thread_id, cr_number, value) )
self.cs.cpu.write_cr( cpu_thread_id, cr_number, value )
return True
self.logger.log( "[CHIPSEC] CPUID < EAX: 0x%08X" % eax)
self.logger.log( "[CHIPSEC] ECX: 0x%08X" % ecx)
(_eax,_ebx,_ecx,_edx) = self.cs.cpu.cpuid( eax, ecx )
self.logger.log( "[CHIPSEC] CPUID > EAX: 0x%08X" % _eax )
self.logger.log( "[CHIPSEC] EBX: 0x%08X" % _ebx )
self.logger.log( "[CHIPSEC] ECX: 0x%08X" % _ecx )
self.logger.log( "[CHIPSEC] EDX: 0x%08X" % _edx )
elif op == "pt":
if len(self.argv) == 4:
cr3 = int(self.argv[3],16)
pt_fname = 'pt_%08X' % cr3
self.logger.log( "[CHIPSEC] paging physical base (CR3): 0x%016X" % cr3 )
self.logger.log( "[CHIPSEC] dumping paging hierarchy to '%s'..." % pt_fname )
self.cs.cpu.dump_page_tables( cr3, pt_fname )
else:
value = self.cs.cpu.read_cr( cpu_thread_id, cr_number )
self.logger.log( "[CHIPSEC] CPU: %d read CR%d -> 0x%08X" % (cpu_thread_id, cr_number, value) )
return value
for tid in range(self.cs.msr.get_cpu_thread_count()):
cr3 = self.cs.cpu.read_cr( tid, 3 )
pt_fname = 'cpu%d_pt_%08X' % (tid,cr3)
self.logger.log( "[CHIPSEC][cpu%d] paging physical base (CR3): 0x%016X" % (tid,cr3) )
self.logger.log( "[CHIPSEC][cpu%d] dumping paging hierarchy to '%s'..." % (tid,pt_fname) )
self.cs.cpu.dump_page_tables( cr3, pt_fname )
else:
print CPUCommand.__doc__
-67
View File
@@ -1,67 +0,0 @@
#!/usr/local/bin/python
#CHIPSEC: Platform Security Assessment Framework
#Copyright (c) 2010-2015, Intel Corporation
#
#This program is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public License
#as published by the Free Software Foundation; Version 2.
#
#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with this program; if not, write to the Free Software
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
#Contact information:
#chipsec@intel.com
#
__version__ = '1.0'
from chipsec.command import BaseCommand
# ###################################################################
#
# CPUid
#
# ###################################################################
class CPUIDCommand(BaseCommand):
"""
>>> chipsec_util cpuid <eax> [ecx]
Examples:
>>> chipsec_util cpuid 40000000
"""
def requires_driver(self):
# No driver required when printing the util documentation
if len(self.argv) < 3:
return False
return True
def run(self):
if len(self.argv) < 3:
print CPUIDCommand.__doc__
return
eax = int(self.argv[2],16)
ecx = int(self.argv[3],16) if 4 == len(self.argv) else 0
self.logger.log( "[CHIPSEC] CPUID < EAX: 0x%08X" % eax)
self.logger.log( "[CHIPSEC] ECX: 0x%08X" % ecx)
val = self.cs.cpuid.cpuid( eax, ecx )
self.logger.log( "[CHIPSEC] CPUID > EAX: 0x%08X" % (val[0]) )
self.logger.log( "[CHIPSEC] EBX: 0x%08X" % (val[1]) )
self.logger.log( "[CHIPSEC] ECX: 0x%08X" % (val[2]) )
self.logger.log( "[CHIPSEC] EDX: 0x%08X" % (val[3]) )
commands = { 'cpuid': CPUIDCommand }
+120
View File
@@ -0,0 +1,120 @@
#!/usr/local/bin/python
#CHIPSEC: Platform Security Assessment Framework
#Copyright (c) 2010-2016, Intel Corporation
#
#This program is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public License
#as published by the Free Software Foundation; Version 2.
#
#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with this program; if not, write to the Free Software
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
#Contact information:
#chipsec@intel.com
#
__version__ = '1.0'
import os
import sys
import time
import chipsec_util
from chipsec.command import BaseCommand
from chipsec.logger import *
from chipsec.file import *
from chipsec.hal.ec import *
# Embedded Controller
class ECCommand(BaseCommand):
"""
>>> chipsec_util ec dump [<size>]
>>> chipsec_util ec command <command>
>>> chipsec_util ec read <start_offset> [<size>]
>>> chipsec_util ec write <offset> <byte_val>
>>> chipsec_util ec index [<offset>]
Examples:
>>> chipsec_util ec dump
>>> chipsec_util ec command 0x001
>>> chipsec_util ec read 0x2F
>>> chipsec_util ec write 0x2F 0x00
>>> chipsec_util ec index
"""
def requires_driver(self):
# No driver required when printing the util documentation
if len(self.argv) < 3:
return False
return True
def run(self):
if len(self.argv) < 3:
print ECCommand.__doc__
return
op = self.argv[2]
t = time.time()
try:
_ec = EC( self.cs )
except BaseException, msg:
print msg
return
if ( 'command' == op ):
cmd = int(self.argv[3],16)
self.logger.log( "[CHIPSEC] Sending EC command 0x%X" % cmd )
_ec.write_command( cmd )
elif ( 'dump' == op ):
size = int(self.argv[3],16) if len(self.argv) > 3 else 0x100
buf = _ec.read_range( 0, size )
self.logger.log( "[CHIPSEC] EC RAM:" )
print_buffer( buf )
elif ( 'read' == op ):
start_off = int(self.argv[3],16)
if len(self.argv) > 4:
size = int(self.argv[4],16)
buf = _ec.read_range( start_off, size )
self.logger.log( "[CHIPSEC] EC memory read: offset 0x%X size 0x%X" % (start_off, size) )
print_buffer( buf )
else:
val = _ec.read_memory( start_off ) if start_off < 0x100 else _ec.read_memory_extended( start_off )
self.logger.log( "[CHIPSEC] EC memory read: offset 0x%X = 0x%X" % (start_off, val) )
elif ( 'write' == op ):
off = int(self.argv[3],16)
val = int(self.argv[4],16)
self.logger.log( "[CHIPSEC] EC memory write: offset 0x%X = 0x%X" % (off, val) )
if off < 0x100: _ec.write_memory( off, val )
else: _ec.write_memory_extended( off, val )
elif ( 'index' == op ):
if len(self.argv) == 3:
self.logger.log( "[CHIPSEC] EC index I/O: dumping memory..." )
mem = []
for off in range(0x10000):
mem.append( chr(_ec.read_idx( off )) )
print_buffer( mem )
del mem
elif len(self.argv) == 4:
off = int(self.argv[3],16)
val = _ec.read_idx(off)
self.logger.log( "[CHIPSEC] EC index I/O: reading memory offset 0x%X: 0x%X" % (off, val) )
else:
self.logger.error( "unknown command-line option '%.32s'" % op )
print ECCommand.__doc__
return
self.logger.log( "[CHIPSEC] (ec) time elapsed %.3f" % (time.time()-t) )
commands = { 'ec': ECCommand }
+4 -1
View File
@@ -45,6 +45,7 @@ class IOMMUCommand(BaseCommand):
>>> chipsec_util iommu config [iommu_engine]
>>> chipsec_util iommu status [iommu_engine]
>>> chipsec_util iommu enable|disable <iommu_engine>
>>> chipsec_util iommu pt
Examples:
@@ -52,6 +53,7 @@ class IOMMUCommand(BaseCommand):
>>> chipsec_util iommu config VTD
>>> chipsec_util iommu status GFXVTD
>>> chipsec_util iommu enable VTD
>>> chipsec_util iommu pt
"""
def requires_driver(self):
@@ -102,6 +104,7 @@ class IOMMUCommand(BaseCommand):
for e in _iommu_engines:
if 'config' == op: _iommu.dump_IOMMU_configuration( e )
elif 'pt' == op: _iommu.dump_IOMMU_page_tables( e )
elif 'status' == op: _iommu.dump_IOMMU_status( e )
elif 'enable' == op: _iommu.set_IOMMU_Translation( e, 1 )
elif 'disable' == op: _iommu.set_IOMMU_Translation( e, 0 )
@@ -112,4 +115,4 @@ class IOMMUCommand(BaseCommand):
self.logger.log( "[CHIPSEC] (iommu) time elapsed %.3f" % (time.time()-t) )
commands = { 'iommu': IOMMUCommand }
commands = { 'iommu': IOMMUCommand }
+100
View File
@@ -0,0 +1,100 @@
#!/usr/local/bin/python
#CHIPSEC: Platform Security Assessment Framework
#Copyright (c) 2010-2016, Intel Corporation
#
#This program is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public License
#as published by the Free Software Foundation; Version 2.
#
#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with this program; if not, write to the Free Software
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
#Contact information:
#chipsec@intel.com
#
__version__ = '1.0'
import os
import sys
import time
import chipsec_util
from chipsec.command import BaseCommand
from chipsec.logger import *
from chipsec.file import *
from chipsec.hal.msgbus import MsgBus
# Message Bus
class MsgBusCommand(BaseCommand):
"""
>>> chipsec_util msgbus read <port> <register>
>>> chipsec_util msgbus write <port> <register> <value>
>>> chipsec_util msgbus message <port> <register> <opcode> [value]
>>>
>>> <port> : message bus port of the target unit
>>> <register>: message bus register/offset in the target unit port
>>> <value> : value to be written to the message bus register/offset
>>> <opcode> : opcode of the message on the message bus
Examples:
>>> chipsec_util msgbus read 0x3 0x2E
>>> chipsec_util msgbus write 0x3 0x27 0xE0000001
>>> chipsec_util msgbus message 0x3 0x2E 0x10
>>> chipsec_util msgbus message 0x3 0x2E 0x11 0x0
"""
def requires_driver(self):
# No driver required when printing the util documentation
if len(self.argv) < 3:
return False
return True
def run(self):
if len(self.argv) > 7 or len(self.argv) < 5:
print MsgBusCommand.__doc__
return
op = self.argv[2]
t = time.time()
_msgbus = self.cs.msgbus
res = None
port = int(self.argv[3], 16)
reg = int(self.argv[4], 16)
if 'read' == op:
self.logger.log("[CHIPSEC] msgbus read: port 0x%02X + 0x%08X" % (port, reg))
res = _msgbus.msgbus_reg_read( port, reg )
elif 'write' == op:
if len(self.argv) < 6:
print msgbuscmd.__doc__
return
val = int(self.argv[5], 16)
self.logger.log("[CHIPSEC] msgbus write: port 0x%02X + 0x%08X < 0x%08X" % (port, reg, val))
res = _msgbus.msgbus_reg_write( port, reg, val )
elif 'message' == op:
opcode = int(self.argv[5], 16)
val = None if len(self.argv) < 7 else int(self.argv[6], 16)
self.logger.log("[CHIPSEC] msgbus message: port 0x%02X + 0x%08X, opcode: 0x%02X" % (port, reg, opcode))
if val is not None: self.logger.log("[CHIPSEC] data: 0x%08X" % val)
res = _msgbus.msgbus_send_message( port, reg, opcode, val )
else:
print msgbuscmd.__doc__
return
if res is not None: self.logger.log("[CHIPSEC] result: 0x%08X" % res)
self.logger.log( "[CHIPSEC] (msgbus) time elapsed %.3f" % (time.time()-t) )
commands = { 'msgbus': MsgBusCommand }
+22 -23
View File
@@ -18,8 +18,8 @@
#Contact information:
#chipsec@intel.com
#
"""
CHIPSEC includes functionality for reading and writing the SPI flash. When an image file is created from reading the SPI flash, this image can be parsed to reveal sections, files, variables, etc.
@@ -75,61 +75,60 @@ class SPICommand(BaseCommand):
t = time.time()
_msg = "it may take a few minutes (use DEBUG or VERBOSE logger options to see progress)"
if ( 'erase' == spi_op ):
spi_fla = int(self.argv[3],16)
self.logger.log( "[CHIPSEC] Erasing SPI Flash block at FLA = 0x%X" % spi_fla )
#if not _spi.disable_BIOS_write_protection():
# self.logger.error( "Could not disable SPI Flash protection. Still trying.." )
self.logger.log( "[CHIPSEC] erasing SPI flash memory block at FLA = 0x%X" % spi_fla )
ok = _spi.erase_spi_block( spi_fla )
if ok: self.logger.log_result( "SPI Flash erase done" )
else: self.logger.warn( "SPI Flash erase returned error (turn on VERBOSE)" )
if ok: self.logger.log_result( "completed SPI flash memory erase" )
else: self.logger.warn( "SPI flash erase returned error (turn on VERBOSE)" )
elif ( 'write' == spi_op and 5 == len(self.argv) ):
spi_fla = int(self.argv[3],16)
filename = self.argv[4]
self.logger.log( "[CHIPSEC] Writing to SPI Flash at FLA = 0x%X from '%.64s'" % (spi_fla, filename) )
#if not _spi.disable_BIOS_write_protection():
# self.logger.error( "Could not disable SPI Flash protection. Still trying.." )
self.logger.log( "[CHIPSEC] writing to SPI flash memory at FLA = 0x%X from '%.64s'" % (spi_fla, filename) )
ok = _spi.write_spi_from_file( spi_fla, filename )
if ok: self.logger.log_result( "SPI Flash write done" )
else: self.logger.warn( "SPI Flash write returned error (turn on VERBOSE)" )
if ok: self.logger.log( "[CHIPSEC] completed SPI flash memory write" )
else: self.logger.warn( "SPI flash write returned error (turn on VERBOSE)" )
elif ( 'read' == spi_op ):
spi_fla = int(self.argv[3],16)
length = int(self.argv[4],16)
self.logger.log( "[CHIPSEC] Reading 0x%x bytes from SPI Flash starting at FLA = 0x%X" % (length, spi_fla) )
self.logger.log( "[CHIPSEC] reading 0x%x bytes from SPI Flash starting at FLA = 0x%X" % (length, spi_fla) )
self.logger.log( "[CHIPSEC] %s" % _msg )
out_file = None
if 6 == len(self.argv):
out_file = self.argv[5]
buf = _spi.read_spi_to_file( spi_fla, length, out_file )
if (buf is None): self.logger.error( "SPI Flash read didn't return any data (turn on VERBOSE)" )
else: self.logger.log_result( "SPI Flash read done" )
if (buf is None): self.logger.error( "SPI flash read didn't return any data (turn on VERBOSE)" )
else: self.logger.log( "[CHIPSEC] completed SPI flash memory read" )
elif ( 'info' == spi_op ):
self.logger.log( "[CHIPSEC] SPI Flash Info\n" )
self.logger.log( "[CHIPSEC] SPI flash memory information\n" )
ok = _spi.display_SPI_map()
elif ( 'dump' == spi_op ):
out_file = 'rom.bin'
if 4 == len(self.argv):
out_file = self.argv[3]
self.logger.log( "[CHIPSEC] Dumping entire SPI Flash to '%s'" % out_file )
self.logger.log( "[CHIPSEC] dumping entire SPI flash memory to '%s'" % out_file )
self.logger.log( "[CHIPSEC] %s" % _msg )
# @TODO: don't assume SPI Flash always ends with BIOS region
(base,limit,freg) = _spi.get_SPI_region( BIOS )
spi_size = limit + 1
self.logger.log( "[CHIPSEC] BIOS Region: Base = 0x%08X, Limit = 0x%08X" % (base,limit) )
self.logger.log( "[CHIPSEC] Dumping 0x%08X bytes (to the end of BIOS region)" % spi_size )
self.logger.log( "[CHIPSEC] BIOS region: base = 0x%08X, limit = 0x%08X" % (base,limit) )
self.logger.log( "[CHIPSEC] dumping 0x%08X bytes (to the end of BIOS region)" % spi_size )
buf = _spi.read_spi_to_file( 0, spi_size, out_file )
if (buf is None): self.logger.error( "Dumping SPI Flash didn't return any data (turn on VERBOSE)" )
else: self.logger.log_result( "Done dumping SPI Flash" )
if (buf is None): self.logger.error( "dumping SPI Flash didn't return any data (turn on VERBOSE)" )
else: self.logger.log( "[CHIPSEC] completed SPI flash dump to '%s'" % out_file )
elif ( 'disable-wp' == spi_op ):
self.logger.log( "[CHIPSEC] Trying to disable BIOS write protection.." )
self.logger.log( "[CHIPSEC] trying to disable BIOS write protection.." )
#
# This write protection only matters for BIOS range in SPI flash memory
#
if _spi.disable_BIOS_write_protection():
self.logger.log_good( "BIOS region write protection is disabled in SPI flash" )
else:
self.logger.log_bad( "Couldn't disable BIOS region write protection in SPI flash" )
self.logger.log_bad( "couldn't disable BIOS region write protection in SPI flash" )
else:
print SPICommand.__doc__
return
+124
View File
@@ -0,0 +1,124 @@
#!/usr/local/bin/python
#CHIPSEC: Platform Security Assessment Framework
#Copyright (c) 2010-2016, Intel Corporation
#
#This program is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public License
#as published by the Free Software Foundation; Version 2.
#
#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with this program; if not, write to the Free Software
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
#Contact information:
#chipsec@intel.com
#
__version__ = '1.0'
import os
import sys
import time
import chipsec_util
from chipsec.command import BaseCommand
from chipsec.logger import *
from chipsec.file import *
from chipsec.hal.vmm import *
class VMMCommand(BaseCommand):
"""
>>> chipsec_util vmm hypercall <rax> <rbx> <rcx> <rdx> <rdi> <rsi> [r8] [r9] [r10] [r11]
>>> chipsec_util vmm hypercall <eax> <ebx> <ecx> <edx> <edi> <esi>
>>> chipsec_util vmm pt|ept <ept_pointer>
Examples:
>>> chipsec_util vmm hypercall 32 0 0 0 0 0
>>> chipsec_util vmm pt 0x524B01E
"""
def requires_driver(self):
# No driver required when printing the util documentation
if len(self.argv) < 3:
return False
return True
def run(self):
if len(self.argv) < 3:
print VMMCommand.__doc__
return
op = self.argv[2]
t = time.time()
try:
vmm = VMM( self.cs )
except VMMRuntimeError, msg:
print msg
return
vmm.init();
if op == "hypercall":
gprs_cnt = len(self.argv) - 3
if (gprs_cnt < 6) or (gprs_cnt > 10):
print VMMCommand.__doc__
return
gpr = self.argv[3:]
while (len(gpr) < 10):
gpr.append('0')
(rax, rbx, rcx, rdx, rsi, rdi, r8, r9, r10, r11) = tuple([int(x, 16) for x in gpr])
self.logger.log( "[CHIPSEC] > hypercall" )
self.logger.log( "[CHIPSEC] RAX: 0x%016x" % rax )
self.logger.log( "[CHIPSEC] RBX: 0x%016x" % rbx )
self.logger.log( "[CHIPSEC] RCX: 0x%016x" % rcx )
self.logger.log( "[CHIPSEC] RDX: 0x%016x" % rdx )
self.logger.log( "[CHIPSEC] RSI: 0x%016x" % rsi )
self.logger.log( "[CHIPSEC] RDI: 0x%016x" % rdi )
self.logger.log( "[CHIPSEC] R8 : 0x%016x" % r8 )
self.logger.log( "[CHIPSEC] R9 : 0x%016x" % r9 )
self.logger.log( "[CHIPSEC] R10: 0x%016x" % r10 )
self.logger.log( "[CHIPSEC] R11: 0x%016x" % r11 )
rax = vmm.hypercall( rax, rbx, rcx, rdx, rsi, rdi, r8, r9, r10, r11 )
self.logger.log( "[CHIPSEC] < RAX: 0x%016x" % rax )
elif op in ['pt','ept']:
if len(self.argv) == 4:
eptp = int(self.argv[3],16)
pt_fname = 'ept_%08X' % eptp
self.logger.log( "[CHIPSEC] EPT physical base: 0x%016X" % eptp )
self.logger.log( "[CHIPSEC] dumping EPT to '%s'..." % pt_fname )
vmm.dump_SLAT_page_tables( eptp, pt_fname )
else:
self.logger.log( "[CHIPSEC] finding EPT hierarchy in memory is not implemented yet" )
print VMMCommand.__doc__
return
else:
self.logger.log( "Unknown command: %s" % op )
print VMMCommand.__doc__
return
self.logger.log( "[CHIPSEC] (vmm) time elapsed %.3f" % (time.time()-t) )
commands = { 'vmm': VMMCommand }