hackedteam/vector-edk

View on GitHub
vector-uefi/fd/tool/chipsec/modules/common/bios_wp.py

Summary

Maintainability
C
1 day
Test Coverage
#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
#




## \addtogroup modules
# __chipsec/modules/common/bios.py__ - checks if BIOS Write Protection HW mechanisms are enabled
#

from chipsec.module_common import *
TAGS = [MTAG_BIOS]

from chipsec.hal.mmio import *
from chipsec.hal.spi import *

import fnmatch
import os


class bios_wp(BaseModule):
    
    def __init__(self):
        BaseModule.__init__(self)
        self.spi    = SPI( self.cs )
    
    def check_BIOS_write_protection(self):
        self.logger.start_test( "BIOS Region Write Protection" )
        #
        # 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 )
        self.logger.log( BcRegister )
    
        # Is the BIOS flash region write protected?
        write_protected = 0
        if 1 == BcRegister.BLE and 0 == BcRegister.BIOSWE:
            if 1 == BcRegister.SMM_BWP:
                self.logger.log_good( "BIOS region write protection is enabled (writes restricted to SMM)" )
                write_protected = 1
            else:
                self.logger.log_important( "Enhanced SMM BIOS region write protection has not been enabled (SMM_BWP is not used)" )
        else:
            self.logger.log_bad( "BIOS region write protection is disabled!" )
    
        return write_protected == 1
    
    def check_SPI_protected_ranges(self):
        #self.logger.start_test( "SPI Protected Ranges" )
        (bios_base,bios_limit,bios_freg) = self.spi.get_SPI_region( BIOS )
        self.logger.log( "\n[*] BIOS Region: Base = 0x%08X, Limit = 0x%08X" % (bios_base,bios_limit) )
        self.spi.display_SPI_Protected_Ranges()
    
        pr_cover_bios = False
        pr_partial_cover_bios = False
    #    for j in range(5):
    #        (base,limit,wpe,rpe,pr_reg_off,pr_reg_value) = spi.get_SPI_Protected_Range( j )
    #        if (wpe == 1 and base < limit and base <= bios_base and limit >= bios_limit):
    #            pr_cover_bios = True
    #        if (wpe == 1 and base < limit and limit > bios_base):
    #            pr_partial_cover_bios = True
    
        areas_to_protect  = [(bios_base, bios_limit)]
        protected_areas = list()
    
    
        for j in range(5):
            (base,limit,wpe,rpe,pr_reg_off,pr_reg_value) = self.spi.get_SPI_Protected_Range( j )
            if base > limit: continue
            if wpe == 1:
                for area in areas_to_protect:
                    # overlap bottom
                    start,end = area
                    if base <= start and limit >= start:
                        if limit > end:
                            areas_to_protect.remove(area)
                        else:
                            areas_to_protect.remove(area)
                            area = (limit+1,end)
                            areas_to_protect.append(area)
                            
                    # overlap top
                    elif base <= end and limit >= end:
                        if base < start:
                            areas_to_protect.remove(area)
                        else:
                            areas_to_protect.remove(area)
                            area = (start,base-1)
                            areas_to_protect.append(area)
                            start,end = area
                    # split
                    elif base > start and limit < end:
                        areas_to_protect.remove(area)
                        areas_to_protect.append((start,base-1))
                        areas_to_protect.append((limit+1, end))
    
    
        if (len(areas_to_protect)  == 0):
            pr_cover_bios = True
        else:
            if (len(areas_to_protect) != 1 or areas_to_protect[0] != (bios_base,bios_limit)):
                pr_partial_cover_bios = True
    
        if pr_partial_cover_bios:
            self.logger.log( '' )
            self.logger.log_important( "SPI protected ranges write-protect parts of BIOS region (other parts of BIOS can be modified)" )
    
        else:
            if not pr_cover_bios:
                self.logger.log( '' )
                self.logger.log_important( "None of the SPI protected ranges write-protect BIOS region" )
    
        return pr_cover_bios
    
    # --------------------------------------------------------------------------
    # run( module_argv )
    # Required function: run here all tests from this module
    # --------------------------------------------------------------------------
    def run(self, module_argv ):
        wp = self.check_BIOS_write_protection()    
        spr = self.check_SPI_protected_ranges()
        #spi.display_SPI_Ranges_Access_Permissions()
        #check_SMI_locks()
    
        self.logger.log('')
        if wp:
            if spr:  self.logger.log_passed_check( "BIOS is write protected (by SMM and SPI Protected Ranges)" )
            else:    self.logger.log_passed_check( "BIOS is write protected" )
        else:
            if spr:  self.logger.log_passed_check( "SPI Protected Ranges are configured to write protect BIOS" )
            else:
                self.logger.log_important( 'BIOS should enable all available SMM based write protection mechanisms or configure SPI protected ranges to protect the entire BIOS region' )
                self.logger.log_failed_check( "BIOS is NOT protected completely" )
    
        return wp or spr