All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.rivulet.internal.fuzz.generator.RerunGeneratorWrapper Maven / Gradle / Ivy

The newest version!
package io.rivulet.internal.fuzz.generator;

import edu.columbia.cs.psl.phosphor.runtime.Taint;
import edu.columbia.cs.psl.phosphor.struct.LazyCharArrayObjTags;
import edu.columbia.cs.psl.phosphor.struct.TaintedBooleanWithObjTag;

import io.rivulet.internal.rerun.RerunConfigBuilder;
import io.rivulet.internal.rerun.SinglePayloadRerunConfigBuilder;
import io.rivulet.internal.rerun.TestRerunConfiguration;
import io.rivulet.internal.*;

import java.util.*;

public abstract class RerunGeneratorWrapper extends RivuletAutoTaintWrapper implements RerunGenerator {

	// Maximum number of characters from a tainted chunk's original value that can be added to a payload
	private static final int MAX_APPEND = 250;
	// Replacement String used to replace tainted chunks when generating reruns because the original tainted values may
	// have caused the String to be malformed
	private static final String STAND_IN = "text";

	/* Base implementation of isApplicable. Checks if the violation resulted from a tainted value flowing to one of the sinks
	 * that this generator targets for checking on reruns. */
	@Override
	public boolean isApplicable(Violation violation) {
		return getTargetedBaseSinks().contains(violation.getBaseSink());
	}

	public TaintedBooleanWithObjTag isApplicable$$PHOSPHORTAGGED(Violation violation, TaintedBooleanWithObjTag ret) {
		ret.taint = null;
		ret.val = isApplicable(violation);
		return ret;
	}

	/* Returns valid rerun configurations that can be used to verify the specified violation. */
	public Collection generateReruns(Violation violation, Object receiver, Object[] arguments) {
		return generateReruns(violation, generateRerunBuilders(violation, receiver, arguments));
	}

	protected LinkedHashSet generateReruns(Violation violation, Iterable builders) {
		LinkedHashSet ret = new LinkedHashSet<>();
		for(RerunConfigBuilder builder : builders) {
			builder.autoTainterClass(getClass());
			ret.addAll(builder.build(violation));
		}
		return ret;
	}

	/* Returns rerun configuration builders that can be used to create reruns to verify the specified violation. */
	public Iterable generateRerunBuilders(Violation violation, Object receiver, Object[] arguments) {
		return new LinkedList<>();
	}

	/* Returns a list of the sink methods that this generator is concerned with checking. Returns null if the generator is concerned
	 * with the same set of sinks as the original run. During a test rerun, only the methods returned by getTargetedBaseSinks
	 * for the generator that created the rerun will be considered sink methods regardless of any annotations on the test's method
	 * or class, any sink methods that reported violations on the original test run and the methods specified in phosphor.sinks file. */
	public abstract List getTargetedBaseSinks();

	/* Returns whether the specified String contains at least one tainted character. */
	public static boolean containsTaintedChar(String s) {
		Taint[] taints = getStringValueTaints(s);
		if(taints == null) {
			return false;
		}
		for(Taint taint : taints) {
			if(taint != null && !taint.isEmpty()) {
				return true;
			}
		}
		return false;
	}

	/* Returns a shortened version of the specified String. */
	public String truncate(String str) {
		return (str.length() > MAX_APPEND) ? str.substring(0, MAX_APPEND) : str;
	}

	/* Returns a set containing the reruns configurations created using from tainted portions of the specified String the
	 * incorporate the values of the tainted portions into the specified payloads. Uses the specified regex to remove
	 * parts of the values of the tainted portions that might interfere with or break the payload. */
	protected Collection generateRerunsUsingTaintedChunks(Violation originalViolation, String str,
																				  Iterable payloads, int argIndex, String removeRegex) {
		LinkedHashSet configs = new LinkedHashSet<>();
		// Build a tainted chunk to violation map
		LinkedHashMap violationMap = createSourceValueViolationMap(originalViolation, str, argIndex);
		Violation violation = originalViolation.copyWithTaintedValues(new LinkedList<>());
		super.checkTaint(str, 0, violation);
		violation = TaintedSinkValueSet.processViolation(violation);
		if(!violation.getTaintedValues().isEmpty()) {
			for(String payload : payloads) {
				if(payload.contains("%s")) {
					// Fill in original values and generate on a per value basis
					for(String value: violationMap.keySet()) {
						String sanitizedValue = value.replaceAll(removeRegex, "");
						String filledPayload = fillInFormatSpecifiers(payload, truncate(sanitizedValue));
						configs.addAll(generateReruns(violationMap.get(value), Collections.singletonList(new SinglePayloadRerunConfigBuilder(filledPayload))));
					}
				} else {
					configs.addAll(generateReruns(violation, Collections.singletonList(new SinglePayloadRerunConfigBuilder(payload))));
				}
			}
		}
		return configs;
	}

