Add locking for threaded operation.

This commit is contained in:
Mike Auty
2019-03-02 18:07:48 +00:00
parent 1e9205a75f
commit 9fadee1a17
4 changed files with 37 additions and 14 deletions
+3 -1
View File
@@ -38,7 +38,6 @@ SYMBOL_BASEPATHS = [
]
BANG = "!"
PACKAGE_VERSION = "3.0.0_alpha1"
DISABLE_MULTITHREADED_SCANNING = False
AUTOMAGIC_CONFIG_PATH = 'automagic'
LOGLEVEL_V = 9
@@ -56,3 +55,6 @@ LINUX_BANNERS_PATH = os.path.join(CACHE_PATH, "linux_banners.cache")
MAC_BANNERS_PATH = os.path.join(CACHE_PATH, "mac_banners.cache")
ProgressCallback = Optional[Callable[[float, str], None]]
# Options are 'multiprocessing', 'threading' or None
PARALLELISM = 'multiprocessing'
+1 -1
View File
@@ -212,7 +212,7 @@ class DataLayerInterface(interfaces.configuration.ConfigurableInterface, metacla
progress = DummyProgress() # type: ProgressValue
scan_iterator = functools.partial(self._scan_iterator, scanner, sections)
scan_metric = self._scan_metric(scanner, sections)
if scanner.thread_safe and not constants.DISABLE_MULTITHREADED_SCANNING:
if scanner.thread_safe and not constants.PARALLELISM:
progress = multiprocessing.Manager().Value("Q", 0)
scan_chunk = functools.partial(self._scan_chunk, scanner, progress)
with multiprocessing.Pool() as pool:
+32 -10
View File
@@ -17,10 +17,11 @@
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
# specific language governing rights and limitations under the License.
#
import threading
from contextlib import contextmanager
from typing import Any, Dict, IO, List, Optional
from volatility.framework import exceptions, interfaces
from volatility.framework import exceptions, interfaces, constants
from volatility.framework.configuration import requirements
from volatility.framework.layers import resources
@@ -77,6 +78,15 @@ class BufferDataLayer(interfaces.layers.DataLayerInterface):
]
class DummyLock:
def __enter__(self):
pass
def __exit__(self, type, value, traceback):
pass
class FileLayer(interfaces.layers.DataLayerInterface):
"""a DataLayer backed by a file on the filesystem"""
@@ -93,6 +103,12 @@ class FileLayer(interfaces.layers.DataLayerInterface):
self._accessor = resources.ResourceAccessor()
self._file_ = None # type: Optional[IO[Any]]
self._size = None # type: Optional[int]
# Construct the lock now (shared if made before threading) in case we ever need it
if constants.PARALLELISM == 'threading':
self._lock = threading.Lock()
else:
# We don't need a lock for multiprocessing because child threads can't inherit file descriptors by default
self._lock = DummyLock()
# Instantiate the file to throw exceptions if the file doesn't open
_ = self._file
@@ -115,10 +131,11 @@ class FileLayer(interfaces.layers.DataLayerInterface):
# Zero based, so we return the size of the file minus 1
if self._size:
return self._size
orig = self._file.tell()
self._file.seek(0, 2)
self._size = self._file.tell()
self._file.seek(orig)
with self._lock:
orig = self._file.tell()
self._file.seek(0, 2)
self._size = self._file.tell()
self._file.seek(orig)
return self._size
@property
@@ -141,8 +158,12 @@ class FileLayer(interfaces.layers.DataLayerInterface):
invalid_address = self.maximum_address + 1
raise exceptions.InvalidAddressException(self.name, invalid_address,
"Offset outside of the buffer boundaries")
self._file.seek(offset)
data = self._file.read(length)
# TODO: implement locking for multi-threading
with self._lock:
self._file.seek(offset)
data = self._file.read(length)
if len(data) < length:
if pad:
data += (b"\x00" * (length - len(data)))
@@ -162,8 +183,9 @@ class FileLayer(interfaces.layers.DataLayerInterface):
invalid_address = self.maximum_address + 1
raise exceptions.InvalidAddressException(self.name, invalid_address,
"Data segment outside of the " + self.name + " file boundaries")
self._file.seek(offset)
self._file.write(data)
with self._lock:
self._file.seek(offset)
self._file.write(data)
def __getstate__(self) -> Dict[str, Any]:
"""Do not store the open _file_ attribute, our property will ensure the file is open when needed
@@ -43,8 +43,7 @@ class BytesScanner(layers.ScannerInterface):
class RegExScanner(layers.ScannerInterface):
# TODO: Document why this isn't thread safe?
thread_safe = False
thread_safe = True
def __init__(self, pattern: bytes, flags: int = 0) -> None:
super().__init__()