Skip to content

Commit 16a5ccd

Browse files
aschackmullmichaelnebel
authored andcommitted
Java: Simplify model generator query using flow state.
1 parent d953382 commit 16a5ccd

File tree

2 files changed

+77
-129
lines changed

2 files changed

+77
-129
lines changed

java/ql/src/utils/model-generator/CaptureSummaryModels.ql

Lines changed: 58 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,7 @@ import ModelGeneratorUtils
1414

1515
string captureFlow(TargetAPI api) {
1616
result = captureQualifierFlow(api) or
17-
result = captureParameterFlowToReturnValue(api) or
18-
result = captureFieldFlowIn(api) or
19-
result = captureParameterToParameterFlow(api) or
20-
result = captureFieldFlow(api)
17+
result = captureThroughFlow(api)
2118
}
2219

2320
/**
@@ -40,31 +37,63 @@ string captureQualifierFlow(TargetAPI api) {
4037
result = asValueModel(api, "Argument[-1]", "ReturnValue")
4138
}
4239

43-
class FieldToReturnConfig extends TaintTracking::Configuration {
44-
FieldToReturnConfig() { this = "FieldToReturnConfig" }
40+
class TaintRead extends DataFlow::FlowState {
41+
TaintRead() { this = "TaintRead" }
42+
}
43+
44+
class TaintStore extends DataFlow::FlowState {
45+
TaintStore() { this = "TaintStore" }
46+
}
4547

46-
override predicate isSource(DataFlow::Node source) {
47-
source instanceof DataFlow::InstanceParameterNode
48+
class ThroughFlowConfig extends TaintTracking::Configuration {
49+
ThroughFlowConfig() { this = "ThroughFlowConfig" }
50+
51+
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) {
52+
source instanceof DataFlow::ParameterNode and
53+
source.getEnclosingCallable() instanceof TargetAPI and
54+
state instanceof TaintRead
4855
}
4956

50-
override predicate isSink(DataFlow::Node sink) {
57+
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) {
5158
sink instanceof ReturnNodeExt and
5259
not sink.(ReturnNode).asExpr().(ThisAccess).isOwnInstanceAccess() and
53-
not exists(captureQualifierFlow(sink.asExpr().getEnclosingCallable()))
60+
not exists(captureQualifierFlow(sink.asExpr().getEnclosingCallable())) and
61+
(state instanceof TaintRead or state instanceof TaintStore)
5462
}
5563

56-
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
57-
isRelevantTaintStep(node1, node2)
64+
override predicate isAdditionalFlowStep(
65+
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
66+
DataFlow::FlowState state2
67+
) {
68+
exists(TypedContent tc |
69+
store(node1, tc, node2, _) and
70+
isRelevantContent(tc.getContent()) and
71+
(state1 instanceof TaintRead or state1 instanceof TaintStore) and
72+
state2 instanceof TaintStore
73+
)
74+
or
75+
exists(DataFlow::Content c |
76+
readStep(node1, c, node2) and
77+
isRelevantContent(c) and
78+
state1 instanceof TaintRead and
79+
state2 instanceof TaintRead
80+
)
5881
}
5982

83+
override predicate isSanitizer(DataFlow::Node n) { not isRelevantType(n.getType()) }
84+
6085
override DataFlow::FlowFeature getAFeature() {
6186
result instanceof DataFlow::FeatureEqualSourceSinkCallContext
6287
}
6388
}
6489

6590
/**
66-
* Capture APIs that return tainted instance data.
67-
* Example of an API that returns tainted instance data:
91+
* Capture APIs that transfer taint from an input parameter to an output return
92+
* value or parameter.
93+
* Allows a sequence of read steps followed by a sequence of store steps.
94+
*
95+
* Examples:
96+
*
6897
* ```
6998
* public class Foo {
7099
* private String tainted;
@@ -83,48 +112,7 @@ class FieldToReturnConfig extends TaintTracking::Configuration {
83112
* p;Foo;true;returnsTainted;;Argument[-1];ReturnValue;taint
84113
* p;Foo;true;putsTaintIntoParameter;(List);Argument[-1];Argument[0];taint
85114
* ```
86-
*/
87-
string captureFieldFlow(TargetAPI api) {
88-
exists(FieldToReturnConfig config, ReturnNodeExt returnNodeExt |
89-
config.hasFlow(_, returnNodeExt) and
90-
returnNodeExt.getEnclosingCallable() = api and
91-
not api.getDeclaringType() instanceof EnumType and
92-
isRelevantType(returnNodeExt.getType())
93-
|
94-
result = asTaintModel(api, "Argument[-1]", returnNodeAsOutput(api, returnNodeExt))
95-
)
96-
}
97-
98-
class ParameterToFieldConfig extends TaintTracking::Configuration {
99-
ParameterToFieldConfig() { this = "ParameterToFieldConfig" }
100-
101-
override predicate isSource(DataFlow::Node source) {
102-
source instanceof DataFlow::ParameterNode and
103-
isRelevantType(source.getType())
104-
}
105-
106-
override predicate isSink(DataFlow::Node sink) {
107-
thisAccess(sink.(DataFlow::PostUpdateNode).getPreUpdateNode())
108-
}
109-
110-
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
111-
store(node1, _, node2, _)
112-
}
113-
114-
override DataFlow::FlowFeature getAFeature() {
115-
result instanceof DataFlow::FeatureEqualSourceSinkCallContext
116-
}
117-
}
118-
119-
private predicate thisAccess(DataFlow::Node n) {
120-
n.asExpr().(InstanceAccess).isOwnInstanceAccess()
121-
or
122-
n.(DataFlow::ImplicitInstanceAccess).getInstanceAccess() instanceof OwnInstanceAccess
123-
}
124-
125-
/**
126-
* Captures APIs that accept input and store them in a field.
127-
* Example:
115+
*
128116
* ```
129117
* public class Foo {
130118
* private String tainted;
@@ -134,96 +122,38 @@ private predicate thisAccess(DataFlow::Node n) {
134122
* ```
135123
* Captured Model:
136124
* `p;Foo;true;doSomething;(String);Argument[0];Argument[-1];taint`
137-
*/
138-
string captureFieldFlowIn(TargetAPI api) {
139-
exists(DataFlow::Node source, ParameterToFieldConfig config |
140-
config.hasFlow(source, _) and
141-
source.asParameter().getCallable() = api
142-
|
143-
result =
144-
asTaintModel(api, "Argument[" + source.asParameter().getPosition() + "]", "Argument[-1]")
145-
)
146-
}
147-
148-
class ParameterToReturnValueTaintConfig extends TaintTracking::Configuration {
149-
ParameterToReturnValueTaintConfig() { this = "ParameterToReturnValueTaintConfig" }
150-
151-
override predicate isSource(DataFlow::Node source) {
152-
exists(TargetAPI api |
153-
api = source.asParameter().getCallable() and
154-
isRelevantType(api.getReturnType()) and
155-
isRelevantType(source.asParameter().getType())
156-
)
157-
}
158-
159-
override predicate isSink(DataFlow::Node sink) { sink instanceof ReturnNode }
160-
161-
// consider store steps to track taint across objects to model factory methods returning tainted objects
162-
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
163-
store(node1, _, node2, _)
164-
}
165-
166-
override DataFlow::FlowFeature getAFeature() {
167-
result instanceof DataFlow::FeatureEqualSourceSinkCallContext
168-
}
169-
}
170-
171-
predicate paramFlowToReturnValueExists(Parameter p) {
172-
exists(ParameterToReturnValueTaintConfig config, ReturnStmt rtn |
173-
config.hasFlow(DataFlow::parameterNode(p), DataFlow::exprNode(rtn.getResult()))
174-
)
175-
}
176-
177-
/**
178-
* Capture APIs that return (parts of) data passed in as a parameter.
179-
* Example:
125+
*
180126
* ```
181127
* public class Foo {
182-
*
183128
* public String returnData(String tainted) {
184129
* return tainted.substring(0,10)
185130
* }
186131
* }
187132
* ```
188133
* Captured Model:
189-
* ```
190-
* p;Foo;true;returnData;;Argument[0];ReturnValue;taint
191-
* ```
192-
*/
193-
string captureParameterFlowToReturnValue(TargetAPI api) {
194-
exists(Parameter p |
195-
p = api.getAParameter() and
196-
paramFlowToReturnValueExists(p)
197-
|
198-
result = asTaintModel(api, parameterAccess(p), "ReturnValue")
199-
)
200-
}
201-
202-
/**
203-
* Capture APIs that pass tainted data from a parameter to a parameter.
204-
* Example:
134+
* `p;Foo;true;returnData;;Argument[0];ReturnValue;taint`
135+
*
205136
* ```
206137
* public class Foo {
207-
*
208138
* public void addToList(String tainted, List<String> foo) {
209139
* foo.add(tainted);
210140
* }
211141
* }
212142
* ```
213143
* Captured Model:
214-
* ```
215-
* p;Foo;true;addToList;;Argument[0];Argument[1];taint
216-
* ```
144+
* `p;Foo;true;addToList;;Argument[0];Argument[1];taint`
217145
*/
218-
string captureParameterToParameterFlow(TargetAPI api) {
219-
exists(DataFlow::ParameterNode source, DataFlow::PostUpdateNode sink |
220-
source.getEnclosingCallable() = api and
221-
sink.getPreUpdateNode().asExpr() = api.getAParameter().getAnAccess() and
222-
TaintTracking::localTaint(source, sink)
146+
string captureThroughFlow(TargetAPI api) {
147+
exists(
148+
ThroughFlowConfig config, DataFlow::ParameterNode p, ReturnNodeExt returnNodeExt, string input,
149+
string output
223150
|
224-
result =
225-
asTaintModel(api, parameterAccess(source.asParameter()),
226-
parameterAccess(sink.getPreUpdateNode().asExpr().(VarAccess).getVariable()))
151+
config.hasFlow(p, returnNodeExt) and
152+
returnNodeExt.getEnclosingCallable() = api and
153+
input = parameterNodeAsInput(p) and
154+
output = returnNodeAsOutput(api, returnNodeExt) and
155+
input != output and
156+
result = asTaintModel(api, input, output)
227157
)
228158
}
229159

java/ql/src/utils/model-generator/ModelGeneratorUtils.qll

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,11 +151,29 @@ predicate isRelevantTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
151151
)
152152
}
153153

