mirror of
https://github.com/chipsec/chipsec
synced 2026-06-08 13:31:00 +00:00
1259e568de
Signed-off-by: Nathaniel Mitchell <nathaniel.p.mitchell@intel.com>
211 lines
8.2 KiB
Python
211 lines
8.2 KiB
Python
# CHIPSEC: Platform Security Assessment Framework
|
|
# Copyright (c) 2019-2021, 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.2'
|
|
|
|
from typing import List, Optional, Tuple
|
|
from chipsec.library.defines import bit, is_set
|
|
from chipsec.hal.hal_base import HALBase
|
|
from chipsec.library.exceptions import CSReadError, HWAccessViolationError
|
|
|
|
|
|
class LockResult:
|
|
DEFINED = bit(0) # lock exists within configuration
|
|
HAS_CONFIG = bit(1) # lock configuration exists
|
|
LOCKED = bit(2) # lock matches value within xml
|
|
CAN_READ = bit(3) # system is able to access the lock
|
|
INCONSISTENT = bit(4) # all lock results do not match
|
|
|
|
|
|
class Locks(HALBase):
|
|
def __init__(self, cs):
|
|
super(Locks, self).__init__(cs)
|
|
|
|
def get_locks(self) -> List[str]:
|
|
"""
|
|
Return a list of locks defined within the configuration file
|
|
"""
|
|
return self.cs.lock.get_list()
|
|
|
|
def set_cache(self, lock_obj: "LOCKSHelper", reg_obj_list: List["RegisterHelper"]) -> None:
|
|
"""
|
|
Set the cache for the lock and its associated registers.
|
|
Arguments:
|
|
lock_obj: The lock object containing the lock definition.
|
|
reg_obj_list: A list of register objects associated with the lock.
|
|
"""
|
|
self.lock_cache = lock_obj
|
|
self.reg_cache = reg_obj_list
|
|
|
|
def clear_cache(self) -> None:
|
|
"""
|
|
Clear the cache for the lock and its associated registers.
|
|
"""
|
|
self.lock_cache = None
|
|
self.reg_cache = None
|
|
|
|
def get_cache(self) -> Tuple[Optional["LOCKSHelper"], Optional[List["RegisterHelper"]]]:
|
|
"""
|
|
Get the cached lock and register objects.
|
|
Returns:
|
|
A tuple containing the cached lock object and a list of register objects.
|
|
"""
|
|
return (self.lock_cache, self.reg_cache)
|
|
|
|
def read_lock(self) -> int:
|
|
"""
|
|
Read the lock value from the cached register.
|
|
Returns:
|
|
The value of the lock field.
|
|
"""
|
|
if self.lock_cache is None or self.reg_cache is None:
|
|
raise CSReadError('Lock cache is not set')
|
|
return self.reg_cache.read_field(self.lock_cache.field)
|
|
|
|
def lock_valid(self, lock_name: str, instance: Optional["instance"] = None) -> int:
|
|
"""
|
|
Validate the lock by its name and instance.
|
|
Arguments:
|
|
lock_name: The name of the lock to validate.
|
|
instance: Optional instance to validate against.
|
|
Returns:
|
|
An integer representing the validation result, which can include:
|
|
- LockResult.DEFINED: Lock is defined in the configuration.
|
|
- LockResult.HAS_CONFIG: Lock has a configuration.
|
|
- LockResult.CAN_READ: Lock can be read.
|
|
- LockResult.INCONSISTENT: Lock values are inconsistent.
|
|
- LockResult.LOCKED: Lock is locked with the expected value.
|
|
"""
|
|
self.clear_cache()
|
|
res = self.validate_lock_definition(lock_name)
|
|
if not res:
|
|
return res
|
|
|
|
lock_obj = self.cs.lock.get(lock_name)
|
|
|
|
reg_list = self.get_registers(lock_obj, instance)
|
|
self.set_cache(lock_obj, reg_list)
|
|
|
|
if not reg_list:
|
|
self.logger.log_hal(f"Lock '{lock_name}' has no register defined")
|
|
return res
|
|
|
|
if not lock_obj.has_lock_value():
|
|
self.logger.log_hal(f"Lock '{lock_name}' has no lock value defined")
|
|
return res
|
|
|
|
if not reg_list[0].has_field(lock_obj.get_field()):
|
|
self.logger.log_hal(f"Lock '{lock_name}' has no field defined")
|
|
return res
|
|
|
|
res |= LockResult.HAS_CONFIG
|
|
try:
|
|
self.read_lock()
|
|
res |= LockResult.CAN_READ
|
|
except CSReadError as e:
|
|
self.logger.log_hal(f"Error reading lock: {e}")
|
|
except HWAccessViolationError as e:
|
|
self.logger.log_hal(f"Hardware access violation: {e}")
|
|
|
|
return res
|
|
|
|
def is_locked(self, lock_name: str, bus: Optional[int] = None) -> int:
|
|
"""
|
|
Return whether the lock has the value setting
|
|
Arguments:
|
|
lock_name: The name of the lock to check.
|
|
bus: Optional bus number to specify the bus context.
|
|
Returns:
|
|
An integer representing the lock state, which can include:
|
|
- LockResult.INCONSISTENT: Lock values are inconsistent.
|
|
- LockResult.LOCKED: Lock is locked with the expected value.
|
|
"""
|
|
res = self.lock_valid(lock_name, bus)
|
|
if is_set(res, LockResult.HAS_CONFIG) and is_set(res, LockResult.CAN_READ):
|
|
res |= self._is_lock_consistent()
|
|
res |= self._check_lock_values()
|
|
return res
|
|
|
|
def _is_lock_consistent(self) -> int:
|
|
"""
|
|
Check if the lock is consistent across all registers.
|
|
Returns:
|
|
An integer indicating the consistency of the lock.
|
|
Returns LockResult.INCONSISTENT if the values are not consistent.
|
|
Returns 0 if they are consistent.
|
|
"""
|
|
lock_obj, reg_list = self.get_cache()
|
|
lock_field = lock_obj.get_field()
|
|
reg_list.read()
|
|
if not reg_list.is_all_field_value(reg_list[0].get_field(lock_field), lock_field):
|
|
return LockResult.INCONSISTENT
|
|
return 0
|
|
|
|
def _check_lock_values(self) -> int:
|
|
"""
|
|
Check if all registers in the list have the same value for the specified field.
|
|
Returns:
|
|
An integer indicating the lock state.
|
|
Returns LockResult.LOCKED if all registers have the expected value.
|
|
Returns 0 if they do not match.
|
|
"""
|
|
lock_obj, reg_list = self.get_cache()
|
|
locked_value = lock_obj.lock_value
|
|
reg_list.read()
|
|
if reg_list.is_all_field_value(locked_value, lock_obj.get_field()):
|
|
return LockResult.LOCKED
|
|
return 0
|
|
|
|
def validate_lock_definition(self, lock_name: str) -> int:
|
|
"""
|
|
Validate if the lock is defined in the configuration file.
|
|
Arguments:
|
|
lock_name: The name of the lock to validate.
|
|
Returns:
|
|
An integer representing the validation result, which can include:
|
|
- LockResult.DEFINED: Lock is defined in the configuration.
|
|
- 0: Lock is not defined.
|
|
"""
|
|
lock_obj = self.cs.lock.get(lock_name)
|
|
if lock_obj is None:
|
|
self.logger.log_hal(f"Lock '{lock_name}' is not defined in the configuration file")
|
|
return 0
|
|
return LockResult.DEFINED
|
|
|
|
def get_registers(self, lock_obj, instance: Optional["instance"]) -> List:
|
|
"""
|
|
Retrieve registers associated with the lock.
|
|
Arguments:
|
|
lock_obj: The lock object containing the lock definition.
|
|
instance: Optional instance to filter the registers.
|
|
Returns:
|
|
A list of register objects associated with the lock.
|
|
If an instance is provided, it returns the registers for that specific instance.
|
|
If no instance is provided, it returns all registers associated with the lock.
|
|
"""
|
|
lock_register = lock_obj.get_register()
|
|
if instance:
|
|
reg_obj = self.cs.register.get_instance_by_name(lock_register, instance)
|
|
return list(reg_obj)
|
|
return self.cs.register.get_list_by_name(lock_register)
|
|
|
|
|
|
haldata = {"arch": [HALBase.MfgIds.Any], 'name': {'locks': "Locks"}}
|