@@ -9,6 +9,8 @@ import ModelGeneratorUtils
99import semmle.code.java.dataflow.TaintTracking
1010import semmle.code.java.dataflow.internal.DataFlowImplCommon
1111import semmle.code.java.dataflow.internal.DataFlowNodes
12+ import semmle.code.java.dataflow.internal.DataFlowPrivate
13+ import semmle.code.java.dataflow.InstanceAccess
1214import ModelGeneratorUtils
1315
1416string captureFlow ( Callable api ) {
@@ -39,6 +41,36 @@ string captureQualifierFlow(Callable api) {
3941 result = asValueModel ( api , "Argument[-1]" , "ReturnValue" )
4042}
4143
44+ class FieldToReturnConfig extends TaintTracking:: Configuration {
45+ FieldToReturnConfig ( ) { this = "FieldToReturnConfig" }
46+
47+ override predicate isSource ( DataFlow:: Node source ) {
48+ source instanceof DataFlow:: InstanceParameterNode
49+ }
50+
51+ override predicate isSink ( DataFlow:: Node sink ) { sink instanceof ReturnNodeExt }
52+
53+ override predicate isAdditionalTaintStep ( DataFlow:: Node node1 , DataFlow:: Node node2 ) {
54+ exists ( DataFlow:: Content f |
55+ readStep ( node1 , f , node2 ) and
56+ if f instanceof DataFlow:: FieldContent
57+ then isRelevantType ( f .( DataFlow:: FieldContent ) .getField ( ) .getType ( ) )
58+ else any ( )
59+ )
60+ or
61+ exists ( DataFlow:: Content f | storeStep ( node1 , f , node2 ) |
62+ f instanceof DataFlow:: ArrayContent or
63+ f instanceof DataFlow:: CollectionContent or
64+ f instanceof DataFlow:: MapKeyContent or
65+ f instanceof DataFlow:: MapValueContent
66+ )
67+ }
68+
69+ override DataFlow:: FlowFeature getAFeature ( ) {
70+ result instanceof DataFlow:: FeatureEqualSourceSinkCallContext
71+ }
72+ }
73+
4274/**
4375 * Capture APIs that return tainted instance data.
4476 * Example of an API that returns tainted instance data:
@@ -62,15 +94,17 @@ string captureQualifierFlow(Callable api) {
6294 * ```
6395 */
6496string captureFieldFlow ( Callable api ) {
65- exists ( FieldAccess fa , ReturnNodeExt returnNode |
66- not ( fa .getField ( ) .isStatic ( ) and fa .getField ( ) .isFinal ( ) ) and
67- fa .getField ( ) .getDeclaringType ( ) = api .getDeclaringType ( ) and
68- returnNode .getEnclosingCallable ( ) = api and
69- isRelevantType ( api .getReturnType ( ) ) and
97+ exists ( FieldToReturnConfig config , ReturnNodeExt returnNodeExt |
98+ config .hasFlow ( _, returnNodeExt ) and
99+ returnNodeExt .getEnclosingCallable ( ) = api and
70100 not api .getDeclaringType ( ) instanceof EnumType and
71- TaintTracking:: localTaint ( DataFlow:: exprNode ( fa ) , returnNode )
101+ isRelevantType ( returnNodeExt .getType ( ) ) and
102+ not (
103+ returnNodeExt .getKind ( ) instanceof ValueReturnKind and
104+ exists ( captureQualifierFlow ( api ) )
105+ )
72106 |
73- result = asTaintModel ( api , "Argument[-1]" , asOutput ( api , returnNode ) )
107+ result = asTaintModel ( api , "Argument[-1]" , asOutput ( api , returnNodeExt ) )
74108 )
75109}
76110
@@ -94,12 +128,26 @@ class ParameterToFieldConfig extends TaintTracking::Configuration {
94128 }
95129
96130 override predicate isSink ( DataFlow:: Node sink ) {
131+ thisAccess ( sink .( DataFlow:: PostUpdateNode ) .getPreUpdateNode ( ) )
132+ }
133+
134+ override predicate isAdditionalTaintStep ( DataFlow:: Node node1 , DataFlow:: Node node2 ) {
97135 exists ( FieldAssignment a |
98- a .getSource ( ) = sink .asExpr ( ) and
99- a .getDest ( ) . ( FieldAccess ) . getField ( ) . getDeclaringType ( ) =
100- sink . getEnclosingCallable ( ) .getDeclaringType ( )
136+ a .getSource ( ) = node1 .asExpr ( ) and
137+ DataFlow :: getFieldQualifier ( a .getDest ( ) ) = node2 . ( DataFlow :: PostUpdateNode ) . getPreUpdateNode ( ) and
138+ isRelevantType ( a . getDest ( ) .( FieldAccess ) . getField ( ) . getType ( ) )
101139 )
102140 }
141+
142+ override DataFlow:: FlowFeature getAFeature ( ) {
143+ result instanceof DataFlow:: FeatureEqualSourceSinkCallContext
144+ }
145+ }
146+
147+ private predicate thisAccess ( DataFlow:: Node n ) {
148+ n .asExpr ( ) .( InstanceAccess ) .isOwnInstanceAccess ( )
149+ or
150+ n .( DataFlow:: ImplicitInstanceAccess ) .getInstanceAccess ( ) instanceof OwnInstanceAccess
103151}
104152
105153/**
@@ -116,30 +164,16 @@ class ParameterToFieldConfig extends TaintTracking::Configuration {
116164 * `p;Foo;true;doSomething;(String);Argument[0];Argument[-1];taint`
117165 */
118166string captureFieldFlowIn ( Callable api ) {
119- exists ( DataFlow:: PathNode source , DataFlow :: PathNode sink |
167+ exists ( DataFlow:: Node source , ParameterToFieldConfig config |
120168 not api .isStatic ( ) and
121- restrictedFlow ( source , sink ) and
122- source .getNode ( ) . asParameter ( ) .getCallable ( ) = api
169+ config . hasFlow ( source , _ ) and
170+ source .asParameter ( ) .getCallable ( ) = api
123171 |
124172 result =
125- asTaintModel ( api , "Argument[" + source .getNode ( ) .asParameter ( ) .getPosition ( ) + "]" ,
126- "Argument[-1]" )
173+ asTaintModel ( api , "Argument[" + source .asParameter ( ) .getPosition ( ) + "]" , "Argument[-1]" )
127174 )
128175}
129176
130- predicate restrictedEdge ( DataFlow:: PathNode n1 , DataFlow:: PathNode n2 ) {
131- n1 .getASuccessor ( ) = n2 and
132- n1 .getNode ( ) .getEnclosingCallable ( ) .getDeclaringType ( ) =
133- n2 .getNode ( ) .getEnclosingCallable ( ) .getDeclaringType ( )
134- }
135-
136- predicate restrictedFlow ( DataFlow:: PathNode src , DataFlow:: PathNode sink ) {
137- src .getConfiguration ( ) instanceof ParameterToFieldConfig and
138- src .isSource ( ) and
139- src .getConfiguration ( ) .isSink ( sink .getNode ( ) ) and
140- restrictedEdge * ( src , sink )
141- }
142-
143177class ParameterToReturnValueTaintConfig extends TaintTracking:: Configuration {
144178 ParameterToReturnValueTaintConfig ( ) { this = "ParameterToReturnValueTaintConfig" }
145179
0 commit comments