Skip to content

Commit bf6f6ee

Browse files
authored
Merge pull request github#12225 from geoffw0/nsstring
Swift: Taint models for NSString
2 parents 59bd1e5 + f807905 commit bf6f6ee

File tree

9 files changed

+2366
-4
lines changed

9 files changed

+2366
-4
lines changed

swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ private module Frameworks {
8585
private import codeql.swift.frameworks.StandardLibrary.FilePath
8686
private import codeql.swift.frameworks.StandardLibrary.InputStream
8787
private import codeql.swift.frameworks.StandardLibrary.NsData
88+
private import codeql.swift.frameworks.StandardLibrary.NsObject
89+
private import codeql.swift.frameworks.StandardLibrary.NsString
8890
private import codeql.swift.frameworks.StandardLibrary.NsUrl
8991
private import codeql.swift.frameworks.StandardLibrary.Sequence
9092
private import codeql.swift.frameworks.StandardLibrary.String
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/**
2+
* Provides models for `NSObject` and related Swift classes.
3+
*/
4+
5+
import swift
6+
private import codeql.swift.dataflow.DataFlow
7+
private import codeql.swift.dataflow.ExternalFlow
8+
private import codeql.swift.dataflow.FlowSteps
9+
10+
/**
11+
* A model for `NSObject`, `NSCopying` and `NSMutableCopying` members that permit taint flow.
12+
*/
13+
private class NsObjectSummaries extends SummaryModelCsv {
14+
override predicate row(string row) {
15+
row =
16+
[
17+
";NSObject;true;copy();;;Argument[-1];ReturnValue;taint",
18+
";NSObject;true;mutableCopy();;;Argument[-1];ReturnValue;taint",
19+
";NSCopying;true;copy(with:);;;Argument[-1];ReturnValue;taint",
20+
";NSMutableCopying;true;mutableCopy(with:);;;Argument[-1];ReturnValue;taint",
21+
]
22+
}
23+
}
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
/**
2+
* Provides models for `NSString` and related Swift classes.
3+
*/
4+
5+
import swift
6+
private import codeql.swift.dataflow.DataFlow
7+
private import codeql.swift.dataflow.ExternalFlow
8+
private import codeql.swift.dataflow.FlowSteps
9+
10+
/**
11+
* A model for `NSString` members that are sources of remote flow.
12+
*/
13+
private class NsStringSource extends SourceModelCsv {
14+
override predicate row(string row) {
15+
row =
16+
[
17+
// NSString(contentsOf:) is a remote flow source
18+
";NSString;true;init(contentsOf:);;;ReturnValue;remote",
19+
";NSString;true;init(contentsOf:encoding:);;;ReturnValue;remote",
20+
";NSString;true;init(contentsOf:usedEncoding:);;;ReturnValue;remote",
21+
";NSString;true;string(withContentsOf:);;;ReturnValue;remote",
22+
// NSString(contentsOfFile:) is a local flow source
23+
";NSString;true;init(contentsOfFile:);;;ReturnValue;local",
24+
";NSString;true;init(contentsOfFile:encoding:);;;ReturnValue;local",
25+
";NSString;true;init(contentsOfFile:usedEncoding:);;;ReturnValue;local",
26+
";NSString;true;string(withContentsOfFile:);;;ReturnValue;local"
27+
]
28+
}
29+
}
30+
31+
/**
32+
* A model for `NSString` and `NSMtableString` members that permit taint flow.
33+
*/
34+
private class NsStringSummaries extends SummaryModelCsv {
35+
override predicate row(string row) {
36+
row =
37+
[
38+
";NSString;true;init(bytes:length:encoding:);;;Argument[0];ReturnValue;taint",
39+
";NSString;true;init(bytesNoCopy:length:encoding:freeWhenDone:);;;Argument[0];ReturnValue;taint",
40+
";NSString;true;init(bytesNoCopy:length:encoding:deallocator:);;;Argument[0];ReturnValue;taint",
41+
";NSString;true;init(characters:length:);;;Argument[0];ReturnValue;taint",
42+
";NSString;true;init(charactersNoCopy:length:freeWhenDone:);;;Argument[0];ReturnValue;taint",
43+
";NSString;true;init(charactersNoCopy:length:dellocator:);;;Argument[0];ReturnValue;taint",
44+
";NSString;true;init(string:);;;Argument[0];ReturnValue;taint",
45+
";NSString;true;init(cString:);;;Argument[0];ReturnValue;taint",
46+
";NSString;true;init(cString:encoding:);;;Argument[0];ReturnValue;taint",
47+
";NSString;true;init(cString:length:);;;Argument[0];ReturnValue;taint",
48+
";NSString;true;init(cStringNoCopy:length:freeWhenDone:);;;Argument[0];ReturnValue;taint",
49+
";NSString;true;init(utf8String:);;;Argument[0];ReturnValue;taint",
50+
";NSString;true;init(format:arguments:);;;Argument[0..1];ReturnValue;taint",
51+
";NSString;true;init(format:locale:arguments:);;;Argument[0];ReturnValue;taint",
52+
";NSString;true;init(format:locale:arguments:);;;Argument[2];ReturnValue;taint",
53+
";NSString;true;init(format:_:);;;Argument[0];ReturnValue;taint", //0..
54+
";NSString;true;init(format:locale:_:);;;Argument[0];ReturnValue;taint", //0,2..
55+
";NSString;true;init(data:encoding:);;;Argument[0];ReturnValue;taint",
56+
";NSString;true;init(contentsOfFile:);;;Argument[0];ReturnValue;taint",
57+
";NSString;true;init(contentsOfFile:encoding:);;;Argument[0];ReturnValue;taint",
58+
";NSString;true;init(contentsOfFile:usedEncoding:);;;Argument[0];ReturnValue;taint",
59+
";NSString;true;init(contentsOf:);;;Argument[0];ReturnValue;taint",
60+
";NSString;true;init(contentsOf:encoding:);;;Argument[0];ReturnValue;taint",
61+
";NSString;true;init(contentsOf:usedEncoding:);;;Argument[0];ReturnValue;taint",
62+
";NSString;true;init(coder:);;;Argument[0];ReturnValue;taint",
63+
";NSString;true;localizedStringWithFormat(_:_:);;;Argument[0];ReturnValue;taint", //0..
64+
";NSString;true;character(at:);;;Argument[-1];ReturnValue;taint",
65+
";NSString;true;getCharacters(_:);;;Argument[-1];Argument[0];taint",
66+
";NSString;true;getCharacters(_:range:);;;Argument[-1];Argument[0];taint",
67+
";NSString;true;getBytes(_:maxLength:usedLength:encoding:options:range:remaining:);;;Argument[-1];Argument[0];taint",
68+
";NSString;true;cString(using:);;;Argument[-1];ReturnValue;taint",
69+
";NSString;true;cString();;;Argument[-1];ReturnValue;taint",
70+
";NSString;true;lossyCString();;;Argument[-1];ReturnValue;taint",
71+
";NSString;true;getCString(_:);;;Argument[-1];Argument[0];taint",
72+
";NSString;true;getCString(_:maxLength:);;;Argument[-1];Argument[0];taint",
73+
";NSString;true;getCString(_:maxLength:encoding:);;;Argument[-1];Argument[0];taint",
74+
";NSString;true;getCString(_:maxLength:range:remaining:);;;Argument[-1];Argument[0];taint",
75+
";NSString;true;appendingFormat(_:_:);;;Argument[-1..0];ReturnValue;taint", // -1..
76+
";NSString;true;appending(_:);;;Argument[-1..0];ReturnValue;taint",
77+
";NSString;true;padding(toLength:withPad:startingAt:);;;Argument[-1];ReturnValue;taint",
78+
";NSString;true;padding(toLength:withPad:startingAt:);;;Argument[1];ReturnValue;taint",
79+
";NSString;true;lowercased(with:);;;Argument[-1];ReturnValue;taint",
80+
";NSString;true;uppercased(with:);;;Argument[-1];ReturnValue;taint",
81+
";NSString;true;capitalized(with:);;;Argument[-1];ReturnValue;taint",
82+
";NSString;true;components(separatedBy:);;;Argument[-1];ReturnValue;taint",
83+
";NSString;true;trimmingCharacters(in:);;;Argument[-1];ReturnValue;taint",
84+
";NSString;true;substring(from:);;;Argument[-1];ReturnValue;taint",
85+
";NSString;true;substring(with:);;;Argument[-1];ReturnValue;taint",
86+
";NSString;true;substring(to:);;;Argument[-1];ReturnValue;taint",
87+
";NSString;true;folding(options:locale:);;;Argument[-1];ReturnValue;taint",
88+
";NSString;true;applyingTransform(_:reverse:);;;Argument[-1];ReturnValue;taint",
89+
";NSString;true;replacingOccurrences(of:with:);;;Argument[-1];ReturnValue;taint",
90+
";NSString;true;replacingOccurrences(of:with:);;;Argument[1];ReturnValue;taint",
91+
";NSString;true;replacingOccurrences(of:with:options:range:);;;Argument[-1];ReturnValue;taint",
92+
";NSString;true;replacingOccurrences(of:with:options:range:);;;Argument[1];ReturnValue;taint",
93+
";NSString;true;replacingCharacters(in:with:);;;Argument[-1];ReturnValue;taint",
94+
";NSString;true;replacingCharacters(in:with:);;;Argument[1];ReturnValue;taint",
95+
";NSString;true;propertyList();;;Argument[-1];ReturnValue;taint",
96+
";NSString;true;propertyListFromStringsFileFormat();;;Argument[-1];ReturnValue;taint",
97+
";NSString;true;variantFittingPresentationWidth(_:);;;Argument[-1];ReturnValue;taint",
98+
";NSString;true;stringEncoding(for:encodingOptions:convertedString:usedLossyCompression:);;;Argument[0];Argument[2];taint",
99+
";NSString;true;data(using:);;;Argument[-1];ReturnValue;taint",
100+
";NSString;true;data(using:allowLossyConversion:);;;Argument[-1];ReturnValue;taint",
101+
";NSString;true;path(withComponents:);;;Argument[0];ReturnValue;taint",
102+
";NSString;true;completePath(into:caseSensitive:matchesInto:filterTypes:);;;Argument[-1];Argument[0];taint",
103+
";NSString;true;completePath(into:caseSensitive:matchesInto:filterTypes:);;;Argument[-1];Argument[2];taint",
104+
";NSString;true;getFileSystemRepresentation(_:maxLength:);;;Argument[-1];Argument[0];taint",
105+
";NSString;true;appendingPathComponent(_:);;;Argument[-1..0];ReturnValue;taint",
106+
";NSString;true;appendingPathComponent(_:conformingTo:);;;Argument[-1..0];ReturnValue;taint",
107+
";NSString;true;appendingPathExtension(_:);;;Argument[-1..0];ReturnValue;taint",
108+
";NSString;true;strings(byAppendingPaths:);;;Argument[-1..0];ReturnValue;taint",
109+
";NSString;true;addingPercentEncoding(withAllowedCharacters:);;;Argument[-1];ReturnValue;taint",
110+
";NSString;true;string(withCString:);;;Argument[0];ReturnValue;taint",
111+
";NSString;true;string(withCString:length:);;;Argument[0];ReturnValue;taint",
112+
";NSString;true;string(withContentsOfFile:);;;Argument[0];ReturnValue;taint",
113+
";NSString;true;string(withContentsOf:);;;Argument[0];ReturnValue;taint",
114+
";NSString;true;addingPercentEscapes(using:);;;Argument[-1];ReturnValue;taint",
115+
";NSString;true;replacingPercentEscapes(using:);;;Argument[-1];ReturnValue;taint",
116+
";NSString;true;applyTransform(_:reverse:range:updatedRange:);;;Argument[-1];ReturnValue;taint",
117+
";NSMutableString;true;append(_:);;;Argument[0];Argument[-1];taint",
118+
";NSMutableString;true;insert(_:at:);;;Argument[0];Argument[-1];taint",
119+
";NSMutableString;true;replaceCharacters(in:with:);;;Argument[1];Argument[-1];taint",
120+
";NSMutableString;true;replaceOccurrences(of:with:options:range:);;;Argument[1];Argument[-1];taint",
121+
";NSMutableString;true;setString(_:);;;Argument[0];Argument[-1];taint",
122+
";NSMutableString;true;appendFormat(_:_:);;;Argument[0];Argument[-1];taint", //0..
123+
]
124+
}
125+
}
126+
127+
/**
128+
* A content implying that, if an `NSString` is tainted, then many of its fields are
129+
* tainted.
130+
*/
131+
private class NsStringFieldsInheritTaint extends TaintInheritingContent,
132+
DataFlow::Content::FieldContent {
133+
NsStringFieldsInheritTaint() {
134+
exists(FieldDecl f | this.getField() = f |
135+
(
136+
f.getEnclosingDecl().(NominalTypeDecl).getName() = "NSString" or
137+
f.getEnclosingDecl().(ExtensionDecl).getExtendedTypeDecl().getName() = "NSString"
138+
) and
139+
f.getName() =
140+
[
141+
"utf8String", "lowercased", "localizedLowedCase", "uppercased", "localizedUppercase",
142+
"capitalized", "localizedCapitalized", "decomposedStringWithCanonicalMapping",
143+
"decomposedStringWithCompatibilityMapping", "precomposedStringWithCanonicalMapping",
144+
"precomposedStringWithCompatibilityMapping", "doubleValue", "floatValue", "intValue",
145+
"integerValue", "longLongValue", "boolValue", "description", "pathComponents",
146+
"fileSystemRepresentation", "lastPathComponent", "pathExtension",
147+
"abbreviatingWithTildeInPath", "deletingLastPathComponent", "deletingPathExtension",
148+
"expandingTildeInPath", "resolvingSymlinksInPath", "standardizingPath",
149+
"removingPercentEncoding"
150+
]
151+
)
152+
}
153+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
2+
// --- stubs ---
3+
4+
struct URL {
5+
init?(string: String) {}
6+
}
7+
8+
class NSObject {
9+
}
10+
11+
class NSString : NSObject {
12+
init(string aString: String) {}
13+
14+
convenience init?(contentsOfFile path: String) { self.init(string: "") }
15+
convenience init(contentsOfFile path: String, encoding enc: UInt) throws { self.init(string: "") }
16+
convenience init(contentsOfFile path: String, usedEncoding enc: UnsafeMutablePointer<UInt>?) throws { self.init(string: "") }
17+
convenience init?(contentsOf url: URL) { self.init(string: "") }
18+
convenience init(contentsOf url: URL, encoding enc: UInt) throws { self.init(string: "") }
19+
convenience init(contentsOf url: URL, usedEncoding enc: UnsafeMutablePointer<UInt>?) throws { self.init(string: "") }
20+
21+
class func string(withContentsOfFile path: String) -> Any? { return nil }
22+
class func string(withContentsOf url: URL) -> Any? { return nil }
23+
}
24+
25+
// --- tests ---
26+
27+
func testNSStrings() {
28+
do
29+
{
30+
let path = "file.txt"
31+
let string1 = try NSString(contentsOfFile: path) // $ $ source=local
32+
let string2 = try NSString(contentsOfFile: path, encoding: 0) // $ source=local
33+
let string3 = try NSString(contentsOfFile: path, usedEncoding: nil) // $ source=local
34+
let string4 = NSString.string(withContentsOfFile: path) // $ source=local
35+
36+
let url = URL(string: "http://example.com/")!
37+
let string5 = try NSString(contentsOf: url) // $ source=remote
38+
let string6 = try NSString(contentsOf: url, encoding: 0) // $ source=remote
39+
let string7 = try NSString(contentsOf: url, usedEncoding: nil) // $ source=remote
40+
let string8 = NSString.string(withContentsOf: url) // $ source=remote
41+
} catch {
42+
// ...
43+
}
44+
}

0 commit comments

Comments
 (0)