	/* Returns a mapping between continuously tainted sink value chunks and violations containing only label information from
	 * the chunk. */
	private LinkedHashMap createSourceValueViolationMap(Violation originalViolation, String taintedString,
																		   int argIndex) {
		LinkedHashMap taintedChunkMap = new LinkedHashMap<>();
		for(TaintedSinkValueImpl taintedChunk : TaintedSinkValue.getContinuousTaintedChunks(getStringValueTag(taintedString), argIndex)) {
			Violation chunkViolation = originalViolation.copyWithTaintedValues(Collections.singletonList(taintedChunk));
			chunkViolation = TaintedSinkValueSet.processViolation(chunkViolation);
			taintedChunkMap.put(taintedChunk.getSinkValue(), chunkViolation);
		}
		return taintedChunkMap;
	}

	/* Formats the specified format string with copies of the specified String argument. */
	private String fillInFormatSpecifiers(String format, String arg) {
		int count = 0;
		for(int i = 0; i < format.length() - 1; i++) {
			if(format.charAt(i) == '%') {
				char next = format.charAt(++i);
				if(next == 's') {
					count++;
				}
			}
		}
		String[] arr = new String[count];
		for(int i  = 0; i < count; i++) {
			arr[i] = arg;
		}
		return String.format(format, (Object[]) arr);
	}

	/* Replaces each tainted section in the specified string with a stand-in value that contains only alphabetic letters.
	 * Each character of the replacement is tainted with a combined tag containing all of the tags in the original
	 * tainted section. */
	protected static String replaceTaintedChunksWithStandIns(String str) {
		if(str == null) {
			return null;
		}
		str = ParseUtils.removeDummyPositionTags(str);
		LazyCharArrayObjTags tags = getStringValueTag(str);
		InvocationRanges taintedRanges = new InvocationRanges(-1);
		if(tags != null && tags.taints != null) {
			for(int i = 0; i < tags.taints.length; i++) {
				Taint tag = tags.taints[i];
				if(tag != null && !tag.isEmpty()) {
					taintedRanges.addInt(i);
				}
			}
			int[] ranges = taintedRanges.getRangesCopy();
			if(ranges.length > 0) {
				TaintedStringBuilder builder = new TaintedStringBuilder();
				int previousEnd = 0;
				for(int i = 0; i < ranges.length; i+= 2) {
					int start = ranges[i];
					int end = ranges[i+1];
					// Append non-tainted portion between the start of this chunk and the end of the last chunk
					builder.append(str.substring(previousEnd, start));
					// Append the replace in place of the original tainted portion
					@SuppressWarnings("unchecked")
					Taint[] taints = (Taint[]) new Taint[end - start];
					System.arraycopy(tags.taints, start, taints, 0, taints.length);
					builder.append(TaintedStringBuilder.taintChars(new String(STAND_IN.toCharArray()), Taint.combineTaintArray(taints)));
					previousEnd = end;
				}
				return builder.append(str.substring(ranges[ranges.length-1])).toString();
			}
		}
		return new String(str);
	}

	/* Returns a processed violation for the specified String using information from the specified original violation. */
	protected Violation makeProcessedViolation(Violation originalViolation, String taintedString) {
		Violation violation = originalViolation.copyWithTaintedValues(new LinkedList<>());
		super.checkTaint(taintedString, 0, violation);
		return TaintedSinkValueSet.processViolation(violation);
	}

	/* Returns whether the first character of the specified String is tainted. */
	protected static boolean firstCharTainted(String s) {
		if(s == null) {
			return false;
		}
		@SuppressWarnings("unchecked")
		Taint[] taints = getStringValueTaints(s);
		if(taints == null || taints.length == 0) {
			return false;
		}
		return taints[0] != null && !taints[0].isEmpty();
	}

	/* Returns whether every character of the specified String is tainted. */
	protected static boolean allCharsTainted(String s) {
		if(s == null) {
			return false;
		}
		@SuppressWarnings("unchecked")
		Taint[] taints = getStringValueTaints(s);
		if(taints == null) {
			return false;
		}
		for(Taint taint : taints) {
			if(taint == null || taint.isEmpty()) {
				return false;
			}
		}
		return true;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy