@@ -159,6 +159,44 @@ 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 ( [ "checkedCollection" , "checkedList" , "checkedMap" , "checkedNavigableMap" ,
171+ "checkedNavigableSet" , "checkedSet" , "checkedSortedMap" , "checkedSortedSet" ,
172+ "enumeration" , "list" , "max" , "min" , "singleton" , "singletonList" ,
173+ "synchronizedCollection" , "synchronizedList" , "synchronizedMap" ,
174+ "synchronizedNavigableMap" , "synchronizedNavigableSet" , "synchronizedSet" ,
175+ "synchronizedSortedMap" , "synchronizedSortedSet" , "unmodifiableCollection" ,
176+ "unmodifiableList" , "unmodifiableMap" , "unmodifiableNavigableMap" ,
177+ "unmodifiableNavigableSet" , "unmodifiableSet" , "unmodifiableSortedMap" ,
178+ "unmodifiableSortedSet" ] ) and
179+ arg = 0
180+ or
181+ method .hasName ( [ "nCopies" , "singletonMap" ] ) and arg = 1
182+ )
183+ }
184+
185+ /**
186+ * Holds if `method` is a library method that writes tainted data to the
187+ * `output`th argument if the `input`th argument is tainted.
188+ */
189+ private predicate taintPreservingArgToArg ( Method method , int input , int output ) {
190+ method .getDeclaringType ( ) .hasQualifiedName ( "java.util" , "Collections" ) and
191+ (
192+ method .hasName ( [ "copy" , "fill" ] ) and
193+ input = 1 and
194+ output = 0
195+ or
196+ method .hasName ( "replaceAll" ) and input = 2 and output = 0
197+ )
198+ }
199+
162200private predicate argToQualifierStep ( Expr tracked , Expr sink ) {
163201 exists ( Method m , int i , MethodAccess ma |
164202 taintPreservingArgumentToQualifier ( m , i ) and
@@ -168,13 +206,44 @@ private predicate argToQualifierStep(Expr tracked, Expr sink) {
168206 )
169207}
170208
209+ /** Access to a method that passes taint from an argument. */
210+ private predicate argToMethodStep ( Expr tracked , MethodAccess sink ) {
211+ exists ( Method m , int i |
212+ m = sink .getMethod ( ) and
213+ taintPreservingArgumentToMethod ( m , i ) and
214+ tracked = sink .getArgument ( i )
215+ )
216+ }
217+
218+ /**
219+ * Holds if `tracked` and `sink` are arguments to a method that transfers taint
220+ * between arguments.
221+ */
222+ private predicate argToArgStep ( Expr tracked , Expr sink ) {
223+ exists ( MethodAccess ma , Method method , int input , int output |
224+ ma .getMethod ( ) = method and
225+ ma .getArgument ( input ) = tracked and
226+ ma .getArgument ( output ) = sink and
227+ (
228+ taintPreservingArgToArg ( method , input , output )
229+ or
230+ method .getDeclaringType ( ) .hasQualifiedName ( "java.util" , "Collections" ) and
231+ method .hasName ( "addAll" ) and
232+ input >= 1 and
233+ output = 0
234+ )
235+ )
236+ }
237+
171238/**
172239 * Holds if the step from `n1` to `n2` is either extracting a value from a
173240 * container, inserting a value into a container, or transforming one container
174241 * to another. This is restricted to cases where `n2` is the returned value of
175242 * a call.
176243 */
177- predicate containerReturnValueStep ( Expr n1 , Expr n2 ) { qualifierToMethodStep ( n1 , n2 ) }
244+ predicate containerReturnValueStep ( Expr n1 , Expr n2 ) {
245+ qualifierToMethodStep ( n1 , n2 ) or argToMethodStep ( n1 , n2 )
246+ }
178247
179248/**
180249 * Holds if the step from `n1` to `n2` is either extracting a value from a
@@ -183,7 +252,8 @@ predicate containerReturnValueStep(Expr n1, Expr n2) { qualifierToMethodStep(n1,
183252 */
184253predicate containerUpdateStep ( Expr n1 , Expr n2 ) {
185254 qualifierToArgumentStep ( n1 , n2 ) or
186- argToQualifierStep ( n1 , n2 )
255+ argToQualifierStep ( n1 , n2 ) or
256+ argToArgStep ( n1 , n2 )
187257}
188258
189259/**
0 commit comments