@@ -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+
162197private 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 */
184243predicate 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