@@ -14,6 +14,24 @@ import swift
1414import codeql.swift.dataflow.DataFlow
1515import DataFlow:: PathGraph
1616
17+ /**
18+ * A flow state for this query, which is a type of Swift string encoding.
19+ */
20+ class StringLengthConflationFlowState extends string {
21+ string singular ;
22+
23+ StringLengthConflationFlowState ( ) {
24+ this = "String" and singular = "a String"
25+ or
26+ this = "NSString" and singular = "an NSString"
27+ }
28+
29+ /**
30+ * Gets text for the singular form of this flow state.
31+ */
32+ string getSingular ( ) { result = singular }
33+ }
34+
1735/**
1836 * A configuration for tracking string lengths originating from source that is
1937 * a `String` or an `NSString` object, to a sink of a different kind that
@@ -40,7 +58,11 @@ class StringLengthConflationConfiguration extends DataFlow::Configuration {
4058 )
4159 }
4260
43- override predicate isSink ( DataFlow:: Node node , string flowstate ) {
61+ /**
62+ * Holds if `node` is a sink and `flowstate` is the *correct* flow state for
63+ * that sink. We actually want to report incorrect flow states.
64+ */
65+ predicate isSinkImpl ( DataFlow:: Node node , string flowstate ) {
4466 // arguments to method calls...
4567 exists (
4668 string className , string methodName , string paramName , ClassDecl c , AbstractFunctionDecl f ,
@@ -78,7 +100,7 @@ class StringLengthConflationConfiguration extends DataFlow::Configuration {
78100 f .getName ( ) = methodName and
79101 f .getParam ( pragma [ only_bind_into ] ( arg ) ) .getName ( ) = paramName and
80102 call .getArgument ( pragma [ only_bind_into ] ( arg ) ) .getExpr ( ) = node .asExpr ( ) and
81- flowstate = "String" // `String` length flowing into ` NSString`
103+ flowstate = "NSString"
82104 )
83105 or
84106 // arguments to function calls...
@@ -89,7 +111,7 @@ class StringLengthConflationConfiguration extends DataFlow::Configuration {
89111 call .getStaticTarget ( ) .getName ( ) = funcName and
90112 call .getStaticTarget ( ) .getParam ( pragma [ only_bind_into ] ( arg ) ) .getName ( ) = paramName and
91113 call .getArgument ( pragma [ only_bind_into ] ( arg ) ) .getExpr ( ) = node .asExpr ( ) and
92- flowstate = "String" // `String` length flowing into ` NSString`
114+ flowstate = "NSString"
93115 )
94116 or
95117 // arguments to function calls...
@@ -122,7 +144,16 @@ class StringLengthConflationConfiguration extends DataFlow::Configuration {
122144 .getParam ( pragma [ only_bind_into ] ( arg ) )
123145 .getName ( ) = paramName and
124146 call .getArgument ( pragma [ only_bind_into ] ( arg ) ) .getExpr ( ) = node .asExpr ( ) and
125- flowstate = "NSString" // `NSString` length flowing into `String`
147+ flowstate = "String"
148+ )
149+ }
150+
151+ override predicate isSink ( DataFlow:: Node node , string flowstate ) {
152+ // Permit any *incorrect* flowstate, as those are the results the query
153+ // should report.
154+ exists ( string correctFlowState |
155+ isSinkImpl ( node , correctFlowState ) and
156+ flowstate .( StringLengthConflationFlowState ) != correctFlowState
126157 )
127158 }
128159
@@ -134,15 +165,13 @@ class StringLengthConflationConfiguration extends DataFlow::Configuration {
134165
135166from
136167 StringLengthConflationConfiguration config , DataFlow:: PathNode source , DataFlow:: PathNode sink ,
137- string flowstate , string message
168+ StringLengthConflationFlowState sourceFlowState , StringLengthConflationFlowState sinkFlowstate ,
169+ string message
138170where
139171 config .hasFlowPath ( source , sink ) and
140- config .isSink ( sink .getNode ( ) , flowstate ) and
141- (
142- flowstate = "String" and
143- message = "This String length is used in an NSString, but it may not be equivalent."
144- or
145- flowstate = "NSString" and
146- message = "This NSString length is used in a String, but it may not be equivalent."
147- )
172+ config .isSource ( source .getNode ( ) , sourceFlowState ) and
173+ config .isSinkImpl ( sink .getNode ( ) , sinkFlowstate ) and
174+ message =
175+ "This " + sourceFlowState + " length is used in " + sinkFlowstate .getSingular ( ) +
176+ ", but it may not be equivalent."
148177select sink .getNode ( ) , source , sink , message
0 commit comments