#!/usr/local/bin/python #CHIPSEC: Platform Security Assessment Framework #Copyright (c) 2010-2014, 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-2012 Intel Corporation # # ------------------------------------------------------------------------------- ## \addtogroup hal # chipsec/hal/uefi_common.py # ========================== # Common UEFI functionality (EFI variables, db/dbx decode, etc.) # # __version__ = '1.0' import os import struct from collections import namedtuple from chipsec.file import * from chipsec.logger import * ################################################################################################ # EFI Variable and Variable Store Defines # """ UDK2010.SR1\MdeModulePkg\Include\Guid\VariableFormat.h #ifndef __VARIABLE_FORMAT_H__ #define __VARIABLE_FORMAT_H__ #define EFI_VARIABLE_GUID \ { 0xddcf3616, 0x3275, 0x4164, { 0x98, 0xb6, 0xfe, 0x85, 0x70, 0x7f, 0xfe, 0x7d } } extern EFI_GUID gEfiVariableGuid; /// /// Alignment of variable name and data, according to the architecture: /// * For IA-32 and Intel(R) 64 architectures: 1. /// * For IA-64 architecture: 8. /// #if defined (MDE_CPU_IPF) #define ALIGNMENT 8 #else #define ALIGNMENT 1 #endif // // GET_PAD_SIZE calculates the miminal pad bytes needed to make the current pad size satisfy the alignment requirement. // #if (ALIGNMENT == 1) #define GET_PAD_SIZE(a) (0) #else #define GET_PAD_SIZE(a) (((~a) + 1) & (ALIGNMENT - 1)) #endif /// /// Alignment of Variable Data Header in Variable Store region. /// #define HEADER_ALIGNMENT 4 #define HEADER_ALIGN(Header) (((UINTN) (Header) + HEADER_ALIGNMENT - 1) & (~(HEADER_ALIGNMENT - 1))) /// /// Status of Variable Store Region. /// typedef enum { EfiRaw, EfiValid, EfiInvalid, EfiUnknown } VARIABLE_STORE_STATUS; #pragma pack(1) #define VARIABLE_STORE_SIGNATURE EFI_VARIABLE_GUID /// /// Variable Store Header Format and State. /// #define VARIABLE_STORE_FORMATTED 0x5a #define VARIABLE_STORE_HEALTHY 0xfe /// /// Variable Store region header. /// typedef struct { /// /// Variable store region signature. /// EFI_GUID Signature; /// /// Size of entire variable store, /// including size of variable store header but not including the size of FvHeader. /// UINT32 Size; /// /// Variable region format state. /// UINT8 Format; /// /// Variable region healthy state. /// UINT8 State; UINT16 Reserved; UINT32 Reserved1; } VARIABLE_STORE_HEADER; /// /// Variable data start flag. /// #define VARIABLE_DATA 0x55AA /// /// Variable State flags. /// #define VAR_IN_DELETED_TRANSITION 0xfe ///< Variable is in obsolete transition. #define VAR_DELETED 0xfd ///< Variable is obsolete. #define VAR_HEADER_VALID_ONLY 0x7f ///< Variable header has been valid. #define VAR_ADDED 0x3f ///< Variable has been completely added. /// /// Single Variable Data Header Structure. /// typedef struct { /// /// Variable Data Start Flag. /// UINT16 StartId; /// /// Variable State defined above. /// UINT8 State; UINT8 Reserved; /// /// Attributes of variable defined in UEFI specification. /// UINT32 Attributes; /// /// Size of variable null-terminated Unicode string name. /// UINT32 NameSize; /// /// Size of the variable data without this header. /// UINT32 DataSize; /// /// A unique identifier for the vendor that produces and consumes this varaible. /// EFI_GUID VendorGuid; } VARIABLE_HEADER; #pragma pack() typedef struct _VARIABLE_INFO_ENTRY VARIABLE_INFO_ENTRY; /// /// This structure contains the variable list that is put in EFI system table. /// The variable driver collects all variables that were used at boot service time and produces this list. /// This is an optional feature to dump all used variables in shell environment. /// struct _VARIABLE_INFO_ENTRY { VARIABLE_INFO_ENTRY *Next; ///< Pointer to next entry. EFI_GUID VendorGuid; ///< Guid of Variable. CHAR16 *Name; ///< Name of Variable. UINT32 Attributes; ///< Attributes of variable defined in UEFI specification. UINT32 ReadCount; ///< Number of times to read this variable. UINT32 WriteCount; ///< Number of times to write this variable. UINT32 DeleteCount; ///< Number of times to delete this variable. UINT32 CacheCount; ///< Number of times that cache hits this variable. BOOLEAN Volatile; ///< TRUE if volatile, FALSE if non-volatile. }; #endif // _EFI_VARIABLE_H_ """ # # Variable Store Header Format and State. # VARIABLE_STORE_FORMATTED = 0x5a VARIABLE_STORE_HEALTHY = 0xfe # # Variable Store region header. # #typedef struct { # /// # /// Variable store region signature. # /// # EFI_GUID Signature; # /// # /// Size of entire variable store, # /// including size of variable store header but not including the size of FvHeader. # /// # UINT32 Size; # /// # /// Variable region format state. # /// # UINT8 Format; # /// # /// Variable region healthy state. # /// # UINT8 State; # UINT16 Reserved; # UINT32 Reserved1; #} VARIABLE_STORE_HEADER; # # Signature is EFI_GUID (guid0 guid1 guid2 guid3) VARIABLE_STORE_HEADER_FMT = '<8sIBBHI' VARIABLE_STORE_HEADER_SIZE = struct.calcsize( VARIABLE_STORE_HEADER_FMT ) class VARIABLE_STORE_HEADER( namedtuple('VARIABLE_STORE_HEADER', 'guid0 guid1 guid2 guid3 Size Format State Reserved Reserved1') ): __slots__ = () def __str__(self): return """ EFI Variable Store ----------------------------- Signature : {%08X-%04X-%04X-%04s-%06s} Size : 0x%08X bytes Format : 0x%02X State : 0x%02X Reserved : 0x%04X Reserved1 : 0x%08X """ % ( self.guid0, self.guid1, self.guid2, self.guid3[:2].encode('hex').upper(), self.guid3[-6::].encode('hex').upper(), self.Size, self.Format, self.State, self.Reserved, self.Reserved1 ) # # Variable data start flag. # VARIABLE_DATA_SIGNATURE = struct.pack('=H', 0x55AA ) # # Variable Attributes # EFI_VARIABLE_NON_VOLATILE = 0x00000001 # Variable is non volatile EFI_VARIABLE_BOOTSERVICE_ACCESS = 0x00000002 # Variable is boot time accessible EFI_VARIABLE_RUNTIME_ACCESS = 0x00000004 # Variable is run-time accessible EFI_VARIABLE_HARDWARE_ERROR_RECORD = 0x00000008 # EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS = 0x00000010 # Variable is authenticated EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS = 0x00000020 # Variable is time based authenticated EFI_VARIABLE_APPEND_WRITE = 0x00000040 # Variable allows append UEFI23_1_AUTHENTICATED_VARIABLE_ATTRIBUTES = (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) def IS_VARIABLE_ATTRIBUTE(_c, _Mask): return ( (_c & _Mask) != 0 ) def IS_EFI_VARIABLE_AUTHENTICATED( attr ): return ( IS_VARIABLE_ATTRIBUTE( attr, EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS ) or IS_VARIABLE_ATTRIBUTE( attr, EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS ) ) ################################################################################################# FFS_ATTRIB_FIXED = 0x04 FFS_ATTRIB_DATA_ALIGNMENT = 0x38 FFS_ATTRIB_CHECKSUM = 0x40 EFI_FILE_HEADER_CONSTRUCTION = 0x01 EFI_FILE_HEADER_VALID = 0x02 EFI_FILE_DATA_VALID = 0x04 EFI_FILE_MARKED_FOR_UPDATE = 0x08 EFI_FILE_DELETED = 0x10 EFI_FILE_HEADER_INVALID = 0x20 FFS_FIXED_CHECKSUM = 0xAA EFI_FVB2_ERASE_POLARITY = 0x00000800 EFI_FV_FILETYPE_ALL = 0x00 EFI_FV_FILETYPE_RAW = 0x01 EFI_FV_FILETYPE_FREEFORM = 0x02 EFI_FV_FILETYPE_SECURITY_CORE = 0x03 EFI_FV_FILETYPE_PEI_CORE = 0x04 EFI_FV_FILETYPE_DXE_CORE = 0x05 EFI_FV_FILETYPE_PEIM = 0x06 EFI_FV_FILETYPE_DRIVER = 0x07 EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER = 0x08 EFI_FV_FILETYPE_APPLICATION = 0x09 EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE = 0x0b EFI_FV_FILETYPE_FFS_PAD = 0xf0 FILE_TYPE_NAMES = {0x00: 'FV_ALL', 0x01: 'FV_RAW', 0x02: 'FV_FREEFORM', 0x03: 'FV_SECURITY_CORE', 0x04: 'FV_PEI_CORE', 0x05: 'FV_DXE_CORE', 0x06: 'FV_PEIM', 0x07: 'FV_DRIVER', 0x08: 'FV_COMBINED_PEIM_DRIVER', 0x09: 'FV_APPLICATION', 0x0B: 'FV_FVIMAGE', 0x0F: 'FV_FFS_PAD'} EFI_SECTION_ALL = 0x00 EFI_SECTION_COMPRESSION = 0x01 EFI_SECTION_GUID_DEFINED = 0x02 EFI_SECTION_PE32 = 0x10 EFI_SECTION_PIC = 0x11 EFI_SECTION_TE = 0x12 EFI_SECTION_DXE_DEPEX = 0x13 EFI_SECTION_VERSION = 0x14 EFI_SECTION_USER_INTERFACE = 0x15 EFI_SECTION_COMPATIBILITY16 = 0x16 EFI_SECTION_FIRMWARE_VOLUME_IMAGE = 0x17 EFI_SECTION_FREEFORM_SUBTYPE_GUID = 0x18 EFI_SECTION_RAW = 0x19 EFI_SECTION_PEI_DEPEX = 0x1B EFI_SECTION_SMM_DEPEX = 0x1C SECTION_NAMES = {0x00: 'S_ALL', 0x01: 'S_COMPRESSION', 0x02: 'S_GUID_DEFINED', 0x10: 'S_PE32', 0x11: 'S_PIC', 0x12: 'S_TE', 0x13: 'S_DXE_DEPEX', 0x14: 'S_VERSION', 0x15: 'S_USER_INTERFACE', 0x16: 'S_COMPATIBILITY16', 0x17: 'S_FV_IMAGE', 0x18: 'S_FREEFORM_SUBTYPE_GUID', 0x19: 'S_RAW', 0x1B: 'S_PEI_DEPEX', 0x1C: 'S_SMM_DEPEX'} ################################################################################################# GUID = " 0) and (sig_size == SignatureSize)) or ((sig_size == 0) and (SignatureSize >= 0x10))): sof = 0 sig_list = db[dof+SIGNATURE_LIST_size+SignatureHeaderSize:dof+SignatureListSize] sig_list_size = len(sig_list) while ((sof + guid_size) < sig_list_size): sig_data = sig_list[sof:sof+SignatureSize] owner0, owner1, owner2, owner3 = struct.unpack(GUID, sig_data[:guid_size]) owner = guid_str(owner0, owner1, owner2, owner3) data = sig_data[guid_size:] #logger().log( "owner: %s" % owner ) entries.append( data ) sig_file_name = "%s-%s-%02d.bin" % (short_name, owner, nsig) sig_file_name = os.path.join(decode_dir, sig_file_name) write_file(sig_file_name, data) if (sig_parse_f != None): sig_parse_f(data) sof = sof + SignatureSize nsig = nsig + 1 else: err_str = "Wrong SignatureSize for %s type: 0x%X." % (SignatureType, SignatureSize) if (sig_size > 0): err_str = err_str + " Must be 0x%X." % (sig_size) else: err_str = err_str + " Must be >= 0x10." logger().error( err_str ) entries.append( data ) sig_file_name = "%s-%s-%02d.bin" % (short_name, SignatureType, nsig) sig_file_name = os.path.join(decode_dir, sig_file_name) write_file(sig_file_name, data) nsig = nsig + 1 dof = dof + SignatureListSize return entries def parse_efivar_file( fname, var=None ): if not var: var = read_file( fname ) #path, var_name = os.path.split( fname ) #var_name, ext = os.path.splitext( var_name ) var_path = fname + '.dir' if not os.path.exists( var_path ): os.makedirs( var_path ) parse_db( var, var_path ) ################################################################################################# .