Rework LayerListRequirement from a ListRequirement to a MultiRequirement.

This commit is contained in:
Mike Auty
2018-02-11 18:35:18 +00:00
parent e8212df604
commit b7c68f4e98
3 changed files with 43 additions and 27 deletions
@@ -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
@@ -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
-2
View File
@@ -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),