Merge pull request #4185 from dannysmyda/Fix_memory_leak_in_EFE

EFE - Fixed memory leaks issues and added more informative progress bar updates
This commit is contained in:
Richard Cordovano 2018-10-04 13:37:21 -04:00 committed by GitHub
commit f19cf9fbaa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -29,7 +29,6 @@ import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@ -94,6 +93,10 @@ class SevenZipExtractor {
private String moduleDirAbsolute; private String moduleDirAbsolute;
private Blackboard blackboard; private Blackboard blackboard;
private ProgressHandle progress;
private int numItems;
private String currentArchiveName;
private String getLocalRootAbsPath(String uniqueArchiveFileName) { private String getLocalRootAbsPath(String uniqueArchiveFileName) {
return moduleDirAbsolute + File.separator + uniqueArchiveFileName; return moduleDirAbsolute + File.separator + uniqueArchiveFileName;
@ -478,9 +481,10 @@ class SevenZipExtractor {
HashMap<String, ZipFileStatusWrapper> statusMap = new HashMap<>(); HashMap<String, ZipFileStatusWrapper> statusMap = new HashMap<>();
List<AbstractFile> unpackedFiles = Collections.<AbstractFile>emptyList(); List<AbstractFile> unpackedFiles = Collections.<AbstractFile>emptyList();
ISevenZipInArchive inArchive = null; ISevenZipInArchive inArchive = null;
currentArchiveName = archiveFile.getName();
SevenZipContentReadStream stream = null; SevenZipContentReadStream stream = null;
final ProgressHandle progress = ProgressHandle.createHandle(Bundle.EmbeddedFileExtractorIngestModule_ArchiveExtractor_moduleName()); progress = ProgressHandle.createHandle(Bundle.EmbeddedFileExtractorIngestModule_ArchiveExtractor_moduleName());
//recursion depth check for zip bomb //recursion depth check for zip bomb
Archive parentAr; Archive parentAr;
try { try {
@ -535,12 +539,11 @@ class SevenZipExtractor {
} else { } else {
inArchive = SevenZip.openInArchive(options, stream, password); inArchive = SevenZip.openInArchive(options, stream, password);
} }
int numItems = inArchive.getNumberOfItems(); numItems = inArchive.getNumberOfItems();
logger.log(Level.INFO, "Count of items in archive: {0}: {1}", new Object[]{escapedArchiveFilePath, numItems}); //NON-NLS logger.log(Level.INFO, "Count of items in archive: {0}: {1}", new Object[]{escapedArchiveFilePath, numItems}); //NON-NLS
progress.start(numItems); progress.start(numItems);
progressStarted = true; progressStarted = true;
progress.progress(archiveFile.getName() + ": Analyzing archive metadata and creating local files");
//setup the archive local root folder //setup the archive local root folder
final String uniqueArchiveFileName = FileUtil.escapeFileName(EmbeddedFileExtractorIngestModule.getUniqueName(archiveFile)); final String uniqueArchiveFileName = FileUtil.escapeFileName(EmbeddedFileExtractorIngestModule.getUniqueName(archiveFile));
try { try {
@ -564,15 +567,16 @@ class SevenZipExtractor {
freeDiskSpace = IngestMonitor.DISK_FREE_SPACE_UNKNOWN; freeDiskSpace = IngestMonitor.DISK_FREE_SPACE_UNKNOWN;
} }
Map<Integer, InArchiveItemDetails> archiveDetailsMap = new LinkedHashMap<>(); Map<Integer, InArchiveItemDetails> archiveDetailsMap = new HashMap<>();
for (int inArchiveItemIndex = 0; inArchiveItemIndex < numItems; inArchiveItemIndex++) { for (int inArchiveItemIndex = 0; inArchiveItemIndex < numItems; inArchiveItemIndex++) {
progress.progress(String.format("%s: Analyzing archive metadata and creating local files (%d of %d)", currentArchiveName, inArchiveItemIndex + 1, numItems), 0);
if (isZipBombArchiveItemCheck(archiveFile, inArchive, inArchiveItemIndex, depthMap, escapedArchiveFilePath)) { if (isZipBombArchiveItemCheck(archiveFile, inArchive, inArchiveItemIndex, depthMap, escapedArchiveFilePath)) {
unpackSuccessful = false; unpackSuccessful = false;
return unpackSuccessful; return unpackSuccessful;
} }
String pathInArchive = getPathInArchive(inArchive, inArchiveItemIndex, archiveFile); String pathInArchive = getPathInArchive(inArchive, inArchiveItemIndex, archiveFile);
SevenZipExtractor.UnpackedTree.UnpackedNode unpackedNode = unpackedTree.addNode(pathInArchive); UnpackedTree.UnpackedNode unpackedNode = unpackedTree.addNode(pathInArchive);
final boolean isEncrypted = (Boolean) inArchive.getProperty(inArchiveItemIndex, PropID.ENCRYPTED); final boolean isEncrypted = (Boolean) inArchive.getProperty(inArchiveItemIndex, PropID.ENCRYPTED);
@ -660,11 +664,13 @@ class SevenZipExtractor {
archiveDetailsMap, password, freeDiskSpace); archiveDetailsMap, password, freeDiskSpace);
//According to the documentation, indices in sorted order are optimal //According to the documentation, indices in sorted order are optimal
//for efficiency. Hence, the LinkedHashMap and linear processing of //for efficiency. Hence, the HashMap and linear processing of
//inArchiveItemIndex. False indicates non-test mode //inArchiveItemIndex. False indicates non-test mode
inArchive.extract(extractionIndices, false, archiveCallBack); inArchive.extract(extractionIndices, false, archiveCallBack);
unpackSuccessful = unpackSuccessful & archiveCallBack.wasSuccessful(); unpackSuccessful = unpackSuccessful & archiveCallBack.wasSuccessful();
archiveDetailsMap = null;
// add them to the DB. We wait until the end so that we have the metadata on all of the // add them to the DB. We wait until the end so that we have the metadata on all of the
// intermediate nodes since the order is not guaranteed // intermediate nodes since the order is not guaranteed
@ -672,7 +678,9 @@ class SevenZipExtractor {
unpackedTree.updateOrAddFileToCaseRec(statusMap, archiveFilePath); unpackedTree.updateOrAddFileToCaseRec(statusMap, archiveFilePath);
unpackedFiles = unpackedTree.getAllFileObjects(); unpackedFiles = unpackedTree.getAllFileObjects();
//check if children are archives, update archive depth tracking //check if children are archives, update archive depth tracking
for (AbstractFile unpackedFile : unpackedFiles) { for (int i = 0; i < unpackedFiles.size(); i++) {
progress.progress(String.format("%s: Searching for nested archives (%d of %d)", currentArchiveName, i + 1, unpackedFiles.size()));
AbstractFile unpackedFile = unpackedFiles.get(i);
if (unpackedFile == null) { if (unpackedFile == null) {
continue; continue;
} }
@ -696,7 +704,7 @@ class SevenZipExtractor {
if (archiveFile.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC)) { if (archiveFile.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC)) {
String msg = NbBundle.getMessage(SevenZipExtractor.class, String msg = NbBundle.getMessage(SevenZipExtractor.class,
"EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.errUnpacking.msg", "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.errUnpacking.msg",
archiveFile.getName()); currentArchiveName);
String details = NbBundle.getMessage(SevenZipExtractor.class, String details = NbBundle.getMessage(SevenZipExtractor.class,
"EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.errUnpacking.details", "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.errUnpacking.details",
escapedArchiveFilePath, ex.getMessage()); escapedArchiveFilePath, ex.getMessage());
@ -750,7 +758,7 @@ class SevenZipExtractor {
"EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.encrFileDetected.msg"); "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.encrFileDetected.msg");
String details = NbBundle.getMessage(SevenZipExtractor.class, String details = NbBundle.getMessage(SevenZipExtractor.class,
"EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.encrFileDetected.details", "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.encrFileDetected.details",
archiveFile.getName(), EmbeddedFileExtractorModuleFactory.getModuleName()); currentArchiveName, EmbeddedFileExtractorModuleFactory.getModuleName());
services.postMessage(IngestMessage.createWarningMessage(EmbeddedFileExtractorModuleFactory.getModuleName(), msg, details)); services.postMessage(IngestMessage.createWarningMessage(EmbeddedFileExtractorModuleFactory.getModuleName(), msg, details));
} }
@ -813,6 +821,7 @@ class SevenZipExtractor {
try { try {
output.flush(); output.flush();
output.close(); output.close();
output = null;
} catch (IOException e) { } catch (IOException e) {
logger.log(Level.SEVERE, "Error closing unpack stream for file: {0}", localAbsPath); //NON-NLS logger.log(Level.SEVERE, "Error closing unpack stream for file: {0}", localAbsPath); //NON-NLS
} }
@ -953,7 +962,7 @@ class SevenZipExtractor {
private final AbstractFile archiveFile; private final AbstractFile archiveFile;
private final ISevenZipInArchive inArchive; private final ISevenZipInArchive inArchive;
private SevenZipExtractor.UnpackStream unpackStream = null; private UnpackStream unpackStream = null;
private final Map<Integer, InArchiveItemDetails> archiveDetailsMap; private final Map<Integer, InArchiveItemDetails> archiveDetailsMap;
private final ProgressHandle progressHandle; private final ProgressHandle progressHandle;
@ -1044,6 +1053,11 @@ class SevenZipExtractor {
: writeTime.getTime() / 1000; : writeTime.getTime() / 1000;
accessTimeInSeconds = accessTime == null ? 0L accessTimeInSeconds = accessTime == null ? 0L
: accessTime.getTime() / 1000; : accessTime.getTime() / 1000;
progressHandle.progress(archiveFile.getName() + ": "
+ (String) inArchive.getProperty(inArchiveItemIndex, PropID.PATH),
inArchiveItemIndex);
} }
/** /**
@ -1056,10 +1070,6 @@ class SevenZipExtractor {
*/ */
@Override @Override
public void setOperationResult(ExtractOperationResult result) throws SevenZipException { public void setOperationResult(ExtractOperationResult result) throws SevenZipException {
progressHandle.progress(archiveFile.getName() + ": "
+ (String) inArchive.getProperty(inArchiveItemIndex, PropID.PATH),
inArchiveItemIndex);
final SevenZipExtractor.UnpackedTree.UnpackedNode unpackedNode final SevenZipExtractor.UnpackedTree.UnpackedNode unpackedNode
= archiveDetailsMap.get(inArchiveItemIndex).getUnpackedNode(); = archiveDetailsMap.get(inArchiveItemIndex).getUnpackedNode();
final String localRelPath = archiveDetailsMap.get( final String localRelPath = archiveDetailsMap.get(
@ -1125,6 +1135,7 @@ class SevenZipExtractor {
private class UnpackedTree { private class UnpackedTree {
final UnpackedNode rootNode; final UnpackedNode rootNode;
private int nodesProcessed = 0;
/** /**
* *
@ -1249,6 +1260,7 @@ class SevenZipExtractor {
*/ */
private void updateOrAddFileToCaseRec(UnpackedNode node, FileManager fileManager, HashMap<String, ZipFileStatusWrapper> statusMap, String archiveFilePath) throws TskCoreException { private void updateOrAddFileToCaseRec(UnpackedNode node, FileManager fileManager, HashMap<String, ZipFileStatusWrapper> statusMap, String archiveFilePath) throws TskCoreException {
DerivedFile df; DerivedFile df;
progress.progress(String.format("%s: Adding/updating files in case database (%d of %d)", currentArchiveName, ++nodesProcessed, numItems));
try { try {
String nameInDatabase = getKeyFromUnpackedNode(node, archiveFilePath); String nameInDatabase = getKeyFromUnpackedNode(node, archiveFilePath);
ZipFileStatusWrapper existingFile = nameInDatabase == null ? null : statusMap.get(nameInDatabase); ZipFileStatusWrapper existingFile = nameInDatabase == null ? null : statusMap.get(nameInDatabase);