@@ -8,6 +8,8 @@ private import codeql.swift.StringFormat
88private import codeql.swift.dataflow.DataFlow
99private import codeql.swift.dataflow.TaintTracking
1010private import codeql.swift.dataflow.ExternalFlow
11+ private import codeql.swift.frameworks.StandardLibrary.PointerTypes
12+ private import codeql.swift.security.PredicateInjectionExtensions
1113
1214/**
1315 * A dataflow sink for uncontrolled format string vulnerabilities.
@@ -43,6 +45,49 @@ private class DefaultUncontrolledFormatStringSink extends UncontrolledFormatStri
4345 }
4446}
4547
48+ /**
49+ * Holds if `f`, `ix` describe `pd` and `pd` is a parameter that might be a format
50+ * string.
51+ */
52+ pragma [ noinline]
53+ predicate formatLikeHeuristic ( Callable f , int ix , ParamDecl pd ) {
54+ pd .getName ( ) = [ "format" , "formatString" , "fmt" ] and
55+ pd = f .getParam ( ix )
56+ }
57+
58+ /**
59+ * An uncontrolled format string sink that is determined by imprecise methods.
60+ */
61+ class HeuristicUncontrolledFormatStringSink extends UncontrolledFormatStringSink {
62+ HeuristicUncontrolledFormatStringSink ( ) {
63+ exists ( Callable f , Type argsType |
64+ (
65+ // by parameter name
66+ exists ( CallExpr ce , int ix |
67+ formatLikeHeuristic ( f , ix , _) and
68+ f = ce .getStaticTarget ( ) and
69+ this .asExpr ( ) = ce .getArgument ( ix ) .getExpr ( )
70+ )
71+ or
72+ // by argument name
73+ exists ( Argument a |
74+ a .getLabel ( ) = [ "format" , "formatString" , "fmt" ] and
75+ a .getApplyExpr ( ) .getStaticTarget ( ) = f and
76+ this .asExpr ( ) = a .getExpr ( )
77+ )
78+ ) and
79+ // last parameter is vararg
80+ argsType = f .getParam ( f .getNumberOfParams ( ) - 1 ) .getType ( ) .getUnderlyingType ( ) and
81+ (
82+ argsType instanceof CVaListPointerType or
83+ argsType instanceof VariadicSequenceType
84+ )
85+ ) and
86+ // prevent overlap with `swift/predicate-injection`
87+ not this instanceof PredicateInjectionSink
88+ }
89+ }
90+
4691/**
4792 * A barrier for uncontrolled format string vulnerabilities.
4893 */
0 commit comments