From b7c68f4e98df2db6f7f4e46c445047c1bdbf647e Mon Sep 17 00:00:00 2001 From: Mike Auty Date: Sun, 11 Feb 2018 18:35:18 +0000 Subject: [PATCH] Rework LayerListRequirement from a ListRequirement to a MultiRequirement. --- .../framework/configuration/requirements.py | 63 +++++++++++-------- .../framework/interfaces/configuration.py | 5 ++ volatility/framework/layers/intel.py | 2 - 3 files changed, 43 insertions(+), 27 deletions(-) diff --git a/volatility/framework/configuration/requirements.py b/volatility/framework/configuration/requirements.py index 6e3c4da54..231fe5847 100644 --- a/volatility/framework/configuration/requirements.py +++ b/volatility/framework/configuration/requirements.py @@ -128,40 +128,53 @@ class ChoiceRequirement(interfaces_configuration.RequirementInterface): return [] -class LayerListRequirement(ListRequirement): +class LayerListRequirement(MultiRequirement): """Allows a variable length list of layers that must exist """ - # TODO: Consider making this a ConstructableRequirement such that sub-config options can be held underneath it - # and the swap layers can be reconstructed automatically - - def __init__(self, *args, **kwargs) -> None: - kwargs['element_type'] = str - super().__init__(*args, **kwargs) - def unsatisfied(self, context: interfaces.context.ContextInterface, config_path: str) -> typing.List[str]: - """Determines whether any layer lists are not present (satisified)""" - list_check = super().unsatisfied(context, config_path) - if list_check: - return list_check - - value = self.config_value(context, config_path) - if not isinstance(value, typing.List): - vollog.log(constants.LOGLEVEL_V, "LayerList configuration value was not a list") - return [interfaces_configuration.path_join(config_path, self.name)] - - failed_layers = [] - for item in value: - if item not in context.memory: - failed_layers.append(item) - if failed_layers: - vollog.log(constants.LOGLEVEL_V, - "LayerList unsatisfied due to non-existant layers: {}".format(failed_layers)) + """Validates the provided value to ensure it is one of the available choices""" + ret_list = super().unsatisfied(context, config_path) + if ret_list: + return ret_list + if (self.config_value(context, config_path, None) is None or + self.config_value(context, interfaces_configuration.path_join(config_path, 'number_of_elements'))): return [interfaces_configuration.path_join(config_path, self.name)] return [] + def construct(self, context: interfaces.context.ContextInterface, config_path: str) -> None: + """Method for constructing within the context any required elements from subrequirements""" + new_config_path = interfaces_configuration.path_join(config_path, self.name) + num_layers_path = interfaces_configuration.path_join(new_config_path, "number_of_elements") + number_of_layers = context.config[num_layers_path] + + # Build all the layers that can be built + for i in range(number_of_layers): + layer_req = self.requirements.get(self.name + str(i), None) + if layer_req is not None and isinstance(layer_req, TranslationLayerRequirement): + layer_req.construct(context, new_config_path) + @classmethod def get_requirements(cls) -> typing.List[interfaces.configuration.RequirementInterface]: # This is not optional for the stacker to run, so optional must be marked as False return [IntRequirement("number_of_elements", description = "Determines how many layers are in this list", optional = False)] + + def build_configuration(self, + context: interfaces.context.ContextInterface, + config_path: str) -> interfaces_configuration.HierarchicalDict: + result = interfaces_configuration.HierarchicalDict() + num_elem_config_path = interfaces_configuration.path_join(config_path, self.name, 'number_of_elements') + num_elements = context.config.get(num_elem_config_path, None) + if num_elements is not None: + result["number_of_elements"] = num_elements + for i in range(num_elements): + req = interfaces_configuration.TranslationLayerRequirement(name = self.name + str(i), + description = "Swap Layer", + optional = False) + self.add_requirement(req) + value_path = interfaces_configuration.path_join(config_path, self.name, req.name) + value = context.config.get(value_path, None) + if value is not None: + result.splice(req.name, context.memory[value].build_configuration()) + return result diff --git a/volatility/framework/interfaces/configuration.py b/volatility/framework/interfaces/configuration.py index 0ddf11d00..93970a2b4 100644 --- a/volatility/framework/interfaces/configuration.py +++ b/volatility/framework/interfaces/configuration.py @@ -20,6 +20,7 @@ from abc import ABCMeta, abstractmethod from volatility.framework import constants, interfaces from volatility.framework import validity +from volatility.framework.configuration import requirements from volatility.framework.interfaces.context import ContextInterface CONFIG_SEPARATOR = "." @@ -485,12 +486,16 @@ class ConfigurableInterface(validity.ValidityRoutines, metaclass = ABCMeta): # Do not include the name of constructed classes if value is not None and not isinstance(req, ConstructableRequirementInterface): result[req.name] = value + # TODO: Move this to a generic requirement if isinstance(req, TranslationLayerRequirement): if value is not None: result.splice(req.name, self.context.memory[value].build_configuration()) elif isinstance(req, SymbolRequirement): if value is not None: result.splice(req.name, self.context.symbol_space[value].build_configuration()) + elif isinstance(req, requirements.LayerListRequirement): + if value is not None: + result.splice(req.name, req.build_configuration(self.context, self.config_path)) return result @classmethod diff --git a/volatility/framework/layers/intel.py b/volatility/framework/layers/intel.py index 81626fe37..8c4f0042d 100644 --- a/volatility/framework/layers/intel.py +++ b/volatility/framework/layers/intel.py @@ -182,8 +182,6 @@ class Intel(interfaces.layers.TranslationLayerInterface): return [requirements.TranslationLayerRequirement(name = 'memory_layer', optional = False), requirements.LayerListRequirement(name = 'swap_layers', - min_elements = 0, - max_elements = 100, optional = True), requirements.IntRequirement(name = 'page_map_offset', optional = False),