Skip to content

Commit dfcad7f

Browse files
committed
Swift: Split the query into the usual three files.
1 parent 879dea2 commit dfcad7f

File tree

3 files changed

+182
-166
lines changed

3 files changed

+182
-166
lines changed
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/**
2+
* Provides classes and predicates for reasoning about string length
3+
* conflation vulnerabilities.
4+
*/
5+
6+
import swift
7+
import codeql.swift.dataflow.DataFlow
8+
9+
/**
10+
* A flow state for encoding types of Swift string encoding.
11+
*/
12+
class StringLengthConflationFlowState extends string {
13+
string equivClass;
14+
string singular;
15+
16+
StringLengthConflationFlowState() {
17+
this = "String" and singular = "a String" and equivClass = "String"
18+
or
19+
this = "NSString" and singular = "an NSString" and equivClass = "NSString"
20+
or
21+
this = "String.utf8" and singular = "a String.utf8" and equivClass = "String.utf8"
22+
or
23+
this = "String.utf16" and singular = "a String.utf16" and equivClass = "NSString"
24+
or
25+
this = "String.unicodeScalars" and
26+
singular = "a String.unicodeScalars" and
27+
equivClass = "String.unicodeScalars"
28+
}
29+
30+
/**
31+
* Gets the equivalence class for this flow state. If these are equal,
32+
* they should be treated as equivalent.
33+
*/
34+
string getEquivClass() { result = equivClass }
35+
36+
/**
37+
* Gets text for the singular form of this flow state.
38+
*/
39+
string getSingular() { result = singular }
40+
}
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
/**
2+
* Provides a taint-tracking configuration for reasoning about string length
3+
* conflation vulnerabilities.
4+
*/
5+
6+
import swift
7+
import codeql.swift.dataflow.DataFlow
8+
import codeql.swift.dataflow.TaintTracking
9+
import codeql.swift.security.StringLengthConflationExtensions
10+
11+
/**
12+
* A configuration for tracking string lengths originating from source that is
13+
* a `String` or an `NSString` object, to a sink of a different kind that
14+
* expects an incompatible measure of length.
15+
*/
16+
class StringLengthConflationConfiguration extends TaintTracking::Configuration {
17+
StringLengthConflationConfiguration() { this = "StringLengthConflationConfiguration" }
18+
19+
override predicate isSource(DataFlow::Node node, string flowstate) {
20+
exists(MemberRefExpr memberRef, string className, string varName |
21+
memberRef.getBase().getType().(NominalType).getABaseType*().getName() = className and
22+
memberRef.getMember().(VarDecl).getName() = varName and
23+
node.asExpr() = memberRef and
24+
(
25+
// result of a call to `String.count`
26+
className = "String" and
27+
varName = "count" and
28+
flowstate = "String"
29+
or
30+
// result of a call to `NSString.length`
31+
className = ["NSString", "NSMutableString"] and
32+
varName = "length" and
33+
flowstate = "NSString"
34+
or
35+
// result of a call to `String.utf8.count`
36+
className = "String.UTF8View" and
37+
varName = "count" and
38+
flowstate = "String.utf8"
39+
or
40+
// result of a call to `String.utf16.count`
41+
className = "String.UTF16View" and
42+
varName = "count" and
43+
flowstate = "String.utf16"
44+
or
45+
// result of a call to `String.unicodeScalars.count`
46+
className = "String.UnicodeScalarView" and
47+
varName = "count" and
48+
flowstate = "String.unicodeScalars"
49+
)
50+
)
51+
}
52+
53+
/**
54+
* Holds if `node` is a sink and `flowstate` is the *correct* flow state for
55+
* that sink. We actually want to report incorrect flow states.
56+
*/
57+
predicate isSinkImpl(DataFlow::Node node, string flowstate) {
58+
exists(AbstractFunctionDecl funcDecl, CallExpr call, string funcName, int arg |
59+
(
60+
// arguments to method calls...
61+
exists(string className, ClassOrStructDecl c |
62+
(
63+
// `NSRange.init`
64+
className = "NSRange" and
65+
funcName = "init(location:length:)" and
66+
arg = [0, 1]
67+
or
68+
// `NSString.character`
69+
className = ["NSString", "NSMutableString"] and
70+
funcName = "character(at:)" and
71+
arg = 0
72+
or
73+
// `NSString.character`
74+
className = ["NSString", "NSMutableString"] and
75+
funcName = "substring(from:)" and
76+
arg = 0
77+
or
78+
// `NSString.character`
79+
className = ["NSString", "NSMutableString"] and
80+
funcName = "substring(to:)" and
81+
arg = 0
82+
or
83+
// `NSMutableString.insert`
84+
className = "NSMutableString" and
85+
funcName = "insert(_:at:)" and
86+
arg = 1
87+
) and
88+
c.getName() = className and
89+
c.getABaseTypeDecl*().(ClassOrStructDecl).getAMember() = funcDecl and
90+
call.getStaticTarget() = funcDecl and
91+
flowstate = "NSString"
92+
)
93+
or
94+
// arguments to function calls...
95+
// `NSMakeRange`
96+
funcName = "NSMakeRange(_:_:)" and
97+
arg = [0, 1] and
98+
call.getStaticTarget() = funcDecl and
99+
flowstate = "NSString"
100+
or
101+
// arguments to method calls...
102+
(
103+
// `String.dropFirst`, `String.dropLast`, `String.removeFirst`, `String.removeLast`
104+
funcName = ["dropFirst(_:)", "dropLast(_:)", "removeFirst(_:)", "removeLast(_:)"] and
105+
arg = 0
106+
or
107+
// `String.prefix`, `String.suffix`
108+
funcName = ["prefix(_:)", "suffix(_:)"] and
109+
arg = 0
110+
or
111+
// `String.Index.init`
112+
funcName = "init(encodedOffset:)" and
113+
arg = 0
114+
or
115+
// `String.index`
116+
funcName = ["index(_:offsetBy:)", "index(_:offsetBy:limitBy:)"] and
117+
arg = [0, 1]
118+
or
119+
// `String.formIndex`
120+
funcName = ["formIndex(_:offsetBy:)", "formIndex(_:offsetBy:limitBy:)"] and
121+
arg = [0, 1]
122+
) and
123+
call.getStaticTarget() = funcDecl and
124+
flowstate = "String"
125+
) and
126+
// match up `funcName`, `arg`, `node`.
127+
funcDecl.getName() = funcName and
128+
call.getArgument(arg).getExpr() = node.asExpr()
129+
)
130+
}
131+
132+
override predicate isSink(DataFlow::Node node, string flowstate) {
133+
// Permit any *incorrect* flowstate, as those are the results the query
134+
// should report.
135+
exists(string correctFlowState |
136+
isSinkImpl(node, correctFlowState) and
137+
flowstate.(StringLengthConflationFlowState).getEquivClass() !=
138+
correctFlowState.(StringLengthConflationFlowState).getEquivClass()
139+
)
140+
}
141+
}

