mirror of
https://github.com/github/codeql.git
synced 2026-05-20 22:27:18 +02:00
749 lines
23 KiB
Swift
749 lines
23 KiB
Swift
|
|
// --- stubs ---
|
|
|
|
typealias unichar = UInt16
|
|
|
|
struct Locale {
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
enum CInterop {
|
|
typealias Char = CChar
|
|
typealias PlatformChar = CInterop.Char
|
|
}
|
|
|
|
struct CharacterSet {
|
|
static var whitespaces: CharacterSet { get { return CharacterSet() } }
|
|
}
|
|
|
|
class NSObject {
|
|
}
|
|
|
|
class NSString : NSObject {
|
|
struct CompareOptions : OptionSet {
|
|
init(rawValue: UInt) { self.rawValue = rawValue }
|
|
|
|
var rawValue: UInt
|
|
}
|
|
}
|
|
|
|
extension String : CVarArg {
|
|
typealias CompareOptions = NSString.CompareOptions
|
|
|
|
public var _cVarArgEncoding: [Int] { get { return [] } }
|
|
static var availableStringEncodings: [String.Encoding] { get { [] } }
|
|
static var defaultCStringEncoding: String.Encoding { get { String.Encoding.utf8 } }
|
|
|
|
struct Encoding {
|
|
static let utf8 = Encoding()
|
|
}
|
|
|
|
init?(data: Data, encoding: Encoding) { self.init() }
|
|
|
|
|
|
|
|
init(format: String, _ arguments: CVarArg...) { self.init() }
|
|
init(format: String, arguments: [CVarArg]) { self.init() }
|
|
init(format: String, locale: Locale?, _ args: CVarArg...) { self.init() }
|
|
init(format: String, locale: Locale?, arguments: [CVarArg]) { self.init() }
|
|
|
|
static func localizedStringWithFormat(_ format: String, _ arguments: CVarArg...) -> String { return "" }
|
|
|
|
init?<S>(bytes: S, encoding: String.Encoding) where S : Sequence, S.Element == UInt8 { self.init() }
|
|
|
|
init(cString nullTerminatedUTF8: UnsafePointer<CChar>) { self.init() }
|
|
init(cString nullTerminatedUTF8: UnsafePointer<UInt8>) { self.init() }
|
|
init?(bytesNoCopy bytes: UnsafeMutableRawPointer, length: Int, encoding: String.Encoding, freeWhenDone flag: Bool) { self.init() }
|
|
init?(utf8String bytes: UnsafePointer<CChar>) { self.init() }
|
|
init(utf16CodeUnits: UnsafePointer<unichar>, count: Int) { self.init() }
|
|
init(utf16CodeUnitsNoCopy: UnsafePointer<unichar>, count: Int, freeWhenDone flag: Bool) { self.init() }
|
|
|
|
init(platformString: UnsafePointer<CInterop.PlatformChar>) { self.init() }
|
|
|
|
func withPlatformString<Result>(_ body: (UnsafePointer<CInterop.PlatformChar>) throws -> Result) rethrows -> Result { return 0 as! Result }
|
|
mutating func withMutableCharacters<R>(_ body: (inout String) -> R) -> R { return 0 as! R }
|
|
|
|
|
|
mutating func replaceSubrange<C>(_ subrange: Range<String.Index>, with newElements: C)
|
|
where C : Collection, C.Element == Character {}
|
|
}
|
|
|
|
extension StringProtocol {
|
|
var capitalized: String { get { "" } }
|
|
var localizedCapitalized: String { get { "" } }
|
|
var localizedLowercase: String { get { "" } }
|
|
var localizedUppercase: String { get { "" } }
|
|
var removingPercentEncoding: String? { get { "" } }
|
|
var decomposedStringWithCanonicalMapping: String { get { "" } }
|
|
var decomposedStringWithCompatibilityMapping: String { get { "" } }
|
|
var precomposedStringWithCanonicalMapping: String { get { "" } }
|
|
var precomposedStringWithCompatibilityMapping: String { get { "" } }
|
|
|
|
func lowercased(with locale: Locale?) -> String { return "" }
|
|
func uppercased(with locale: Locale?) -> String { return "" }
|
|
func capitalized(with locale: Locale?) -> String { return "" }
|
|
func substring(from index: Self.Index) -> String { return "" }
|
|
func trimmingCharacters(in set: CharacterSet) -> String { return "" }
|
|
func appending<T>(_ aString: T) -> String where T : StringProtocol { return "" }
|
|
func appendingFormat<T>(_ format: T, _ arguments: CVarArg...) -> String where T : StringProtocol { return "" }
|
|
func padding<T>(toLength newLength: Int, withPad padString: T, startingAt padIndex: Int) -> String where T: StringProtocol { return "" }
|
|
func components(separatedBy separator: CharacterSet) -> [String] { return [] }
|
|
func folding(options: String.CompareOptions = [], locale: Locale?) -> String { return "" }
|
|
func propertyListFromStringsFileFormat() -> [String : String] { return [:] }
|
|
func cString(using encoding: String.Encoding) -> [CChar]? { return nil }
|
|
func enumerateLines(invoking body: @escaping (String, inout Bool) -> Void) {}
|
|
func replacingOccurrences<Target, Replacement>(of target: Target, with replacement: Replacement, options: String.CompareOptions = [], range searchRange: Range<Self.Index>? = nil) -> String
|
|
where Target : StringProtocol, Replacement : StringProtocol { return "" }
|
|
}
|
|
|
|
class Data
|
|
{
|
|
init<S>(_ elements: S) {}
|
|
}
|
|
|
|
extension Data : Collection {
|
|
typealias Index = Int
|
|
|
|
var startIndex: Data.Index { get { return 0 } }
|
|
var endIndex: Data.Index { get { return 0 } }
|
|
subscript(index: Data.Index) -> UInt8 { get { return 0 } }
|
|
func index(after i: Data.Index) -> Data.Index { return 0 }
|
|
}
|
|
|
|
// --- tests ---
|
|
|
|
func source() -> Int { return 0; }
|
|
func sink(arg: Any) {}
|
|
|
|
func taintThroughInterpolatedStrings() {
|
|
var x = source()
|
|
|
|
sink(arg: "\(x)") // $ tainted=137
|
|
|
|
sink(arg: "\(x) \(x)") // $ tainted=137
|
|
|
|
sink(arg: "\(x) \(0) \(x)") // $ tainted=137
|
|
|
|
let y = 42
|
|
|
|
sink(arg: "\(y)") // clean
|
|
|
|
sink(arg: "\(x) hello \(y)") // $ tainted=137
|
|
|
|
sink(arg: "\(y) world \(x)") // $ tainted=137
|
|
|
|
x = 0
|
|
sink(arg: "\(x)") // clean
|
|
}
|
|
|
|
func source2() -> String { return ""; }
|
|
|
|
func taintThroughStringConcatenation() {
|
|
let clean = "abcdef"
|
|
let tainted = source2()
|
|
|
|
sink(arg: clean)
|
|
sink(arg: tainted) // $ tainted=161
|
|
|
|
sink(arg: clean + clean)
|
|
sink(arg: clean + tainted) // $ tainted=161
|
|
sink(arg: tainted + clean) // $ tainted=161
|
|
sink(arg: tainted + tainted) // $ tainted=161
|
|
|
|
sink(arg: ">" + clean + "<")
|
|
sink(arg: ">" + tainted + "<") // $ tainted=161
|
|
|
|
sink(arg: clean.appending(clean))
|
|
sink(arg: clean.appending(tainted)) // $ tainted=161
|
|
sink(arg: tainted.appending(clean)) // $ tainted=161
|
|
sink(arg: tainted.appending(tainted)) // $ tainted=161
|
|
|
|
var str = "abc"
|
|
sink(arg: str)
|
|
str += "def"
|
|
sink(arg: str)
|
|
str += source2()
|
|
sink(arg: str) // $ tainted=183
|
|
|
|
var str2 = "abc"
|
|
sink(arg: str2)
|
|
str2.append("def")
|
|
sink(arg: str2)
|
|
str2.append(source2())
|
|
sink(arg: str2) // $ tainted=190
|
|
|
|
var str3 = "abc"
|
|
sink(arg: str3)
|
|
str3.append(contentsOf: "def")
|
|
sink(arg: str3)
|
|
str3.append(contentsOf: source2())
|
|
sink(arg: str3) // $ tainted=197
|
|
|
|
var str4 = "abc"
|
|
sink(arg: str4)
|
|
str4.write("def")
|
|
sink(arg: str4)
|
|
str4.write(source2())
|
|
sink(arg: str4) // $ tainted=204
|
|
|
|
var str5 = "abc"
|
|
sink(arg: str5)
|
|
str5.insert(contentsOf: "abc", at: str5.startIndex)
|
|
sink(arg: str5)
|
|
str5.insert(contentsOf: source2(), at: str5.startIndex)
|
|
sink(arg: str5) // $ tainted=211
|
|
}
|
|
|
|
func taintThroughSimpleStringOperations() {
|
|
let clean = ""
|
|
let tainted = source2()
|
|
let taintedInt = source()
|
|
|
|
sink(arg: String(clean))
|
|
sink(arg: String(tainted)) // $ tainted=217
|
|
sink(arg: String(taintedInt)) // $ tainted=218
|
|
|
|
sink(arg: String(format: tainted, 1, 2, 3)) // $ tainted=217
|
|
sink(arg: String(format: tainted, arguments: [])) // $ tainted=217
|
|
sink(arg: String(format: tainted, locale: nil, 1, 2, 3)) // $ tainted=217
|
|
sink(arg: String(format: tainted, locale: nil, arguments: [])) // $ tainted=217
|
|
sink(arg: String.localizedStringWithFormat(tainted, 1, 2, 3)) // $ tainted=217
|
|
sink(arg: String.localizedStringWithFormat("%i %s %i", 1, tainted, 3)) // $ tainted=217
|
|
sink(arg: String(format: "%s", tainted)) // $ tainted=217
|
|
sink(arg: String(format: "%i %i %i", 1, 2, taintedInt)) // $ tainted=218
|
|
|
|
sink(arg: String(repeating: clean, count: 2))
|
|
sink(arg: String(repeating: tainted, count: 2)) // $ tainted=217
|
|
|
|
sink(arg: tainted.dropFirst(10)) // $ tainted=217
|
|
sink(arg: tainted.dropLast(10)) // $ tainted=217
|
|
sink(arg: tainted.substring(from: tainted.startIndex)) // $ tainted=217
|
|
sink(arg: tainted.lowercased()) // $ tainted=217
|
|
sink(arg: tainted.uppercased()) // $ tainted=217
|
|
sink(arg: tainted.lowercased(with: nil)) // $ tainted=217
|
|
sink(arg: tainted.uppercased(with: nil)) // $ tainted=217
|
|
sink(arg: tainted.capitalized(with: nil)) // $ tainted=217
|
|
sink(arg: tainted.reversed()) // $ tainted=217
|
|
|
|
sink(arg: tainted.split(separator: ",")) // $ tainted=217
|
|
sink(arg: tainted.split(whereSeparator: {
|
|
c in return (c == ",")
|
|
})) // $ tainted=217
|
|
sink(arg: tainted.trimmingCharacters(in: CharacterSet.whitespaces)) // $ tainted=217
|
|
sink(arg: tainted.padding(toLength: 20, withPad: " ", startingAt: 0)) // $ tainted=217
|
|
sink(arg: tainted.components(separatedBy: CharacterSet.whitespaces)) // $ tainted=217
|
|
sink(arg: tainted.components(separatedBy: CharacterSet.whitespaces)[0]) // $ tainted=217
|
|
sink(arg: tainted.folding(locale: nil)) // $ tainted=217
|
|
sink(arg: tainted.propertyListFromStringsFileFormat()) // $ tainted=217
|
|
sink(arg: tainted.propertyListFromStringsFileFormat()["key"]!) // $ tainted=217
|
|
|
|
sink(arg: clean.enumerateLines(invoking: {
|
|
line, stop in
|
|
sink(arg: line)
|
|
sink(arg: stop)
|
|
}))
|
|
sink(arg: tainted.enumerateLines(invoking: {
|
|
line, stop in
|
|
sink(arg: line) // $ MISSING: tainted=217
|
|
sink(arg: stop)
|
|
}))
|
|
|
|
sink(arg: [clean, clean].joined())
|
|
sink(arg: [tainted, clean].joined()) // $ tainted=217
|
|
sink(arg: [clean, tainted].joined()) // $ tainted=217
|
|
sink(arg: [tainted, tainted].joined()) // $ tainted=217
|
|
|
|
sink(arg: clean.description)
|
|
sink(arg: tainted.description) // $ tainted=217
|
|
sink(arg: clean.debugDescription)
|
|
sink(arg: tainted.debugDescription) // $ tainted=217
|
|
sink(arg: clean.utf8)
|
|
sink(arg: tainted.utf8) // $ tainted=217
|
|
sink(arg: clean.utf16)
|
|
sink(arg: tainted.utf16) // $ tainted=217
|
|
sink(arg: clean.unicodeScalars)
|
|
sink(arg: tainted.unicodeScalars) // $ tainted=217
|
|
sink(arg: clean.utf8CString)
|
|
sink(arg: tainted.utf8CString) // $ tainted=217
|
|
sink(arg: clean.lazy)
|
|
sink(arg: tainted.lazy) // $ tainted=217
|
|
sink(arg: clean.capitalized)
|
|
sink(arg: tainted.capitalized) // $ tainted=217
|
|
sink(arg: clean.localizedCapitalized)
|
|
sink(arg: tainted.localizedCapitalized) // $ tainted=217
|
|
sink(arg: clean.localizedLowercase)
|
|
sink(arg: tainted.localizedLowercase) // $ tainted=217
|
|
sink(arg: clean.localizedUppercase)
|
|
sink(arg: tainted.localizedUppercase) // $ tainted=217
|
|
sink(arg: clean.decomposedStringWithCanonicalMapping)
|
|
sink(arg: tainted.decomposedStringWithCanonicalMapping) // $ tainted=217
|
|
sink(arg: clean.precomposedStringWithCompatibilityMapping)
|
|
sink(arg: tainted.precomposedStringWithCompatibilityMapping) // $ tainted=217
|
|
sink(arg: clean.removingPercentEncoding!)
|
|
sink(arg: tainted.removingPercentEncoding!) // $ tainted=217
|
|
|
|
sink(arg: clean.replacingOccurrences(of: "a", with: "b"))
|
|
sink(arg: tainted.replacingOccurrences(of: "a", with: "b")) // $ tainted=217
|
|
sink(arg: clean.replacingOccurrences(of: "a", with: source2())) // $ tainted=305
|
|
}
|
|
|
|
func taintThroughMutatingStringOperations() {
|
|
var str1 = source2()
|
|
sink(arg: str1) // $ tainted=309
|
|
sink(arg: str1.remove(at: str1.startIndex)) // $ tainted=309
|
|
sink(arg: str1) // $ tainted=309
|
|
|
|
var str2 = source2()
|
|
sink(arg: str2) // $ tainted=314
|
|
str2.removeAll()
|
|
sink(arg: str2) // $ SPURIOUS: tainted=314
|
|
|
|
var str3 = source2()
|
|
sink(arg: str3) // $ tainted=319
|
|
str3.removeAll(where: { _ in true } )
|
|
sink(arg: str3) // $ SPURIOUS: tainted=319
|
|
|
|
var str4 = source2()
|
|
sink(arg: str4) // $ tainted=324
|
|
sink(arg: str4.removeFirst()) // $ tainted=324
|
|
sink(arg: str4) // $ tainted=324
|
|
str4.removeFirst(5)
|
|
sink(arg: str4) // $ tainted=324
|
|
sink(arg: str4.removeLast()) // $ tainted=324
|
|
sink(arg: str4) // $ tainted=324
|
|
str4.removeLast(5)
|
|
sink(arg: str4) // $ tainted=324
|
|
|
|
var str5 = source2()
|
|
sink(arg: str5) // $ tainted=335
|
|
str5.removeSubrange(str5.startIndex ... str5.index(str5.startIndex, offsetBy: 5))
|
|
sink(arg: str5) // $ tainted=335
|
|
|
|
var str6 = source2()
|
|
sink(arg: str6) // $ tainted=340
|
|
str6.makeContiguousUTF8()
|
|
sink(arg: str6) // $ tainted=340
|
|
|
|
var str7 = ""
|
|
sink(arg: str7)
|
|
str7.replaceSubrange((nil as Range<String.Index>?)!, with: source2())
|
|
sink(arg: str7) // $ tainted=347
|
|
}
|
|
|
|
func source3() -> Data { return Data("") }
|
|
|
|
func taintThroughData() {
|
|
let stringClean = String(data: Data(""), encoding: String.Encoding.utf8)
|
|
let stringTainted = String(data: source3(), encoding: String.Encoding.utf8)
|
|
|
|
sink(arg: stringClean!)
|
|
sink(arg: stringTainted!) // $ tainted=355
|
|
|
|
sink(arg: String(decoding: Data(""), as: UTF8.self))
|
|
sink(arg: String(decoding: source3(), as: UTF8.self)) // $ tainted=361
|
|
}
|
|
|
|
func taintThroughEncodings() {
|
|
var clean = ""
|
|
var tainted = source2()
|
|
|
|
clean.withUTF8({
|
|
buffer in
|
|
sink(arg: buffer[0])
|
|
sink(arg: buffer.baseAddress!)
|
|
})
|
|
tainted.withUTF8({
|
|
buffer in
|
|
sink(arg: buffer[0]) // $ tainted=366
|
|
sink(arg: buffer.baseAddress!) // $ MISSING: tainted=366
|
|
})
|
|
|
|
clean.withCString({
|
|
ptr in
|
|
sink(arg: ptr[0])
|
|
})
|
|
tainted.withCString({
|
|
ptr in
|
|
sink(arg: ptr[0]) // $ tainted=366
|
|
})
|
|
clean.withCString(encodedAs: UTF8.self, {
|
|
ptr in
|
|
sink(arg: ptr[0])
|
|
})
|
|
tainted.withCString(encodedAs: UTF8.self, {
|
|
ptr in
|
|
sink(arg: ptr[0]) // $ tainted=366
|
|
})
|
|
|
|
let arrayString1 = clean.cString(using: String.Encoding.utf8)!
|
|
sink(arg: arrayString1)
|
|
arrayString1.withUnsafeBufferPointer({
|
|
buffer in
|
|
sink(arg: buffer[0])
|
|
sink(arg: String(cString: buffer.baseAddress!))
|
|
})
|
|
let arrayString2 = tainted.cString(using: String.Encoding.utf8)!
|
|
sink(arg: arrayString2) // $ tainted=366
|
|
arrayString2.withUnsafeBufferPointer({
|
|
buffer in
|
|
sink(arg: buffer[0]) // $ tainted=366
|
|
sink(arg: String(cString: buffer.baseAddress!)) // $ MISSING: tainted=366
|
|
})
|
|
|
|
clean.withPlatformString({
|
|
ptr in
|
|
sink(arg: ptr[0])
|
|
sink(arg: String(platformString: ptr))
|
|
|
|
let buffer = UnsafeBufferPointer(start: ptr, count: 10)
|
|
let arrayString = Array(buffer)
|
|
sink(arg: buffer[0])
|
|
sink(arg: arrayString[0])
|
|
sink(arg: String(platformString: arrayString))
|
|
})
|
|
tainted.withPlatformString({
|
|
ptr in
|
|
sink(arg: ptr[0]) // $ tainted=366
|
|
sink(arg: String(platformString: ptr)) // $ tainted=366
|
|
|
|
let buffer = UnsafeBufferPointer(start: ptr, count: 10)
|
|
let arrayString = Array(buffer)
|
|
sink(arg: buffer[0]) // $ MISSING: tainted=366
|
|
sink(arg: arrayString[0]) // $ MISSING: tainted=366
|
|
sink(arg: String(platformString: arrayString)) // $ MISSING: tainted=366
|
|
})
|
|
|
|
clean.withContiguousStorageIfAvailable({
|
|
ptr in
|
|
sink(arg: ptr[0])
|
|
sink(arg: ptr.baseAddress!)
|
|
})
|
|
tainted.withContiguousStorageIfAvailable({
|
|
ptr in
|
|
sink(arg: ptr[0]) // $ tainted=366
|
|
sink(arg: ptr.baseAddress!) // $ MISSING: tainted=366
|
|
})
|
|
}
|
|
|
|
func source4() -> UInt8 { return 0 }
|
|
|
|
func taintFromUInt8Array() {
|
|
var cleanUInt8Values: [UInt8] = [0x41, 0x42, 0x43, 0] // "ABC"
|
|
var taintedUInt8Values: [UInt8] = [source4()]
|
|
|
|
sink(arg: taintedUInt8Values[0]) // $ tainted=450
|
|
let r1 = String(unsafeUninitializedCapacity: 256, initializingUTF8With: {
|
|
(buffer: UnsafeMutableBufferPointer<UInt8>) -> Int in
|
|
sink(arg: buffer[0])
|
|
let _ = buffer.initialize(from: cleanUInt8Values)
|
|
sink(arg: buffer[0])
|
|
return 3
|
|
}
|
|
)
|
|
sink(arg: r1)
|
|
let r2 = String(unsafeUninitializedCapacity: 256, initializingUTF8With: {
|
|
(buffer: UnsafeMutableBufferPointer<UInt8>) -> Int in
|
|
sink(arg: buffer[0])
|
|
sink(arg: taintedUInt8Values[0]) // $ tainted=450
|
|
let _ = buffer.initialize(from: taintedUInt8Values)
|
|
sink(arg: buffer[0]) // $ tainted=450
|
|
return 256
|
|
}
|
|
)
|
|
sink(arg: r2) // $ tainted=450
|
|
let r3 = String(unsafeUninitializedCapacity: 256, initializingUTF8With: {
|
|
(buffer: UnsafeMutableBufferPointer<UInt8>) -> Int in
|
|
sink(arg: buffer[0])
|
|
buffer.update(repeating: source4())
|
|
sink(arg: buffer[0]) // $ tainted=475
|
|
return 256
|
|
}
|
|
)
|
|
sink(arg: r3) // $ tainted=475
|
|
|
|
sink(arg: String(bytes: cleanUInt8Values, encoding: String.Encoding.utf8)!)
|
|
sink(arg: String(bytes: taintedUInt8Values, encoding: String.Encoding.utf8)!) // $ tainted=450
|
|
sink(arg: String(cString: cleanUInt8Values))
|
|
sink(arg: String(cString: taintedUInt8Values)) // $ tainted=450
|
|
|
|
try! cleanUInt8Values.withUnsafeBufferPointer({
|
|
(buffer: UnsafeBufferPointer<UInt8>) throws in
|
|
sink(arg: buffer[0])
|
|
sink(arg: buffer.baseAddress!)
|
|
sink(arg: String(cString: buffer.baseAddress!))
|
|
})
|
|
try! taintedUInt8Values.withUnsafeBufferPointer({
|
|
(buffer: UnsafeBufferPointer<UInt8>) throws in
|
|
sink(arg: buffer[0]) // $ tainted=450
|
|
sink(arg: buffer.baseAddress!) // $ MISSING: tainted=450
|
|
sink(arg: String(cString: buffer.baseAddress!)) // $ MISSING: tainted=450
|
|
})
|
|
try! cleanUInt8Values.withUnsafeMutableBytes({
|
|
(buffer: UnsafeMutableRawBufferPointer) throws in
|
|
sink(arg: buffer[0])
|
|
sink(arg: buffer.baseAddress!)
|
|
sink(arg: String(bytesNoCopy: buffer.baseAddress!, length: buffer.count, encoding: String.Encoding.utf8, freeWhenDone: false)!)
|
|
})
|
|
try! taintedUInt8Values.withUnsafeMutableBytes({
|
|
(buffer: UnsafeMutableRawBufferPointer) throws in
|
|
sink(arg: buffer[0]) // $ tainted=450
|
|
sink(arg: buffer.baseAddress!) // $ MISSING: tainted=450
|
|
sink(arg: String(bytesNoCopy: buffer.baseAddress!, length: buffer.count, encoding: String.Encoding.utf8, freeWhenDone: false)!) // $ MISSING: tainted=450
|
|
})
|
|
}
|
|
|
|
func source5() -> CChar { return 0 }
|
|
|
|
func taintThroughCCharArray() {
|
|
let cleanCCharValues: [CChar] = [0x41, 0x42, 0x43, 0]
|
|
let taintedCCharValues: [CChar] = [source5()]
|
|
|
|
cleanCCharValues.withUnsafeBufferPointer({
|
|
ptr in
|
|
sink(arg: ptr[0])
|
|
sink(arg: ptr.baseAddress!)
|
|
sink(arg: String(utf8String: ptr.baseAddress!)!)
|
|
sink(arg: String(validatingUTF8: ptr.baseAddress!)!)
|
|
sink(arg: String(cString: ptr.baseAddress!))
|
|
})
|
|
taintedCCharValues.withUnsafeBufferPointer({
|
|
ptr in
|
|
sink(arg: ptr[0]) // $ tainted=517
|
|
sink(arg: ptr.baseAddress!) // $ MISSING: tainted=517
|
|
sink(arg: String(utf8String: ptr.baseAddress!)!) // $ MISSING: tainted=517
|
|
sink(arg: String(validatingUTF8: ptr.baseAddress!)!) // $ MISSING: tainted=517
|
|
sink(arg: String(cString: ptr.baseAddress!)) // $ MISSING: tainted=517
|
|
})
|
|
|
|
sink(arg: String(cString: cleanCCharValues))
|
|
sink(arg: String(cString: taintedCCharValues)) // $ tainted=517
|
|
}
|
|
|
|
func source6() -> unichar { return 0 }
|
|
|
|
func taintThroughUnicharArray() {
|
|
let cleanUnicharValues: [unichar] = [0x41, 0x42, 0x43, 0]
|
|
let taintedUnicharValues: [unichar] = [source6()]
|
|
|
|
cleanUnicharValues.withUnsafeBufferPointer({
|
|
ptr in
|
|
sink(arg: ptr[0])
|
|
sink(arg: ptr.baseAddress!)
|
|
sink(arg: String(utf16CodeUnits: ptr.baseAddress!, count: ptr.count))
|
|
sink(arg: String(utf16CodeUnitsNoCopy: ptr.baseAddress!, count: ptr.count, freeWhenDone: false))
|
|
})
|
|
taintedUnicharValues.withUnsafeBufferPointer({
|
|
ptr in
|
|
sink(arg: ptr[0]) // $ tainted=544
|
|
sink(arg: ptr.baseAddress!) // $ MISSING: tainted=544
|
|
sink(arg: String(utf16CodeUnits: ptr.baseAddress!, count: ptr.count)) // $ MISSING: tainted=5344
|
|
sink(arg: String(utf16CodeUnitsNoCopy: ptr.baseAddress!, count: ptr.count, freeWhenDone: false)) // $ MISSING: tainted=544
|
|
})
|
|
}
|
|
|
|
func source7() -> Substring { return Substring() }
|
|
|
|
func taintThroughSubstring() {
|
|
let tainted = source2()
|
|
|
|
sink(arg: source7()) // $ tainted=567
|
|
|
|
let sub1 = tainted[tainted.startIndex ..< tainted.endIndex]
|
|
sink(arg: sub1) // $ tainted=565
|
|
sink(arg: String(sub1)) // $ tainted=565
|
|
|
|
let sub2 = tainted.prefix(10)
|
|
sink(arg: sub2) // $ tainted=565
|
|
sink(arg: String(sub2)) // $ tainted=565
|
|
|
|
let sub3 = tainted.prefix(through: tainted.endIndex)
|
|
sink(arg: sub3) // $ tainted=565
|
|
sink(arg: String(sub3)) // $ tainted=565
|
|
|
|
let sub4 = tainted.prefix(upTo: tainted.endIndex)
|
|
sink(arg: sub4) // $ tainted=565
|
|
sink(arg: String(sub4)) // $ tainted=565
|
|
|
|
let sub5 = tainted.suffix(10)
|
|
sink(arg: sub5) // $ tainted=565
|
|
sink(arg: String(sub5)) // $ tainted=565
|
|
|
|
let sub6 = tainted.suffix(from: tainted.startIndex)
|
|
sink(arg: sub6) // $ tainted=565
|
|
sink(arg: String(sub6)) // $ tainted=565
|
|
}
|
|
|
|
func taintedThroughConversion() {
|
|
sink(arg: String(0))
|
|
sink(arg: String(source())) // $ tainted=596
|
|
|
|
sink(arg: Int(0).description)
|
|
sink(arg: source().description) // $ tainted=599
|
|
|
|
sink(arg: String(describing: 0))
|
|
sink(arg: String(describing: source())) // $ tainted=602
|
|
|
|
sink(arg: Int("123")!)
|
|
sink(arg: Int(source2())!) // $ tainted=605
|
|
}
|
|
|
|
func untaintedFields() {
|
|
let tainted = source2()
|
|
|
|
sink(arg: String.availableStringEncodings)
|
|
sink(arg: String.defaultCStringEncoding)
|
|
sink(arg: tainted.isContiguousUTF8)
|
|
}
|
|
|
|
func callbackWithCleanPointer(ptr: UnsafeBufferPointer<String.Element>) throws -> Int {
|
|
sink(arg: ptr[0])
|
|
|
|
return 0
|
|
}
|
|
|
|
func callbackWithTaintedPointer(ptr: UnsafeBufferPointer<String.Element>) throws -> Int {
|
|
sink(arg: ptr[0]) // $ tainted=630
|
|
|
|
return source()
|
|
}
|
|
|
|
func furtherTaintThroughCallbacks() {
|
|
let clean = ""
|
|
let tainted = source2()
|
|
|
|
// return values from the closure (1)
|
|
let result1 = clean.withContiguousStorageIfAvailable({
|
|
ptr in
|
|
return 0
|
|
})
|
|
sink(arg: result1!)
|
|
let result2 = clean.withContiguousStorageIfAvailable({
|
|
ptr in
|
|
return source()
|
|
})
|
|
sink(arg: result2!) // $ tainted=640
|
|
|
|
// return values from the closure (2)
|
|
if let result3 = clean.withContiguousStorageIfAvailable({
|
|
ptr in
|
|
return 0
|
|
}) {
|
|
sink(arg: result3)
|
|
}
|
|
if let result4 = clean.withContiguousStorageIfAvailable({
|
|
ptr in
|
|
return source()
|
|
}) {
|
|
sink(arg: result4) // $ tainted=653
|
|
}
|
|
|
|
// using a non-closure function
|
|
let result5 = try? clean.withContiguousStorageIfAvailable(callbackWithCleanPointer)
|
|
sink(arg: result5!)
|
|
let result6 = try? tainted.withContiguousStorageIfAvailable(callbackWithTaintedPointer)
|
|
sink(arg: result6!) // $ tainted=625
|
|
}
|
|
|
|
func testAppendingFormat() {
|
|
var s1 = source2()
|
|
sink(arg: s1.appendingFormat("%s %i", "", 0)) // $ tainted=666
|
|
|
|
var s2 = ""
|
|
sink(arg: s2.appendingFormat(source2(), "", 0)) // $ tainted=670
|
|
|
|
var s3 = ""
|
|
sink(arg: s3.appendingFormat("%s %i", source2(), 0)) // $ tainted=673
|
|
|
|
var s4 = ""
|
|
sink(arg: s4.appendingFormat("%s %i", "", source())) // $ tainted=676
|
|
}
|
|
|
|
func sourceUInt8() -> UInt8 { return 0 }
|
|
|
|
func testDecodeCString() {
|
|
var input : [UInt8] = [1, 2, 3, sourceUInt8()]
|
|
|
|
let (str1, repaired1) = String.decodeCString(input, as: UTF8.self)!
|
|
sink(arg: str1) // $ tainted=682
|
|
sink(arg: repaired1)
|
|
|
|
input.withUnsafeBufferPointer({
|
|
ptr in
|
|
let (str2, repaired2) = String.decodeCString(ptr.baseAddress, as: UTF8.self)!
|
|
sink(arg: str2) // $ MISSING: tainted=682
|
|
sink(arg: repaired2)
|
|
})
|
|
|
|
let (str3, repaired3) = String.decodeCString(source2(), as: UTF8.self)!
|
|
sink(arg: str3) // $ tainted=695
|
|
sink(arg: repaired3)
|
|
|
|
let (str4, repaired4) = String.decodeCString(&input, as: UTF8.self)!
|
|
sink(arg: str4) // $ tainted=682
|
|
sink(arg: repaired4)
|
|
}
|
|
|
|
func testSubstringMembers() {
|
|
let clean = ""
|
|
let tainted = source2()
|
|
|
|
let sub1 = tainted[..<tainted.index(tainted.endIndex, offsetBy: -5)]
|
|
sink(arg: sub1) // $ tainted=706
|
|
sink(arg: sub1.base) // $ tainted=706
|
|
sink(arg: sub1.utf8) // $ tainted=706
|
|
sink(arg: sub1.capitalized) // $ tainted=706
|
|
sink(arg: sub1.description) // $ tainted=706
|
|
|
|
var sub2 = tainted[tainted.index(tainted.startIndex, offsetBy: 5)...]
|
|
sink(arg: sub2) // $ tainted=706
|
|
let result1 = sub2.withUTF8({
|
|
buffer in
|
|
sink(arg: buffer[0]) // $ tainted=706
|
|
return source()
|
|
})
|
|
sink(arg: result1) // $ tainted=720
|
|
|
|
let sub3 = Substring(sub2.utf8)
|
|
sink(arg: sub3) // $ tainted=706
|
|
|
|
var sub4 = clean.prefix(10)
|
|
sink(arg: sub4)
|
|
sub4.replaceSubrange(..<clean.endIndex, with: sub1)
|
|
sink(arg: sub4) // $ tainted=706
|
|
}
|
|
|
|
// ---
|
|
|
|
func taintMutableCharacters() {
|
|
var str = ""
|
|
|
|
sink(arg: str)
|
|
let rtn = str.withMutableCharacters({
|
|
chars in
|
|
sink(arg: chars)
|
|
chars.append(source2())
|
|
sink(arg: chars) // $ tainted=742
|
|
return source()
|
|
})
|
|
sink(arg: rtn) // $ tainted=744
|
|
sink(arg: str) // $ tainted=742
|
|
}
|