Skip to content

Commit 5cf5c77

Browse files
committed
Java: model java.util.Collections
1 parent a2677f8 commit 5cf5c77

File tree

1 file changed

+62
-2
lines changed

1 file changed

+62
-2
lines changed

java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,41 @@ private predicate taintPreservingArgumentToQualifier(Method method, int arg) {
159159
method.(CollectionMethod).hasName("offer") and arg = 0
160160
}
161161

162+
/**
163+
* Holds if `method` is a library method that returns tainted data if its
164+
* `arg`th argument is tainted.
165+
*/
166+
private predicate taintPreservingArgumentToMethod(Method method, int arg) {
167+
method.getDeclaringType().hasQualifiedName("java.util", "Collections") and
168+
(
169+
method
170+
.hasName(["singleton", "singletonList", "singletonMap", "enumeration", "list", "max", "min",
171+
"asLifoQueue", "checkedCollection", "checkedList", "checkedMap", "checkedSet",
172+
"checkedSortedMap", "checkedSortedSet", "synchronizedCollection", "synchronizedList",
173+
"synchronizedMap", "synchronizedSet", "synchronizedSortedMap",
174+
"synchronizedSortedSet", "unmodifiableCollection", "unmodifiableList",
175+
"unmodifiableMap", "unmodifiableSet", "unmodifiableSortedMap", "unmodifiableSortedSet"]) and
176+
arg = 0
177+
or
178+
method.hasName(["nCopies", "singletonMap"]) and arg = 1
179+
)
180+
}
181+
182+
/**
183+
* Holds if `method` is a library method that writes tainted data to the
184+
* `output`th argument if the `input`th argument is tainted.
185+
*/
186+
private predicate taintPreservingArgToArg(Method method, int input, int output) {
187+
method.getDeclaringType().hasQualifiedName("java.util", "Collections") and
188+
(
189+
method.hasName(["copy", "fill"]) and
190+
input = 1 and
191+
output = 0
192+
or
193+
method.hasName("replaceAll") and input = 2 and output = 0
194+
)
195+
}
196+
162197
private predicate argToQualifierStep(Expr tracked, Expr sink) {
163198
exists(Method m, int i, MethodAccess ma |
164199
taintPreservingArgumentToQualifier(m, i) and
@@ -168,13 +203,37 @@ private predicate argToQualifierStep(Expr tracked, Expr sink) {
168203
)
169204
}
170205

206+
/** Access to a method that passes taint from an argument. */
207+
private predicate argToMethodStep(Expr tracked, MethodAccess sink) {
208+
exists(Method m, int i |
209+
m = sink.(MethodAccess).getMethod() and
210+
taintPreservingArgumentToMethod(m, i) and
211+
tracked = sink.(MethodAccess).getArgument(i)
212+
)
213+
}
214+
215+
/**
216+
* Holds if `tracked` and `sink` are arguments to a method that transfers taint
217+
* between arguments.
218+
*/
219+
private predicate argToArgStep(Expr tracked, Expr sink) {
220+
exists(MethodAccess ma, Method method, int input, int output |
221+
taintPreservingArgToArg(method, input, output) and
222+
ma.getMethod() = method and
223+
ma.getArgument(input) = tracked and
224+
ma.getArgument(output) = sink
225+
)
226+
}
227+
171228
/**
172229
* Holds if the step from `n1` to `n2` is either extracting a value from a
173230
* container, inserting a value into a container, or transforming one container
174231
* to another. This is restricted to cases where `n2` is the returned value of
175232
* a call.
176233
*/
177-
predicate containerReturnValueStep(Expr n1, Expr n2) { qualifierToMethodStep(n1, n2) }
234+
predicate containerReturnValueStep(Expr n1, Expr n2) {
235+
qualifierToMethodStep(n1, n2) or argToMethodStep(n1, n2)
236+
}
178237

179238
/**
180239
* Holds if the step from `n1` to `n2` is either extracting a value from a
@@ -183,7 +242,8 @@ predicate containerReturnValueStep(Expr n1, Expr n2) { qualifierToMethodStep(n1,
183242
*/
184243
predicate containerUpdateStep(Expr n1, Expr n2) {
185244
qualifierToArgumentStep(n1, n2) or
186-
argToQualifierStep(n1, n2)
245+
argToQualifierStep(n1, n2) or
246+
argToArgStep(n1, n2)
187247
}
188248

189249
/**

0 commit comments

Comments
 (0)