Files
chipsec-chipsec/source/tool/chipsec_main.py
T
CHIPSEC ac2ca7264f 1. We have support for uefi variables on Windows and Linux but not
UEFI shell.
2.       Decompression of images in SPI flash parsing is only supported in
Windows.
3.	UEFI - Support for IA32 and i586 (Quark)
4.	Added capability to use modules from an arbitrary path with the -I
/ --import command line option
5.	Module functionality encapsulated in class inheriting BaseModule
6.	Fixed  loading platform specific configuration
7.	Fixed issue with modules which run on multiple logical CPUs
hanging on Bay Trail (Windows/Linux). The issue still exist when running
from UEFI shell
8.	Added template for a module - module_template.py
9.	Added options to flush log files
10.	Added ability to define custom platforms
Driver changes:
1.	Windows - Added IOCTL_ALLOC_PHYSMEM to allocate physical memory
buffer
2.	Linux - Fix wrpci defect
2014-05-29 21:57:40 +01:00

546 lines
21 KiB
Python

#!/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
#
#
## \addtogroup core
# __chipsec_main.py__ -- main application logic and automation functions
#
__version__ = '1.1.0'
import os
import re
import sys
import fnmatch
import time
import traceback
import errno
import chipsec.file
import chipsec.module
_importlib = True
try:
import importlib
except ImportError:
_importlib = False
#import zipfile
from chipsec.logger import logger
CHIPSEC_FOLDER = os.path.abspath(chipsec.file.get_main_dir())
version=" "
VERSION_FILE = os.path.join( CHIPSEC_FOLDER , "VERSION" )
if os.path.exists( VERSION_FILE ):
with open(VERSION_FILE, "r") as verFile:
version = verFile.read()
def get_chipsec_version():
return "%s"% (__version__)
logger().log( '' )
logger().log( "################################################################\n"
"## ##\n"
"## CHIPSEC: Platform Hardware Security Assessment Framework ##\n"
"## ##\n"
"################################################################" )
logger().log( "Version %s \n" %get_chipsec_version() )
from chipsec.helper.oshelper import OsHelperError
from chipsec.chipset import cs, Chipset_Code, CHIPSET_ID_UNKNOWN, CHIPSET_ID_COMMON, UnknownChipsetError, AVAILABLE_MODULES, DISABLED_MODULES
_cs = cs()
from chipsec.file import *
VERBOSE = False
CHIPSEC_LOADED_AS_EXE = chipsec.file.main_is_frozen()
USER_MODULE_TAGS = []
##################################################################################
# Module API
##################################################################################
ZIP_MODULES_RE = None
def f_mod(x):
return ( x.find('__init__') == -1 and ZIP_MODULES_RE.match(x) )
def map_modname(x):
return (x.rpartition('.')[0]).replace('/','.')
#return ((x.split('/', 2)[2]).rpartition('.')[0]).replace('/','.')
def map_pass(x):
return x
Import_Path = "chipsec.modules."
Modules_Path = os.path.join(CHIPSEC_FOLDER,"chipsec","modules")
IMPORT_PATHS = []
Loaded_Modules = []
_list_tags = False
AVAILABLE_TAGS = []
MODPATH_RE = re.compile("^\w+(\.\w+)*$")
def isModuleDisabled(module_path):
try:
if(len(DISABLED_MODULES)>0):
if(module_path in DISABLED_MODULES[_cs.id]):
return True
except KeyError, msg:
logger().log(str(msg))
return False
def import_module(module_path):
module = None
if not MODPATH_RE.match(module_path):
logger().error( "Invalid module path: %s" % module_path )
else:
try:
module = importlib.import_module( module_path )
# Support for older Python < 2.5
#if _importlib:
# module = importlib.import_module( module_path )
#else:
# #module = __import__(module_path)
# exec 'import ' + module_path
except BaseException, msg:
logger().error( "Exception occurred during import of %s: '%s'" % (module_path, str(msg)) )
if logger().VERBOSE: logger().log_bad(traceback.format_exc())
return module
def verify_module_tags(module):
run_it = True
if len(USER_MODULE_TAGS) > 0 or _list_tags:
run_it = False
module_tags= module.get_tags()
for mt in module_tags:
if _list_tags:
if mt not in AVAILABLE_TAGS: AVAILABLE_TAGS.append(mt)
elif mt in USER_MODULE_TAGS:
run_it = True
return run_it
def old_run_module( module_path, module_argv ):
module_path = module_path.replace( os.sep, '.' )
module = import_module(module_path)
if module == None and _importlib: return None
run_it = True
if len(USER_MODULE_TAGS) > 0 or _list_tags:
run_it = False
module_tags=[]
try:
module_tags = getattr( module, 'TAGS' )
# Support for older Python < 2.5
#if _importlib:
# module_tags = getattr( module, 'TAGS' )
#else:
# exec ('module_tags = ' +module_path + '.TAGS')
except:
#logger().log(module_path)
#logger().log_bad(traceback.format_exc())
pass
for mt in module_tags:
if _list_tags:
if mt not in AVAILABLE_TAGS: AVAILABLE_TAGS.append(mt)
elif mt in USER_MODULE_TAGS:
run_it = True
if module_argv:
logger().log( "[*] Module arguments (%d):" % len(module_argv) )
logger().log( module_argv )
else:
module_argv = []
if run_it:
try:
result = False
result = getattr( module, 'run' )( module_argv )
# Support for older Python < 2.5
#if _importlib:
# result = getattr( module, 'run' )( module_argv )
#else:
# exec ('result = ' + module_path + '.run(module_argv)')
return result
except (None,Exception) , msg:
if logger().VERBOSE: logger().log_bad(traceback.format_exc())
logger().log_error_check( "Exception occurred during %s.run(): '%s'" % (module_path, str(msg)) )
return None
else:
from chipsec.module_common import ModuleResult
return ModuleResult.SKIPPED
def run_module( modx, module_argv ):
from chipsec.module_common import ModuleResult
result = None
try:
if not modx.do_import(): return ModuleResult.ERROR
if not _list_tags: logger().log( "[*] Module path: %s" % modx.get_location() )
if verify_module_tags( modx ):
result = modx.run( module_argv )
else:
return ModuleResult.SKIPPED
except (None,Exception) , msg:
result = ModuleResult.ERROR
if logger().VERBOSE: logger().log_bad(traceback.format_exc())
logger().log_error_check( "Exception occurred during %s.run(): '%s'" % (modx.get_name(), str(msg)) )
return result
##
# full_path can be one of three things:
# 1. the actual full path to the py or pyc file i.e. c:\some_path\chipsec\modules\common\bios_wp.py
# 2. a path to the pyc file inside a zip file i.e. chipsec/modules/common/bios_wp.pyc
# 3. the name of the module i.e. chipsec.modules.common.bios_wp
def get_module_name(full_path):
name = full_path
# case #1, the full path: remove prefix
if full_path.startswith(CHIPSEC_FOLDER+os.path.sep):
name = full_path.replace ( CHIPSEC_FOLDER+os.path.sep, '')
else:
for path in IMPORT_PATHS:
if full_path.startswith(os.path.abspath(path)+os.path.sep):
name = full_path.replace ( os.path.abspath(path)+os.path.sep, '')
# case #1 and #2: remove the extension
if name.lower().endswith('.py') : name = name[:-3]
if name.lower().endswith('.pyc'): name = name[:-4]
# case #1: replace slashes with dots
name = name.replace( os.path.sep, '.' )
# case #2: when in a zip it is always forward slash
name = name.replace( '/', '.' )
# Add 'chipsec.modules.' if shor module name was provided and alternative import paths were not specified
if [] == IMPORT_PATHS and not name.startswith( Import_Path ):
name = Import_Path + name
return name
#
# module_path is a file path relative to chipsec
# E.g. chipsec/modules/common/module.py
#
def load_module( module_path, module_argv ):
module_name = get_module_name(module_path)
module = chipsec.module.Module(module_name)
if module not in Loaded_Modules:
Loaded_Modules.append( (module,module_argv) )
if not _list_tags: logger().log( "[+] loaded %s" % module.get_name() )
return True
# @TODO: Fix it!
def unload_module( module_path ):
if module_path in Loaded_Modules:
Loaded_Modules.remove( module_path )
return True
def load_modules_from_path( from_path ):
if logger().VERBOSE: logger().log_bad( os.path.abspath( from_path ) )
for dirname, subdirs, mod_fnames in os.walk( os.path.abspath( from_path ) ):
for modx in mod_fnames:
if fnmatch.fnmatch( modx, '*.py' ) and not fnmatch.fnmatch( modx, '__init__.py' ):
load_module( os.path.join( dirname, modx ), None )
def load_my_modules():
#
# Step 1.
# Load modules common to all supported platforms
#
common_path = os.path.join( Modules_Path, 'common' )
logger().log( "[*] loading common modules from \"%s\" .." % common_path.replace(os.getcwd(),'.') )
load_modules_from_path( common_path )
#
# Step 2.
# Load platform-specific modules from the corresponding platform module directory
#
chipset_path = os.path.join( Modules_Path, _cs.code.lower() )
if (CHIPSET_ID_UNKNOWN != _cs.id) and os.path.exists( chipset_path ):
logger().log( "[*] loading platform specific modules from \"%s\" .." % chipset_path.replace(os.getcwd(),'.') )
load_modules_from_path( chipset_path )
else:
logger().log( "[*] No platform specific modules to load" )
#
# Step 3.
# Enumerate all modules from the root module directory
# Load modules which support current platform (register themselves with AVAILABLE_MODULES[current_platform_id])
#
logger().log( "[*] loading modules from \"%s\" .." % Modules_Path.replace(os.getcwd(),'.') )
for modx in os.listdir( os.path.abspath( Modules_Path ) ):
if fnmatch.fnmatch(modx, '*.py') and not fnmatch.fnmatch(modx, '__init__.py'):
import_modx = Import_Path + modx.split('.')[0]
try:
__import__( import_modx )
except BaseException, e:
logger().log_bad("Failed to import module %s : %s"%(import_modx,str(e)))
raise
# removed temporary
#if isModuleDisabled(modx):
# AVAILABLE_MODULES[ _cs.id ][modx.split('.')[0]] = "invalidmodule." + modx.split('.')[0]
for modx in AVAILABLE_MODULES[ CHIPSET_ID_COMMON ]:
load_module( os.path.join( os.path.abspath( Modules_Path ), modx + '.py' ), None )
try:
for modx in AVAILABLE_MODULES[ _cs.id ]:
load_module( os.path.join( os.path.abspath( Modules_Path ), modx + '.py' ), None )
except KeyError:
pass
#print Loaded_Modules
def load_user_modules():
for import_path in IMPORT_PATHS:
logger().log( "[*] loading modules from \"%s\" .." % import_path )
load_modules_from_path(import_path)
def clear_loaded_modules():
del Loaded_Modules[:]
def print_loaded_modules():
if Loaded_Modules == []:
logger().log( "No modules have been loaded" )
for (modx,modx_argv) in Loaded_Modules:
logger().log( modx )
def run_loaded_modules():
from chipsec.module_common import ModuleResult
failed = []
errors = []
warnings = []
passed = []
skipped = []
executed = 0
if not _list_tags: logger().log( "[*] running loaded modules .." )
t = time.time()
for (modx,modx_argv) in Loaded_Modules:
executed += 1
if not _list_tags: logger().start_module( modx.get_name( ) )
result = run_module( modx, modx_argv )
if result == ModuleResult.DEPRECATED:
logger().log_warning( 'Module %s does not inherit BaseModule class. Attempting to locate run function..' % str(modx) )
result = old_run_module( modx.get_name(), modx_argv )
if not _list_tags: logger().end_module( modx.get_name() )
if None == result or ModuleResult.ERROR == result:
errors.append( modx )
elif False == result or ModuleResult.FAILED == result:
failed.append( modx )
elif True == result or ModuleResult.PASSED == result:
passed.append( modx )
elif ModuleResult.WARNING == result:
warnings.append( modx )
elif ModuleResult.SKIPPED == result:
skipped.append( modx )
if not _list_tags:
logger().log( "" )
logger().log( "[CHIPSEC] *************************** SUMMARY ***************************" )
logger().log( "[CHIPSEC] Time elapsed %.3f" % (time.time()-t) )
logger().log( "[CHIPSEC] Modules total %d" % executed )
logger().log( "[CHIPSEC] Modules failed to run %d:" % len(errors) )
for mod in errors: logger().error( str(mod) )
logger().log( "[CHIPSEC] Modules passed %d:" % len(passed) )
for fmod in passed: logger().log_passed( str(fmod) )
logger().log( "[CHIPSEC] Modules failed %d:" % len(failed) )
for fmod in failed: logger().log_failed( str(fmod) )
logger().log( "[CHIPSEC] Modules with warnings %d:" % len(warnings) )
for fmod in warnings: logger().log_warning( str(fmod) )
logger().log( "[CHIPSEC] Modules skipped %d:" % len(skipped) )
for fmod in skipped: logger().log_skipped( str(fmod) )
logger().log( "[CHIPSEC] *****************************************************************" )
logger().log( "[CHIPSEC] Version: %s"% get_chipsec_version() )
else:
logger().log( "[*] Available tags are:" )
for at in AVAILABLE_TAGS: logger().log(" %s"%at)
return len(failed)
##################################################################################
# Running all chipset configuration security checks
##################################################################################
def run_all_modules():
if CHIPSEC_LOADED_AS_EXE:
import zipfile
myzip = zipfile.ZipFile( os.path.join(CHIPSEC_FOLDER, "library.zip" ))
global ZIP_MODULES_RE
ZIP_MODULES_RE = re.compile("^chipsec\/modules\/\w+\.pyc$|^chipsec\/modules\/common\/(\w+\/)*\w+\.pyc$|^chipsec\/modules\/"+_cs.code.lower()+"\/\w+\.pyc$", re.IGNORECASE|re.VERBOSE)
zip_modules = []
zip_modules.extend( map(map_pass, filter(f_mod, myzip.namelist())) )
logger().log( "Loaded modules from ZIP:" )
for zmodx in zip_modules:
module_name = get_module_name(zmodx)
mod = chipsec.module.Module(module_name)
logger().log(mod.get_name())
Loaded_Modules.append( (mod,None) )
else:
load_my_modules()
load_user_modules()
return run_loaded_modules()
def usage():
print "\nUSAGE: %.65s [options]" % sys.argv[0]
print "OPTIONS:"
print "-m --module specify module to run (example: -m common.bios)"
print "-a --module_args additional module arguments, format is 'arg0,arg1..'"
print "-v --verbose verbose mode"
print "-l --log output to log file"
print "\nADVANCED OPTIONS:"
print "-p --platform explicitly specify platform code. Should be among the supported platforms:"
print " [ %s ]" % (" | ".join( ["%.4s" % c for c in Chipset_Code]))
print "-n --no_driver chipsec won't need kernel mode functions so don't load chipsec driver"
print "-i --ignore_platform run chipsec even if the platform is not recognized"
print "-e --exists chipsec service has already been manually installed and started (driver loaded)."
print "-x --xml specify filename for xml output (JUnit style)."
print "-t --moduletype run tests of a specific type (tag)."
print " --list_tags list all the available options for -t,--moduletype"
print "-I --import specify additional path to load modules from"
##################################################################################
# Entry point for command-line execution
##################################################################################
if __name__ == "__main__":
import getopt
try:
opts, args = getopt.getopt(sys.argv[1:], "ip:m:ho:vea:nl:t:x:I:",
["ignore_platform", "platform=", "module=", "help", "output=",
"verbose", "exists", "module_args=", "no_driver", "log=",
"moduletype=", "xml=","list_tags", "include"])
except getopt.GetoptError, err:
print str(err)
usage()
sys.exit(errno.EINVAL)
_output = 'chipsec.log'
_module = None
_module_argv = None
_platform = None
_start_svc = True
_no_driver = False
_unkownPlatform = True
_list_tags = False
for o, a in opts:
if o in ("-v", "--verbose"):
logger().VERBOSE = True
logger().log( "[*] Verbose mode is ON (-v command-line option or chipsec_main.logger().VERBOSE in Python console)" )
elif o in ("-h", "--help"):
usage()
sys.exit(0)
elif o in ("-o", "--output"):
_output = a
elif o in ("-p", "--platform"):
_platform = a.upper()
elif o in ("-m", "--module"):
#_module = a.lower()
_module = a
elif o in ("-a", "--module_args"):
_module_argv = a.split(',')
elif o in ("-e", "--exists"):
_start_svc = False
elif o in ("-i", "--ignore_platform"):
logger().log( "[*] Ignoring unsupported platform warning and continue execution" )
_unkownPlatform = False
elif o in ("-l", "--log"):
logger().log( "[*] Output to log file '%s' (--log option or chipsec_main.logger().set_log_file in Python console)" % a )
logger().set_log_file( a )
elif o in ("-t", "--moduletype"):
usertags = a.upper().split(",")
for tag in usertags:
USER_MODULE_TAGS.append(tag)
elif o in ("-n", "--no_driver"):
_no_driver = True
elif o in ("-x", "--xml"):
logger().set_xml_file(a)
elif o in ("--list_tags"):
_list_tags = True
elif o in ("-I","--import"):
IMPORT_PATHS.append(a)
else:
assert False, "unknown option"
for import_path in IMPORT_PATHS:
sys.path.append(os.path.abspath( import_path ) )
# If no driver needed, we won't start/stop service
if _no_driver: _start_svc = False
try:
# If no driver needed, we won't initialize chipset with automatic platform detection
if not _no_driver: _cs.init( _platform, _start_svc )
except UnknownChipsetError , msg:
logger().error( "Platform is not supported (%s)." % str(msg) )
if _unkownPlatform:
logger().error( 'To run anyways please use -i command-line option\n\n' )
if logger().VERBOSE: logger().log_bad(traceback.format_exc())
sys.exit( errno.ENODEV )
logger().warn("Platform dependent functionality is likely to be incorrect")
except OsHelperError as os_helper_error:
logger().error(str(os_helper_error))
if logger().VERBOSE: logger().log_bad(traceback.format_exc())
sys.exit(os_helper_error.errorcode)
logger().log( " " )
logger().log( "OS : %s %s %s %s" % (_cs.helper.os_system, _cs.helper.os_release, _cs.helper.os_version, _cs.helper.os_machine) )
logger().log( "Platform: %s\n VID: %04X\n DID: %04X" % (_cs.longname, _cs.vid, _cs.did))
logger().log( "CHIPSEC : %s"% get_chipsec_version() )
logger().xmlAux.add_test_suite_property( "OS", "%s %s %s %s" % (_cs.helper.os_system, _cs.helper.os_release, _cs.helper.os_version, _cs.helper.os_machine) )
logger().xmlAux.add_test_suite_property( "Platform", "%s, VID: %04X, DID: %04X" % (_cs.longname, _cs.vid, _cs.did) )
logger().xmlAux.add_test_suite_property( "CHIPSEC", "%s"% get_chipsec_version() )
logger().log( " " )
if logger().VERBOSE: logger().log("[*] Running from %s" % os.getcwd())
modules_failed = 0
if _module:
load_module( _module, _module_argv )
modules_failed = run_loaded_modules()
#unload_module( _module );
else:
modules_failed = run_all_modules()
logger().saveXML()
_cs.destroy( _start_svc )
del _cs
sys.exit(-modules_failed)