Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#33] IMA baselines can match measurements based solely on hashes #34

Merged
merged 1 commit into from
Nov 1, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions HIRS_Utils/src/main/java/hirs/data/persist/IMAPolicy.java
Original file line number Diff line number Diff line change
Expand Up @@ -457,9 +457,11 @@ public final synchronized Multimap<String, String> getPathEquivalences() {
Multimap<String, String> equivalentPaths = HashMultimap.create();

// define equivalences
equivalentPaths.put("/bin/", "/usr/bin/");
equivalentPaths.put("/lib/", "/usr/lib/");
equivalentPaths.put("/lib64/", "/usr/lib64/");
equivalentPaths.put("/bin/", "/usr/bin/");
equivalentPaths.put("/lib/", "/usr/lib/");
equivalentPaths.put("/lib64/", "/usr/lib64/");
equivalentPaths.put("/usr/bin/", "/usr/sbin/");
equivalentPaths.put("/sbin/", "/usr/sbin/");

iadgovuser26 marked this conversation as resolved.
Show resolved Hide resolved
// populate inverse relationships
Multimap<String, String> bidirectionalEquivalences = HashMultimap.create();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package hirs.data.persist;

import com.fasterxml.jackson.annotation.JsonIgnore;
import hirs.ima.matching.BatchImaMatchStatus;
import hirs.persist.ImaBaselineRecordManager;

import javax.persistence.Entity;
Expand All @@ -14,6 +15,7 @@
*/
@Entity
public abstract class ImaAcceptableRecordBaseline extends ImaBaseline<IMABaselineRecord> {

/**
* Creates a new ImaAcceptableRecordBaseline with the given name.
*
Expand All @@ -29,6 +31,34 @@ public ImaAcceptableRecordBaseline(final String name) {
protected ImaAcceptableRecordBaseline() {
}

/**
* Similar to contains, but only considers the hash value and does not consider
* the path as relevant to matching at all.
*
* Each type of baseline specifies its own
* 'contains' algorithm for deciding whether the given measurements are
* considered as matches, mismatches, or unknowns to the baseline. The 'contains' method
* of ImaAcceptableRecordBaselines that is normally used to judge measurement records
* against baseline records considers both paths and hashes; this method offers an
* additional mechanism for finding matching baseline records solely based
* on matching hash values.
*
* @param records
* measurement records to find in this baseline
* @param recordManager
* an ImaBaselineRecordManager that can be used to retrieve persisted records
* @param imaPolicy
* the IMA policy to use while determining if a baseline contains the given records
*
* @return batch match status for the measurement records, according only to hashes
*/
@JsonIgnore
public abstract BatchImaMatchStatus<IMABaselineRecord> containsHashes(
Collection<IMAMeasurementRecord> records,
ImaBaselineRecordManager recordManager,
IMAPolicy imaPolicy
);

/**
* Returns an unmodifiable set of IMA baseline records found in the IMA
* baseline. The returned set only contains the baseline records from this
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ protected ImaBaseline() {
* @param imaPolicy
* the IMA policy to use while determining if a baseline contains the given records
*
* @return search status for the measurement record
* @return batch match status for the measurement records
*/
public abstract BatchImaMatchStatus<T> contains(
Collection<IMAMeasurementRecord> records,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,16 @@
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.google.common.base.Preconditions;
import hirs.ima.matching.BatchImaMatchStatus;
import hirs.ima.matching.IMAMatchStatus;
import hirs.ima.matching.ImaBlacklistRecordMatcher;
import hirs.persist.ImaBaselineRecordManager;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.OneToMany;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

/**
Expand Down Expand Up @@ -53,22 +50,10 @@ public BatchImaMatchStatus<ImaBlacklistRecord> contains(
final Collection<IMAMeasurementRecord> records,
final ImaBaselineRecordManager recordManager,
final IMAPolicy imaPolicy) {
if (records == null) {
throw new IllegalArgumentException("Records cannot be null");
}

if (imaPolicy == null) {
throw new IllegalArgumentException("IMA policy cannot be null");
}

ImaBlacklistRecordMatcher recordMatcher =
new ImaBlacklistRecordMatcher(imaBlacklistRecords, imaPolicy, this);
List<IMAMatchStatus<ImaBlacklistRecord>> matchStatuses = new ArrayList<>();
for (IMAMeasurementRecord record : records) {
matchStatuses.add(recordMatcher.contains(record));
}

return new BatchImaMatchStatus<>(matchStatuses);
Preconditions.checkArgument(records != null, "Records cannot be null");
Preconditions.checkArgument(imaPolicy != null, "IMA policy cannot be null");
return new ImaBlacklistRecordMatcher(imaBlacklistRecords, imaPolicy, this)
.batchMatch(records);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,15 @@

import com.fasterxml.jackson.annotation.JsonIgnore;

import com.google.common.base.Preconditions;
import hirs.ima.matching.BatchImaMatchStatus;
import hirs.ima.matching.IMAMatchStatus;
import hirs.ima.matching.ImaIgnoreSetRecordMatcher;
import hirs.persist.ImaBaselineRecordManager;
import hirs.utils.RegexFilePathMatcher;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.persistence.Access;
Expand Down Expand Up @@ -157,21 +155,10 @@ public final BatchImaMatchStatus<ImaIgnoreSetRecord> contains(
final ImaBaselineRecordManager recordManager,
final IMAPolicy imaPolicy
) {
if (records == null) {
throw new IllegalArgumentException("Records cannot be null");
}

if (imaPolicy == null) {
throw new IllegalArgumentException("IMA policy cannot be null");
}

ImaIgnoreSetRecordMatcher recordMatcher =
new ImaIgnoreSetRecordMatcher(imaIgnoreSetRecords, imaPolicy, this);
List<IMAMatchStatus<ImaIgnoreSetRecord>> matchStatuses = new ArrayList<>();
for (IMAMeasurementRecord record : records) {
matchStatuses.add(recordMatcher.contains(record));
}
return new BatchImaMatchStatus<>(matchStatuses);
Preconditions.checkArgument(records != null, "Records cannot be null");
Preconditions.checkArgument(imaPolicy != null, "IMA policy cannot be null");
return new ImaIgnoreSetRecordMatcher(imaIgnoreSetRecords, imaPolicy, this)
.batchMatch(records);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
package hirs.data.persist;

import com.google.common.base.Preconditions;
import hirs.ima.matching.BatchImaMatchStatus;
import hirs.ima.matching.IMAMatchStatus;
import hirs.ima.matching.ImaAcceptableRecordMatcher;
import hirs.ima.matching.ImaAcceptableHashRecordMatcher;
import hirs.ima.matching.ImaAcceptablePathAndHashRecordMatcher;
import hirs.ima.matching.ImaRecordMatcher;
import hirs.persist.ImaBaselineRecordManager;
import hirs.utils.Callback;
import org.hibernate.Criteria;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
* This class defines the basis of operation for a baseline that supports querying
Expand Down Expand Up @@ -50,13 +52,8 @@ public final BatchImaMatchStatus<IMABaselineRecord> contains(
final Collection<IMAMeasurementRecord> records,
final ImaBaselineRecordManager recordManager,
final IMAPolicy imaPolicy) {
if (records == null) {
throw new IllegalArgumentException("Records cannot be null");
}

if (recordManager == null) {
throw new IllegalArgumentException("ImaBaselineRecordManager cannot be null");
}
Preconditions.checkArgument(records != null, "records cannot be null");
Preconditions.checkArgument(recordManager != null, "record manager cannot be null");

final Collection<String> pathsToFind = new HashSet<>();
for (IMAMeasurementRecord record : records) {
Expand All @@ -79,14 +76,45 @@ public IMABaselineRecord call(final IMABaselineRecord baselineRecord) {
}
});

ImaAcceptableRecordMatcher recordMatcher =
new ImaAcceptableRecordMatcher(retrievedRecords, imaPolicy, this);
List<IMAMatchStatus<IMABaselineRecord>> matchStatuses = new ArrayList<>();
for (IMAMeasurementRecord record : records) {
matchStatuses.add(recordMatcher.contains(record));
}
return new ImaAcceptablePathAndHashRecordMatcher(retrievedRecords, imaPolicy, this)
.batchMatch(records);
}

/**
* Check membership of the given {@link IMAMeasurementRecord}s in this baseline.
*
* @param records the records to attempt to match
* @param recordManager the {@link ImaBaselineRecordManager} to query
* @param imaPolicy the IMA policy to use while determining if a baseline contains the records
*
* @return a collection of {@link IMAMatchStatus}es reflecting the results
*/
@Override
public final BatchImaMatchStatus<IMABaselineRecord> containsHashes(
final Collection<IMAMeasurementRecord> records,
final ImaBaselineRecordManager recordManager,
final IMAPolicy imaPolicy) {
Preconditions.checkArgument(records != null, "records cannot be null");
Preconditions.checkArgument(recordManager != null, "record manager cannot be null");

final Set<Digest> hashesToFind = records.stream()
.filter(Objects::nonNull)
.map(IMAMeasurementRecord::getHash)
.collect(Collectors.toSet());

Collection<IMABaselineRecord> retrievedRecords = recordManager.iterateOverBaselineRecords(
this, new Callback<IMABaselineRecord, IMABaselineRecord>() {
@Override
public IMABaselineRecord call(final IMABaselineRecord baselineRecord) {
if (hashesToFind.contains(baselineRecord.getHash())) {
return baselineRecord;
}
return null;
}
});

return new BatchImaMatchStatus<>(matchStatuses);
return new ImaAcceptableHashRecordMatcher(retrievedRecords, imaPolicy, this)
.batchMatch(records);
}

@Override
Expand Down
36 changes: 19 additions & 17 deletions HIRS_Utils/src/main/java/hirs/data/persist/SimpleImaBaseline.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package hirs.data.persist;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.google.common.base.Preconditions;
import hirs.ima.matching.BatchImaMatchStatus;
import hirs.ima.matching.IMAMatchStatus;
import hirs.ima.matching.ImaAcceptableRecordMatcher;
import hirs.ima.matching.ImaAcceptableHashRecordMatcher;
import hirs.ima.matching.ImaAcceptablePathAndHashRecordMatcher;
import hirs.persist.ImaBaselineRecordManager;
import org.apache.logging.log4j.Logger;

Expand All @@ -15,12 +16,10 @@
import javax.persistence.FetchType;
import javax.persistence.OneToMany;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import static org.apache.logging.log4j.LogManager.getLogger;
Expand Down Expand Up @@ -175,21 +174,24 @@ public final BatchImaMatchStatus<IMABaselineRecord> contains(
final Collection<IMAMeasurementRecord> records,
final ImaBaselineRecordManager recordManager,
final IMAPolicy imaPolicy) {
if (records == null) {
throw new IllegalArgumentException("Records cannot be null");
}
Preconditions.checkArgument(records != null, "Records cannot be null");
Preconditions.checkArgument(imaPolicy != null, "IMA policy cannot be null");

if (imaPolicy == null) {
throw new IllegalArgumentException("IMA policy cannot be null");
}
return new ImaAcceptablePathAndHashRecordMatcher(imaRecords, imaPolicy, this)
.batchMatch(records);
}

ImaAcceptableRecordMatcher recordMatcher =
new ImaAcceptableRecordMatcher(imaRecords, imaPolicy, this);
List<IMAMatchStatus<IMABaselineRecord>> matchStatuses = new ArrayList<>();
for (IMAMeasurementRecord record : records) {
matchStatuses.add(recordMatcher.contains(record));
}
return new BatchImaMatchStatus<>(matchStatuses);

@Override
public BatchImaMatchStatus<IMABaselineRecord> containsHashes(
final Collection<IMAMeasurementRecord> records,
final ImaBaselineRecordManager recordManager,
final IMAPolicy imaPolicy) {
Preconditions.checkArgument(records != null, "Records cannot be null");
Preconditions.checkArgument(imaPolicy != null, "IMA policy cannot be null");

return new ImaAcceptableHashRecordMatcher(imaRecords, imaPolicy, this)
.batchMatch(records);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -307,4 +307,11 @@ public boolean equals(final Object o) {
public int hashCode() {
return Objects.hash(matchStatuses);
}

@Override
public String toString() {
return "BatchImaMatchStatus{"
+ "matchStatuses=" + matchStatuses
+ '}';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package hirs.ima.matching;

import com.google.common.base.Preconditions;
import hirs.data.persist.IMABaselineRecord;
import hirs.data.persist.IMAMeasurementRecord;
import hirs.data.persist.IMAPolicy;
import hirs.data.persist.ImaBaseline;
import hirs.data.persist.ReportMatchStatus;

import java.util.Collection;
import java.util.Set;

/**
* This class extends the base matching functionality of {@link ImaRecordMatcher} to
* compare {@link IMAMeasurementRecord}s against a collection of {@link IMABaselineRecord}s
* based solely on their hashes.
*/
public class ImaAcceptableHashRecordMatcher extends ImaRecordMatcher<IMABaselineRecord> {
/**
* Construct a new ImaAcceptablePathAndHashRecordMatcher.
*
* @param records the baseline records to use for matching
* @param imaPolicy the IMA policy to reference during matching; its partial path and path
* equivalence settings influence matching behavior
* @param imaBaseline the IMA baseline these records were sourced from; this is only used to
*/
public ImaAcceptableHashRecordMatcher(
final Collection<IMABaselineRecord> records,
final IMAPolicy imaPolicy,
final ImaBaseline imaBaseline) {
super(records, imaPolicy, imaBaseline);
}

/**
* Returns an IMAMatchStatus indicating whether the given {@link IMAMeasurementRecord} is
* contained within the originally provided {@link IMABaselineRecord}s.
*
* @param record the record to look up
* @return an IMAMatchStatus indicating whether the record is a match or unknown to
* the given baseline records
*/
@Override
public IMAMatchStatus<IMABaselineRecord> contains(final IMAMeasurementRecord record) {
Preconditions.checkArgument(record != null, "Cannot match on null record.");

final Set<IMABaselineRecord> matchingRecords = getRelatedBaselineRecordsByHash(record);

if (matchingRecords.isEmpty()) {
return new IMAMatchStatus<>(record, ReportMatchStatus.UNKNOWN, getImaBaseline());
}

return new IMAMatchStatus<>(
record,
ReportMatchStatus.MATCH,
matchingRecords,
getImaBaseline()
);
}
}
Loading