154+
predicate isRelevantContent(DataFlow::Content f) {
155+
isRelevantType(f.(DataFlow::FieldContent).getField().getType()) or
156+
f instanceof DataFlow::ArrayContent or
157+
f instanceof DataFlow::CollectionContent or
158+
f instanceof DataFlow::MapKeyContent or
159+
f instanceof DataFlow::MapValueContent
160+
}
161+
162+
string parameterNodeAsInput(DataFlow::ParameterNode p) {
163+
result = parameterAccess(p.asParameter())
164+
or
165+
result = "Argument[-1]" and p instanceof DataFlow::InstanceParameterNode
166+
}
167+
154168
string returnNodeAsOutput(TargetAPI api, ReturnNodeExt node) {
155169
if node.getKind() instanceof ValueReturnKind
156170
then result = "ReturnValue"
157171
else
158-
result = parameterAccess(api.getParameter(node.getKind().(ParamUpdateReturnKind).getPosition()))
172+
exists(int pos | pos = node.getKind().(ParamUpdateReturnKind).getPosition() |
173+
result = parameterAccess(api.getParameter(pos))
174+
or
175+
result = "Argument[-1]" and pos = -1
176+
)
159177
}
160178

161179
string parameterAccess(Parameter p) {

0 commit comments

Comments
 (0)