Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
io.rivulet.internal.RivuletAutoTaintWrapper Maven / Gradle / Ivy
package io.rivulet.internal;
import edu.columbia.cs.psl.phosphor.TaintUtils;
import edu.columbia.cs.psl.phosphor.runtime.MultiTainter;
import edu.columbia.cs.psl.phosphor.runtime.Taint;
import edu.columbia.cs.psl.phosphor.runtime.TaintSourceWrapper;
import edu.columbia.cs.psl.phosphor.struct.*;
import io.rivulet.BufferedHttpMessageParser;
import io.rivulet.RemoteTaintServerFacade;
import io.rivulet.internal.fuzz.generator.*;
import io.rivulet.internal.rerun.TestRerunConfiguration;
import sun.nio.ch.FileChannelImpl;
import java.lang.ref.ReferenceQueue;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;
public class RivuletAutoTaintWrapper extends TaintSourceWrapper {
// Whether JUnit tests are currently being run. If true, violations should not be directly printed by this class and
// this class should generate rerun configurations
private static boolean runningJUnitTests = true;
// Whether at least one sink method was entered
private static final AtomicBoolean reachedSink = new AtomicBoolean(false);
// Maps violations that occurred due to some tainted value reaching a sink to reruns configurations generated for
// the violation
private static final LinkedHashMap> violationConfigsMap = new LinkedHashMap<>();
// Stores information used for a test rerun
private static TestRerunConfiguration currentRerunConfig = null;
// The maximum depth for recursive taint checking
private static final int MAX_DEPTH = 10;
// Value given to the mark field of any object enqueued in the queue of object to check for Taint instances to indicate
// that that it was checked on a particular pass
private static int currentMarkLevel = Integer.MIN_VALUE + 1;
// Maps Classes to a list of record objects containing the fields and their offsets for the class
private final IdentityHashMap classInfoMap = new IdentityHashMap<>();
// How deeply nested the sink currently being checked is, increases when entering a sink and decreases when
// exiting one.
private static final ThreadLocal currentNestingLevel =
ThreadLocal.withInitial(new Supplier() {
@Override
public Integer get() {
return 0;
}
});
// One level deeper than the nesting level at which the last reported violation. A value of -1 indicates that there are no
// reported violations on the stack.
private static final ThreadLocal lastViolationLevel =
ThreadLocal.withInitial(new Supplier() {
@Override
public Integer get() {
return -1;
}
});
// Maps actual sources, arg index pairs to the number of times a label with index information has been generated for that source. */
private static final ConcurrentHashMap invocationIDMap = new ConcurrentHashMap<>();
// List of generators that can be used to create rerun configurations for violations
private static List rerunGenerators = null;
// Maps channels to the parser used to parse bytes read from it. Used to buffer http response bytes that need to be
// until the full response is written
private static final HashMap parserMap = new HashMap<>();
// Tracks nested calls to http response sinks
private static final ThreadLocal lastHttpResponseSinkLevel =
ThreadLocal.withInitial(new Supplier() {
@Override
public Integer get() {
return 0;
}
});
public static RemoteTaintServerFacade remoteTaintServerFacade = null;
//Make sure that NIO doesn't try to directly transfer files, we won't see the content and it will break everything...
static{
try{
Field f = FileChannelImpl.class.getDeclaredField("transferSupported");
f.setAccessible(true);
f.set(null, false);
}catch(Throwable t){
t.printStackTrace();
}
}
public static int getNumberOfViolations() {
if(remoteTaintServerFacade != null)
return remoteTaintServerFacade.getNumberOfViolations();
return getViolations().size();
}
/* Creates a label from the specified information and assigns it the specified invocation id if
* TaintTrackingRunListener is tracking violations. */
private SourceInfoTaintLabel generateBaseLabel(String baseSource, String actualSource, int argIndex, Class> originalClass,
boolean fullyReplaceable, int invocationID) {
originalClass = TaintUtils.getUnwrappedClass(originalClass);
if(!runningJUnitTests) {
// TaintTrackingRunListener is not tracking violation output, indexInfo shouldn't be added because reruns aren't
// being generated
return new SourceInfoTaintLabel(baseSource, actualSource, argIndex, originalClass, fullyReplaceable);
} else {
InvocationRanges indexInfo = new InvocationRanges(invocationID);
return new IndexedSourceInfoTaintLabel(baseSource, actualSource, argIndex, originalClass, fullyReplaceable,
indexInfo, null);
}
}
/* Creates a new label from the specified base label but with the specified originalClass and fullyReplaceable values. */
private SourceInfoTaintLabel generateLabelFromBase(SourceInfoTaintLabel baseLabel, Class> originalClass, boolean fullyReplaceable) {
originalClass = TaintUtils.getUnwrappedClass(originalClass);
if(baseLabel instanceof IndexedSourceInfoTaintLabel) {
return new IndexedSourceInfoTaintLabel((IndexedSourceInfoTaintLabel)baseLabel, originalClass, fullyReplaceable);
} else {
return new SourceInfoTaintLabel(baseLabel, originalClass, fullyReplaceable);
}
}
/* If the specified base label has index information returns a new label from the specified base label but with only
* the specified index indicated as present in its index information. Otherwise, returns a copy of the base label. */
private SourceInfoTaintLabel generateLabelFromBase(SourceInfoTaintLabel baseLabel, int index) {
if(baseLabel instanceof IndexedSourceInfoTaintLabel) {
return new IndexedSourceInfoTaintLabel((IndexedSourceInfoTaintLabel)baseLabel, index);
} else {
return new SourceInfoTaintLabel(baseLabel);
}
}
/* Returns a new String created to help with String interning if the specified String and its characters are not
* tainted. Otherwise, returns the original String. */
private String unintern(String s) {
Taint taint = getTaint(s);
if((taint == null || taint.isEmpty()) && (getStringValueTag(s) == null || getStringValueTag(s).taints == null)) {
return new String(s);
} else {
return s;
}
}
/* Taints the specified object with a new taint with the specified label. */
private Object autoTaint(Object ret, SourceInfoTaintLabel label) {
if(ret == null) {
return null;
} else if(ret instanceof String && label.getFullyReplaceable()) {
ret = unintern((String) ret);
}
ret = getReplacement(ret, label);
if(ret instanceof String) {
// Taint the String's value array
String str = (String) ret;
LazyCharArrayObjTags tags = getStringValueTag(str);
combineTaintsOnArray(tags, new Taint<>(label));
setStringValueTag(str, tags);
}
return super.autoTaint(ret, new Taint<>(label));
}
/* Called by sources for the arguments and return value. Taints the specified object with the specified tag. This
* object can only be fully replaced on a rerun if it is a return value (indicated by the argIndex being -1). */
@Override
public Object autoTaint(Object ret, String baseSource, String actualSource, int argIndex) {
// Assign an invocation id for the call of the the actual source method
NumberedObject key = new NumberedObject(actualSource, argIndex);
invocationIDMap.putIfAbsent(key, new AtomicInteger(0));
int invocationID = invocationIDMap.get(key).getAndIncrement();
if(ret == null) {
return null;
}
SourceInfoTaintLabel baseLabel = generateBaseLabel(baseSource, actualSource, argIndex, ret.getClass(), argIndex == -1, invocationID);
if(ret instanceof LazyArrayObjTags) {
// autoTainting a 1D primitive array - indices should be recorded
return autoTaintWithIndexInfo((LazyArrayObjTags) ret, baseLabel);
} else if(ret instanceof String) {
// autoTainting a String - indices should be recorded
return autoTaintWithIndexInfo((String) ret, baseLabel);
} else if(ret instanceof Map) {
return autoTaintMap((Map) ret, baseLabel);
} else if(ret instanceof Collection) {
return autoTaintCollection((Collection) ret, baseLabel);
} else {
if(ret.getClass().isArray()) {
// Taint the array's elements
for(int i = 0; i < Array.getLength(ret); i++) {
Array.set(ret, i, autoTaint(Array.get(ret, i), generateLabelFromBase(baseLabel, ret.getClass().getComponentType(), true)));
}
}
return autoTaint(ret, baseLabel);
}
}
/* Taints the specified String's character with a label containing index info. */
private Object autoTaintWithIndexInfo(String ret, SourceInfoTaintLabel baseLabel) {
if(baseLabel.getFullyReplaceable()) {
ret = unintern(ret);
}
// Try to replace the entire String
ret = (String)getReplacement(ret, baseLabel);
if(baseLabel instanceof IndexedSourceInfoTaintLabel) {
baseLabel = new IndexedSourceInfoTaintLabel((IndexedSourceInfoTaintLabel)baseLabel, IndexedSourceInfoTaintLabel.copyPrimitiveArray(((String) ret).toCharArray()));
}
// Taint the String's value array
char[] val = ret.toCharArray();
Taint[] currentTaints = getStringValueTaints(ret);
@SuppressWarnings("unchecked")
Taint[] taints = (Taint[])(currentTaints == null ? new Taint[val.length] : currentTaints);
for(int i = 0; i < taints.length; i++) {
Taint tag = new Taint<>(generateLabelFromBase(baseLabel, i));
if(taints[i] == null) {
taints[i] = tag;
} else {
taints[i].addDependency(tag);
}
}
setStringValueTag(ret, new LazyCharArrayObjTags(val, taints));
return ret;
}
/* Taints the specified LazyArrayObjTags' elements with labels containing index info. */
private Object autoTaintWithIndexInfo(LazyArrayObjTags ret, SourceInfoTaintLabel baseLabel) {
ret = (LazyArrayObjTags)getReplacement(ret, baseLabel);
if(baseLabel instanceof IndexedSourceInfoTaintLabel) {
baseLabel = new IndexedSourceInfoTaintLabel((IndexedSourceInfoTaintLabel)baseLabel, IndexedSourceInfoTaintLabel.copyPrimitiveArray(ret.getVal()));
}
@SuppressWarnings("unchecked")
Taint[] taints = (Taint[])(ret.taints == null ? new Taint[ret.getLength()] : ret.taints);
for(int i = 0; i < taints.length; i++) {
Taint tag = new Taint<>(generateLabelFromBase(baseLabel, i));
if(taints[i] == null) {
taints[i] = tag;
} else {
taints[i].addDependency(tag);
}
}
ret.taints = taints;
return ret;
}
/* Taints the specified Collection and its elements. */
@SuppressWarnings("unchecked")
private Object autoTaintCollection(Collection c, SourceInfoTaintLabel baseLabel) {
boolean tryEntireCollectionReplacement = false;
Object[] elements = c.toArray();
try {
c.clear();
for(Object e : elements) {
c.add(autoTaint(e, generateLabelFromBase(baseLabel, e.getClass(), true)));
}
} catch(UnsupportedOperationException ex) {
// The object being tainted is probably some sort of unmodifiable or immutable collection.
// If this isn't a rerun or we aren't tainting a return value just taint the value don't bother trying to replace it.
tryEntireCollectionReplacement = true;
for(Object e : c) {
autoTaint(e, generateLabelFromBase(baseLabel, e.getClass(), baseLabel.getFullyReplaceable()));
}
}
if(baseLabel.getFullyReplaceable() && tryEntireCollectionReplacement) {
// c is the return value of the source method, we can try to swap out the entire object to replace its elements
Object replacement = tryEntireMapOrCollectionReplacement(c, baseLabel);
if(replacement != null) {
return autoTaint(replacement, baseLabel);
}
}
return autoTaint(c, baseLabel);
}
/* Taints the specified Map and its values. */
@SuppressWarnings("unchecked")
private Object autoTaintMap(Map map, SourceInfoTaintLabel baseLabel) {
boolean tryEntireMapReplacement = false;
for(Object _e: map.entrySet()) {
Map.Entry e = (Map.Entry) _e;
try {
e.setValue(autoTaint(e.getValue(), generateLabelFromBase(baseLabel, e.getValue().getClass(), true)));
} catch(UnsupportedOperationException ex) {
// The object being tainted is probably some sort of unmodifiable or immutable map.
// If this isn't a rerun or we aren't tainting a return value just taint the value don't bother trying to replace it.
tryEntireMapReplacement = true;
autoTaint(e.getValue(), generateLabelFromBase(baseLabel, e.getValue().getClass(), baseLabel.getFullyReplaceable()));
}
}
if(baseLabel.getFullyReplaceable() && tryEntireMapReplacement) {
// map is the return value of the source method, we can try to swap out the entire object to replace its values
Object replacement = tryEntireMapOrCollectionReplacement(map, baseLabel);
if(replacement != null) {
return autoTaint(replacement, baseLabel);
}
}
return autoTaint(map, baseLabel);
}
/* Tries to create a new instance of the specified object's type and fill it with replacement values. Returns null if
* this fails at any point for any reason. */
@SuppressWarnings("unchecked")
private Object tryEntireMapOrCollectionReplacement(Object obj, SourceInfoTaintLabel baseLabel) {
try {
if(obj instanceof Map) {
Map map = (Map)obj;
Map replacement = map.getClass().newInstance();
for(Object o: map.entrySet()) {
Map.Entry e = (Map.Entry) o;
replacement.put(e.getKey(), autoTaint(e.getValue(), generateLabelFromBase(baseLabel, e.getValue().getClass(), true)));
}
return replacement;
} else if(obj instanceof Collection) {
Collection col = (Collection)obj;
Collection replacement = col.getClass().newInstance();
Object[] elements = col.toArray();
for(Object e : elements) {
replacement.add(autoTaint(e, generateLabelFromBase(baseLabel, e.getClass(), true)));
}
return replacement;
} else {
return null;
}
} catch(Exception e) {
return null;
}
}
/* Returns the appropriate valueToTry value for the specified source and count from the currentConfig, if there is not
* an appropriate value returns the specified original value. */
private static Object getReplacement(Object originalValue, SourceInfoTaintLabel label) {
if(currentRerunConfig != null && currentRerunConfig.hasReplacementValue(originalValue, label)) {
return currentRerunConfig.getReplacementValue(originalValue, label);
} else {
return originalValue;
}
}
/* Sets the mark field for the specified object to the currentMarkLevel if the object has a mark field. Returns true
* if the object has a mark field that was not already set to the currentMarkLevel that was successfully set to the
* currentMarkLevel. */
private boolean setMark(Object obj, Set marked) {
if(obj == null || obj.getClass() == null) {
return false;
}
Class> clazz = obj.getClass();
if(!classInfoMap.containsKey(clazz)) {
classInfoMap.put(clazz, new ClassOffsetInfo(clazz));
}
ClassOffsetInfo info = classInfoMap.get(clazz);
if(info.hasMarkField()) {
return info.setMarkFieldForObject(currentMarkLevel, obj);
} else if(!shouldDeepCheckTaint(clazz) || clazz.isArray()) {
// The fields of these classes are not enqueued so they should not cause any infinite checking loops
return true;
} else {
return marked.add(obj);
}
}
/* Adds all of the non-null, non-visited values of the fields of the specified object to the stack. */
private void enqueueFields(Object obj, int depth, SinglyLinkedList stack, Set marked) {
Class> clazz = obj.getClass();
if(!classInfoMap.containsKey(clazz)) {
classInfoMap.put(clazz, new ClassOffsetInfo(clazz));
}
for(ClassOffsetInfo.FieldInfo info : classInfoMap.get(clazz).getFields()) {
Object fieldValue = info.getObject(obj);
if(fieldValue != null) {
if(setMark(fieldValue, marked)) {
stack.push(new NumberedObject(fieldValue, depth+1));
}
}
}
}
/* Returns whether or not the fields of an instance of the specified class should be checked for taint tags. */
private static boolean shouldDeepCheckTaint(Class> clazz) {
if(clazz == null || clazz.getName() == null) {
return false;
}
Package pack = clazz.getPackage();
String name = clazz.getName();
if(pack != null && (pack.equals(Package.getPackage("java.lang.reflect")) || pack.equals(Package.getPackage("sun.reflect")))) {
// The specified class is associated with reflection
return false;
} else if(name.contains("/")) {
// The specified class is a VM-anonymous class (not anonymous inner class)
return false;
} else {
return !clazz.equals(Object.class) && !ReferenceQueue.class.isAssignableFrom(clazz) && !Number.class.isAssignableFrom(clazz) &&
!clazz.equals(Character.class) && !clazz.equals(Boolean.class) && !clazz.isPrimitive() &&
!TaintedPrimitiveWithObjTag.class.isAssignableFrom(clazz);
}
}
/* Called after entering sink methods. */
@Override
public synchronized void checkTaint(Object self, Object[] arguments, String baseSink, String actualSink) {
if(XssGenerator.isXssSink(baseSink)) {
checkTaintHttpResponse(self, arguments, baseSink, actualSink);
} else {
// Check whether this sink is nested inside another sink which reported a violation
if(arguments != null && (lastViolationLevel.get() == -1 || currentNestingLevel.get() < lastViolationLevel.get())) {
Violation violation = new Violation(baseSink, actualSink);
for(int i = 0; i < arguments.length; i++) {
checkTaint(arguments[i], i, violation);
}
if(!violation.getTaintedValues().isEmpty()) {
lastViolationLevel.set(currentNestingLevel.get() + 1);
synchronized(violationConfigsMap) {
if(!violationConfigsMap.containsKey(violation) && !runningJUnitTests) {
System.out.println(violation.toString(false, null));
} else if(!violationConfigsMap.containsKey(violation) && runningJUnitTests) {
generateRerunConfigs(violation, self, arguments);
}
}
}
}
}
}
/* Specified checkTaint for http responses that buffers bytes until a full response it written. */
private synchronized void checkTaintHttpResponse(Object self, Object[] arguments, String baseSink, String actualSink) {
if(arguments != null && lastHttpResponseSinkLevel.get() == 1) {
// Make sure call to http response sink is not nested to prevent double writing bytes
try {
if(!parserMap.containsKey(self)) {
parserMap.put(self, BufferedHttpMessageParser.getResponseParser());
}
BufferedHttpMessageParser parser = parserMap.get(self);
if(arguments.length == 1) {
if(arguments[0] instanceof ByteBuffer) {
parser.appendBytes((ByteBuffer) arguments[0]);
} else if(arguments[0] instanceof ByteBuffer[]) {
for(ByteBuffer buffer : (ByteBuffer[]) arguments[0]) {
parser.appendBytes(buffer);
}
}
} else if(arguments.length == 3) {
if(arguments[0] instanceof ByteBuffer[] && arguments[1] instanceof TaintedIntWithObjTag
&& arguments[2] instanceof TaintedIntWithObjTag) {
int offset = ((TaintedIntWithObjTag)arguments[1]).val;
int len = ((TaintedIntWithObjTag)arguments[2]).val;
ByteBuffer[] buffers = (ByteBuffer[]) arguments[0];
for(int i = offset; i < offset+len; i++) {
parser.appendBytes(buffers[i]);
}
}
}
while(parser.hasParsedMessage()) {
BufferedHttpMessageParser.ParsedMessage parsed = parser.getParsedMessage();
if(parsed.hasHtmlContent()) {
Violation violation = new Violation(baseSink, actualSink);
// Check the response body for taint tags
String html = parsed.getEntityString();
checkTaint(html, 0, violation);
if(!violation.getTaintedValues().isEmpty()) {
lastViolationLevel.set(currentNestingLevel.get() + 1);
synchronized(violationConfigsMap) {
if(!violationConfigsMap.containsKey(violation) && !runningJUnitTests) {
System.out.println(violation.toString(false, null));
} else if(!violationConfigsMap.containsKey(violation) && runningJUnitTests) {
generateRerunConfigs(violation, self, new Object[]{html});
}
}
}
}
}
} catch(Exception e) {
//
}
}
}
/* Reports violations if the specified object or its fields are tainted. Filters the sinkValue added to the violation
* to be only the tainted parts of arrays, if reporting a tainted array. */
public void checkTaint(Object obj, int argIndex, Violation violation) {
checkTaint(obj, argIndex, violation, true);
}
/* Reports violations if the specified object or its fields are tainted. */
public void checkTaint(Object obj, int argIndex, Violation violation, boolean filterSinkValue) {
if(obj != null) {
SinglyLinkedList stack = new SinglyLinkedList<>();
Set marked = Collections.newSetFromMap(new IdentityHashMap<>());
setMark(obj, marked);
stack.push(new NumberedObject(obj, 1));
while(!stack.isEmpty()) {
NumberedObject poppedObj = stack.pop();
Object curObj = poppedObj.obj;
int curDepth = poppedObj.num;
if(curObj != null && !shallowCheckTaint(curObj, argIndex, violation, filterSinkValue) && curDepth < MAX_DEPTH && shouldDeepCheckTaint(curObj.getClass())) {
if(curObj instanceof Object[]) {
// curObj is a non-primitive array
for(Object el : (Object[]) curObj) {
if(setMark(el, marked)) {
stack.push(new NumberedObject(el, curDepth + 1));
}
}
} else {
enqueueFields(curObj, curDepth, stack, marked);
}
}
}
currentMarkLevel++;
}
}
/* Checks the specified object and reports a violation if it is tainted. Returns whether a violation was reported. */
private boolean shallowCheckTaint(Object obj, int argIndex, Violation violation, boolean filterSinkValue) {
Taint tag = getTaint(obj);
if(obj != null && tag != null && !tag.isEmpty()) {
if(obj instanceof TaintedPrimitiveWithObjTag) {
TaintedPrimitiveWithObjTag o = (TaintedPrimitiveWithObjTag) obj;
taintViolation(tag, o.getValue(), argIndex, violation, filterSinkValue);
return true;
} else {
taintViolation(tag, obj, argIndex, violation, filterSinkValue);
return true;
}
} else {
return false;
}
}
/* Returns the cast taint of the specified object. */
@SuppressWarnings("unchecked")
private Taint getTaint(Object obj) {
if(obj instanceof LazyArrayObjTags) {
Taint[] taints = (Taint[])((LazyArrayObjTags) obj).taints;
return Taint.combineTaintArray(taints);
} else if(obj instanceof TaintedPrimitiveWithObjTag) {
TaintedPrimitiveWithObjTag taintedObj = (TaintedPrimitiveWithObjTag)obj;
return (Taint) taintedObj.taint;
} else {
return (Taint) MultiTainter.getTaint(obj);
}
}
private void taintViolation(Taint taint, Object taintedObj, int argIndex, Violation violation, boolean filterSinkValue) {
if(taintedObj instanceof LazyArrayObjTags && filterSinkValue) {
for(TaintedSinkValue taintedChunk : TaintedSinkValue.getContinuousTaintedChunks((LazyArrayObjTags)taintedObj, argIndex)) {
if(!taintedChunk.getTaintSources().isEmpty()) {
violation.addTaintedValue(taintedChunk);
}
}
} else {
TaintedSinkValueImpl taintedValue = new TaintedSinkValueImpl(TaintedStringBuilder.formatTaintedValue(taintedObj), TaintUtils.getUnwrappedClass(taintedObj.getClass()), argIndex, taint);
violation.addTaintedValue(taintedValue);
}
}
/* Initializes the list of rerun generators if necessary. */
private static synchronized void setUpGenerators() {
if(rerunGenerators == null || rerunGenerators.isEmpty()) {
rerunGenerators = Arrays.asList(
new RCEGenerator(),
new SqlInjectionGenerator(),
new XssGenerator(),
new OgnlInjectionGenerator(),
new XStreamGenerator(),
new ELGenerator()
);
}
}
/* Creates rerun configurations that attempt to verify the specified violation. */
private void generateRerunConfigs(Violation violation, Object receiver, Object[] arguments) {
violationConfigsMap.put(violation, new LinkedHashSet<>());
if(runningJUnitTests && currentRerunConfig == null) {
// Generate configuration if in original test run
setUpGenerators();
LinkedHashSet configs = violationConfigsMap.get(violation);
for(RerunGenerator gen : rerunGenerators) {
if(gen.isApplicable(violation)) {
configs.addAll(gen.generateReruns(TaintedSinkValueSet.processViolation(violation), receiver, arguments));
}
}
}
}
/* Called after a sink method makes its calls to checkTaint but before the rest of the method body executes. */
@Override
public void enteringSink(String baseSink, String actualSink) {
reachedSink.set(true);
// Increase the nesting level
currentNestingLevel.set(currentNestingLevel.get() + 1);
if(XssGenerator.isXssSink(baseSink)) {
// Increase the http response nesting level
lastHttpResponseSinkLevel.set(lastHttpResponseSinkLevel.get() + 1);
}
}
/* Called just before a sink method returns. */
@Override
public void exitingSink(String baseSink, String actualSink) {
if(currentNestingLevel.get() < lastViolationLevel.get()) {
lastViolationLevel.set(-1); // Clear the last violation
}
currentNestingLevel.set(currentNestingLevel.get() - 1); // Decrease the nesting level
if(XssGenerator.isXssSink(baseSink)) {
// Decrease the http response nesting level
lastHttpResponseSinkLevel.set(lastHttpResponseSinkLevel.get() - 1);
}
}
/* Returns whether at least one sink method was entered. Sets reachedSink to false. */
public static boolean checkAndClearReachedSink() {
if(remoteTaintServerFacade != null)
return remoteTaintServerFacade.checkAndClearReachedSink();
return reachedSink.getAndSet(false);
}
/* Prepares for the start of a new test. */
public static void resetForNextTest() {
lastViolationLevel.set(-1);
currentNestingLevel.set(0);
lastHttpResponseSinkLevel.set(0);
reachedSink.getAndSet(false);
invocationIDMap.clear();
}
/* Setter for runningJUnitTests. */
public static void setRunningJUnitTests(boolean runningJUnitTests) {
RivuletAutoTaintWrapper.runningJUnitTests = runningJUnitTests;
}
/* Getter for currentRerunConfig. */
public static TestRerunConfiguration getCurrentRerunConfig() {
if(remoteTaintServerFacade != null)
return remoteTaintServerFacade.getCurrentRerunConfig();
return currentRerunConfig;
}
/* Setter for currentRerunConfig. */
public static void setCurrentRerunConfig(TestRerunConfiguration currentRerunConfig) {
RivuletAutoTaintWrapper.currentRerunConfig = currentRerunConfig;
}
@Override
@SuppressWarnings("unused")
public boolean shouldInstrumentMethodForImplicitLightTracking(String className, String methodName, String methodDescriptor) {
return false;
}
/* Returns a shallow copy of the set of reported violations. */
public static Set getViolations() {
return new LinkedHashSet<>(violationConfigsMap.keySet());
}
/* Returns a shallow copy of the current value of violationConfigsMap and then clear the original map. */
public static LinkedHashMap> getAndClearViolationConfigsMap() {
LinkedHashMap> ret = new LinkedHashMap<>(violationConfigsMap);
violationConfigsMap.clear();
return ret;
}
/* Record type that stores an object and an int. */
public static class NumberedObject {
Object obj;
int num;
NumberedObject(Object obj, int num) {
this.obj = obj;
this.num = num;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
NumberedObject that = (NumberedObject) o;
if (num != that.num) return false;
return obj != null ? obj.equals(that.obj) : that.obj == null;
}
@Override
public int hashCode() {
int result = obj != null ? obj.hashCode() : 0;
result = 31 * result + num;
return result;
}
@Override
public String toString() {
return String.format("{%s = #%d}", obj, num);
}
}
}