Merge pull request #17330 from michaelnebel/java/modelgenfieldbased

Java/C#: Field based model generator (Experimental).
This commit is contained in:
Michael Nebel
2024-09-06 11:11:46 +02:00
committed by GitHub
27 changed files with 575 additions and 33 deletions

View File

@@ -18,17 +18,35 @@ private class ReturnNodeExt extends DataFlow::Node {
kind = DataFlowImplCommon::getParamReturnPosition(this, _).getKind()
}
string getOutput() {
kind instanceof DataFlowImplCommon::ValueReturnKind and
/**
* Gets the kind of the return node.
*/
DataFlowImplCommon::ReturnKindExt getKind() { result = kind }
}
bindingset[c]
private signature string printCallableParamSig(Callable c, ParameterPosition p);
private module PrintReturnNodeExt<printCallableParamSig/2 printCallableParam> {
string getOutput(ReturnNodeExt node) {
node.getKind() instanceof DataFlowImplCommon::ValueReturnKind and
result = "ReturnValue"
or
exists(ParameterPosition pos |
pos = kind.(DataFlowImplCommon::ParamUpdateReturnKind).getPosition() and
result = paramReturnNodeAsOutput(returnNodeEnclosingCallable(this), pos)
pos = node.getKind().(DataFlowImplCommon::ParamUpdateReturnKind).getPosition() and
result = printCallableParam(returnNodeEnclosingCallable(node), pos)
)
}
}
string getOutput(ReturnNodeExt node) {
result = PrintReturnNodeExt<paramReturnNodeAsOutput/2>::getOutput(node)
}
string getContentOutput(ReturnNodeExt node) {
result = PrintReturnNodeExt<paramReturnNodeAsContentOutput/2>::getOutput(node)
}
class DataFlowSummaryTargetApi extends SummaryTargetApi {
DataFlowSummaryTargetApi() { not isUninterestingForDataFlowModels(this) }
}
@@ -71,7 +89,8 @@ private predicate isRelevantTaintStep(DataFlow::Node node1, DataFlow::Node node2
* Holds if content `c` is either a field, a synthetic field or language specific
* content of a relevant type or a container like content.
*/
private predicate isRelevantContent(DataFlow::ContentSet c) {
pragma[nomagic]
private predicate isRelevantContent0(DataFlow::ContentSet c) {
isRelevantTypeInContent(c) or
containerContent(c)
}
@@ -85,6 +104,16 @@ string parameterNodeAsInput(DataFlow::ParameterNode p) {
result = qualifierString() and p instanceof InstanceParameterNode
}
/**
* Gets the MaD string representation of the parameter `p`
* when used in content flow.
*/
string parameterNodeAsContentInput(DataFlow::ParameterNode p) {
result = parameterContentAccess(p.asParameter())
or
result = qualifierString() and p instanceof InstanceParameterNode
}
/**
* Gets the MaD input string representation of `source`.
*/
@@ -170,7 +199,7 @@ module PropagateFlowConfig implements DataFlow::StateConfigSig {
) {
exists(DataFlow::ContentSet c |
DataFlowImplCommon::store(node1, c.getAStoreContent(), node2, _, _) and
isRelevantContent(c) and
isRelevantContent0(c) and
(
state1 instanceof TaintRead and state2.(TaintStore).getStep() = 1
or
@@ -180,7 +209,7 @@ module PropagateFlowConfig implements DataFlow::StateConfigSig {
or
exists(DataFlow::ContentSet c |
DataFlowPrivate::readStep(node1, c, node2) and
isRelevantContent(c) and
isRelevantContent0(c) and
state1.(TaintRead).getStep() + 1 = state2.(TaintRead).getStep()
)
}
@@ -196,6 +225,9 @@ module PropagateFlowConfig implements DataFlow::StateConfigSig {
module PropagateFlow = TaintTracking::GlobalWithState<PropagateFlowConfig>;
/**
* Gets the summary model(s) of `api`, if there is flow from parameters to return value or parameter.
*/
string captureThroughFlow0(
DataFlowSummaryTargetApi api, DataFlow::ParameterNode p, ReturnNodeExt returnNodeExt
) {
@@ -203,7 +235,7 @@ string captureThroughFlow0(
p.getEnclosingCallable() = api and
returnNodeExt.(DataFlow::Node).getEnclosingCallable() = api and
input = parameterNodeAsInput(p) and
output = returnNodeExt.getOutput() and
output = getOutput(returnNodeExt) and
input != output and
result = Printing::asTaintModel(api, input, output)
)
@@ -219,6 +251,69 @@ string captureThroughFlow(DataFlowSummaryTargetApi api) {
)
}
private module PropagateContentFlowConfig implements ContentDataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source instanceof DataFlow::ParameterNode and
source.getEnclosingCallable() instanceof DataFlowSummaryTargetApi
}
predicate isSink(DataFlow::Node sink) {
sink instanceof ReturnNodeExt and
sink.getEnclosingCallable() instanceof DataFlowSummaryTargetApi
}
predicate isAdditionalFlowStep = isAdditionalContentFlowStep/2;
predicate isBarrier(DataFlow::Node n) {
exists(Type t | t = n.getType() and not isRelevantType(t))
}
int accessPathLimit() { result = 2 }
predicate isRelevantContent(DataFlow::ContentSet s) { isRelevantContent0(s) }
DataFlow::FlowFeature getAFeature() {
result instanceof DataFlow::FeatureEqualSourceSinkCallContext
}
}
private module PropagateContentFlow = ContentDataFlow::Global<PropagateContentFlowConfig>;
private string getContent(PropagateContentFlow::AccessPath ap, int i) {
exists(ContentSet head, PropagateContentFlow::AccessPath tail |
head = ap.getHead() and
tail = ap.getTail()
|
i = 0 and
result = "." + printContent(head)
or
i > 0 and result = getContent(tail, i - 1)
)
}
private string printStoreAccessPath(PropagateContentFlow::AccessPath ap) {
result = concat(int i | | getContent(ap, i), "" order by i)
}
private string printReadAccessPath(PropagateContentFlow::AccessPath ap) {
result = concat(int i | | getContent(ap, i), "" order by i desc)
}
string captureContentFlow(DataFlowSummaryTargetApi api) {
exists(
DataFlow::ParameterNode p, ReturnNodeExt returnNodeExt, string input, string output,
PropagateContentFlow::AccessPath reads, PropagateContentFlow::AccessPath stores,
boolean preservesValue
|
PropagateContentFlow::flow(p, reads, returnNodeExt, stores, preservesValue) and
returnNodeExt.getEnclosingCallable() = api and
input = parameterNodeAsContentInput(p) + printReadAccessPath(reads) and
output = getContentOutput(returnNodeExt) + printStoreAccessPath(stores) and
input != output and
result = Printing::asModel(api, input, output, preservesValue)
)
}
/**
* A dataflow configuration used for finding new sources.
* The sources are the already known existing sources and the sinks are the API return nodes.
@@ -261,7 +356,7 @@ string captureSource(DataFlowSourceTargetApi api) {
ExternalFlow::sourceNode(source, kind) and
api = sink.getEnclosingCallable() and
not irrelevantSourceSinkApi(source.getEnclosingCallable(), api) and
result = Printing::asSourceModel(api, sink.getOutput(), kind)
result = Printing::asSourceModel(api, getOutput(sink), kind)
)
}

View File

@@ -5,11 +5,14 @@
private import csharp as CS
private import semmle.code.csharp.commons.Util as Util
private import semmle.code.csharp.commons.Collections as Collections
private import semmle.code.csharp.commons.QualifiedName as QualifiedName
private import semmle.code.csharp.dataflow.internal.DataFlowDispatch
private import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
private import semmle.code.csharp.frameworks.system.linq.Expressions
private import semmle.code.csharp.frameworks.System
private import semmle.code.csharp.dataflow.internal.TaintTrackingPrivate as TaintTrackingPrivate
import semmle.code.csharp.dataflow.internal.ExternalFlow as ExternalFlow
import semmle.code.csharp.dataflow.internal.ContentDataFlow as ContentDataFlow
import semmle.code.csharp.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon
import semmle.code.csharp.dataflow.internal.DataFlowPrivate as DataFlowPrivate
import semmle.code.csharp.dataflow.internal.DataFlowDispatch as DataFlowDispatch
@@ -22,6 +25,8 @@ class Type = CS::Type;
class Callable = CS::Callable;
class ContentSet = DataFlow::ContentSet;
/**
* Holds if any of the parameters of `api` are `System.Func<>`.
*/
@@ -241,20 +246,40 @@ string parameterAccess(CS::Parameter p) {
else result = "Argument[" + p.getPosition() + "]"
}
/**
* Gets the MaD string representation of the parameter `p`
* when used in content flow.
*/
string parameterContentAccess(CS::Parameter p) { result = "Argument[" + p.getPosition() + "]" }
class InstanceParameterNode = DataFlowPrivate::InstanceParameterNode;
class ParameterPosition = DataFlowDispatch::ParameterPosition;
private signature string parameterAccessSig(Parameter p);
module ParamReturnNodeAsOutput<parameterAccessSig/1 getParamAccess> {
bindingset[c]
string paramReturnNodeAsOutput(CS::Callable c, ParameterPosition pos) {
result = getParamAccess(c.getParameter(pos.getPosition()))
or
pos.isThisParameter() and
result = qualifierString()
}
}
/**
* Gets the MaD string representation of return through parameter at position
* `pos` of callable `c`.
*/
bindingset[c]
string paramReturnNodeAsOutput(CS::Callable c, ParameterPosition pos) {
result = parameterAccess(c.getParameter(pos.getPosition()))
or
pos.isThisParameter() and
result = qualifierString()
result = ParamReturnNodeAsOutput<parameterAccess/1>::paramReturnNodeAsOutput(c, pos)
}
bindingset[c]
string paramReturnNodeAsContentOutput(Callable c, ParameterPosition pos) {
result = ParamReturnNodeAsOutput<parameterContentAccess/1>::paramReturnNodeAsOutput(c, pos)
}
/**
@@ -344,3 +369,44 @@ predicate isRelevantSourceKind(string kind) { any() }
* Holds if the the content `c` is a container.
*/
predicate containerContent(DataFlow::ContentSet c) { c.isElement() }
/**
* Holds if there is a taint step from `node1` to `node2` in content flow.
*/
predicate isAdditionalContentFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
TaintTrackingPrivate::defaultAdditionalTaintStep(nodeFrom, nodeTo, _) and
not nodeTo.asExpr() instanceof CS::ElementAccess and
not exists(DataFlow::ContentSet c |
DataFlowPrivate::readStep(nodeFrom, c, nodeTo) and containerContent(c)
)
}
bindingset[d]
private string getFullyQualifiedName(Declaration d) {
exists(string qualifier, string name |
d.hasFullyQualifiedName(qualifier, name) and
result = QualifiedName::getQualifiedName(qualifier, name)
)
}
/**
* Gets the MaD string representation of the contentset `c`.
*/
string printContent(DataFlow::ContentSet c) {
exists(CS::Field f, string name | name = getFullyQualifiedName(f) |
c.isField(f) and
if f.isEffectivelyPublic()
then result = "Field[" + name + "]"
else result = "SyntheticField[" + name + "]"
)
or
exists(CS::Property p, string name | name = getFullyQualifiedName(p) |
c.isProperty(p) and
if p.isEffectivelyPublic()
then result = "Property[" + name + "]"
else result = "SyntheticField[" + name + "]"
)
or
c.isElement() and
result = "Element"
}

View File

@@ -0,0 +1,2 @@
unexpectedModel
expectedModel

View File

@@ -0,0 +1,12 @@
extensions:
- addsTo:
pack: codeql/csharp-all
extensible: summaryModel
data:
- [ "Models", "ManuallyModelled", False, "HasSummary", "(System.Object)", "", "Argument[0]", "ReturnValue", "value", "manual"]
- addsTo:
pack: codeql/csharp-all
extensible: neutralModel
data:
- [ "Models", "ManuallyModelled", "HasNeutralSummary", "(System.Object)", "summary", "manual"]

View File

@@ -0,0 +1,11 @@
import csharp
import utils.modelgenerator.internal.CaptureModels
import TestUtilities.InlineMadTest
module InlineMadTestConfig implements InlineMadTestConfigSig {
string getCapturedModel(Callable c) { result = captureContentFlow(c) }
string getKind() { result = "contentbased-summary" }
}
import InlineMadTest<InlineMadTestConfig>

View File

@@ -13,18 +13,21 @@ public class BasicFlow
private string tainted;
// summary=Models;BasicFlow;false;ReturnThis;(System.Object);;Argument[this];ReturnValue;value;df-generated
// contentbased-summary=Models;BasicFlow;false;ReturnThis;(System.Object);;Argument[this];ReturnValue;value;df-generated
public BasicFlow ReturnThis(object input)
{
return this;
}
// summary=Models;BasicFlow;false;ReturnParam0;(System.String,System.Object);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=Models;BasicFlow;false;ReturnParam0;(System.String,System.Object);;Argument[0];ReturnValue;value;df-generated
public string ReturnParam0(string input0, object input1)
{
return input0;
}
// summary=Models;BasicFlow;false;ReturnParam1;(System.String,System.Object);;Argument[1];ReturnValue;taint;df-generated
// contentbased-summary=Models;BasicFlow;false;ReturnParam1;(System.String,System.Object);;Argument[1];ReturnValue;value;df-generated
public object ReturnParam1(string input0, object input1)
{
return input1;
@@ -32,24 +35,29 @@ public class BasicFlow
// summary=Models;BasicFlow;false;ReturnParamMultiple;(System.Object,System.Object);;Argument[0];ReturnValue;taint;df-generated
// summary=Models;BasicFlow;false;ReturnParamMultiple;(System.Object,System.Object);;Argument[1];ReturnValue;taint;df-generated
// contentbased-summary=Models;BasicFlow;false;ReturnParamMultiple;(System.Object,System.Object);;Argument[0];ReturnValue;value;df-generated
// contentbased-summary=Models;BasicFlow;false;ReturnParamMultiple;(System.Object,System.Object);;Argument[1];ReturnValue;value;df-generated
public object ReturnParamMultiple(object input0, object input1)
{
return (System.DateTime.Now.DayOfWeek == System.DayOfWeek.Monday) ? input0 : input1;
}
// summary=Models;BasicFlow;false;ReturnSubstring;(System.String);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=Models;BasicFlow;false;ReturnSubstring;(System.String);;Argument[0];ReturnValue;taint;df-generated
public string ReturnSubstring(string s)
{
return s.Substring(0, 1);
}
// summary=Models;BasicFlow;false;SetField;(System.String);;Argument[0];Argument[this];taint;df-generated
// contentbased-summary=Models;BasicFlow;false;SetField;(System.String);;Argument[0];Argument[this].SyntheticField[Models.BasicFlow.tainted];value;df-generated
public void SetField(string s)
{
tainted = s;
}
// summary=Models;BasicFlow;false;ReturnField;();;Argument[this];ReturnValue;taint;df-generated
// contentbased-summary=Models;BasicFlow;false;ReturnField;();;Argument[this].SyntheticField[Models.BasicFlow.tainted];ReturnValue;value;df-generated
public string ReturnField()
{
return tainted;
@@ -61,72 +69,84 @@ public class CollectionFlow
private string tainted;
// summary=Models;CollectionFlow;false;ReturnArrayElement;(System.Object[]);;Argument[0].Element;ReturnValue;taint;df-generated
// contentbased-summary=Models;CollectionFlow;false;ReturnArrayElement;(System.Object[]);;Argument[0].Element;ReturnValue;value;df-generated
public object ReturnArrayElement(object[] input)
{
return input[0];
}
// summary=Models;CollectionFlow;false;AssignToArray;(System.Object,System.Object[]);;Argument[0];Argument[1].Element;taint;df-generated
// contentbased-summary=Models;CollectionFlow;false;AssignToArray;(System.Object,System.Object[]);;Argument[0];Argument[1].Element;value;df-generated
public void AssignToArray(object data, object[] target)
{
target[0] = data;
}
// summary=Models;CollectionFlow;false;AssignFieldToArray;(System.Object[]);;Argument[this];Argument[0].Element;taint;df-generated
// contentbased-summary=Models;CollectionFlow;false;AssignFieldToArray;(System.Object[]);;Argument[this].SyntheticField[Models.CollectionFlow.tainted];Argument[0].Element;value;df-generated
public void AssignFieldToArray(object[] target)
{
target[0] = tainted;
}
// summary=Models;CollectionFlow;false;ReturnListElement;(System.Collections.Generic.List<System.Object>);;Argument[0].Element;ReturnValue;taint;df-generated
// contentbased-summary=Models;CollectionFlow;false;ReturnListElement;(System.Collections.Generic.List<System.Object>);;Argument[0].Element;ReturnValue;value;df-generated
public object ReturnListElement(List<object> input)
{
return input[0];
}
// summary=Models;CollectionFlow;false;AddToList;(System.Collections.Generic.List<System.Object>,System.Object);;Argument[1];Argument[0].Element;taint;df-generated
// contentbased-summary=Models;CollectionFlow;false;AddToList;(System.Collections.Generic.List<System.Object>,System.Object);;Argument[1];Argument[0].Element;value;df-generated
public void AddToList(List<object> input, object data)
{
input.Add(data);
}
// summary=Models;CollectionFlow;false;AddFieldToList;(System.Collections.Generic.List<System.String>);;Argument[this];Argument[0].Element;taint;df-generated
// contentbased-summary=Models;CollectionFlow;false;AddFieldToList;(System.Collections.Generic.List<System.String>);;Argument[this].SyntheticField[Models.CollectionFlow.tainted];Argument[0].Element;value;df-generated
public void AddFieldToList(List<string> input)
{
input.Add(tainted);
}
// summary=Models;CollectionFlow;false;ReturnFieldInAList;();;Argument[this];ReturnValue;taint;df-generated
// contentbased-summary=Models;CollectionFlow;false;ReturnFieldInAList;();;Argument[this].SyntheticField[Models.CollectionFlow.tainted];ReturnValue.Element;value;df-generated
public List<string> ReturnFieldInAList()
{
return new List<string> { tainted };
}
// summary=Models;CollectionFlow;false;ReturnComplexTypeArray;(System.String[]);;Argument[0].Element;ReturnValue;taint;df-generated
// SPURIOUS-summary=Models;CollectionFlow;false;ReturnComplexTypeArray;(System.String[]);;Argument[0].Element;ReturnValue;taint;df-generated
// contentbased-summary=Models;CollectionFlow;false;ReturnComplexTypeArray;(System.String[]);;Argument[0];ReturnValue;value;df-generated
public string[] ReturnComplexTypeArray(string[] a)
{
return a;
}
// summary=Models;CollectionFlow;false;ReturnBulkTypeList;(System.Collections.Generic.List<System.Byte>);;Argument[0].Element;ReturnValue;taint;df-generated
// SPURIOUS-summary=Models;CollectionFlow;false;ReturnBulkTypeList;(System.Collections.Generic.List<System.Byte>);;Argument[0].Element;ReturnValue;taint;df-generated
// contentbased-summary=Models;CollectionFlow;false;ReturnBulkTypeList;(System.Collections.Generic.List<System.Byte>);;Argument[0];ReturnValue;value;df-generated
public List<byte> ReturnBulkTypeList(List<byte> a)
{
return a;
}
// summary=Models;CollectionFlow;false;ReturnComplexTypeDictionary;(System.Collections.Generic.Dictionary<System.Int32,System.String>);;Argument[0].Element;ReturnValue;taint;df-generated
// SPURIOUS-summary=Models;CollectionFlow;false;ReturnComplexTypeDictionary;(System.Collections.Generic.Dictionary<System.Int32,System.String>);;Argument[0].Element;ReturnValue;taint;df-generated
// contentbased-summary=Models;CollectionFlow;false;ReturnComplexTypeDictionary;(System.Collections.Generic.Dictionary<System.Int32,System.String>);;Argument[0];ReturnValue;value;df-generated
public Dictionary<int, string> ReturnComplexTypeDictionary(Dictionary<int, string> a)
{
return a;
}
// summary=Models;CollectionFlow;false;ReturnUntypedArray;(System.Array);;Argument[0].Element;ReturnValue;taint;df-generated
// SPURIOUS-summary=Models;CollectionFlow;false;ReturnUntypedArray;(System.Array);;Argument[0].Element;ReturnValue;taint;df-generated
// contentbased-summary=Models;CollectionFlow;false;ReturnUntypedArray;(System.Array);;Argument[0];ReturnValue;value;df-generated
public Array ReturnUntypedArray(Array a)
{
return a;
}
// summary=Models;CollectionFlow;false;ReturnUntypedList;(System.Collections.IList);;Argument[0].Element;ReturnValue;taint;df-generated
// SPURIOUS-summary=Models;CollectionFlow;false;ReturnUntypedList;(System.Collections.IList);;Argument[0].Element;ReturnValue;taint;df-generated
// contentbased-summary=Models;CollectionFlow;false;ReturnUntypedList;(System.Collections.IList);;Argument[0];ReturnValue;value;df-generated
public IList ReturnUntypedList(IList a)
{
return a;
@@ -159,19 +179,22 @@ public class IEnumerableFlow
{
private string tainted;
// summary=Models;IEnumerableFlow;false;ReturnIEnumerable;(System.Collections.Generic.IEnumerable<System.String>);;Argument[0].Element;ReturnValue;taint;df-generated
// SPURIOUS-summary=Models;IEnumerableFlow;false;ReturnIEnumerable;(System.Collections.Generic.IEnumerable<System.String>);;Argument[0].Element;ReturnValue;taint;df-generated
// contentbased-summary=Models;IEnumerableFlow;false;ReturnIEnumerable;(System.Collections.Generic.IEnumerable<System.String>);;Argument[0];ReturnValue;value;df-generated
public IEnumerable<string> ReturnIEnumerable(IEnumerable<string> input)
{
return input;
}
// summary=Models;IEnumerableFlow;false;ReturnIEnumerableElement;(System.Collections.Generic.IEnumerable<System.Object>);;Argument[0].Element;ReturnValue;taint;df-generated
// contentbased-summary=Models;IEnumerableFlow;false;ReturnIEnumerableElement;(System.Collections.Generic.IEnumerable<System.Object>);;Argument[0].Element;ReturnValue;value;df-generated
public object ReturnIEnumerableElement(IEnumerable<object> input)
{
return input.First();
}
// summary=Models;IEnumerableFlow;false;ReturnFieldInIEnumerable;();;Argument[this];ReturnValue;taint;df-generated
// contentbased-summary=Models;IEnumerableFlow;false;ReturnFieldInIEnumerable;();;Argument[this].SyntheticField[Models.IEnumerableFlow.tainted];ReturnValue.Element;value;df-generated
public IEnumerable<string> ReturnFieldInIEnumerable()
{
return new List<string> { tainted };
@@ -183,42 +206,49 @@ public class GenericFlow<T>
private T tainted;
// summary=Models;GenericFlow<T>;false;SetGenericField;(T);;Argument[0];Argument[this];taint;df-generated
// contentbased-summary=Models;GenericFlow<T>;false;SetGenericField;(T);;Argument[0];Argument[this].SyntheticField[Models.GenericFlow`1.tainted];value;df-generated
public void SetGenericField(T t)
{
tainted = t;
}
// summary=Models;GenericFlow<T>;false;ReturnGenericField;();;Argument[this];ReturnValue;taint;df-generated
// contentbased-summary=Models;GenericFlow<T>;false;ReturnGenericField;();;Argument[this].SyntheticField[Models.GenericFlow`1.tainted];ReturnValue;value;df-generated
public T ReturnGenericField()
{
return tainted;
}
// summary=Models;GenericFlow<T>;false;AddFieldToGenericList;(System.Collections.Generic.List<T>);;Argument[this];Argument[0].Element;taint;df-generated
// contentbased-summary=Models;GenericFlow<T>;false;AddFieldToGenericList;(System.Collections.Generic.List<T>);;Argument[this].SyntheticField[Models.GenericFlow`1.tainted];Argument[0].Element;value;df-generated
public void AddFieldToGenericList(List<T> input)
{
input.Add(tainted);
}
// summary=Models;GenericFlow<T>;false;ReturnFieldInGenericList;();;Argument[this];ReturnValue;taint;df-generated
// contentbased-summary=Models;GenericFlow<T>;false;ReturnFieldInGenericList;();;Argument[this].SyntheticField[Models.GenericFlow`1.tainted];ReturnValue.Element;value;df-generated
public List<T> ReturnFieldInGenericList()
{
return new List<T> { tainted };
}
// summary=Models;GenericFlow<T>;false;ReturnGenericParam<S>;(S);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=Models;GenericFlow<T>;false;ReturnGenericParam<S>;(S);;Argument[0];ReturnValue;value;df-generated
public S ReturnGenericParam<S>(S input)
{
return input;
}
// summary=Models;GenericFlow<T>;false;ReturnGenericElement<S>;(System.Collections.Generic.List<S>);;Argument[0].Element;ReturnValue;taint;df-generated
// contentbased-summary=Models;GenericFlow<T>;false;ReturnGenericElement<S>;(System.Collections.Generic.List<S>);;Argument[0].Element;ReturnValue;value;df-generated
public S ReturnGenericElement<S>(List<S> input)
{
return input[0];
}
// summary=Models;GenericFlow<T>;false;AddToGenericList<S>;(System.Collections.Generic.List<S>,S);;Argument[1];Argument[0].Element;taint;df-generated
// contentbased-summary=Models;GenericFlow<T>;false;AddToGenericList<S>;(System.Collections.Generic.List<S>,S);;Argument[1];Argument[0].Element;value;df-generated
public void AddToGenericList<S>(List<S> input, S data)
{
input.Add(data);
@@ -228,6 +258,7 @@ public class GenericFlow<T>
public abstract class BaseClassFlow
{
// summary=Models;BaseClassFlow;true;ReturnParam;(System.Object);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=Models;BaseClassFlow;true;ReturnParam;(System.Object);;Argument[0];ReturnValue;value;df-generated
public virtual object ReturnParam(object input)
{
return input;
@@ -237,6 +268,7 @@ public abstract class BaseClassFlow
public class DerivedClass1Flow : BaseClassFlow
{
// summary=Models;DerivedClass1Flow;false;ReturnParam1;(System.String,System.String);;Argument[1];ReturnValue;taint;df-generated
// contentbased-summary=Models;DerivedClass1Flow;false;ReturnParam1;(System.String,System.String);;Argument[1];ReturnValue;value;df-generated
public string ReturnParam1(string input0, string input1)
{
return input1;
@@ -246,12 +278,14 @@ public class DerivedClass1Flow : BaseClassFlow
public class DerivedClass2Flow : BaseClassFlow
{
// summary=Models;BaseClassFlow;true;ReturnParam;(System.Object);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=Models;BaseClassFlow;true;ReturnParam;(System.Object);;Argument[0];ReturnValue;value;df-generated
public override object ReturnParam(object input)
{
return input;
}
// summary=Models;DerivedClass2Flow;false;ReturnParam0;(System.String,System.Int32);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=Models;DerivedClass2Flow;false;ReturnParam0;(System.String,System.Int32);;Argument[0];ReturnValue;value;df-generated
public string ReturnParam0(string input0, int input1)
{
return input0;
@@ -263,6 +297,7 @@ public class OperatorFlow
public readonly object Field;
// summary=Models;OperatorFlow;false;OperatorFlow;(System.Object);;Argument[0];Argument[this];taint;df-generated
// contentbased-summary=Models;OperatorFlow;false;OperatorFlow;(System.Object);;Argument[0];Argument[this].Field[Models.OperatorFlow.Field];value;df-generated
public OperatorFlow(object o)
{
Field = o;
@@ -270,6 +305,7 @@ public class OperatorFlow
// Flow Summary.
// summary=Models;OperatorFlow;false;op_Addition;(Models.OperatorFlow,Models.OperatorFlow);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=Models;OperatorFlow;false;op_Addition;(Models.OperatorFlow,Models.OperatorFlow);;Argument[0];ReturnValue;value;df-generated
public static OperatorFlow operator +(OperatorFlow a, OperatorFlow b)
{
return a;
@@ -310,6 +346,7 @@ public class EqualsGetHashCodeNoFlow
}
// summary=Models;EqualsGetHashCodeNoFlow;false;Equals;(System.String);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=Models;EqualsGetHashCodeNoFlow;false;Equals;(System.String);;Argument[0];ReturnValue;value;df-generated
public string Equals(string s)
{
return s;
@@ -327,12 +364,14 @@ public class Properties
private string tainted;
// summary=Models;Properties;false;get_Prop1;();;Argument[this];ReturnValue;taint;df-generated
// contentbased-summary=Models;Properties;false;get_Prop1;();;Argument[this].SyntheticField[Models.Properties.tainted];ReturnValue;value;df-generated
public string Prop1
{
get { return tainted; }
}
// summary=Models;Properties;false;set_Prop2;(System.String);;Argument[0];Argument[this];taint;df-generated
// contentbased-summary=Models;Properties;false;set_Prop2;(System.String);;Argument[0];Argument[this].SyntheticField[Models.Properties.tainted];value;df-generated
public string Prop2
{
set { tainted = value; }
@@ -513,6 +552,7 @@ public class Inheritance
public class AImplBasePublic : BasePublic
{
// summary=Models;Inheritance+BasePublic;true;Id;(System.String);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=Models;Inheritance+BasePublic;true;Id;(System.String);;Argument[0];ReturnValue;value;df-generated
public override string Id(string x)
{
return x;
@@ -542,6 +582,7 @@ public class Inheritance
public class BImpl : B
{
// summary=Models;Inheritance+IPublic1;true;Id;(System.String);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=Models;Inheritance+IPublic1;true;Id;(System.String);;Argument[0];ReturnValue;value;df-generated
public override string Id(string x)
{
return x;
@@ -551,6 +592,7 @@ public class Inheritance
private class CImpl : C
{
// summary=Models;Inheritance+IPublic2;true;Id;(System.String);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=Models;Inheritance+IPublic2;true;Id;(System.String);;Argument[0];ReturnValue;value;df-generated
public override string Id(string x)
{
return x;
@@ -572,6 +614,7 @@ public class Inheritance
private string tainted;
// summary=Models;Inheritance+IPublic3;true;get_Prop;();;Argument[this];ReturnValue;taint;df-generated
// contentbased-summary=Models;Inheritance+IPublic3;true;get_Prop;();;Argument[this].SyntheticField[Models.Inheritance+DImpl.tainted];ReturnValue;value;df-generated
public override string Prop { get { return tainted; } }
}
}
@@ -586,14 +629,54 @@ public class MemberFlow
}
// summary=Models;MemberFlow;false;M1;(Models.MemberFlow+C);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=Models;MemberFlow;false;M1;(Models.MemberFlow+C);;Argument[0].Property[Models.MemberFlow+C.Prop];ReturnValue;value;df-generated
public string M1(C c)
{
return c.Prop;
}
// summary=Models;MemberFlow;false;M2;(Models.MemberFlow+C);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=Models;MemberFlow;false;M2;(Models.MemberFlow+C);;Argument[0].Field[Models.MemberFlow+C.Field];ReturnValue;value;df-generated
public string M2(C c)
{
return c.Field;
}
}
public class IDictionaryFlow
{
// summary=Models;IDictionaryFlow;false;ReturnIDictionaryValue;(System.Collections.Generic.IDictionary<System.Object,System.Object>,System.Object);;Argument[0].Element;ReturnValue;taint;df-generated
// contentbased-summary=Models;IDictionaryFlow;false;ReturnIDictionaryValue;(System.Collections.Generic.IDictionary<System.Object,System.Object>,System.Object);;Argument[0].Element.Property[System.Collections.Generic.KeyValuePair`2.Value];ReturnValue;value;df-generated
public object ReturnIDictionaryValue(IDictionary<object, object> input, object key)
{
return input[key];
}
}
public class NestedFieldFlow
{
public NestedFieldFlow FieldA;
public NestedFieldFlow FieldB;
// summary=Models;NestedFieldFlow;false;Move;();;Argument[this];ReturnValue;taint;df-generated
// contentbased-summary=Models;NestedFieldFlow;false;Move;();;Argument[this].Field[Models.NestedFieldFlow.FieldA];ReturnValue.Field[Models.NestedFieldFlow.FieldB];value;df-generated
public NestedFieldFlow Move()
{
return new NestedFieldFlow() { FieldB = this.FieldA };
}
// summary=Models;NestedFieldFlow;false;MoveNested;();;Argument[this];ReturnValue;taint;df-generated
// contentbased-summary=Models;NestedFieldFlow;false;MoveNested;();;Argument[this].Field[Models.NestedFieldFlow.FieldB].Field[Models.NestedFieldFlow.FieldA];ReturnValue.Field[Models.NestedFieldFlow.FieldA].Field[Models.NestedFieldFlow.FieldB];value;df-generated
public NestedFieldFlow MoveNested()
{
return new NestedFieldFlow() { FieldA = FieldB.Move() };
}
// summary=Models;NestedFieldFlow;false;ReverseFields;();;Argument[this];ReturnValue;taint;df-generated
// contentbased-summary=Models;NestedFieldFlow;false;ReverseFields;();;Argument[this].Field[Models.NestedFieldFlow.FieldA].Field[Models.NestedFieldFlow.FieldB];ReturnValue.Field[Models.NestedFieldFlow.FieldA].Field[Models.NestedFieldFlow.FieldB];value;df-generated
public NestedFieldFlow ReverseFields()
{
var x = new NestedFieldFlow() { FieldB = this.FieldA.FieldB };
return new NestedFieldFlow() { FieldA = x };
}
}

View File

@@ -0,0 +1,7 @@
private import java
private import DataFlowImplSpecific
private import codeql.dataflow.internal.ContentDataFlowImpl
module ContentDataFlow {
import MakeImplContentDataFlow<Location, JavaDataFlow>
}

View File

@@ -0,0 +1,13 @@
/**
* @name Capture content based summary models.
* @description Finds applicable content based summary models to be used by other queries.
* @kind diagnostic
* @id java/utils/modelgenerator/contentbased-summary-models
* @tags modelgenerator
*/
import internal.CaptureModels
from DataFlowSummaryTargetApi api, string flow
where flow = captureContentFlow(api)
select flow order by flow

View File

@@ -18,17 +18,35 @@ private class ReturnNodeExt extends DataFlow::Node {
kind = DataFlowImplCommon::getParamReturnPosition(this, _).getKind()
}
string getOutput() {
kind instanceof DataFlowImplCommon::ValueReturnKind and
/**
* Gets the kind of the return node.
*/
DataFlowImplCommon::ReturnKindExt getKind() { result = kind }
}
bindingset[c]
private signature string printCallableParamSig(Callable c, ParameterPosition p);
private module PrintReturnNodeExt<printCallableParamSig/2 printCallableParam> {
string getOutput(ReturnNodeExt node) {
node.getKind() instanceof DataFlowImplCommon::ValueReturnKind and
result = "ReturnValue"
or
exists(ParameterPosition pos |
pos = kind.(DataFlowImplCommon::ParamUpdateReturnKind).getPosition() and
result = paramReturnNodeAsOutput(returnNodeEnclosingCallable(this), pos)
pos = node.getKind().(DataFlowImplCommon::ParamUpdateReturnKind).getPosition() and
result = printCallableParam(returnNodeEnclosingCallable(node), pos)
)
}
}
string getOutput(ReturnNodeExt node) {
result = PrintReturnNodeExt<paramReturnNodeAsOutput/2>::getOutput(node)
}
string getContentOutput(ReturnNodeExt node) {
result = PrintReturnNodeExt<paramReturnNodeAsContentOutput/2>::getOutput(node)
}
class DataFlowSummaryTargetApi extends SummaryTargetApi {
DataFlowSummaryTargetApi() { not isUninterestingForDataFlowModels(this) }
}
@@ -71,7 +89,8 @@ private predicate isRelevantTaintStep(DataFlow::Node node1, DataFlow::Node node2
* Holds if content `c` is either a field, a synthetic field or language specific
* content of a relevant type or a container like content.
*/
private predicate isRelevantContent(DataFlow::ContentSet c) {
pragma[nomagic]
private predicate isRelevantContent0(DataFlow::ContentSet c) {
isRelevantTypeInContent(c) or
containerContent(c)
}
@@ -85,6 +104,16 @@ string parameterNodeAsInput(DataFlow::ParameterNode p) {
result = qualifierString() and p instanceof InstanceParameterNode
}
/**
* Gets the MaD string representation of the parameter `p`
* when used in content flow.
*/
string parameterNodeAsContentInput(DataFlow::ParameterNode p) {
result = parameterContentAccess(p.asParameter())
or
result = qualifierString() and p instanceof InstanceParameterNode
}
/**
* Gets the MaD input string representation of `source`.
*/
@@ -170,7 +199,7 @@ module PropagateFlowConfig implements DataFlow::StateConfigSig {
) {
exists(DataFlow::ContentSet c |
DataFlowImplCommon::store(node1, c.getAStoreContent(), node2, _, _) and
isRelevantContent(c) and
isRelevantContent0(c) and
(
state1 instanceof TaintRead and state2.(TaintStore).getStep() = 1
or
@@ -180,7 +209,7 @@ module PropagateFlowConfig implements DataFlow::StateConfigSig {
or
exists(DataFlow::ContentSet c |
DataFlowPrivate::readStep(node1, c, node2) and
isRelevantContent(c) and
isRelevantContent0(c) and
state1.(TaintRead).getStep() + 1 = state2.(TaintRead).getStep()
)
}
@@ -196,6 +225,9 @@ module PropagateFlowConfig implements DataFlow::StateConfigSig {
module PropagateFlow = TaintTracking::GlobalWithState<PropagateFlowConfig>;
/**
* Gets the summary model(s) of `api`, if there is flow from parameters to return value or parameter.
*/
string captureThroughFlow0(
DataFlowSummaryTargetApi api, DataFlow::ParameterNode p, ReturnNodeExt returnNodeExt
) {
@@ -203,7 +235,7 @@ string captureThroughFlow0(
p.getEnclosingCallable() = api and
returnNodeExt.(DataFlow::Node).getEnclosingCallable() = api and
input = parameterNodeAsInput(p) and
output = returnNodeExt.getOutput() and
output = getOutput(returnNodeExt) and
input != output and
result = Printing::asTaintModel(api, input, output)
)
@@ -219,6 +251,69 @@ string captureThroughFlow(DataFlowSummaryTargetApi api) {
)
}
private module PropagateContentFlowConfig implements ContentDataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source instanceof DataFlow::ParameterNode and
source.getEnclosingCallable() instanceof DataFlowSummaryTargetApi
}
predicate isSink(DataFlow::Node sink) {
sink instanceof ReturnNodeExt and
sink.getEnclosingCallable() instanceof DataFlowSummaryTargetApi
}
predicate isAdditionalFlowStep = isAdditionalContentFlowStep/2;
predicate isBarrier(DataFlow::Node n) {
exists(Type t | t = n.getType() and not isRelevantType(t))
}
int accessPathLimit() { result = 2 }
predicate isRelevantContent(DataFlow::ContentSet s) { isRelevantContent0(s) }
DataFlow::FlowFeature getAFeature() {
result instanceof DataFlow::FeatureEqualSourceSinkCallContext
}
}
private module PropagateContentFlow = ContentDataFlow::Global<PropagateContentFlowConfig>;
private string getContent(PropagateContentFlow::AccessPath ap, int i) {
exists(ContentSet head, PropagateContentFlow::AccessPath tail |
head = ap.getHead() and
tail = ap.getTail()
|
i = 0 and
result = "." + printContent(head)
or
i > 0 and result = getContent(tail, i - 1)
)
}
private string printStoreAccessPath(PropagateContentFlow::AccessPath ap) {
result = concat(int i | | getContent(ap, i), "" order by i)
}
private string printReadAccessPath(PropagateContentFlow::AccessPath ap) {
result = concat(int i | | getContent(ap, i), "" order by i desc)
}
string captureContentFlow(DataFlowSummaryTargetApi api) {
exists(
DataFlow::ParameterNode p, ReturnNodeExt returnNodeExt, string input, string output,
PropagateContentFlow::AccessPath reads, PropagateContentFlow::AccessPath stores,
boolean preservesValue
|
PropagateContentFlow::flow(p, reads, returnNodeExt, stores, preservesValue) and
returnNodeExt.getEnclosingCallable() = api and
input = parameterNodeAsContentInput(p) + printReadAccessPath(reads) and
output = getContentOutput(returnNodeExt) + printStoreAccessPath(stores) and
input != output and
result = Printing::asModel(api, input, output, preservesValue)
)
}
/**
* A dataflow configuration used for finding new sources.
* The sources are the already known existing sources and the sinks are the API return nodes.
@@ -261,7 +356,7 @@ string captureSource(DataFlowSourceTargetApi api) {
ExternalFlow::sourceNode(source, kind) and
api = sink.getEnclosingCallable() and
not irrelevantSourceSinkApi(source.getEnclosingCallable(), api) and
result = Printing::asSourceModel(api, sink.getOutput(), kind)
result = Printing::asSourceModel(api, getOutput(sink), kind)
)
}

View File

@@ -4,10 +4,12 @@
private import java as J
private import semmle.code.java.dataflow.internal.DataFlowPrivate
private import semmle.code.java.dataflow.internal.DataFlowUtil as DataFlowUtil
private import semmle.code.java.dataflow.internal.ContainerFlow as ContainerFlow
private import semmle.code.java.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
private import semmle.code.java.dataflow.internal.ModelExclusions
private import semmle.code.java.dataflow.DataFlow as Df
private import semmle.code.java.dataflow.internal.ContentDataFlow as Cdf
private import semmle.code.java.dataflow.SSA as Ssa
private import semmle.code.java.dataflow.TaintTracking as Tt
import semmle.code.java.dataflow.ExternalFlow as ExternalFlow
@@ -17,6 +19,8 @@ import semmle.code.java.dataflow.internal.DataFlowDispatch as DataFlowDispatch
module DataFlow = Df::DataFlow;
module ContentDataFlow = Cdf::ContentDataFlow;
module TaintTracking = Tt::TaintTracking;
class Type = J::Type;
@@ -25,6 +29,8 @@ class Unit = J::Unit;
class Callable = J::Callable;
class ContentSet = DataFlowUtil::ContentSet;
private predicate isInfrequentlyUsed(J::CompilationUnit cu) {
cu.getPackage().getName().matches("javax.swing%") or
cu.getPackage().getName().matches("java.awt%")
@@ -217,6 +223,12 @@ string parameterAccess(J::Parameter p) {
else result = "Argument[" + p.getPosition() + "]"
}
/**
* Gets the MaD string representation of the parameter `p`
* when used in content flow.
*/
string parameterContentAccess(J::Parameter p) { result = "Argument[" + p.getPosition() + "]" }
class InstanceParameterNode = DataFlow::InstanceParameterNode;
class ParameterPosition = DataFlowDispatch::ParameterPosition;
@@ -232,6 +244,17 @@ string paramReturnNodeAsOutput(Callable c, ParameterPosition pos) {
result = qualifierString() and pos = -1
}
/**
* Gets the MaD string representation of return through parameter at position
* `pos` of callable `c` for content flow.
*/
bindingset[c]
string paramReturnNodeAsContentOutput(Callable c, ParameterPosition pos) {
result = parameterContentAccess(c.getParameter(pos))
or
result = qualifierString() and pos = -1
}
/**
* Gets the enclosing callable of `ret`.
*/
@@ -305,3 +328,34 @@ bindingset[kind]
predicate isRelevantSourceKind(string kind) { any() }
predicate containerContent = DataFlowPrivate::containerContent/1;
/**
* Holds if there is a taint step from `node1` to `node2` in content flow.
*/
predicate isAdditionalContentFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
TaintTracking::defaultAdditionalTaintStep(node1, node2, _) and
not exists(DataFlow::Content f |
DataFlowPrivate::readStep(node1, f, node2) and containerContent(f)
)
}
/**
* Gets the MaD string representation of the contentset `c`.
*/
string printContent(ContentSet c) {
exists(Field f, string name |
f = c.(DataFlowUtil::FieldContent).getField() and name = f.getQualifiedName()
|
if f.isPublic() then result = "Field[" + name + "]" else result = "SyntheticField[" + name + "]"
)
or
result = "SyntheticField[" + c.(DataFlowUtil::SyntheticFieldContent).getField() + "]"
or
c instanceof DataFlowUtil::CollectionContent and result = "Element"
or
c instanceof DataFlowUtil::ArrayContent and result = "ArrayElement"
or
c instanceof DataFlowUtil::MapValueContent and result = "MapValue"
or
c instanceof DataFlowUtil::MapKeyContent and result = "MapKey"
}

View File

@@ -0,0 +1,2 @@
unexpectedModel
expectedModel

View File

@@ -0,0 +1,11 @@
import java
import utils.modelgenerator.internal.CaptureModels
import TestUtilities.InlineMadTest
module InlineMadTestConfig implements InlineMadTestConfigSig {
string getCapturedModel(Callable c) { result = captureContentFlow(c) }
string getKind() { result = "contentbased-summary" }
}
import InlineMadTest<InlineMadTestConfig>

View File

@@ -2,16 +2,18 @@ package p;
public final class Factory {
private String value;
public String value;
private int intValue;
// summary=p;Factory;false;create;(String,int);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=p;Factory;false;create;(String,int);;Argument[0];ReturnValue.Field[p.Factory.value];value;df-generated
public static Factory create(String value, int foo) {
return new Factory(value, foo);
}
// summary=p;Factory;false;create;(String);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=p;Factory;false;create;(String);;Argument[0];ReturnValue.Field[p.Factory.value];value;df-generated
public static Factory create(String value) {
return new Factory(value, 0);
}
@@ -22,6 +24,7 @@ public final class Factory {
}
// summary=p;Factory;false;getValue;();;Argument[this];ReturnValue;taint;df-generated
// contentbased-summary=p;Factory;false;getValue;();;Argument[this].Field[p.Factory.value];ReturnValue;value;df-generated
public String getValue() {
return value;
}

View File

@@ -5,6 +5,7 @@ public final class FinalClass {
private static final String C = "constant";
// summary=p;FinalClass;false;returnsInput;(String);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=p;FinalClass;false;returnsInput;(String);;Argument[0];ReturnValue;value;df-generated
public String returnsInput(String input) {
return input;
}

View File

@@ -3,6 +3,7 @@ package p;
public final class FluentAPI {
// summary=p;FluentAPI;false;returnsThis;(String);;Argument[this];ReturnValue;value;df-generated
// contentbased-summary=p;FluentAPI;false;returnsThis;(String);;Argument[this];ReturnValue;value;df-generated
public FluentAPI returnsThis(String input) {
return this;
}

View File

@@ -7,12 +7,14 @@ public final class ImmutablePojo {
private final long x;
// summary=p;ImmutablePojo;false;ImmutablePojo;(String,int);;Argument[0];Argument[this];taint;df-generated
// contentbased-summary=p;ImmutablePojo;false;ImmutablePojo;(String,int);;Argument[0];Argument[this].SyntheticField[p.ImmutablePojo.value];value;df-generated
public ImmutablePojo(String value, int x) {
this.value = value;
this.x = x;
}
// summary=p;ImmutablePojo;false;getValue;();;Argument[this];ReturnValue;taint;df-generated
// contentbased-summary=p;ImmutablePojo;false;getValue;();;Argument[this].SyntheticField[p.ImmutablePojo.value];ReturnValue;value;df-generated
public String getValue() {
return value;
}
@@ -24,6 +26,8 @@ public final class ImmutablePojo {
// summary=p;ImmutablePojo;false;or;(String);;Argument[0];ReturnValue;taint;df-generated
// summary=p;ImmutablePojo;false;or;(String);;Argument[this];ReturnValue;taint;df-generated
// contentbased-summary=p;ImmutablePojo;false;or;(String);;Argument[0];ReturnValue;value;df-generated
// contentbased-summary=p;ImmutablePojo;false;or;(String);;Argument[this].SyntheticField[p.ImmutablePojo.value];ReturnValue;value;df-generated
public String or(String defaultValue) {
return value != null ? value : defaultValue;
}

View File

@@ -11,6 +11,7 @@ public class Inheritance {
public class AImplBasePrivateImpl extends BasePrivate {
// summary=p;Inheritance$AImplBasePrivateImpl;true;id;(String);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=p;Inheritance$AImplBasePrivateImpl;true;id;(String);;Argument[0];ReturnValue;value;df-generated
@Override
public String id(String s) {
return s;
@@ -19,6 +20,7 @@ public class Inheritance {
public class AImplBasePublic extends BasePublic {
// summary=p;Inheritance$BasePublic;true;id;(String);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=p;Inheritance$BasePublic;true;id;(String);;Argument[0];ReturnValue;value;df-generated
@Override
public String id(String s) {
return s;
@@ -59,6 +61,7 @@ public class Inheritance {
public class BImpl extends B {
// summary=p;Inheritance$IPublic1;true;id;(String);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=p;Inheritance$IPublic1;true;id;(String);;Argument[0];ReturnValue;value;df-generated
@Override
public String id(String s) {
return s;
@@ -67,6 +70,7 @@ public class Inheritance {
public class CImpl extends C {
// summary=p;Inheritance$C;true;id;(String);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=p;Inheritance$C;true;id;(String);;Argument[0];ReturnValue;value;df-generated
@Override
public String id(String s) {
return s;
@@ -75,6 +79,7 @@ public class Inheritance {
public class DImpl extends D {
// summary=p;Inheritance$IPublic2;true;id;(String);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=p;Inheritance$IPublic2;true;id;(String);;Argument[0];ReturnValue;value;df-generated
@Override
public String id(String s) {
return s;
@@ -83,6 +88,7 @@ public class Inheritance {
public class EImpl extends E {
// summary=p;Inheritance$EImpl;true;id;(String);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=p;Inheritance$EImpl;true;id;(String);;Argument[0];ReturnValue;value;df-generated
@Override
public String id(String s) {
return s;

View File

@@ -10,12 +10,14 @@ public class InnerClasses {
public class CaptureMe {
// summary=p;InnerClasses$CaptureMe;true;yesCm;(String);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=p;InnerClasses$CaptureMe;true;yesCm;(String);;Argument[0];ReturnValue;value;df-generated
public String yesCm(String input) {
return input;
}
}
// summary=p;InnerClasses;true;yes;(String);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=p;InnerClasses;true;yes;(String);;Argument[0];ReturnValue;value;df-generated
public String yes(String input) {
return input;
}

View File

@@ -19,21 +19,25 @@ public final class InnerHolder {
private StringBuilder sb = new StringBuilder();
// summary=p;InnerHolder;false;setContext;(String);;Argument[0];Argument[this];taint;df-generated
// contentbased-summary=p;InnerHolder;false;setContext;(String);;Argument[0];Argument[this].SyntheticField[p.InnerHolder.context].SyntheticField[p.InnerHolder$Context.value];value;df-generated
public void setContext(String value) {
context = new Context(value);
}
// summary=p;InnerHolder;false;explicitSetContext;(String);;Argument[0];Argument[this];taint;df-generated
// contentbased-summary=p;InnerHolder;false;explicitSetContext;(String);;Argument[0];Argument[this].SyntheticField[p.InnerHolder.context].SyntheticField[p.InnerHolder$Context.value];value;df-generated
public void explicitSetContext(String value) {
this.context = new Context(value);
}
// summary=p;InnerHolder;false;append;(String);;Argument[0];Argument[this];taint;df-generated
// contentbased-summary=p;InnerHolder;false;append;(String);;Argument[0];Argument[this].SyntheticField[p.InnerHolder.sb];taint;df-generated
public void append(String value) {
sb.append(value);
}
// summary=p;InnerHolder;false;getValue;();;Argument[this];ReturnValue;taint;df-generated
// contentbased-summary=p;InnerHolder;false;getValue;();;Argument[this].SyntheticField[p.InnerHolder.context].SyntheticField[p.InnerHolder$Context.value];ReturnValue;value;df-generated
public String getValue() {
return context.getValue();
}

View File

@@ -13,6 +13,7 @@ public final class Joiner {
private String emptyValue;
// summary=p;Joiner;false;Joiner;(CharSequence);;Argument[0];Argument[this];taint;df-generated
// contentbased-summary=p;Joiner;false;Joiner;(CharSequence);;Argument[0];Argument[this].SyntheticField[p.Joiner.delimiter];taint;df-generated
public Joiner(CharSequence delimiter) {
this(delimiter, "", "");
}
@@ -20,6 +21,9 @@ public final class Joiner {
// summary=p;Joiner;false;Joiner;(CharSequence,CharSequence,CharSequence);;Argument[0];Argument[this];taint;df-generated
// summary=p;Joiner;false;Joiner;(CharSequence,CharSequence,CharSequence);;Argument[1];Argument[this];taint;df-generated
// summary=p;Joiner;false;Joiner;(CharSequence,CharSequence,CharSequence);;Argument[2];Argument[this];taint;df-generated
// contentbased-summary=p;Joiner;false;Joiner;(CharSequence,CharSequence,CharSequence);;Argument[0];Argument[this].SyntheticField[p.Joiner.delimiter];taint;df-generated
// contentbased-summary=p;Joiner;false;Joiner;(CharSequence,CharSequence,CharSequence);;Argument[1];Argument[this].SyntheticField[p.Joiner.prefix];taint;df-generated
// contentbased-summary=p;Joiner;false;Joiner;(CharSequence,CharSequence,CharSequence);;Argument[2];Argument[this].SyntheticField[p.Joiner.suffix];taint;df-generated
public Joiner(CharSequence delimiter, CharSequence prefix, CharSequence suffix) {
Objects.requireNonNull(prefix, "The prefix must not be null");
Objects.requireNonNull(delimiter, "The delimiter must not be null");
@@ -32,6 +36,9 @@ public final class Joiner {
// summary=p;Joiner;false;setEmptyValue;(CharSequence);;Argument[0];Argument[this];taint;df-generated
// summary=p;Joiner;false;setEmptyValue;(CharSequence);;Argument[this];ReturnValue;value;df-generated
// contentbased-summary=p;Joiner;false;setEmptyValue;(CharSequence);;Argument[0];Argument[this].SyntheticField[p.Joiner.emptyValue];taint;df-generated
// contentbased-summary=p;Joiner;false;setEmptyValue;(CharSequence);;Argument[0];ReturnValue.SyntheticField[p.Joiner.emptyValue];taint;df-generated
// contentbased-summary=p;Joiner;false;setEmptyValue;(CharSequence);;Argument[this];ReturnValue;value;df-generated
public Joiner setEmptyValue(CharSequence emptyValue) {
this.emptyValue =
Objects.requireNonNull(emptyValue, "The empty value must not be null").toString();
@@ -71,6 +78,8 @@ public final class Joiner {
}
// summary=p;Joiner;false;add;(CharSequence);;Argument[this];ReturnValue;value;df-generated
// contentbased-summary=p;Joiner;false;add;(CharSequence);;Argument[this].SyntheticField[p.Joiner.elts].ArrayElement;ReturnValue.SyntheticField[p.Joiner.elts].ArrayElement;value;df-generated
// contentbased-summary=p;Joiner;false;add;(CharSequence);;Argument[this];ReturnValue;value;df-generated
public Joiner add(CharSequence newElement) {
final String elt = String.valueOf(newElement);
if (elts == null) {
@@ -94,6 +103,8 @@ public final class Joiner {
}
// summary=p;Joiner;false;merge;(Joiner);;Argument[this];ReturnValue;value;df-generated
// contentbased-summary=p;Joiner;false;merge;(Joiner);;Argument[this].SyntheticField[p.Joiner.elts].ArrayElement;ReturnValue.SyntheticField[p.Joiner.elts].ArrayElement;value;df-generated
// contentbased-summary=p;Joiner;false;merge;(Joiner);;Argument[this];ReturnValue;value;df-generated
public Joiner merge(Joiner other) {
Objects.requireNonNull(other);
if (other.elts == null) {

View File

@@ -17,6 +17,7 @@ class MultipleImpl2 {
public class Impl2 implements IInterface {
// summary=p;MultipleImpl2$IInterface;true;m;(Object);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=p;MultipleImpl2$IInterface;true;m;(Object);;Argument[0];ReturnValue;value;df-generated
public Object m(Object value) {
return value;
}

View File

@@ -10,6 +10,7 @@ public class MultipleImpls {
public static class Strat1 implements Strategy {
// summary=p;MultipleImpls$Strategy;true;doSomething;(String);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=p;MultipleImpls$Strategy;true;doSomething;(String);;Argument[0];ReturnValue;value;df-generated
public String doSomething(String value) {
return value;
}
@@ -29,12 +30,18 @@ public class MultipleImpls {
private String foo;
// summary=p;MultipleImpls$Strategy;true;doSomething;(String);;Argument[0];Argument[this];taint;df-generated
// A field based model should not be lifted if the field pertains to the concrete
// implementation.
// SPURIOUS-contentbased-summary=p;MultipleImpls$Strategy;true;doSomething;(String);;Argument[0];Argument[this].SyntheticField[p.MultipleImpls$Strat2.foo];value;df-generated
public String doSomething(String value) {
this.foo = value;
return "none";
}
// summary=p;MultipleImpls$Strat2;true;getValue;();;Argument[this];ReturnValue;taint;df-generated
// A field based model should not be lifted if the field pertains to the concrete
// implementation.
// SPURIOUS-contentbased-summary=p;MultipleImpls$Strat2;true;getValue;();;Argument[this].SyntheticField[p.MultipleImpls$Strat2.foo];ReturnValue;value;df-generated
public String getValue() {
return this.foo;
}

View File

@@ -8,6 +8,7 @@ import java.util.List;
public class ParamFlow {
// summary=p;ParamFlow;true;returnsInput;(String);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=p;ParamFlow;true;returnsInput;(String);;Argument[0];ReturnValue;value;df-generated
public String returnsInput(String input) {
return input;
}
@@ -19,6 +20,8 @@ public class ParamFlow {
// summary=p;ParamFlow;true;returnMultipleParameters;(String,String);;Argument[0];ReturnValue;taint;df-generated
// summary=p;ParamFlow;true;returnMultipleParameters;(String,String);;Argument[1];ReturnValue;taint;df-generated
// contentbased-summary=p;ParamFlow;true;returnMultipleParameters;(String,String);;Argument[0];ReturnValue;value;df-generated
// contentbased-summary=p;ParamFlow;true;returnMultipleParameters;(String,String);;Argument[1];ReturnValue;value;df-generated
public String returnMultipleParameters(String one, String two) {
if (System.currentTimeMillis() > 100) {
return two;
@@ -27,26 +30,31 @@ public class ParamFlow {
}
// summary=p;ParamFlow;true;returnArrayElement;(String[]);;Argument[0].ArrayElement;ReturnValue;taint;df-generated
// contentbased-summary=p;ParamFlow;true;returnArrayElement;(String[]);;Argument[0].ArrayElement;ReturnValue;value;df-generated
public String returnArrayElement(String[] input) {
return input[0];
}
// summary=p;ParamFlow;true;returnVarArgElement;(String[]);;Argument[0].ArrayElement;ReturnValue;taint;df-generated
// contentbased-summary=p;ParamFlow;true;returnVarArgElement;(String[]);;Argument[0].ArrayElement;ReturnValue;value;df-generated
public String returnVarArgElement(String... input) {
return input[0];
}
// summary=p;ParamFlow;true;returnCollectionElement;(List);;Argument[0].Element;ReturnValue;taint;df-generated
// contentbased-summary=p;ParamFlow;true;returnCollectionElement;(List);;Argument[0].Element;ReturnValue;value;df-generated
public String returnCollectionElement(List<String> input) {
return input.get(0);
}
// summary=p;ParamFlow;true;returnIteratorElement;(Iterator);;Argument[0].Element;ReturnValue;taint;df-generated
// contentbased-summary=p;ParamFlow;true;returnIteratorElement;(Iterator);;Argument[0].Element;ReturnValue;value;df-generated
public String returnIteratorElement(Iterator<String> input) {
return input.next();
}
// summary=p;ParamFlow;true;returnIterableElement;(Iterable);;Argument[0].Element;ReturnValue;taint;df-generated
// contentbased-summary=p;ParamFlow;true;returnIterableElement;(Iterable);;Argument[0].Element;ReturnValue;value;df-generated
public String returnIterableElement(Iterable<String> input) {
return input.iterator().next();
}
@@ -57,16 +65,19 @@ public class ParamFlow {
}
// summary=p;ParamFlow;true;writeChunked;(byte[],OutputStream);;Argument[0];Argument[1];taint;df-generated
// contentbased-summary=p;ParamFlow;true;writeChunked;(byte[],OutputStream);;Argument[0];Argument[1];taint;df-generated
public void writeChunked(byte[] data, OutputStream output) throws IOException {
output.write(data, 0, data.length);
}
// summary=p;ParamFlow;true;writeChunked;(char[],OutputStream);;Argument[0];Argument[1];taint;df-generated
// contentbased-summary=p;ParamFlow;true;writeChunked;(char[],OutputStream);;Argument[0];Argument[1];taint;df-generated
public void writeChunked(char[] data, OutputStream output) throws IOException {
output.write(String.valueOf(data).getBytes(), 0, data.length);
}
// summary=p;ParamFlow;true;addTo;(String,List);;Argument[0];Argument[1].Element;taint;df-generated
// contentbased-summary=p;ParamFlow;true;addTo;(String,List);;Argument[0];Argument[1].Element;value;df-generated
public void addTo(String data, List<String> target) {
target.add(data);
}

View File

@@ -24,18 +24,20 @@ public final class Pojo {
private int intValue = 2;
private byte[] byteArray = new byte[] {1, 2, 3};
public byte[] byteArray = new byte[] {1, 2, 3};
private float[] floatArray = new float[] {1, 2, 3};
private char[] charArray = new char[] {'a', 'b', 'c'};
private List<Character> charList = Arrays.asList('a', 'b', 'c');
private Byte[] byteObjectArray = new Byte[] {1, 2, 3};
// summary=p;Pojo;false;getValue;();;Argument[this];ReturnValue;taint;df-generated
// contentbased-summary=p;Pojo;false;getValue;();;Argument[this].SyntheticField[p.Pojo.value];ReturnValue;value;df-generated
public String getValue() {
return value;
}
// summary=p;Pojo;false;setValue;(String);;Argument[0];Argument[this];taint;df-generated
// contentbased-summary=p;Pojo;false;setValue;(String);;Argument[0];Argument[this].SyntheticField[p.Pojo.value];value;df-generated
public void setValue(String value) {
this.value = value;
}
@@ -62,11 +64,13 @@ public final class Pojo {
}
// summary=p;Pojo;false;getCharArray;();;Argument[this];ReturnValue;taint;df-generated
// contentbased-summary=p;Pojo;false;getCharArray;();;Argument[this].SyntheticField[p.Pojo.charArray];ReturnValue;value;df-generated
public char[] getCharArray() {
return charArray;
}
// summary=p;Pojo;false;getByteArray;();;Argument[this];ReturnValue;taint;df-generated
// contentbased-summary=p;Pojo;false;getByteArray;();;Argument[this].Field[p.Pojo.byteArray];ReturnValue;value;df-generated
public byte[] getByteArray() {
return byteArray;
}
@@ -87,11 +91,13 @@ public final class Pojo {
}
// summary=p;Pojo;false;getBoxedChars;();;Argument[this];ReturnValue;taint;df-generated
// contentbased-summary=p;Pojo;false;getBoxedChars;();;Argument[this].SyntheticField[p.Pojo.charList];ReturnValue;value;df-generated
public List<Character> getBoxedChars() {
return charList;
}
// summary=p;Pojo;false;getBoxedBytes;();;Argument[this];ReturnValue;taint;df-generated
// contentbased-summary=p;Pojo;false;getBoxedBytes;();;Argument[this].SyntheticField[p.Pojo.byteObjectArray];ReturnValue;value;df-generated
public Byte[] getBoxedBytes() {
return byteObjectArray;
}
@@ -107,6 +113,7 @@ public final class Pojo {
}
// summary=p;Pojo;false;fillIn;(List);;Argument[this];Argument[0].Element;taint;df-generated
// contentbased-summary=p;Pojo;false;fillIn;(List);;Argument[this].SyntheticField[p.Pojo.value];Argument[0].Element;value;df-generated
public void fillIn(List<String> target) {
target.add(value);
}

View File

@@ -29,6 +29,9 @@ public class PrivateFlowViaPublicInterface {
}
// summary=p;PrivateFlowViaPublicInterface$SPI;true;openStream;();;Argument[this];ReturnValue;taint;df-generated
// A field based model should not be lifted if the field pertains to the concrete
// implementation.
// SPURIOUS-contentbased-summary=p;PrivateFlowViaPublicInterface$SPI;true;openStream;();;Argument[this].SyntheticField[p.PrivateFlowViaPublicInterface$PrivateImplWithSink.file];ReturnValue;taint;df-generated
@Override
public OutputStream openStream() throws IOException {
return new FileOutputStream(file);
@@ -51,6 +54,9 @@ public class PrivateFlowViaPublicInterface {
}
// summary=p;PrivateFlowViaPublicInterface;true;createAnSPI;(File);;Argument[0];ReturnValue;taint;df-generated
// A field based model should not be lifted if the field pertains to the concrete
// implementation.
// SPURIOUS-contentbased-summary=p;PrivateFlowViaPublicInterface;true;createAnSPI;(File);;Argument[0];ReturnValue.SyntheticField[p.PrivateFlowViaPublicInterface$PrivateImplWithSink.file];value;df-generated
public static SPI createAnSPI(File file) {
return new PrivateImplWithSink(file);
}

View File

@@ -33,6 +33,7 @@ class Generator:
self.generateSources = False
self.generateSummaries = False
self.generateNeutrals = False
self.generateContentSummaries = False
self.generateTypeBasedSummaries = False
self.dryRun = False
self.dirname = "modelgenerator"
@@ -50,6 +51,7 @@ Which models are generated is controlled by the flags:
--with-sources
--with-summaries
--with-neutrals
--with-content-summaries (Experimental). May not be used in conjunction with --with-summaries
--with-typebased-summaries (Experimental)
If none of these flags are specified, all models are generated except for the type based models.
@@ -81,6 +83,10 @@ Requirements: `codeql` should both appear on your path.
generator.printHelp()
sys.exit(0)
if "--with-summaries" in sys.argv and "--with-content-summaries" in sys.argv:
generator.printHelp()
sys.exit(0)
if "--with-sinks" in sys.argv:
sys.argv.remove("--with-sinks")
generator.generateSinks = True
@@ -97,6 +103,10 @@ Requirements: `codeql` should both appear on your path.
sys.argv.remove("--with-neutrals")
generator.generateNeutrals = True
if "--with-content-summaries" in sys.argv:
sys.argv.remove("--with-content-summaries")
generator.generateContentSummaries = True
if "--with-typebased-summaries" in sys.argv:
sys.argv.remove("--with-typebased-summaries")
generator.generateTypeBasedSummaries = True
@@ -105,7 +115,7 @@ Requirements: `codeql` should both appear on your path.
sys.argv.remove("--dry-run")
generator.dryRun = True
if not generator.generateSinks and not generator.generateSources and not generator.generateSummaries and not generator.generateNeutrals and not generator.generateTypeBasedSummaries:
if not generator.generateSinks and not generator.generateSources and not generator.generateSummaries and not generator.generateNeutrals and not generator.generateTypeBasedSummaries and not generator.generateContentSummaries:
generator.generateSinks = generator.generateSources = generator.generateSummaries = generator.generateNeutrals = True
n = len(sys.argv)
@@ -162,8 +172,13 @@ Requirements: `codeql` should both appear on your path.
neutralAddsTo = self.getAddsTo("CaptureNeutralModels.ql", helpers.neutralModelPredicate)
else:
neutralAddsTo = { }
return helpers.merge(summaryAddsTo, sinkAddsTo, sourceAddsTo, neutralAddsTo)
if self.generateContentSummaries:
contentSummaryAddsTo = self.getAddsTo("CaptureContentSummaryModels.ql", helpers.summaryModelPredicate)
else:
contentSummaryAddsTo = { }
return helpers.merge(summaryAddsTo, contentSummaryAddsTo, sinkAddsTo, sourceAddsTo, neutralAddsTo)
def makeTypeBasedContent(self):
if self.generateTypeBasedSummaries:

View File

@@ -97,6 +97,18 @@ module ModelPrintingImpl<ModelPrintingLangSig Lang> {
result = asSummaryModel(api, input, output, "taint")
}
/**
* Gets the summary model for `api` with `input` and `output`.
*/
bindingset[input, output, preservesValue]
string asModel(Printing::SummaryApi api, string input, string output, boolean preservesValue) {
preservesValue = true and
result = asValueModel(api, input, output)
or
preservesValue = false and
result = asTaintModel(api, input, output)
}
/**
* Gets the sink model for `api` with `input` and `kind`.
*/