Skip to content

Commit 85a0fd9

Browse files
committed
Swift: Test taint through NSString.
1 parent f07c598 commit 85a0fd9

File tree

1 file changed

+325
-0
lines changed

1 file changed

+325
-0
lines changed
Lines changed: 325 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,325 @@
1+
2+
// --- stubs ---
3+
4+
typealias unichar = UInt16
5+
6+
class NSObject {
7+
}
8+
9+
class NSString : NSObject {
10+
struct EncodingConversionOptions : OptionSet {
11+
let rawValue: Int
12+
}
13+
14+
struct CompareOptions : OptionSet {
15+
let rawValue: Int
16+
}
17+
18+
init(characters: UnsafePointer<unichar>, length: Int) {}
19+
init(charactersNoCopy characters: UnsafeMutablePointer<unichar>, length: Int, freeWhenDone freeBuffer: Bool) {}
20+
init(string aString: String) {}
21+
22+
convenience init(format: String, arguments argList: CVaListPointer) { self.init(string: "") }
23+
convenience init(format: String, locale: Any?, arguments argList: CVaListPointer) { self.init(string: "") }
24+
convenience init(format: NSString, _ args: CVarArg...) { self.init(string: "") }
25+
convenience init(format: NSString, locale: Locale?, _ args: CVarArg...) { self.init(string: "") }
26+
convenience init(contentsOfFile path: String, encoding enc: UInt) throws { self.init(string: "") }
27+
convenience init(contentsOfFile path: String, usedEncoding enc: UnsafeMutablePointer<UInt>?) throws { self.init(string: "") }
28+
convenience init(contentsOf url: URL, encoding enc: UInt) throws { self.init(string: "") }
29+
convenience init(contentsOf url: URL, usedEncoding enc: UnsafeMutablePointer<UInt>?) throws { self.init(string: "") }
30+
31+
convenience init?(bytes: UnsafeRawPointer, length len: Int, encoding: UInt) { self.init(string: "") }
32+
convenience init?(bytesNoCopy bytes: UnsafeMutableRawPointer, length len: Int, encoding: UInt, freeWhenDone freeBuffer: Bool) { self.init(string: "") }
33+
convenience init?(cString nullTerminatedCString: UnsafePointer<CChar>, encoding: UInt) { self.init(string: "") }
34+
convenience init?(cString bytes: UnsafePointer<CChar>) { self.init(string: "") }
35+
convenience init?(utf8String nullTerminatedCString: UnsafePointer<CChar>) { self.init(string: "") }
36+
convenience init?(data: Data, encoding: UInt) { self.init(string: "") }
37+
convenience init?(contentsOfFile path: String) { self.init(string: "") }
38+
convenience init?(contentsOf url: URL) { self.init(string: "") }
39+
40+
class func localizedStringWithFormat(_ format: NSString, _ args: CVarArg) -> Self { return (nil as Self?)! }
41+
class func path(withComponents components: [String]) -> String { return "" }
42+
class func string(withCString bytes: UnsafePointer<CChar>) -> Any? { return nil }
43+
class func string(withCString bytes: UnsafePointer<CChar>, length: Int) -> Any? { return nil }
44+
class func string(withContentsOfFile path: String) -> Any? { return nil }
45+
class func string(withContentsOf url: URL) -> Any? { return nil }
46+
47+
func character(at index: Int) -> unichar { return 0 }
48+
func getCharacters(_ buffer: UnsafeMutablePointer<unichar>, range: NSRange) {}
49+
func getCharacters(_ buffer: UnsafeMutablePointer<unichar>) {}
50+
func getBytes(_ buffer: UnsafeMutableRawPointer?, maxLength maxBufferCount: Int, usedLength usedBufferCount: UnsafeMutablePointer<Int>?, encoding: UInt, options: NSString.EncodingConversionOptions = [], range: NSRange, remaining leftover: NSRangePointer?) -> Bool { return true }
51+
func cString(using encoding: UInt) -> UnsafePointer<CChar>? { return nil }
52+
func cString() -> UnsafePointer<CChar>? { return nil }
53+
func lossyCString() -> UnsafePointer<CChar>? { return nil }
54+
func getCString(_ buffer: UnsafeMutablePointer<CChar>, maxLength maxBufferCount: Int, encoding: UInt) -> Bool { return false }
55+
func getCString(_ bytes: UnsafeMutablePointer<CChar>) {}
56+
func appendingFormat(_ format: NSString, _ args: CVarArg...) -> NSString { return NSString(string: "") }
57+
func appending(_ aString: String) -> String { return "" }
58+
func padding(toLength newLength: Int, withPad padString: String, startingAt padIndex: Int) -> String { return "" }
59+
func lowercased(with locale: Locale?) -> String { return "" }
60+
func uppercased(with locale: Locale?) -> String { return "" }
61+
func capitalized(with locale: Locale?) -> String { return "" }
62+
func components(separatedBy separator: String) -> [String] { return [] }
63+
func components(separatedBy separator: CharacterSet) -> [String] { return [] }
64+
func trimmingCharacters(in set: CharacterSet) -> String { return "" }
65+
func substring(from: Int) -> String { return "" }
66+
func substring(with range: NSRange) -> String { return "" }
67+
func substring(to: Int) -> String { return "" }
68+
func folding(options: NSString.CompareOptions = [], locale: Locale?) -> String { return "" }
69+
func applyingTransform(_ transform: StringTransform, reverse: Bool) -> String? { return "" }
70+
func enumerateLines(_ block: @escaping (String, UnsafeMutablePointer<ObjCBool>) -> Void) { }
71+
func propertyList() -> Any { return 0 }
72+
func propertyListFromStringsFileFormat() -> [AnyHashable: Any]? { return nil }
73+
func variantFittingPresentationWidth(_ width: Int) -> String { return "" }
74+
func data(using encoding: UInt) -> Data? { return nil }
75+
func data(using encoding: UInt, allowLossyConversion lossy: Bool) -> Data? { return nil }
76+
func appendingPathComponent(_ str: String) -> String { return "" }
77+
func appendingPathComponent(_ partialName: String, conformingTo contentType: UTType) -> String { return "" }
78+
func appendingPathExtension(_ str: String) -> String? { return "" }
79+
func strings(byAppendingPaths paths: [String]) -> [String] { return [] }
80+
func completePath(into outputName: AutoreleasingUnsafeMutablePointer<NSString?>?, caseSensitive flag: Bool, matchesInto outputArray: AutoreleasingUnsafeMutablePointer<NSArray?>?, filterTypes: [String]?) -> Int { return 1 }
81+
func getFileSystemRepresentation(_ cname: UnsafeMutablePointer<CChar>, maxLength max: Int) -> Bool { return true }
82+
}
83+
84+
class NSArray : NSObject {
85+
}
86+
87+
struct _NSRange {
88+
init(location: Int, length: Int) {}
89+
}
90+
91+
typealias NSRange = _NSRange
92+
typealias NSRangePointer = UnsafeMutablePointer<NSRange>
93+
94+
struct URL {
95+
init?(string: String) {}
96+
}
97+
98+
struct Data {
99+
init<S>(_ elements: S) {}
100+
init(bytes: UnsafeRawPointer, count: Int) {}
101+
}
102+
103+
struct CharacterSet {
104+
static var whitespaces: CharacterSet { get { return CharacterSet() } }
105+
}
106+
107+
struct StringTransform {
108+
static var toLatin: StringTransform { get { return StringTransform() } }
109+
}
110+
111+
struct Locale {
112+
}
113+
114+
struct ObjCBool {
115+
}
116+
117+
struct UTType {
118+
}
119+
120+
// --- tests ---
121+
122+
func sourceString() -> String { return "" }
123+
func sourceNSString() -> NSString { return NSString(string: "") }
124+
func sourceUnicharString() -> UnsafePointer<unichar> { return (nil as UnsafePointer<unichar>?)! }
125+
func sourceMutableUnicharString() -> UnsafeMutablePointer<unichar> { return (nil as UnsafeMutablePointer<unichar>?)! }
126+
func sourceURL() -> URL { return URL(string: "")! }
127+
func sourceUnsafeRawPointer() -> UnsafeRawPointer { return (nil as UnsafeRawPointer?)! }
128+
func sourceUnsafeMutableRawPointer() -> UnsafeMutableRawPointer { return (nil as UnsafeMutableRawPointer?)! }
129+
func sourceCString() -> UnsafePointer<CChar> { return (nil as UnsafePointer<CChar>?)! }
130+
func sourceData() -> Data { return Data(0) }
131+
func sourceStringArray() -> [String] { return [] }
132+
133+
func sink(arg: Any) {}
134+
135+
func taintThroughInterpolatedStrings() {
136+
// simple initializers
137+
138+
sink(arg: NSString(characters: sourceUnicharString(), length: 512)) // $ MISSING: tainted=
139+
sink(arg: NSString(charactersNoCopy: sourceMutableUnicharString(), length: 512, freeWhenDone: false)) // $ MISSING: tainted=
140+
sink(arg: NSString(string: sourceString())) // $ MISSING: tainted=
141+
sink(arg: NSString(format: sourceString(), arguments: (nil as CVaListPointer?)!)) // $ MISSING: tainted=
142+
sink(arg: NSString(format: sourceString(), locale: nil, arguments: (nil as CVaListPointer?)!)) // $ MISSING: tainted=
143+
sink(arg: NSString(format: sourceNSString())) // $ MISSING: tainted=
144+
sink(arg: NSString(format: sourceNSString(), locale: nil)) // $ MISSING: tainted=
145+
146+
// initializers that can throw
147+
148+
sink(arg: try! NSString(contentsOfFile: sourceString(), encoding: 0)) // $ MISSING: tainted=
149+
sink(arg: try! NSString(contentsOfFile: sourceString(), usedEncoding: nil)) // $ MISSING: tainted=
150+
sink(arg: try! NSString(contentsOf: sourceURL(), encoding: 0)) // $ MISSING: tainted=
151+
sink(arg: try! NSString(contentsOf: URL(string: sourceString())!, encoding: 0)) // $ MISSING: tainted=
152+
sink(arg: try! NSString(contentsOf: sourceURL(), usedEncoding: nil)) // $ MISSING: tainted=
153+
sink(arg: try! NSString(contentsOf: URL(string: sourceString())!, usedEncoding: nil)) // $ MISSING: tainted=
154+
155+
// initializers returning an optional
156+
157+
sink(arg: NSString(bytes: sourceUnsafeRawPointer(), length: 1024, encoding: 0)) // $ MISSING: tainted=
158+
sink(arg: NSString(bytes: sourceUnsafeRawPointer(), length: 1024, encoding: 0)!) // $ MISSING: tainted=
159+
sink(arg: NSString(bytes: UnsafeRawPointer(sourceUnsafeMutableRawPointer()), length: 1024, encoding: 0)!) // $ MISSING: tainted=
160+
161+
sink(arg: NSString(bytesNoCopy: sourceUnsafeMutableRawPointer(), length: 1024, encoding: 0, freeWhenDone: false)) // $ MISSING: tainted=
162+
sink(arg: NSString(bytesNoCopy: sourceUnsafeMutableRawPointer(), length: 1024, encoding: 0, freeWhenDone: false)!) // $ MISSING: tainted=
163+
sink(arg: NSString(bytesNoCopy: UnsafeMutableRawPointer(mutating: sourceUnsafeRawPointer()), length: 1024, encoding: 0, freeWhenDone: false)!) // $ MISSING: tainted=
164+
165+
sink(arg: NSString(cString: sourceCString(), encoding: 0)) // $ MISSING: tainted=
166+
sink(arg: NSString(cString: sourceCString(), encoding: 0)!) // $ MISSING: tainted=
167+
sink(arg: NSString(cString: sourceUnsafeRawPointer().bindMemory(to: CChar.self, capacity: 1024), encoding: 0)!) // $ MISSING: tainted=
168+
169+
sink(arg: NSString(cString: sourceCString())) // $ MISSING: tainted=
170+
sink(arg: NSString(cString: sourceCString())!) // $ MISSING: tainted=
171+
sink(arg: NSString(cString: sourceUnsafeRawPointer().bindMemory(to: CChar.self, capacity: 1024))!) // $ MISSING: tainted=
172+
173+
sink(arg: NSString(utf8String: sourceCString())) // $ MISSING: tainted=
174+
sink(arg: NSString(utf8String: sourceCString())!) // $ MISSING: tainted=
175+
sink(arg: NSString(utf8String: sourceUnsafeRawPointer().bindMemory(to: CChar.self, capacity: 1024))!) // $ MISSING: tainted=
176+
177+
sink(arg: NSString(data: sourceData(), encoding: 0)) // $ MISSING: tainted=
178+
sink(arg: NSString(data: sourceData(), encoding: 0)!) // $ MISSING: tainted=
179+
sink(arg: NSString(data: Data(bytes: sourceUnsafeRawPointer(), count: 1024), encoding: 0)!) // $ MISSING: tainted=
180+
181+
sink(arg: NSString(contentsOfFile: sourceString())) // $ MISSING: tainted=
182+
sink(arg: NSString(contentsOfFile: sourceString())!) // $ MISSING: tainted=
183+
184+
sink(arg: NSString(contentsOf: sourceURL())) // $ MISSING: tainted=
185+
sink(arg: NSString(contentsOf: sourceURL())!) // $ MISSING: tainted=
186+
187+
// simple methods (taint flow to return value)
188+
189+
let harmless = NSString(string: "harmless")
190+
let myRange = NSRange(location:0, length: 128)
191+
192+
sink(arg: NSString.localizedStringWithFormat(sourceNSString(), (nil as CVarArg?)!)) // $ MISSING: tainted=
193+
sink(arg: sourceNSString().character(at: 0)) // $ MISSING: tainted=
194+
sink(arg: sourceNSString().cString(using: 0)!) // $ MISSING: tainted=
195+
sink(arg: sourceNSString().cString()) // $ MISSING: tainted=
196+
sink(arg: sourceNSString().lossyCString()) // $ MISSING: tainted=
197+
sink(arg: sourceNSString().padding(toLength: 256, withPad: " ", startingAt: 0)) // $ MISSING: tainted=
198+
sink(arg: harmless.padding(toLength: 256, withPad: sourceString(), startingAt: 0)) // $ MISSING: tainted=
199+
sink(arg: sourceNSString().lowercased(with: nil)) // $ MISSING: tainted=
200+
sink(arg: sourceNSString().uppercased(with: nil)) // $ MISSING: tainted=
201+
sink(arg: sourceNSString().capitalized(with: nil)) // $ MISSING: tainted=
202+
sink(arg: sourceNSString().components(separatedBy: ",")) // $ MISSING: tainted=
203+
sink(arg: sourceNSString().components(separatedBy: ",")[0]) // $ MISSING: tainted=
204+
sink(arg: sourceNSString().components(separatedBy: CharacterSet.whitespaces)) // $ MISSING: tainted=
205+
sink(arg: sourceNSString().components(separatedBy: CharacterSet.whitespaces)[0]) // $ MISSING: tainted=
206+
sink(arg: sourceNSString().trimmingCharacters(in: CharacterSet.whitespaces)) // $ MISSING: tainted=
207+
sink(arg: sourceNSString().substring(from: 0)) // $ MISSING: tainted=
208+
sink(arg: sourceNSString().substring(with: myRange)) // $ MISSING: tainted=
209+
sink(arg: sourceNSString().substring(to: 80)) // $ MISSING: tainted=
210+
sink(arg: sourceNSString().folding(locale: nil)) // $ MISSING: tainted=
211+
sink(arg: sourceNSString().applyingTransform(StringTransform.toLatin, reverse: false)) // $ MISSING: tainted=
212+
sink(arg: sourceNSString().propertyList()) // $ MISSING: tainted=
213+
sink(arg: sourceNSString().propertyListFromStringsFileFormat()) // $ MISSING: tainted=
214+
sink(arg: sourceNSString().variantFittingPresentationWidth(80)) // $ MISSING: tainted=
215+
sink(arg: sourceNSString().data(using: 0)) // $ MISSING: tainted=
216+
sink(arg: sourceNSString().data(using: 0, allowLossyConversion: false)) // $ MISSING: tainted=
217+
sink(arg: NSString.path(withComponents: ["a", "b", "c"])) // $ MISSING: tainted=
218+
sink(arg: NSString.path(withComponents: sourceStringArray())) // $ MISSING: tainted=
219+
sink(arg: NSString.path(withComponents: ["a", sourceString(), "c"])) // $ MISSING: tainted=
220+
sink(arg: NSString.string(withCString: sourceCString())) // $ MISSING: tainted=
221+
sink(arg: NSString.string(withCString: sourceCString(), length: 128)) // $ MISSING: tainted=
222+
sink(arg: NSString.string(withContentsOfFile: sourceString())) // $ MISSING: tainted=
223+
sink(arg: NSString.string(withContentsOf: sourceURL())) // $ MISSING: tainted=
224+
225+
// appending
226+
227+
sink(arg: harmless.appendingFormat(harmless, (nil as CVarArg?)!))
228+
sink(arg: harmless.appendingFormat(sourceNSString(), (nil as CVarArg?)!)) // $ MISSING: tainted=
229+
sink(arg: sourceNSString().appendingFormat(harmless, (nil as CVarArg?)!)) // $ MISSING: tainted=
230+
231+
sink(arg: harmless.appendingPathComponent(""))
232+
sink(arg: harmless.appendingPathComponent(sourceString())) // $ MISSING: tainted=
233+
sink(arg: sourceNSString().appendingPathComponent("")) // $ MISSING: tainted=
234+
235+
sink(arg: harmless.appendingPathComponent("", conformingTo: (nil as UTType?)!))
236+
sink(arg: harmless.appendingPathComponent(sourceString(), conformingTo: (nil as UTType?)!)) // $ MISSING: tainted=
237+
sink(arg: sourceNSString().appendingPathComponent("", conformingTo: (nil as UTType?)!)) // $ MISSING: tainted=
238+
239+
sink(arg: harmless.appendingPathExtension(""))
240+
sink(arg: harmless.appendingPathExtension(sourceString())) // $ MISSING: tainted=
241+
sink(arg: sourceNSString().appendingPathExtension("")) // $ MISSING: tainted=
242+
243+
var str1 = harmless
244+
sink(arg: str1)
245+
str1.appending("")
246+
sink(arg: str1)
247+
str1.appending(sourceString())
248+
sink(arg: str1) // $ MISSING: tainted=
249+
str1.appending("")
250+
sink(arg: str1) // $ MISSING: tainted=
251+
252+
sink(arg: harmless.strings(byAppendingPaths: [""]))
253+
sink(arg: harmless.strings(byAppendingPaths: [""])[0])
254+
sink(arg: harmless.strings(byAppendingPaths: [sourceString()])) // $ MISSING: tainted=
255+
sink(arg: harmless.strings(byAppendingPaths: [sourceString()])[0]) // $ MISSING: tainted=
256+
sink(arg: sourceNSString().strings(byAppendingPaths: [""])) // $ MISSING: tainted=
257+
sink(arg: sourceNSString().strings(byAppendingPaths: [""])[0]) // $ MISSING: tainted=
258+
259+
// other methods
260+
261+
var ptr1 = (nil as UnsafeMutablePointer<unichar>?)!
262+
sink(arg: ptr1)
263+
harmless.getCharacters(ptr1, range: myRange)
264+
sink(arg: ptr1)
265+
sourceNSString().getCharacters(ptr1, range: myRange)
266+
sink(arg: ptr1) // $ MISSING: tainted=
267+
268+
var ptr2 = (nil as UnsafeMutablePointer<unichar>?)!
269+
sink(arg: ptr2)
270+
harmless.getCharacters(ptr2)
271+
sink(arg: ptr2)
272+
sourceNSString().getCharacters(ptr2)
273+
sink(arg: ptr2) // $ MISSING: tainted=
274+
275+
var ptr3 = (nil as UnsafeMutableRawPointer?)!
276+
sink(arg: ptr3)
277+
harmless.getBytes(ptr3, maxLength: 128, usedLength: nil, encoding: 0, range: myRange, remaining: nil)
278+
sink(arg: ptr3)
279+
sourceNSString().getBytes(ptr3, maxLength: 128, usedLength: nil, encoding: 0, range: myRange, remaining: nil)
280+
sink(arg: ptr3) // $ MISSING: tainted=
281+
282+
var ptr4 = (nil as UnsafeMutablePointer<CChar>?)!
283+
sink(arg: ptr4)
284+
harmless.getCString(ptr4, maxLength: 128, encoding: 0)
285+
sink(arg: ptr4)
286+
sourceNSString().getCString(ptr4, maxLength: 128, encoding: 0)
287+
sink(arg: ptr4) // $ MISSING: tainted=
288+
289+
var ptr5 = (nil as UnsafeMutablePointer<CChar>?)!
290+
sink(arg: ptr5)
291+
harmless.getCString(ptr5)
292+
sink(arg: ptr5)
293+
sourceNSString().getCString(ptr5)
294+
sink(arg: ptr5) // $ MISSING: tainted=
295+
296+
sink(arg: harmless.enumerateLines({
297+
line, stop in
298+
sink(arg: line)
299+
sink(arg: stop)
300+
}))
301+
sink(arg: sourceNSString().enumerateLines({
302+
line, stop in
303+
sink(arg: line) // $ MISSING: tainted=
304+
sink(arg: stop)
305+
}))
306+
307+
var str10 = sourceNSString()
308+
var outLongest = (nil as AutoreleasingUnsafeMutablePointer<NSString?>?)!
309+
var outArray = (nil as AutoreleasingUnsafeMutablePointer<NSArray?>?)!
310+
if (str10.completePath(into: outLongest, caseSensitive: false, matchesInto: outArray, filterTypes: nil) > 0) {
311+
sink(arg: outLongest) // $ MISSING: tainted=
312+
sink(arg: outLongest.pointee) // $ MISSING: tainted=
313+
sink(arg: outLongest.pointee!) // $ MISSING: tainted=
314+
sink(arg: outArray) // $ MISSING: tainted=
315+
sink(arg: outArray.pointee) // $ MISSING: tainted=
316+
sink(arg: outArray.pointee!) // $ MISSING: tainted=
317+
}
318+
319+
var str11 = sourceNSString()
320+
var outBuffer = (nil as UnsafeMutablePointer<CChar>?)!
321+
if (str11.getFileSystemRepresentation(outBuffer, maxLength: 256)) {
322+
sink(arg: outBuffer) // $ MISSING: tainted=
323+
sink(arg: outBuffer.pointee) // $ MISSING: tainted=
324+
}
325+
}

0 commit comments

Comments
 (0)