swift/ql/src/queries/Security/CWE-135/StringLengthConflation.ql

Lines changed: 1 addition & 166 deletions
Original file line numberDiff line numberDiff line change
@@ -12,174 +12,9 @@
1212

1313
import swift
1414
import codeql.swift.dataflow.DataFlow
15-
import codeql.swift.dataflow.TaintTracking
15+
import codeql.swift.security.StringLengthConflationQuery
1616
import DataFlow::PathGraph
1717

18-
/**
19-
* A flow state for this query, which is a type of Swift string encoding.
20-
*/
21-
class StringLengthConflationFlowState extends string {
22-
string equivClass;
23-
string singular;
24-
25-
StringLengthConflationFlowState() {
26-
this = "String" and singular = "a String" and equivClass = "String"
27-
or
28-
this = "NSString" and singular = "an NSString" and equivClass = "NSString"
29-
or
30-
this = "String.utf8" and singular = "a String.utf8" and equivClass = "String.utf8"
31-
or
32-
this = "String.utf16" and singular = "a String.utf16" and equivClass = "NSString"
33-
or
34-
this = "String.unicodeScalars" and
35-
singular = "a String.unicodeScalars" and
36-
equivClass = "String.unicodeScalars"
37-
}
38-
39-
/**
40-
* Gets the equivalence class for this flow state. If these are equal,
41-
* they should be treated as equivalent.
42-
*/
43-
string getEquivClass() { result = equivClass }
44-
45-
/**
46-
* Gets text for the singular form of this flow state.
47-
*/
48-
string getSingular() { result = singular }
49-
}
50-
51-
/**
52-
* A configuration for tracking string lengths originating from source that is
53-
* a `String` or an `NSString` object, to a sink of a different kind that
54-
* expects an incompatible measure of length.
55-
*/
56-
class StringLengthConflationConfiguration extends TaintTracking::Configuration {
57-
StringLengthConflationConfiguration() { this = "StringLengthConflationConfiguration" }
58-
59-
override predicate isSource(DataFlow::Node node, string flowstate) {
60-
exists(MemberRefExpr memberRef, string className, string varName |
61-
memberRef.getBase().getType().(NominalType).getABaseType*().getName() = className and
62-
memberRef.getMember().(VarDecl).getName() = varName and
63-
node.asExpr() = memberRef and
64-
(
65-
// result of a call to `String.count`
66-
className = "String" and
67-
varName = "count" and
68-
flowstate = "String"
69-
or
70-
// result of a call to `NSString.length`
71-
className = ["NSString", "NSMutableString"] and
72-
varName = "length" and
73-
flowstate = "NSString"
74-
or
75-
// result of a call to `String.utf8.count`
76-
className = "String.UTF8View" and
77-
varName = "count" and
78-
flowstate = "String.utf8"
79-
or
80-
// result of a call to `String.utf16.count`
81-
className = "String.UTF16View" and
82-
varName = "count" and
83-
flowstate = "String.utf16"
84-
or
85-
// result of a call to `String.unicodeScalars.count`
86-
className = "String.UnicodeScalarView" and
87-
varName = "count" and
88-
flowstate = "String.unicodeScalars"
89-
)
90-
)
91-
}
92-
93-
/**
94-
* Holds if `node` is a sink and `flowstate` is the *correct* flow state for
95-
* that sink. We actually want to report incorrect flow states.
96-
*/
97-
predicate isSinkImpl(DataFlow::Node node, string flowstate) {
98-
exists(AbstractFunctionDecl funcDecl, CallExpr call, string funcName, int arg |
99-
(
100-
// arguments to method calls...
101-
exists(string className, ClassOrStructDecl c |
102-
(
103-
// `NSRange.init`
104-
className = "NSRange" and
105-
funcName = "init(location:length:)" and
106-
arg = [0, 1]
107-
or
108-
// `NSString.character`
109-
className = ["NSString", "NSMutableString"] and
110-
funcName = "character(at:)" and
111-
arg = 0
112-
or
113-
// `NSString.character`
114-
className = ["NSString", "NSMutableString"] and
115-
funcName = "substring(from:)" and
116-
arg = 0
117-
or
118-
// `NSString.character`
119-
className = ["NSString", "NSMutableString"] and
120-
funcName = "substring(to:)" and
121-
arg = 0
122-
or
123-
// `NSMutableString.insert`
124-
className = "NSMutableString" and
125-
funcName = "insert(_:at:)" and
126-
arg = 1
127-
) and
128-
c.getName() = className and
129-
c.getABaseTypeDecl*().(ClassOrStructDecl).getAMember() = funcDecl and
130-
call.getStaticTarget() = funcDecl and
131-
flowstate = "NSString"
132-
)
133-
or
134-
// arguments to function calls...
135-
// `NSMakeRange`
136-
funcName = "NSMakeRange(_:_:)" and
137-
arg = [0, 1] and
138-
call.getStaticTarget() = funcDecl and
139-
flowstate = "NSString"
140-
or
141-
// arguments to method calls...
142-
(
143-
// `String.dropFirst`, `String.dropLast`, `String.removeFirst`, `String.removeLast`
144-
funcName = ["dropFirst(_:)", "dropLast(_:)", "removeFirst(_:)", "removeLast(_:)"] and
145-
arg = 0
146-
or
147-
// `String.prefix`, `String.suffix`
148-
funcName = ["prefix(_:)", "suffix(_:)"] and
149-
arg = 0
150-
or
151-
// `String.Index.init`
152-
funcName = "init(encodedOffset:)" and
153-
arg = 0
154-
or
155-
// `String.index`
156-
funcName = ["index(_:offsetBy:)", "index(_:offsetBy:limitBy:)"] and
157-
arg = [0, 1]
158-
or
159-
// `String.formIndex`
160-
funcName = ["formIndex(_:offsetBy:)", "formIndex(_:offsetBy:limitBy:)"] and
161-
arg = [0, 1]
162-
) and
163-
call.getStaticTarget() = funcDecl and
164-
flowstate = "String"
165-
) and
166-
// match up `funcName`, `arg`, `node`.
167-
funcDecl.getName() = funcName and
168-
call.getArgument(arg).getExpr() = node.asExpr()
169-
)
170-
}
171-
172-
override predicate isSink(DataFlow::Node node, string flowstate) {
173-
// Permit any *incorrect* flowstate, as those are the results the query
174-
// should report.
175-
exists(string correctFlowState |
176-
isSinkImpl(node, correctFlowState) and
177-
flowstate.(StringLengthConflationFlowState).getEquivClass() !=
178-
correctFlowState.(StringLengthConflationFlowState).getEquivClass()
179-
)
180-
}
181-
}
182-
18318
from
18419
StringLengthConflationConfiguration config, DataFlow::PathNode source, DataFlow::PathNode sink,
18520
StringLengthConflationFlowState sourceFlowState, StringLengthConflationFlowState sinkFlowstate,

0 commit comments

Comments
 (0)