From a4b4a8eed3a26d9087e9eeb9af9587ef2fd59599 Mon Sep 17 00:00:00 2001 From: Mike Auty Date: Sat, 4 Nov 2017 18:45:08 +0000 Subject: [PATCH] Improve the error handling with automagics. --- volatility/cli/__init__.py | 8 ++++++-- volatility/framework/automagic/__init__.py | 13 +++++++++++-- volatility/framework/automagic/stacker.py | 10 +++------- volatility/framework/interfaces/layers.py | 7 +++++-- volatility/framework/layers/physical.py | 2 ++ 5 files changed, 27 insertions(+), 13 deletions(-) diff --git a/volatility/cli/__init__.py b/volatility/cli/__init__.py index 29939aa7f..b3bd5353d 100644 --- a/volatility/cli/__init__.py +++ b/volatility/cli/__init__.py @@ -158,13 +158,17 @@ class CommandLine(object): ### # Clever magic figures out how to fulfill each requirement that might not be fulfilled if not args.quiet: - automagic.run(automagics, ctx, plugin, "plugins", progress_callback = progress_callback) + errors = automagic.run(automagics, ctx, plugin, "plugins", progress_callback = progress_callback) else: - automagic.run(automagics, ctx, plugin, "plugins") + errors = automagic.run(automagics, ctx, plugin, "plugins") # Check all the requirements and/or go back to the automagic step unsatisfied = plugin.unsatisfied(ctx, plugin_config_path) if unsatisfied: + for error in errors: + error_string = [x for x in error.format_exception_only()][-1] + vollog.warning("Automagic exception occured: {}".format(error_string[:-1])) + vollog.log(constants.LOGLEVEL_V, "\n".join(error.format(chain = True))) raise RuntimeError("Unable to validate the plugin configuration: {}".format(unsatisfied)) print("\n\n") diff --git a/volatility/framework/automagic/__init__.py b/volatility/framework/automagic/__init__.py index fbd5f7fd3..9fe98fc5f 100644 --- a/volatility/framework/automagic/__init__.py +++ b/volatility/framework/automagic/__init__.py @@ -9,6 +9,7 @@ loading of file format types) as well as a module to reconstruct layers based on import logging import sys +import traceback from volatility.framework import class_subclasses, import_files, interfaces from volatility.framework.automagic import construct_layers, stacker, windows, pdbscan @@ -55,6 +56,8 @@ def run(automagics, context, configurable, config_path, progress_callback = None This is where any automagic is allowed to run, and alter the context in order to satisfy/improve all requirements + Returns a list of traceback objects that occurred during the autorun procedure + .. note:: The order of the `automagics` list is important. An `automagic` that populates configurations may be necessary for an `automagic` that populates the context based on the configuration information. """ @@ -75,6 +78,12 @@ def run(automagics, context, configurable, config_path, progress_callback = None for req in configurable.get_requirements(): requirement.add_requirement(req) + exceptions = [] + for automagic in automagics: - vollog.info("Running automagic: {}".format(automagic.__class__.__name__)) - automagic(context, config_path, requirement, progress_callback) + try: + vollog.info("Running automagic: {}".format(automagic.__class__.__name__)) + automagic(context, config_path, requirement, progress_callback) + except Exception as excp: + exceptions.append(traceback.TracebackException.from_exception(excp)) + return exceptions diff --git a/volatility/framework/automagic/stacker.py b/volatility/framework/automagic/stacker.py index 369a0cd69..5bdf959f9 100644 --- a/volatility/framework/automagic/stacker.py +++ b/volatility/framework/automagic/stacker.py @@ -45,13 +45,9 @@ class LayerStacker(interfaces.automagic.AutomagicInterface): if unsatisfied: vollog.info("Unable to run LayerStacker, unsatisfied requirement: {}".format(unsatisfied)) return unsatisfied - if 'single_location' not in self.config: - vollog.info("Unable to run LayerStacker, single_location parameter not provided") - return [] - location = self.config["single_location"] - if not location: - vollog.info("Unable to run LayerStacker, single_location parameter not provided") - return [] + if not self.config.get('single_location', None): + raise ValueError("Unable to run LayerStacker, single_location parameter not provided") + location = self.config['single_location'] self._check_type(location, str) self._check_type(requirement, interfaces.configuration.RequirementInterface) diff --git a/volatility/framework/interfaces/layers.py b/volatility/framework/interfaces/layers.py index f28622a6a..914dfdbfe 100644 --- a/volatility/framework/interfaces/layers.py +++ b/volatility/framework/interfaces/layers.py @@ -227,7 +227,8 @@ class DataLayerInterface(configuration.ConfigurableInterface, validity.ValidityR "Scanning {} using {}".format(self.name, scanner.__class__.__name__)) yield from scan_chunk(value) except Exception as e: - vollog.debug("Exception: {}".format(str(e))) + # We don't care the kind of exception, so catch and report on everything, yielding nothing further + vollog.debug("Scan Failure: {}".format(str(e))) def _scan_iterator(self, scanner, min_address, max_address): return range(min_address, max_address, scanner.chunk_size) @@ -423,6 +424,7 @@ class ResourceAccessor(object): if url_type == 'file': curfile = urllib.request.urlopen(url, context = self._context) else: + # TODO: find a way to check if we already have this file (look at http headers?) block_size = 1028 * 8 temp_filename = os.path.join(constants.CACHE_PATH, "data_" + hashlib.sha512(bytes(url, 'latin-1')).hexdigest()) @@ -433,7 +435,8 @@ class ResourceAccessor(object): break cache_file.write(block) if self._progress_callback: - self._progress_callback("Reading file: {}".format(url)) + # TODO: Figure out the size and therefore percentage complete + self._progress_callback(0, "Reading file {}".format(url)) cache_file.close() # Re-open the cache with a different mode curfile = open(temp_filename) diff --git a/volatility/framework/layers/physical.py b/volatility/framework/layers/physical.py index 84df807c5..bf69b6afc 100644 --- a/volatility/framework/layers/physical.py +++ b/volatility/framework/layers/physical.py @@ -61,6 +61,8 @@ class FileLayer(interfaces.layers.DataLayerInterface): self._location = self.config["location"] self._file_ = None self._size = None + # Instantiate the file to throw exceptions if the file doesn't open + _ = self._file @property def location(self):