@@ -248,20 +248,85 @@ private Expr getAHostnameSanitizingPrefix() {
248248 result .( AddExpr ) .getAnOperand ( ) = getAHostnameSanitizingPrefix ( )
249249}
250250
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+ }
253256}
254257
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+ }
256304
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 ( )
260316 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+ }
265330}
266331
267332/**
@@ -275,25 +340,14 @@ private class HostnameSanitizedExpr extends Expr {
275340 this =
276341 any ( AddExpr add | add .getLeftOperand ( ) = getAHostnameSanitizingPrefix ( ) ) .getRightOperand ( )
277342 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
292343 // 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
295349 appendSanitizingConstant .getArgument ( 0 ) = getAHostnameSanitizingPrefix ( ) and
296- getNextAppend * ( appendSanitizingConstant ) = subsequentAppend and
350+ v . getSubsequentAppendIncludingAssignmentChains ( appendSanitizingConstant ) = subsequentAppend and
297351 this = subsequentAppend .getArgument ( 0 )
298352 )
299353 or
0 commit comments