@@ -248,20 +248,85 @@ private Expr getAHostnameSanitizingPrefix() {
248
248
result .( AddExpr ) .getAnOperand ( ) = getAHostnameSanitizingPrefix ( )
249
249
}
250
250
251
- private MethodAccess getNextAppend ( MethodAccess append ) {
252
- result = any ( StringBuilderVar sbv ) .getNextAppend ( append )
251
+ private class StringBuilderAppend extends MethodAccess {
252
+ StringBuilderAppend ( ) {
253
+ this .getMethod ( ) .getDeclaringType ( ) instanceof StringBuildingType and
254
+ this .getMethod ( ) .hasName ( "append" )
255
+ }
253
256
}
254
257
255
- private Expr getQualifier ( MethodAccess e ) { result = e .getQualifier ( ) }
258
+ private class StringBuilderConstructorOrAppend extends Call {
259
+ StringBuilderConstructorOrAppend ( ) {
260
+ this instanceof StringBuilderAppend or
261
+ this .( ClassInstanceExpr ) .getConstructedType ( ) instanceof StringBuildingType
262
+ }
263
+ }
264
+
265
+ private Expr getQualifier ( Expr e ) { result = e .( MethodAccess ) .getQualifier ( ) }
266
+
267
+ /**
268
+ * An extension of `StringBuilderVar` that also accounts for strings appended in StringBuilder/Buffer's constructor
269
+ * and in `append` calls chained onto the constructor call.
270
+ *
271
+ * The original `StringBuilderVar` doesn't care about these because it is designed to model taint, and
272
+ * in taint rules terms these are not needed, as the connection between construction, appends and the
273
+ * eventual `toString` is more obvious.
274
+ */
275
+ private class StringBuilderVarExt extends StringBuilderVar {
276
+ /**
277
+ * Returns a first assignment after this StringBuilderVar is first assigned.
278
+ *
279
+ * For example, for `StringBuilder sbv = new StringBuilder("1").append("2"); sbv.append("3").append("4");`
280
+ * this returns the append of `"3"`.
281
+ */
282
+ private StringBuilderAppend getAFirstAppendAfterAssignment ( ) {
283
+ //
284
+ result = this .getAnAppend ( ) and not result = this .getNextAppend ( _)
285
+ }
286
+
287
+ /**
288
+ * Gets the next `append` after `prev`, where `prev` is, perhaps after some more `append` or other
289
+ * chained calls, assigned to this `StringBuilderVar`.
290
+ */
291
+ private StringBuilderAppend getNextAssignmentChainedAppend ( StringBuilderConstructorOrAppend prev ) {
292
+ getQualifier * ( result ) = this .getAnAssignedValue ( ) and
293
+ result .getQualifier ( ) = prev
294
+ }
295
+
296
+ /**
297
+ * Get a constructor call or `append` call that contributes a string to this string builder.
298
+ */
299
+ StringBuilderConstructorOrAppend getAConstructorOrAppend ( ) {
300
+ exists ( this .getNextAssignmentChainedAppend ( result ) ) or
301
+ result = this .getAnAssignedValue ( ) or
302
+ result = this .getAnAppend ( )
303
+ }
256
304
257
- private MethodAccess getAChainedAppend ( Expr e ) {
258
- (
259
- result .getQualifier ( ) = e
305
+ /**
306
+ * Like `StringBuilderVar.getNextAppend`, except including appends and constructors directly
307
+ * assigned to this `StringBuilderVar`.
308
+ */
309
+ private StringBuilderAppend getNextAppendIncludingAssignmentChains (
310
+ StringBuilderConstructorOrAppend prev
311
+ ) {
312
+ result = getNextAssignmentChainedAppend ( prev )
313
+ or
314
+ prev = this .getAnAssignedValue ( ) and
315
+ result = this .getAFirstAppendAfterAssignment ( )
260
316
or
261
- result .getQualifier ( ) = getAChainedAppend ( e )
262
- ) and
263
- result .getCallee ( ) .getDeclaringType ( ) instanceof StringBuildingType and
264
- result .getCallee ( ) .getName ( ) = "append"
317
+ result = this .getNextAppend ( prev )
318
+ }
319
+
320
+ /**
321
+ * Implements `StringBuilderVarExt.getNextAppendIncludingAssignmentChains+(prev)`.
322
+ */
323
+ StringBuilderAppend getSubsequentAppendIncludingAssignmentChains (
324
+ StringBuilderConstructorOrAppend prev
325
+ ) {
326
+ result = this .getNextAppendIncludingAssignmentChains ( prev ) or
327
+ result =
328
+ this .getSubsequentAppendIncludingAssignmentChains ( this .getNextAppendIncludingAssignmentChains ( prev ) )
329
+ }
265
330
}
266
331
267
332
/**
@@ -275,25 +340,14 @@ private class HostnameSanitizedExpr extends Expr {
275
340
this =
276
341
any ( AddExpr add | add .getLeftOperand ( ) = getAHostnameSanitizingPrefix ( ) ) .getRightOperand ( )
277
342
or
278
- // Sanitize all appends to a StringBuilder that is initialized with a sanitizing prefix:
279
- // (note imprecision: if the same StringBuilder/StringBuffer has more than one constructor call,
280
- // this sanitizes all of its append calls, not just those that may follow the constructor).
281
- exists ( StringBuilderVar sbv , ConstructorCall constructor , Expr initializer |
282
- initializer = sbv .getAnAssignedValue ( ) and
283
- constructor = getQualifier * ( initializer ) and
284
- constructor .getArgument ( 0 ) = getAHostnameSanitizingPrefix ( ) and
285
- (
286
- this = sbv .getAnAppend ( ) .getArgument ( 0 )
287
- or
288
- this = getAChainedAppend ( constructor ) .getArgument ( 0 )
289
- )
290
- )
291
- or
292
343
// Sanitize expressions that come after a sanitizing prefix in a sequence of StringBuilder operations:
293
- exists ( MethodAccess appendSanitizingConstant , MethodAccess subsequentAppend |
294
- appendSanitizingConstant = any ( StringBuilderVar v ) .getAnAppend ( ) and
344
+ exists (
345
+ StringBuilderConstructorOrAppend appendSanitizingConstant ,
346
+ StringBuilderAppend subsequentAppend , StringBuilderVarExt v
347
+ |
348
+ appendSanitizingConstant = v .getAConstructorOrAppend ( ) and
295
349
appendSanitizingConstant .getArgument ( 0 ) = getAHostnameSanitizingPrefix ( ) and
296
- getNextAppend * ( appendSanitizingConstant ) = subsequentAppend and
350
+ v . getSubsequentAppendIncludingAssignmentChains ( appendSanitizingConstant ) = subsequentAppend and
297
351
this = subsequentAppend .getArgument ( 0 )
298
352
)
299
353
or
0 commit comments