diff --git a/cpp/ql/src/utils/modelgenerator/CaptureContentSummaryModels.ql b/cpp/ql/src/utils/modelgenerator/CaptureContentSummaryModels.ql index be0cf4434311..a15a584e13d0 100644 --- a/cpp/ql/src/utils/modelgenerator/CaptureContentSummaryModels.ql +++ b/cpp/ql/src/utils/modelgenerator/CaptureContentSummaryModels.ql @@ -10,5 +10,5 @@ import internal.CaptureModels import SummaryModels from DataFlowSummaryTargetApi api, string flow -where flow = ContentSensitive::captureFlow(api, _) +where flow = ContentSensitive::captureFlow(api, _, _, _, _) select flow order by flow diff --git a/cpp/ql/src/utils/modelgenerator/internal/CaptureModels.qll b/cpp/ql/src/utils/modelgenerator/internal/CaptureModels.qll index 93abe205f1a6..b86b2400fccc 100644 --- a/cpp/ql/src/utils/modelgenerator/internal/CaptureModels.qll +++ b/cpp/ql/src/utils/modelgenerator/internal/CaptureModels.qll @@ -189,15 +189,15 @@ module ModelGeneratorCommonInput implements ModelGeneratorCommonInputSig;true;template_returnThis;(T);;Argument[-1];ReturnValue[*];taint;df-generated + //heuristic-summary=Models;TemplatedFlow;true;template_returnThis;(T);;Argument[-1];ReturnValue[*];value;df-generated //contentbased-summary=Models;TemplatedFlow;true;template_returnThis;(T);;Argument[-1];ReturnValue[*];value;dfc-generated TemplatedFlow* template_returnThis(T input) { return this; } - //heuristic-summary=Models;TemplatedFlow;true;template_returnParam0;(T *,T *);;Argument[0];ReturnValue;taint;df-generated - //heuristic-summary=Models;TemplatedFlow;true;template_returnParam0;(T *,T *);;Argument[*0];ReturnValue[*];taint;df-generated + //heuristic-summary=Models;TemplatedFlow;true;template_returnParam0;(T *,T *);;Argument[0];ReturnValue;value;df-generated + //heuristic-summary=Models;TemplatedFlow;true;template_returnParam0;(T *,T *);;Argument[*0];ReturnValue[*];value;df-generated //contentbased-summary=Models;TemplatedFlow;true;template_returnParam0;(T *,T *);;Argument[0];ReturnValue;value;dfc-generated //contentbased-summary=Models;TemplatedFlow;true;template_returnParam0;(T *,T *);;Argument[*0];ReturnValue[*];value;dfc-generated T* template_returnParam0(T* input0, T* input1) { @@ -105,8 +105,8 @@ namespace Models { return tainted; } - //heuristic-summary=Models;TemplatedFlow;true;templated_function;(U *,T *);;Argument[0];ReturnValue;taint;df-generated - //heuristic-summary=Models;TemplatedFlow;true;templated_function;(U *,T *);;Argument[*0];ReturnValue[*];taint;df-generated + //heuristic-summary=Models;TemplatedFlow;true;templated_function;(U *,T *);;Argument[0];ReturnValue;value;df-generated + //heuristic-summary=Models;TemplatedFlow;true;templated_function;(U *,T *);;Argument[*0];ReturnValue[*];value;df-generated //contentbased-summary=Models;TemplatedFlow;true;templated_function;(U *,T *);;Argument[0];ReturnValue;value;dfc-generated //contentbased-summary=Models;TemplatedFlow;true;templated_function;(U *,T *);;Argument[*0];ReturnValue[*];value;dfc-generated template @@ -130,7 +130,7 @@ namespace Models { } //heuristic-summary=;;true;toplevel_function;(int *);;Argument[0];ReturnValue;taint;df-generated -//heuristic-summary=;;true;toplevel_function;(int *);;Argument[*0];ReturnValue;taint;df-generated +//heuristic-summary=;;true;toplevel_function;(int *);;Argument[*0];ReturnValue;value;df-generated //heuristic-summary=;;true;toplevel_function;(int *);;Argument[0];Argument[*0];taint;df-generated //contentbased-summary=;;true;toplevel_function;(int *);;Argument[0];Argument[*0];taint;dfc-generated //contentbased-summary=;;true;toplevel_function;(int *);;Argument[0];ReturnValue;taint;dfc-generated @@ -145,13 +145,13 @@ static int static_toplevel_function(int* p) { } struct NonFinalStruct { - //heuristic-summary=;NonFinalStruct;true;public_not_final_member_function;(int);;Argument[0];ReturnValue;taint;df-generated + //heuristic-summary=;NonFinalStruct;true;public_not_final_member_function;(int);;Argument[0];ReturnValue;value;df-generated //contentbased-summary=;NonFinalStruct;true;public_not_final_member_function;(int);;Argument[0];ReturnValue;value;dfc-generated virtual int public_not_final_member_function(int x) { return x; } - //heuristic-summary=;NonFinalStruct;false;public_final_member_function;(int);;Argument[0];ReturnValue;taint;df-generated + //heuristic-summary=;NonFinalStruct;false;public_final_member_function;(int);;Argument[0];ReturnValue;value;df-generated //contentbased-summary=;NonFinalStruct;false;public_final_member_function;(int);;Argument[0];ReturnValue;value;dfc-generated virtual int public_final_member_function(int x) final { return x; @@ -171,13 +171,13 @@ struct NonFinalStruct { }; struct FinalStruct final { - //heuristic-summary=;FinalStruct;false;public_not_final_member_function_2;(int);;Argument[0];ReturnValue;taint;df-generated + //heuristic-summary=;FinalStruct;false;public_not_final_member_function_2;(int);;Argument[0];ReturnValue;value;df-generated //contentbased-summary=;FinalStruct;false;public_not_final_member_function_2;(int);;Argument[0];ReturnValue;value;dfc-generated virtual int public_not_final_member_function_2(int x) { return x; } - //heuristic-summary=;FinalStruct;false;public_final_member_function_2;(int);;Argument[0];ReturnValue;taint;df-generated + //heuristic-summary=;FinalStruct;false;public_final_member_function_2;(int);;Argument[0];ReturnValue;value;df-generated //contentbased-summary=;FinalStruct;false;public_final_member_function_2;(int);;Argument[0];ReturnValue;value;dfc-generated virtual int public_final_member_function_2(int x) final { return x; @@ -211,7 +211,7 @@ struct HasInt { //contentbased-summary=;;true;copy_struct;(HasInt *,const HasInt *);;Argument[*1];Argument[*0];value;dfc-generated //heuristic-summary=;;true;copy_struct;(HasInt *,const HasInt *);;Argument[1];Argument[*0];taint;df-generated //heuristic-summary=;;true;copy_struct;(HasInt *,const HasInt *);;Argument[1];Argument[*1];taint;df-generated -//heuristic-summary=;;true;copy_struct;(HasInt *,const HasInt *);;Argument[*1];Argument[*0];taint;df-generated +//heuristic-summary=;;true;copy_struct;(HasInt *,const HasInt *);;Argument[*1];Argument[*0];value;df-generated int copy_struct(HasInt *out, const HasInt *in) { *out = *in; return 1; diff --git a/csharp/ql/src/utils/modelgenerator/CaptureContentSummaryModels.ql b/csharp/ql/src/utils/modelgenerator/CaptureContentSummaryModels.ql index 4d56c922a397..6030960a1a78 100644 --- a/csharp/ql/src/utils/modelgenerator/CaptureContentSummaryModels.ql +++ b/csharp/ql/src/utils/modelgenerator/CaptureContentSummaryModels.ql @@ -10,5 +10,5 @@ import internal.CaptureModels import SummaryModels from DataFlowSummaryTargetApi api, string flow -where flow = ContentSensitive::captureFlow(api, _) +where flow = ContentSensitive::captureFlow(api, _, _, _, _) select flow order by flow diff --git a/csharp/ql/src/utils/modelgenerator/debug/CaptureSummaryModelsPartialPath.ql b/csharp/ql/src/utils/modelgenerator/debug/CaptureSummaryModelsPartialPath.ql index 60d7b42a46df..bcf061eed45e 100644 --- a/csharp/ql/src/utils/modelgenerator/debug/CaptureSummaryModelsPartialPath.ql +++ b/csharp/ql/src/utils/modelgenerator/debug/CaptureSummaryModelsPartialPath.ql @@ -15,7 +15,7 @@ import PartialFlow::PartialPathGraph int explorationLimit() { result = 3 } -module PartialFlow = Heuristic::PropagateFlow::FlowExplorationFwd; +module PartialFlow = Heuristic::PropagateTaintFlow::FlowExplorationFwd; from PartialFlow::PartialPathNode source, PartialFlow::PartialPathNode sink, diff --git a/csharp/ql/src/utils/modelgenerator/debug/CaptureSummaryModelsPath.ql b/csharp/ql/src/utils/modelgenerator/debug/CaptureSummaryModelsPath.ql index a53958ad0e6d..096aea1790e6 100644 --- a/csharp/ql/src/utils/modelgenerator/debug/CaptureSummaryModelsPath.ql +++ b/csharp/ql/src/utils/modelgenerator/debug/CaptureSummaryModelsPath.ql @@ -11,16 +11,15 @@ import csharp import utils.modelgenerator.internal.CaptureModels import SummaryModels -import Heuristic -import PropagateFlow::PathGraph +import Heuristic::PropagateTaintFlow::PathGraph from - PropagateFlow::PathNode source, PropagateFlow::PathNode sink, DataFlowSummaryTargetApi api, - DataFlow::Node p, DataFlow::Node returnNodeExt + Heuristic::PropagateTaintFlow::PathNode source, Heuristic::PropagateTaintFlow::PathNode sink, + DataFlowSummaryTargetApi api, DataFlow::Node p, DataFlow::Node returnNodeExt where - PropagateFlow::flowPath(source, sink) and + Heuristic::PropagateTaintFlow::flowPath(source, sink) and p = source.getNode() and returnNodeExt = sink.getNode() and - exists(captureThroughFlow0(api, p, returnNodeExt)) + Heuristic::captureThroughFlow0(api, p, returnNodeExt) select sink.getNode(), source, sink, "There is flow from $@ to the $@.", source.getNode(), "parameter", sink.getNode(), "return value" diff --git a/csharp/ql/src/utils/modelgenerator/internal/CaptureModels.qll b/csharp/ql/src/utils/modelgenerator/internal/CaptureModels.qll index b0300e4a87f1..db3d72bd27bb 100644 --- a/csharp/ql/src/utils/modelgenerator/internal/CaptureModels.qll +++ b/csharp/ql/src/utils/modelgenerator/internal/CaptureModels.qll @@ -124,13 +124,13 @@ module ModelGeneratorCommonInput implements ModelGeneratorCommonInputSig::paramReturnNodeAsOutput(c, pos) + string paramReturnNodeAsApproximateOutput(CS::Callable c, ParameterPosition pos) { + result = ParamReturnNodeAsOutput::paramReturnNodeAsOutput(c, pos) } bindingset[c] - string paramReturnNodeAsContentOutput(Callable c, ParameterPosition pos) { - result = ParamReturnNodeAsOutput::paramReturnNodeAsOutput(c, pos) + string paramReturnNodeAsExactOutput(Callable c, ParameterPosition pos) { + result = ParamReturnNodeAsOutput::paramReturnNodeAsOutput(c, pos) } ParameterPosition getReturnKindParamPosition(ReturnKind kind) { diff --git a/csharp/ql/src/utils/modelgenerator/internal/CaptureTypeBasedSummaryModels.qll b/csharp/ql/src/utils/modelgenerator/internal/CaptureTypeBasedSummaryModels.qll index baba462c8a24..84cb0db45da8 100644 --- a/csharp/ql/src/utils/modelgenerator/internal/CaptureTypeBasedSummaryModels.qll +++ b/csharp/ql/src/utils/modelgenerator/internal/CaptureTypeBasedSummaryModels.qll @@ -39,7 +39,7 @@ private predicate localTypeParameter(Callable callable, TypeParameter tp) { */ private predicate parameter(Callable callable, string input, TypeParameter tp) { exists(Parameter p | - input = ModelGeneratorInput::parameterAccess(p) and + input = ModelGeneratorInput::parameterApproximateAccess(p) and p = callable.getAParameter() and ( // Parameter of type tp diff --git a/csharp/ql/test/utils/modelgenerator/dataflow/CaptureContentSummaryModels.ql b/csharp/ql/test/utils/modelgenerator/dataflow/CaptureContentSummaryModels.ql index 0c8134546d24..a52b96b02327 100644 --- a/csharp/ql/test/utils/modelgenerator/dataflow/CaptureContentSummaryModels.ql +++ b/csharp/ql/test/utils/modelgenerator/dataflow/CaptureContentSummaryModels.ql @@ -4,7 +4,7 @@ import SummaryModels import utils.test.InlineMadTest module InlineMadTestConfig implements InlineMadTestConfigSig { - string getCapturedModel(Callable c) { result = ContentSensitive::captureFlow(c, _) } + string getCapturedModel(Callable c) { result = ContentSensitive::captureFlow(c, _, _, _, _) } string getKind() { result = "contentbased-summary" } } diff --git a/csharp/ql/test/utils/modelgenerator/dataflow/CaptureHeuristicSummaryModels.ql b/csharp/ql/test/utils/modelgenerator/dataflow/CaptureHeuristicSummaryModels.ql index b5a3b31a0354..cf52ff8cf25b 100644 --- a/csharp/ql/test/utils/modelgenerator/dataflow/CaptureHeuristicSummaryModels.ql +++ b/csharp/ql/test/utils/modelgenerator/dataflow/CaptureHeuristicSummaryModels.ql @@ -4,7 +4,7 @@ import SummaryModels import utils.test.InlineMadTest module InlineMadTestConfig implements InlineMadTestConfigSig { - string getCapturedModel(Callable c) { result = Heuristic::captureFlow(c) } + string getCapturedModel(Callable c) { result = Heuristic::captureFlow(c, _) } string getKind() { result = "heuristic-summary" } } diff --git a/csharp/ql/test/utils/modelgenerator/dataflow/Summaries.cs b/csharp/ql/test/utils/modelgenerator/dataflow/Summaries.cs index f1dbc02512ab..b59513504d9d 100644 --- a/csharp/ql/test/utils/modelgenerator/dataflow/Summaries.cs +++ b/csharp/ql/test/utils/modelgenerator/dataflow/Summaries.cs @@ -19,22 +19,22 @@ public BasicFlow ReturnThis(object input) return this; } - // heuristic-summary=Models;BasicFlow;false;ReturnParam0;(System.String,System.Object);;Argument[0];ReturnValue;taint;df-generated + // heuristic-summary=Models;BasicFlow;false;ReturnParam0;(System.String,System.Object);;Argument[0];ReturnValue;value;df-generated // contentbased-summary=Models;BasicFlow;false;ReturnParam0;(System.String,System.Object);;Argument[0];ReturnValue;value;dfc-generated public string ReturnParam0(string input0, object input1) { return input0; } - // heuristic-summary=Models;BasicFlow;false;ReturnParam1;(System.String,System.Object);;Argument[1];ReturnValue;taint;df-generated + // heuristic-summary=Models;BasicFlow;false;ReturnParam1;(System.String,System.Object);;Argument[1];ReturnValue;value;df-generated // contentbased-summary=Models;BasicFlow;false;ReturnParam1;(System.String,System.Object);;Argument[1];ReturnValue;value;dfc-generated public object ReturnParam1(string input0, object input1) { return input1; } - // heuristic-summary=Models;BasicFlow;false;ReturnParamMultiple;(System.Object,System.Object);;Argument[0];ReturnValue;taint;df-generated - // heuristic-summary=Models;BasicFlow;false;ReturnParamMultiple;(System.Object,System.Object);;Argument[1];ReturnValue;taint;df-generated + // heuristic-summary=Models;BasicFlow;false;ReturnParamMultiple;(System.Object,System.Object);;Argument[0];ReturnValue;value;df-generated + // heuristic-summary=Models;BasicFlow;false;ReturnParamMultiple;(System.Object,System.Object);;Argument[1];ReturnValue;value;df-generated // contentbased-summary=Models;BasicFlow;false;ReturnParamMultiple;(System.Object,System.Object);;Argument[0];ReturnValue;value;dfc-generated // contentbased-summary=Models;BasicFlow;false;ReturnParamMultiple;(System.Object,System.Object);;Argument[1];ReturnValue;value;dfc-generated public object ReturnParamMultiple(object input0, object input1) @@ -133,35 +133,35 @@ public List ReturnFieldInAList() return new List { tainted }; } - // SPURIOUS-heuristic-summary=Models;CollectionFlow;false;ReturnComplexTypeArray;(System.String[]);;Argument[0].Element;ReturnValue;taint;df-generated + // heuristic-summary=Models;CollectionFlow;false;ReturnComplexTypeArray;(System.String[]);;Argument[0];ReturnValue;value;df-generated // contentbased-summary=Models;CollectionFlow;false;ReturnComplexTypeArray;(System.String[]);;Argument[0];ReturnValue;value;dfc-generated public string[] ReturnComplexTypeArray(string[] a) { return a; } - // SPURIOUS-heuristic-summary=Models;CollectionFlow;false;ReturnBulkTypeList;(System.Collections.Generic.List);;Argument[0].Element;ReturnValue;taint;df-generated + // heuristic-summary=Models;CollectionFlow;false;ReturnBulkTypeList;(System.Collections.Generic.List);;Argument[0];ReturnValue;value;df-generated // contentbased-summary=Models;CollectionFlow;false;ReturnBulkTypeList;(System.Collections.Generic.List);;Argument[0];ReturnValue;value;dfc-generated public List ReturnBulkTypeList(List a) { return a; } - // SPURIOUS-heuristic-summary=Models;CollectionFlow;false;ReturnComplexTypeDictionary;(System.Collections.Generic.Dictionary);;Argument[0].Element;ReturnValue;taint;df-generated + // heuristic-summary=Models;CollectionFlow;false;ReturnComplexTypeDictionary;(System.Collections.Generic.Dictionary);;Argument[0];ReturnValue;value;df-generated // contentbased-summary=Models;CollectionFlow;false;ReturnComplexTypeDictionary;(System.Collections.Generic.Dictionary);;Argument[0];ReturnValue;value;dfc-generated public Dictionary ReturnComplexTypeDictionary(Dictionary a) { return a; } - // SPURIOUS-heuristic-summary=Models;CollectionFlow;false;ReturnUntypedArray;(System.Array);;Argument[0].Element;ReturnValue;taint;df-generated + // heuristic-summary=Models;CollectionFlow;false;ReturnUntypedArray;(System.Array);;Argument[0];ReturnValue;value;df-generated // contentbased-summary=Models;CollectionFlow;false;ReturnUntypedArray;(System.Array);;Argument[0];ReturnValue;value;dfc-generated public Array ReturnUntypedArray(Array a) { return a; } - // SPURIOUS-heuristic-summary=Models;CollectionFlow;false;ReturnUntypedList;(System.Collections.IList);;Argument[0].Element;ReturnValue;taint;df-generated + // heuristic-summary=Models;CollectionFlow;false;ReturnUntypedList;(System.Collections.IList);;Argument[0];ReturnValue;value;df-generated // contentbased-summary=Models;CollectionFlow;false;ReturnUntypedList;(System.Collections.IList);;Argument[0];ReturnValue;value;dfc-generated public IList ReturnUntypedList(IList a) { @@ -202,7 +202,7 @@ public IEnumerableFlow(string s) tainted = s; } - // SPURIOUS-heuristic-summary=Models;IEnumerableFlow;false;ReturnIEnumerable;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue;taint;df-generated + // heuristic-summary=Models;IEnumerableFlow;false;ReturnIEnumerable;(System.Collections.Generic.IEnumerable);;Argument[0];ReturnValue;value;df-generated // contentbased-summary=Models;IEnumerableFlow;false;ReturnIEnumerable;(System.Collections.Generic.IEnumerable);;Argument[0];ReturnValue;value;dfc-generated public IEnumerable ReturnIEnumerable(IEnumerable input) { @@ -256,7 +256,7 @@ public List ReturnFieldInGenericList() return new List { tainted }; } - // heuristic-summary=Models;GenericFlow;false;ReturnGenericParam;(S);;Argument[0];ReturnValue;taint;df-generated + // heuristic-summary=Models;GenericFlow;false;ReturnGenericParam;(S);;Argument[0];ReturnValue;value;df-generated // contentbased-summary=Models;GenericFlow;false;ReturnGenericParam;(S);;Argument[0];ReturnValue;value;dfc-generated public S ReturnGenericParam(S input) { @@ -280,7 +280,7 @@ public void AddToGenericList(List input, S data) public abstract class BaseClassFlow { - // heuristic-summary=Models;BaseClassFlow;true;ReturnParam;(System.Object);;Argument[0];ReturnValue;taint;df-generated + // heuristic-summary=Models;BaseClassFlow;true;ReturnParam;(System.Object);;Argument[0];ReturnValue;value;df-generated // contentbased-summary=Models;BaseClassFlow;true;ReturnParam;(System.Object);;Argument[0];ReturnValue;value;dfc-generated public virtual object ReturnParam(object input) { @@ -290,7 +290,7 @@ public virtual object ReturnParam(object input) public class DerivedClass1Flow : BaseClassFlow { - // heuristic-summary=Models;DerivedClass1Flow;false;ReturnParam1;(System.String,System.String);;Argument[1];ReturnValue;taint;df-generated + // heuristic-summary=Models;DerivedClass1Flow;false;ReturnParam1;(System.String,System.String);;Argument[1];ReturnValue;value;df-generated // contentbased-summary=Models;DerivedClass1Flow;false;ReturnParam1;(System.String,System.String);;Argument[1];ReturnValue;value;dfc-generated public string ReturnParam1(string input0, string input1) { @@ -300,14 +300,14 @@ public string ReturnParam1(string input0, string input1) public class DerivedClass2Flow : BaseClassFlow { - // heuristic-summary=Models;BaseClassFlow;true;ReturnParam;(System.Object);;Argument[0];ReturnValue;taint;df-generated + // heuristic-summary=Models;BaseClassFlow;true;ReturnParam;(System.Object);;Argument[0];ReturnValue;value;df-generated // contentbased-summary=Models;BaseClassFlow;true;ReturnParam;(System.Object);;Argument[0];ReturnValue;value;dfc-generated public override object ReturnParam(object input) { return input; } - // heuristic-summary=Models;DerivedClass2Flow;false;ReturnParam0;(System.String,System.Int32);;Argument[0];ReturnValue;taint;df-generated + // heuristic-summary=Models;DerivedClass2Flow;false;ReturnParam0;(System.String,System.Int32);;Argument[0];ReturnValue;value;df-generated // contentbased-summary=Models;DerivedClass2Flow;false;ReturnParam0;(System.String,System.Int32);;Argument[0];ReturnValue;value;dfc-generated public string ReturnParam0(string input0, int input1) { @@ -327,7 +327,7 @@ public OperatorFlow(object o) } // Flow Summary. - // heuristic-summary=Models;OperatorFlow;false;op_Addition;(Models.OperatorFlow,Models.OperatorFlow);;Argument[0];ReturnValue;taint;df-generated + // heuristic-summary=Models;OperatorFlow;false;op_Addition;(Models.OperatorFlow,Models.OperatorFlow);;Argument[0];ReturnValue;value;df-generated // contentbased-summary=Models;OperatorFlow;false;op_Addition;(Models.OperatorFlow,Models.OperatorFlow);;Argument[0];ReturnValue;value;dfc-generated public static OperatorFlow operator +(OperatorFlow a, OperatorFlow b) { @@ -368,7 +368,7 @@ public override bool Equals(object obj) return boolTainted; } - // heuristic-summary=Models;EqualsGetHashCodeNoFlow;false;Equals;(System.String);;Argument[0];ReturnValue;taint;df-generated + // heuristic-summary=Models;EqualsGetHashCodeNoFlow;false;Equals;(System.String);;Argument[0];ReturnValue;value;df-generated // contentbased-summary=Models;EqualsGetHashCodeNoFlow;false;Equals;(System.String);;Argument[0];ReturnValue;value;dfc-generated public string Equals(string s) { @@ -606,7 +606,7 @@ public abstract class BasePublic public class AImplBasePublic : BasePublic { - // heuristic-summary=Models;Inheritance+BasePublic;true;Id;(System.String);;Argument[0];ReturnValue;taint;df-generated + // heuristic-summary=Models;Inheritance+BasePublic;true;Id;(System.String);;Argument[0];ReturnValue;value;df-generated // contentbased-summary=Models;Inheritance+BasePublic;true;Id;(System.String);;Argument[0];ReturnValue;value;dfc-generated public override string Id(string x) { @@ -636,7 +636,7 @@ private abstract class C : IPublic2 public class BImpl : B { - // heuristic-summary=Models;Inheritance+IPublic1;true;Id;(System.String);;Argument[0];ReturnValue;taint;df-generated + // heuristic-summary=Models;Inheritance+IPublic1;true;Id;(System.String);;Argument[0];ReturnValue;value;df-generated // contentbased-summary=Models;Inheritance+IPublic1;true;Id;(System.String);;Argument[0];ReturnValue;value;dfc-generated public override string Id(string x) { @@ -646,7 +646,7 @@ public override string Id(string x) private class CImpl : C { - // heuristic-summary=Models;Inheritance+IPublic2;true;Id;(System.String);;Argument[0];ReturnValue;taint;df-generated + // heuristic-summary=Models;Inheritance+IPublic2;true;Id;(System.String);;Argument[0];ReturnValue;value;df-generated // contentbased-summary=Models;Inheritance+IPublic2;true;Id;(System.String);;Argument[0];ReturnValue;value;dfc-generated public override string Id(string x) { @@ -1035,14 +1035,14 @@ public override object GetValue() public class ParameterModifiers { // contentbased-summary=Models;ParameterModifiers;false;Copy;(System.Object,System.Object);;Argument[0];Argument[1];value;dfc-generated - // heuristic-summary=Models;ParameterModifiers;false;Copy;(System.Object,System.Object);;Argument[0];Argument[1];taint;df-generated + // heuristic-summary=Models;ParameterModifiers;false;Copy;(System.Object,System.Object);;Argument[0];Argument[1];value;df-generated public void Copy(object key, out object value) { value = key; } // contentbased-summary=Models;ParameterModifiers;false;CopyToRef;(System.Object,System.Object);;Argument[0];Argument[1];value;dfc-generated - // heuristic-summary=Models;ParameterModifiers;false;CopyToRef;(System.Object,System.Object);;Argument[0];Argument[1];taint;df-generated + // heuristic-summary=Models;ParameterModifiers;false;CopyToRef;(System.Object,System.Object);;Argument[0];Argument[1];value;df-generated public void CopyToRef(object key, ref object value) { value = key; @@ -1062,7 +1062,7 @@ public void RefParamUse(ref object value) } // contentbased-summary=Models;ParameterModifiers;false;InReturn;(System.Object);;Argument[0];ReturnValue;value;dfc-generated - // heuristic-summary=Models;ParameterModifiers;false;InReturn;(System.Object);;Argument[0];ReturnValue;taint;df-generated + // heuristic-summary=Models;ParameterModifiers;false;InReturn;(System.Object);;Argument[0];ReturnValue;value;df-generated public object InReturn(in object v) { return v; diff --git a/java/ql/src/utils/modelgenerator/CaptureContentSummaryModels.ql b/java/ql/src/utils/modelgenerator/CaptureContentSummaryModels.ql index 1fe70bae0b5b..39e8cd9a0a4a 100644 --- a/java/ql/src/utils/modelgenerator/CaptureContentSummaryModels.ql +++ b/java/ql/src/utils/modelgenerator/CaptureContentSummaryModels.ql @@ -10,5 +10,5 @@ import internal.CaptureModels import SummaryModels from DataFlowSummaryTargetApi api, string flow -where flow = ContentSensitive::captureFlow(api, _) +where flow = ContentSensitive::captureFlow(api, _, _, _, _) select flow order by flow diff --git a/java/ql/src/utils/modelgenerator/debug/CaptureSummaryModelsPartialPath.ql b/java/ql/src/utils/modelgenerator/debug/CaptureSummaryModelsPartialPath.ql index b9dc9ea236a0..1c5204c3b9b2 100644 --- a/java/ql/src/utils/modelgenerator/debug/CaptureSummaryModelsPartialPath.ql +++ b/java/ql/src/utils/modelgenerator/debug/CaptureSummaryModelsPartialPath.ql @@ -16,7 +16,7 @@ import PartialFlow::PartialPathGraph int explorationLimit() { result = 3 } -module PartialFlow = Heuristic::PropagateFlow::FlowExplorationFwd; +module PartialFlow = Heuristic::PropagateTaintFlow::FlowExplorationFwd; from PartialFlow::PartialPathNode source, PartialFlow::PartialPathNode sink, diff --git a/java/ql/src/utils/modelgenerator/debug/CaptureSummaryModelsPath.ql b/java/ql/src/utils/modelgenerator/debug/CaptureSummaryModelsPath.ql index 5925364800c9..20559f00cbfe 100644 --- a/java/ql/src/utils/modelgenerator/debug/CaptureSummaryModelsPath.ql +++ b/java/ql/src/utils/modelgenerator/debug/CaptureSummaryModelsPath.ql @@ -12,16 +12,15 @@ import java import semmle.code.java.dataflow.DataFlow import utils.modelgenerator.internal.CaptureModels import SummaryModels -import Heuristic -import PropagateFlow::PathGraph +import Heuristic::PropagateTaintFlow::PathGraph from - PropagateFlow::PathNode source, PropagateFlow::PathNode sink, DataFlowSummaryTargetApi api, - DataFlow::Node p, DataFlow::Node returnNodeExt + Heuristic::PropagateTaintFlow::PathNode source, Heuristic::PropagateTaintFlow::PathNode sink, + DataFlowSummaryTargetApi api, DataFlow::Node p, DataFlow::Node returnNodeExt where - PropagateFlow::flowPath(source, sink) and + Heuristic::PropagateTaintFlow::flowPath(source, sink) and p = source.getNode() and returnNodeExt = sink.getNode() and - exists(captureThroughFlow0(api, p, returnNodeExt)) + Heuristic::captureThroughFlow0(api, p, returnNodeExt) select sink.getNode(), source, sink, "There is flow from $@ to the $@.", source.getNode(), "parameter", sink.getNode(), "return value" diff --git a/java/ql/src/utils/modelgenerator/internal/CaptureModels.qll b/java/ql/src/utils/modelgenerator/internal/CaptureModels.qll index 09223d23b1c5..aa68a4332910 100644 --- a/java/ql/src/utils/modelgenerator/internal/CaptureModels.qll +++ b/java/ql/src/utils/modelgenerator/internal/CaptureModels.qll @@ -92,7 +92,7 @@ module ModelGeneratorCommonInput implements ModelGeneratorCommonInputSig otherStreams) throws IOException { diff --git a/rust/ql/src/utils/modelgenerator/CaptureContentSummaryModels.ql b/rust/ql/src/utils/modelgenerator/CaptureContentSummaryModels.ql index 4b672e74da59..9dd63e06ea72 100644 --- a/rust/ql/src/utils/modelgenerator/CaptureContentSummaryModels.ql +++ b/rust/ql/src/utils/modelgenerator/CaptureContentSummaryModels.ql @@ -10,5 +10,5 @@ import internal.CaptureModels import SummaryModels from DataFlowSummaryTargetApi api, string flow -where flow = ContentSensitive::captureFlow(api, _) +where flow = ContentSensitive::captureFlow(api, _, _, _, _) select flow order by flow diff --git a/rust/ql/src/utils/modelgenerator/debug/CaptureSummaryModelsPartialPath.ql b/rust/ql/src/utils/modelgenerator/debug/CaptureSummaryModelsPartialPath.ql index b8855b94bf2a..b10b638129b4 100644 --- a/rust/ql/src/utils/modelgenerator/debug/CaptureSummaryModelsPartialPath.ql +++ b/rust/ql/src/utils/modelgenerator/debug/CaptureSummaryModelsPartialPath.ql @@ -15,7 +15,7 @@ import PartialFlow::PartialPathGraph int explorationLimit() { result = 3 } -module PartialFlow = Heuristic::PropagateFlow::FlowExplorationFwd; +module PartialFlow = Heuristic::PropagateTaintFlow::FlowExplorationFwd; from PartialFlow::PartialPathNode source, PartialFlow::PartialPathNode sink, diff --git a/rust/ql/src/utils/modelgenerator/debug/CaptureSummaryModelsPath.ql b/rust/ql/src/utils/modelgenerator/debug/CaptureSummaryModelsPath.ql index ac25306ceeee..7c7a54aea513 100644 --- a/rust/ql/src/utils/modelgenerator/debug/CaptureSummaryModelsPath.ql +++ b/rust/ql/src/utils/modelgenerator/debug/CaptureSummaryModelsPath.ql @@ -11,16 +11,15 @@ private import codeql.rust.dataflow.DataFlow import utils.modelgenerator.internal.CaptureModels import SummaryModels -import Heuristic -import PropagateFlow::PathGraph +import Heuristic::PropagateTaintFlow::PathGraph from - PropagateFlow::PathNode source, PropagateFlow::PathNode sink, DataFlowSummaryTargetApi api, - DataFlow::Node p, DataFlow::Node returnNodeExt + Heuristic::PropagateTaintFlow::PathNode source, Heuristic::PropagateTaintFlow::PathNode sink, + DataFlowSummaryTargetApi api, DataFlow::Node p, DataFlow::Node returnNodeExt where - PropagateFlow::flowPath(source, sink) and + Heuristic::PropagateTaintFlow::flowPath(source, sink) and p = source.getNode() and returnNodeExt = sink.getNode() and - exists(captureThroughFlow0(api, p, returnNodeExt)) + Heuristic::captureThroughFlow0(api, p, returnNodeExt) select sink.getNode(), source, sink, "There is flow from $@ to the $@.", source.getNode(), "parameter", sink.getNode(), "return value" diff --git a/rust/ql/src/utils/modelgenerator/internal/CaptureModels.qll b/rust/ql/src/utils/modelgenerator/internal/CaptureModels.qll index 99e1c527b546..f9b4eee664d6 100644 --- a/rust/ql/src/utils/modelgenerator/internal/CaptureModels.qll +++ b/rust/ql/src/utils/modelgenerator/internal/CaptureModels.qll @@ -54,26 +54,26 @@ module ModelGeneratorCommonInput implements string qualifierString() { result = "Argument[self]" } - string parameterAccess(R::ParamBase p) { + string parameterExactAccess(R::ParamBase p) { result = "Argument[" + any(DataFlowImpl::ParameterPosition pos | p = pos.getParameterIn(_)).toString() + "]" } - string parameterContentAccess(R::ParamBase p) { result = parameterAccess(p) } + string parameterApproximateAccess(R::ParamBase p) { result = parameterExactAccess(p) } class InstanceParameterNode extends DataFlow::ParameterNode { InstanceParameterNode() { this.asParameter() instanceof SelfParam } } bindingset[c] - string paramReturnNodeAsOutput(Callable c, DataFlowImpl::ParameterPosition pos) { - result = paramReturnNodeAsContentOutput(c, pos) + string paramReturnNodeAsApproximateOutput(Callable c, DataFlowImpl::ParameterPosition pos) { + result = paramReturnNodeAsExactOutput(c, pos) } bindingset[c] - string paramReturnNodeAsContentOutput(Callable c, DataFlowImpl::ParameterPosition pos) { - result = parameterContentAccess(c.getParamList().getParam(pos.getPosition())) + string paramReturnNodeAsExactOutput(Callable c, DataFlowImpl::ParameterPosition pos) { + result = parameterExactAccess(c.getParamList().getParam(pos.getPosition())) or pos.isSelf() and result = qualifierString() } diff --git a/rust/ql/test/utils-tests/modelgenerator/CaptureSummaryModels.ql b/rust/ql/test/utils-tests/modelgenerator/CaptureSummaryModels.ql index e0788253f43e..fe5e532394b4 100644 --- a/rust/ql/test/utils-tests/modelgenerator/CaptureSummaryModels.ql +++ b/rust/ql/test/utils-tests/modelgenerator/CaptureSummaryModels.ql @@ -4,7 +4,7 @@ import SummaryModels import utils.test.InlineMadTest module InlineMadTestConfig implements InlineMadTestConfigSig { - string getCapturedModel(Function f) { result = ContentSensitive::captureFlow(f, _) } + string getCapturedModel(Function f) { result = ContentSensitive::captureFlow(f, _, _, _, _) } string getKind() { result = "summary" } } diff --git a/shared/mad/codeql/mad/modelgenerator/internal/ModelGeneratorImpl.qll b/shared/mad/codeql/mad/modelgenerator/internal/ModelGeneratorImpl.qll index dabd687b52b9..829bf267c226 100644 --- a/shared/mad/codeql/mad/modelgenerator/internal/ModelGeneratorImpl.qll +++ b/shared/mad/codeql/mad/modelgenerator/internal/ModelGeneratorImpl.qll @@ -11,6 +11,7 @@ private import codeql.dataflow.internal.ContentDataFlowImpl private import codeql.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon private import codeql.util.Location private import ModelPrinting +private import codeql.util.Unit /** * Provides language-specific model generator parameters. @@ -72,14 +73,14 @@ signature module ModelGeneratorCommonInputSig::getOutput(node) + private string getApproximateOutput(ReturnNodeExt node) { + result = PrintReturnNodeExt::getOutput(node) + } + + private string getExactOutput(ReturnNodeExt node) { + result = PrintReturnNodeExt::getOutput(node) } /** @@ -319,6 +324,16 @@ module MakeModelGeneratorFactory< DataFlowSummaryTargetApi() { not isUninterestingForDataFlowModels(this) } } + /** + * Gets the MaD string representation of the parameter `p` + * when used in exact flow. + */ + private string parameterNodeAsExactInput(DataFlow::ParameterNode p) { + result = parameterExactAccess(asParameter(p)) + or + result = qualifierString() and p instanceof InstanceParameterNode + } + /** * Provides classes and predicates related to capturing summary models * based on heuristic data flow. @@ -335,21 +350,25 @@ module MakeModelGeneratorFactory< /** * Gets the MaD string representation of the parameter node `p`. */ - string parameterNodeAsInput(DataFlow::ParameterNode p) { - result = parameterAccess(asParameter(p)) + private string parameterNodeAsApproximateInput(DataFlow::ParameterNode p) { + result = parameterApproximateAccess(asParameter(p)) or result = qualifierString() and p instanceof InstanceParameterNode } /** * Gets the summary model of `api`, if it follows the `fluent` programming pattern (returns `this`). + * + * The strings `input` and `output` represent the qualifier and the return value, respectively. */ - private string captureQualifierFlow(DataFlowSummaryTargetApi api) { + private string captureQualifierFlow(DataFlowSummaryTargetApi api, string input, string output) { exists(ReturnNodeExt ret | api = returnNodeEnclosingCallable(ret) and isOwnInstanceAccessNode(ret) ) and - result = ModelPrintingSummary::asLiftedValueModel(api, qualifierString(), "ReturnValue") + input = qualifierString() and + output = "ReturnValue" and + result = ModelPrintingSummary::asLiftedValueModel(api, input, output) } private int accessPathLimit0() { result = 2 } @@ -394,14 +413,22 @@ module MakeModelGeneratorFactory< override string toString() { result = "TaintStore(" + step + ")" } } - /** - * A data flow configuration for tracking flow through APIs. - * The sources are the parameters of an API and the sinks are the return values (excluding `this`) and parameters. - * - * This can be used to generate Flow summaries for APIs from parameter to return. - */ - private module PropagateFlowConfig implements DataFlow::StateConfigSig { - class FlowState = TaintState; + private signature module PropagateFlowConfigInputSig { + class FlowState; + + FlowState initialState(); + + default predicate isAdditionalFlowStep( + DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2 + ) { + none() + } + } + + private module PropagateFlowConfig + implements DataFlow::StateConfigSig + { + import PropagateFlowConfigInput predicate isSource(DataFlow::Node source, FlowState state) { source instanceof DataFlow::ParameterNode and @@ -410,7 +437,7 @@ module MakeModelGeneratorFactory< c instanceof DataFlowSummaryTargetApi and not isUninterestingForHeuristicDataFlowModels(c) ) and - state.(TaintRead).getStep() = 0 + state = initialState() } predicate isSink(DataFlow::Node sink, FlowState state) { @@ -421,9 +448,34 @@ module MakeModelGeneratorFactory< predicate isSink(DataFlow::Node sink) { sink instanceof ReturnNodeExt and not isOwnInstanceAccessNode(sink) and - not exists(captureQualifierFlow(getAsExprEnclosingCallable(sink))) + not exists(captureQualifierFlow(getAsExprEnclosingCallable(sink), _, _)) } + predicate isAdditionalFlowStep = PropagateFlowConfigInput::isAdditionalFlowStep/4; + + predicate isBarrier(DataFlow::Node n) { + exists(Type t | t = n.(NodeExtended).getType() and not isRelevantType(t)) + } + + DataFlow::FlowFeature getAFeature() { + result instanceof DataFlow::FeatureEqualSourceSinkCallContext + } + } + + /** + * A module used to construct a data flow configuration for tracking taint- + * flow through APIs. + * The sources are the parameters of an API and the sinks are the return + * values (excluding `this`) and parameters. + * + * This can be used to generate flow summaries for APIs from parameter to + * return. + */ + module PropagateFlowConfigInputTaintInput implements PropagateFlowConfigInputSig { + class FlowState = TaintState; + + FlowState initialState() { result.(TaintRead).getStep() = 0 } + predicate isAdditionalFlowStep( DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2 ) { @@ -445,51 +497,117 @@ module MakeModelGeneratorFactory< state1.(TaintRead).getStep() + 1 = state2.(TaintRead).getStep() ) } + } - predicate isBarrier(DataFlow::Node n) { - exists(Type t | t = n.(NodeExtended).getType() and not isRelevantType(t)) - } + /** + * A data flow configuration for tracking taint-flow through APIs. + * The sources are the parameters of an API and the sinks are the return + * values (excluding `this`) and parameters. + * + * This can be used to generate flow summaries for APIs from parameter to + * return. + */ + private module PropagateTaintFlowConfig = + PropagateFlowConfig; - DataFlow::FlowFeature getAFeature() { - result instanceof DataFlow::FeatureEqualSourceSinkCallContext - } - } + module PropagateTaintFlow = TaintTracking::GlobalWithState; + + /** + * A module used to construct a data flow configuration for tracking + * data flow through APIs. + * The sources are the parameters of an API and the sinks are the return + * values (excluding `this`) and parameters. + * + * This can be used to generate value-preserving flow summaries for APIs + * from parameter to return. + */ + module PropagateFlowConfigInputDataFlowInput implements PropagateFlowConfigInputSig { + class FlowState = Unit; - module PropagateFlow = TaintTracking::GlobalWithState; + FlowState initialState() { any() } + } /** - * Gets the summary model(s) of `api`, if there is flow from parameters to return value or parameter. + * A data flow configuration for tracking data flow through APIs. + * The sources are the parameters of an API and the sinks are the return + * values (excluding `this`) and parameters. + * + * This can be used to generate flow summaries for APIs from parameter to + * return. */ - string captureThroughFlow0( + private module PropagateDataFlowConfig = + PropagateFlowConfig; + + module PropagateDataFlow = DataFlow::GlobalWithState; + + predicate captureThroughFlow0( DataFlowSummaryTargetApi api, DataFlow::ParameterNode p, ReturnNodeExt returnNodeExt ) { - exists(string input, string output | - getEnclosingCallable(p) = api and - getEnclosingCallable(returnNodeExt) = api and - input = parameterNodeAsInput(p) and - output = getOutput(returnNodeExt) and - input != output and - result = ModelPrintingSummary::asLiftedTaintModel(api, input, output) - ) + captureThroughFlow0(api, p, _, returnNodeExt, _, _) + } + + /** + * Holds if there should be a summary of `api` specifying flow + * from `p` (with summary component `input`) to `returnNodeExt` (with + * summary component `output`). + * + * `preservesValue` is true if the summary is value-preserving, or `false` + * otherwise. + */ + private predicate captureThroughFlow0( + DataFlowSummaryTargetApi api, DataFlow::ParameterNode p, string input, + ReturnNodeExt returnNodeExt, string output, boolean preservesValue + ) { + ( + PropagateDataFlow::flow(p, returnNodeExt) and + input = parameterNodeAsExactInput(p) and + output = getExactOutput(returnNodeExt) and + preservesValue = true + or + not PropagateDataFlow::flow(p, returnNodeExt) and + PropagateTaintFlow::flow(p, returnNodeExt) and + input = parameterNodeAsApproximateInput(p) and + output = getApproximateOutput(returnNodeExt) and + preservesValue = false + ) and + getEnclosingCallable(p) = api and + getEnclosingCallable(returnNodeExt) = api and + input != output } /** * Gets the summary model(s) of `api`, if there is flow from parameters to return value or parameter. + * + * `preservesValue` is `true` if the summary is value-preserving, and `false` otherwise. */ - private string captureThroughFlow(DataFlowSummaryTargetApi api) { - exists(DataFlow::ParameterNode p, ReturnNodeExt returnNodeExt | - PropagateFlow::flow(p, returnNodeExt) and - result = captureThroughFlow0(api, p, returnNodeExt) - ) + private string captureThroughFlow( + DataFlowSummaryTargetApi api, string input, string output, boolean preservesValue + ) { + preservesValue = max(boolean b | captureThroughFlow0(api, _, input, _, output, b)) and + result = ModelPrintingSummary::asLiftedModel(api, input, output, preservesValue) + } + + /** + * Gets the summary model(s) of `api`, if there is flow `input` to + * `output`. `preservesValue` is `true` if the summary is value- + * preserving, and `false` otherwise. + */ + string captureFlow( + DataFlowSummaryTargetApi api, string input, string output, boolean preservesValue + ) { + result = captureQualifierFlow(api, input, output) and preservesValue = true + or + result = captureThroughFlow(api, input, output, preservesValue) } /** * Gets the summary model(s) of `api`, if there is flow from parameters to the * return value or parameter or if `api` is a fluent API. + * + * `preservesValue` is `true` if the summary is value-preserving, and `false` otherwise. */ - string captureFlow(DataFlowSummaryTargetApi api) { - result = captureQualifierFlow(api) or - result = captureThroughFlow(api) + string captureFlow(DataFlowSummaryTargetApi api, boolean preservesValue) { + result = captureFlow(api, _, _, preservesValue) } /** @@ -499,7 +617,7 @@ module MakeModelGeneratorFactory< */ string captureNoFlow(DataFlowSummaryTargetApi api) { not exists(DataFlowSummaryTargetApi api0 | - exists(captureFlow(api0)) and api0.lift() = api.lift() + exists(captureFlow(api0, _)) and api0.lift() = api.lift() ) and api.isRelevant() and result = ModelPrintingSummary::asNeutralSummaryModel(api) @@ -550,20 +668,6 @@ module MakeModelGeneratorFactory< private module ContentModelPrinting = Printing::ModelPrintingSummary; - private string getContentOutput(ReturnNodeExt node) { - result = PrintReturnNodeExt::getOutput(node) - } - - /** - * Gets the MaD string representation of the parameter `p` - * when used in content flow. - */ - private string parameterNodeAsContentInput(DataFlow::ParameterNode p) { - result = parameterContentAccess(asParameter(p)) - or - result = qualifierString() and p instanceof InstanceParameterNode - } - private string getContent(PropagateContentFlow::AccessPath ap, int i) { result = "." + printContent(ap.getAtIndex(i)) } @@ -639,8 +743,8 @@ module MakeModelGeneratorFactory< PropagateContentFlow::AccessPath stores | apiFlow(this, parameter, reads, returnNodeExt, stores, _) and - input = parameterNodeAsContentInput(parameter) + printReadAccessPath(reads) and - output = getContentOutput(returnNodeExt) + printStoreAccessPath(stores) + input = parameterNodeAsExactInput(parameter) + printReadAccessPath(reads) and + output = getExactOutput(returnNodeExt) + printStoreAccessPath(stores) ) ) <= 3 } @@ -847,8 +951,8 @@ module MakeModelGeneratorFactory< PropagateContentFlow::AccessPath reads, PropagateContentFlow::AccessPath stores | apiRelevantContentFlow(api, p, reads, returnNodeExt, stores, preservesValue) and - input = parameterNodeAsContentInput(p) + printReadAccessPath(reads) and - output = getContentOutput(returnNodeExt) + printStoreAccessPath(stores) and + input = parameterNodeAsExactInput(p) + printReadAccessPath(reads) and + output = getExactOutput(returnNodeExt) + printStoreAccessPath(stores) and input != output and validateAccessPath(reads) and validateAccessPath(stores) and @@ -861,18 +965,20 @@ module MakeModelGeneratorFactory< } /** - * Gets the content based summary model(s) of the API `api` (if there is flow from a parameter to - * the return value or a parameter). `lift` is true, if the model should be lifted, otherwise false. + * Gets the content based summary model(s) of the API `api` (if there is flow from `input` to + * `output`). `lift` is true, if the model should be lifted, otherwise false. + * `preservesValue` is `true` if the summary is value-preserving, and `false` otherwise. * * Models are lifted to the best type in case the read and store access paths do not * contain a field or synthetic field access. */ - string captureFlow(ContentDataFlowSummaryTargetApi api, boolean lift) { - exists(string input, string output, boolean preservesValue | - captureFlow0(api, input, output, _, lift) and - preservesValue = max(boolean p | captureFlow0(api, input, output, p, lift)) and - result = ContentModelPrinting::asModel(api, input, output, preservesValue, lift) - ) + string captureFlow( + ContentDataFlowSummaryTargetApi api, string input, string output, boolean lift, + boolean preservesValue + ) { + captureFlow0(api, input, output, _, lift) and + preservesValue = max(boolean p | captureFlow0(api, input, output, p, lift)) and + result = ContentModelPrinting::asModel(api, input, output, preservesValue, lift) } } @@ -885,17 +991,32 @@ module MakeModelGeneratorFactory< * generate flow summaries using the heuristic based summary generator. */ string captureFlow(DataFlowSummaryTargetApi api, boolean lift) { - result = ContentSensitive::captureFlow(api, lift) + result = ContentSensitive::captureFlow(api, _, _, lift, _) or - not exists(DataFlowSummaryTargetApi api0 | - (api0 = api or api.lift() = api0) and - exists(ContentSensitive::captureFlow(api0, false)) - or - api0.lift() = api.lift() and - exists(ContentSensitive::captureFlow(api0, true)) - ) and - result = Heuristic::captureFlow(api) and - lift = true + exists(boolean preservesValue, string input, string output | + not exists( + DataFlowSummaryTargetApi api0, string input0, string output0, boolean preservesValue0 + | + // If the heuristic summary is taint-based, and we can generate a content-sensitive + // summary then we omit generating the heuristic summary. + preservesValue = false + or + // If they're both value-preserving then we only generate a heuristic summary if + // we didn't generate a content-sensitive summary on the same input/output pair. + preservesValue = true and + preservesValue0 = true and + input0 = input and + output0 = output + | + (api0 = api or api.lift() = api0) and + exists(ContentSensitive::captureFlow(api0, input0, output0, false, preservesValue0)) + or + api0.lift() = api.lift() and + exists(ContentSensitive::captureFlow(api0, input0, output0, true, preservesValue0)) + ) and + result = Heuristic::captureFlow(api, input, output, preservesValue) and + lift = true + ) } /** @@ -1056,7 +1177,7 @@ module MakeModelGeneratorFactory< sourceNode(source, kind) and api = getEnclosingCallable(sink) and not irrelevantSourceSinkApi(getEnclosingCallable(source), api) and - result = ModelPrintingSourceOrSink::asSourceModel(api, getOutput(sink), kind) + result = ModelPrintingSourceOrSink::asSourceModel(api, getExactOutput(sink), kind) ) } } diff --git a/shared/mad/codeql/mad/modelgenerator/internal/ModelPrinting.qll b/shared/mad/codeql/mad/modelgenerator/internal/ModelPrinting.qll index fc1e0113d1d0..d4fbd9062b63 100644 --- a/shared/mad/codeql/mad/modelgenerator/internal/ModelPrinting.qll +++ b/shared/mad/codeql/mad/modelgenerator/internal/ModelPrinting.qll @@ -96,9 +96,11 @@ module ModelPrintingImpl { /** * Gets the lifted taint summary model for `api` with `input` and `output`. */ - bindingset[input, output] - string asLiftedTaintModel(Printing::SummaryApi api, string input, string output) { - result = asModel(api, input, output, false, true) + bindingset[input, output, preservesValue] + string asLiftedModel( + Printing::SummaryApi api, string input, string output, boolean preservesValue + ) { + result = asModel(api, input, output, preservesValue, true) } /**