@@ -7,13 +7,14 @@ import swift
77import codeql.swift.dataflow.DataFlow
88
99/**
10- * A flow state for encoding types of Swift string encoding.
10+ * A type of Swift string encoding. This class is used as a flow state for
11+ * the string length conflation taint tracking configuration.
1112 */
12- class StringLengthConflationFlowState extends string {
13- string equivClass ;
13+ class StringType extends string {
1414 string singular ;
15+ string equivClass ;
1516
16- StringLengthConflationFlowState ( ) {
17+ StringType ( ) {
1718 this = "String" and singular = "a String" and equivClass = "String"
1819 or
1920 this = "NSString" and singular = "an NSString" and equivClass = "NSString"
@@ -38,3 +39,159 @@ class StringLengthConflationFlowState extends string {
3839 */
3940 string getSingular ( ) { result = singular }
4041}
42+
43+ /**
44+ * A dataflow source for string length conflation vulnerabilities. That is,
45+ * a `DataFlow::Node` where a string length is generated.
46+ */
47+ abstract class StringLengthConflationSource extends DataFlow:: Node {
48+ /**
49+ * Gets the `StringType` for this source.
50+ */
51+ abstract StringType getStringType ( ) ;
52+ }
53+
54+ /**
55+ * A dataflow sink for string length conflation vulnerabilities. That is,
56+ * a `DataFlow::Node` where a string length is used.
57+ */
58+ abstract class StringLengthConflationSink extends DataFlow:: Node {
59+ /**
60+ * Gets the correct `StringType` for this sink.
61+ */
62+ abstract StringType getCorrectStringType ( ) ;
63+ }
64+
65+ abstract class StringLengthConflationSanitizer extends DataFlow:: Node { }
66+
67+ /**
68+ * A unit class for adding additional taint steps.
69+ */
70+ class StringLengthConflationAdditionalTaintStep extends Unit {
71+ /**
72+ * Holds if the step from `node1` to `node2` should be considered a taint
73+ * step for paths related to string length conflation vulnerabilities.
74+ */
75+ abstract predicate step ( DataFlow:: Node nodeFrom , DataFlow:: Node nodeTo ) ;
76+ }
77+
78+ private class DefaultStringLengthConflationSource extends StringLengthConflationSource {
79+ StringType stringType ;
80+
81+ DefaultStringLengthConflationSource ( ) {
82+ exists ( MemberRefExpr memberRef , string className , string varName |
83+ memberRef .getBase ( ) .getType ( ) .( NominalType ) .getABaseType * ( ) .getName ( ) = className and
84+ memberRef .getMember ( ) .( VarDecl ) .getName ( ) = varName and
85+ this .asExpr ( ) = memberRef and
86+ (
87+ // result of a call to `String.count`
88+ className = "String" and
89+ varName = "count" and
90+ stringType = "String"
91+ or
92+ // result of a call to `NSString.length`
93+ className = [ "NSString" , "NSMutableString" ] and
94+ varName = "length" and
95+ stringType = "NSString"
96+ or
97+ // result of a call to `String.utf8.count`
98+ className = "String.UTF8View" and
99+ varName = "count" and
100+ stringType = "String.utf8"
101+ or
102+ // result of a call to `String.utf16.count`
103+ className = "String.UTF16View" and
104+ varName = "count" and
105+ stringType = "String.utf16"
106+ or
107+ // result of a call to `String.unicodeScalars.count`
108+ className = "String.UnicodeScalarView" and
109+ varName = "count" and
110+ stringType = "String.unicodeScalars"
111+ )
112+ )
113+ }
114+
115+ override StringType getStringType ( ) { result = stringType }
116+ }
117+
118+ private class DefaultStringLengthConflationSink extends StringLengthConflationSink {
119+ StringType correctStringType ;
120+
121+ DefaultStringLengthConflationSink ( ) {
122+ exists ( AbstractFunctionDecl funcDecl , CallExpr call , string funcName , int arg |
123+ (
124+ // arguments to method calls...
125+ exists ( string className , ClassOrStructDecl c |
126+ (
127+ // `NSRange.init`
128+ className = "NSRange" and
129+ funcName = "init(location:length:)" and
130+ arg = [ 0 , 1 ]
131+ or
132+ // `NSString.character`
133+ className = [ "NSString" , "NSMutableString" ] and
134+ funcName = "character(at:)" and
135+ arg = 0
136+ or
137+ // `NSString.character`
138+ className = [ "NSString" , "NSMutableString" ] and
139+ funcName = "substring(from:)" and
140+ arg = 0
141+ or
142+ // `NSString.character`
143+ className = [ "NSString" , "NSMutableString" ] and
144+ funcName = "substring(to:)" and
145+ arg = 0
146+ or
147+ // `NSMutableString.insert`
148+ className = "NSMutableString" and
149+ funcName = "insert(_:at:)" and
150+ arg = 1
151+ ) and
152+ c .getName ( ) = className and
153+ c .getABaseTypeDecl * ( ) .( ClassOrStructDecl ) .getAMember ( ) = funcDecl and
154+ call .getStaticTarget ( ) = funcDecl and
155+ correctStringType = "NSString"
156+ )
157+ or
158+ // arguments to function calls...
159+ // `NSMakeRange`
160+ funcName = "NSMakeRange(_:_:)" and
161+ arg = [ 0 , 1 ] and
162+ call .getStaticTarget ( ) = funcDecl and
163+ correctStringType = "NSString"
164+ or
165+ // arguments to method calls...
166+ (
167+ // `String.dropFirst`, `String.dropLast`, `String.removeFirst`, `String.removeLast`
168+ funcName = [ "dropFirst(_:)" , "dropLast(_:)" , "removeFirst(_:)" , "removeLast(_:)" ] and
169+ arg = 0
170+ or
171+ // `String.prefix`, `String.suffix`
172+ funcName = [ "prefix(_:)" , "suffix(_:)" ] and
173+ arg = 0
174+ or
175+ // `String.Index.init`
176+ funcName = "init(encodedOffset:)" and
177+ arg = 0
178+ or
179+ // `String.index`
180+ funcName = [ "index(_:offsetBy:)" , "index(_:offsetBy:limitBy:)" ] and
181+ arg = [ 0 , 1 ]
182+ or
183+ // `String.formIndex`
184+ funcName = [ "formIndex(_:offsetBy:)" , "formIndex(_:offsetBy:limitBy:)" ] and
185+ arg = [ 0 , 1 ]
186+ ) and
187+ call .getStaticTarget ( ) = funcDecl and
188+ correctStringType = "String"
189+ ) and
190+ // match up `funcName`, `arg`, `node`.
191+ funcDecl .getName ( ) = funcName and
192+ call .getArgument ( arg ) .getExpr ( ) = this .asExpr ( )
193+ )
194+ }
195+
196+ override StringType getCorrectStringType ( ) { result = correctStringType }
197+ }
0 commit comments