mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
Merge pull request #13698 from geoffw0/url2
Swift: Expand taint models for URL
This commit is contained in:
5
swift/ql/lib/change-notes/2023-07-06-url-models.md
Normal file
5
swift/ql/lib/change-notes/2023-07-06-url-models.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
|
||||
* Added detail to the taint model for `URL`.
|
||||
@@ -35,6 +35,36 @@ private class UrlRequestFieldsInheritTaint extends TaintInheritingContent,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A content implying that, if a `URLResource` is tainted, then its fields `name`
|
||||
* and `subdirectory` are tainted.
|
||||
*/
|
||||
private class UrlResourceFieldsInheritTaint extends TaintInheritingContent,
|
||||
DataFlow::Content::FieldContent
|
||||
{
|
||||
UrlResourceFieldsInheritTaint() {
|
||||
this.getField().getEnclosingDecl().asNominalTypeDecl().getName() = "URLResource" and
|
||||
this.getField().getName() = ["name", "subdirectory"]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A content implying that, if a `URLResourceValues` is tainted, then certain
|
||||
* fields are tainted.
|
||||
*/
|
||||
private class UrlResourceValuesFieldsInheritTaint extends TaintInheritingContent,
|
||||
DataFlow::Content::FieldContent
|
||||
{
|
||||
UrlResourceValuesFieldsInheritTaint() {
|
||||
this.getField().getEnclosingDecl().asNominalTypeDecl().getName() = "URLResourceValues" and
|
||||
this.getField().getName() =
|
||||
[
|
||||
"name", "path", "canonicalPath", "localizedLabel", "localizedName", "parentDirectory",
|
||||
"thumbnail"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A model for `URL` members that are sources of remote flow.
|
||||
*/
|
||||
@@ -49,14 +79,74 @@ private class UrlRemoteFlowSource extends SourceModelCsv {
|
||||
}
|
||||
|
||||
/**
|
||||
* A model for `URL` members that permit taint flow.
|
||||
* A model for `URL` and related class members that permit taint flow.
|
||||
*/
|
||||
private class UrlSummaries extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
";URL;true;init(string:);(String);;Argument[0];ReturnValue;taint",
|
||||
";URL;true;init(string:relativeTo:);(String,URL?);;Argument[0,1];ReturnValue;taint"
|
||||
";URL;true;init(string:relativeTo:);(String,URL?);;Argument[0..1];ReturnValue;taint",
|
||||
";URL;true;init(fileURLWithPath:);;;Argument[0];ReturnValue;taint",
|
||||
";URL;true;init(fileURLWithPath:isDirectory:);;;Argument[0];ReturnValue;taint",
|
||||
";URL;true;init(fileURLWithPath:relativeTo:);;;Argument[0..1];ReturnValue;taint",
|
||||
";URL;true;init(fileURLWithPath:isDirectory:relativeTo:);;;Argument[0];ReturnValue;taint",
|
||||
";URL;true;init(fileURLWithPath:isDirectory:relativeTo:);;;Argument[2];ReturnValue;taint",
|
||||
";URL;true;init(fileURLWithFileSystemRepresentation:isDirectory:relativeTo:);;;Argument[0];ReturnValue;taint",
|
||||
";URL;true;init(fileURLWithFileSystemRepresentation:isDirectory:relativeTo:);;;Argument[2];ReturnValue;taint",
|
||||
";URL;true;init(fileReferenceLiteralResourceName:);;;Argument[0];ReturnValue;taint",
|
||||
";URL;true;init(_:);;;Argument[0];ReturnValue;taint",
|
||||
";URL;true;init(_:isDirectory:);;;Argument[0];ReturnValue;taint",
|
||||
";URL;true;init(resolvingBookmarkData:options:relativeTo:bookmarkDataIsStale:);;;Argument[0];ReturnValue;taint",
|
||||
";URL;true;init(resolvingBookmarkData:options:relativeTo:bookmarkDataIsStale:);;;Argument[2];ReturnValue;taint",
|
||||
";URL;true;init(resolvingAliasFileAt:options:);;;Argument[0];ReturnValue;taint",
|
||||
";URL;true;init(resource:);;;Argument[0];ReturnValue;taint",
|
||||
";URL;true;init(dataRepresentation:relativeTo:isAbsolute:);;;Argument[0..1];ReturnValue;taint",
|
||||
";URL;true;init(_:strategy:);;;Argument[0];ReturnValue;taint",
|
||||
";URL;true;init(filePath:directoryHint:);;;Argument[0];ReturnValue;taint",
|
||||
";URL;true;init(filePath:directoryHint:relativeTo:);;;Argument[0];ReturnValue;taint",
|
||||
";URL;true;init(filePath:directoryHint:relativeTo:);;;Argument[2];ReturnValue;taint",
|
||||
";URL;true;init(for:in:appropriateFor:create:);;;Argument[0..2];ReturnValue;taint",
|
||||
";URL;true;init(string:encodingInvalidCharacters:);;;Argument[0];ReturnValue;taint",
|
||||
";URL;true;resourceValues(forKeys:);;;Argument[-1];ReturnValue;taint",
|
||||
";URL;true;setResourceValues(_:);;;Argument[0];Argument[-1];taint",
|
||||
";URL;true;setTemporaryResourceValue(_:forKey:);;;Argument[-1..0];Argument[-1];taint",
|
||||
";URL;true;withUnsafeFileSystemRepresentation(_:);;;Argument[-1],Argument[0].Parameter[0];ReturnValue;taint",
|
||||
";URL;true;withUnsafeFileSystemRepresentation(_:);;;Argument[0].ReturnValue;ReturnValue;taint",
|
||||
";URL;true;resolvingSymlinksInPath();;;Argument[-1];ReturnValue;taint",
|
||||
";URL;true;appendPathComponent(_:);;;Argument[-1..0];Argument[-1];taint",
|
||||
";URL;true;appendPathComponent(_:isDirectory:);;;Argument[-1..0];Argument[-1];taint",
|
||||
";URL;true;appendPathComponent(_:conformingTo:);;;Argument[-1..0];Argument[-1];taint",
|
||||
";URL;true;appendingPathComponent(_:);;;Argument[-1..0];ReturnValue;taint",
|
||||
";URL;true;appendingPathComponent(_:isDirectory:);;;Argument[-1..0];ReturnValue;taint",
|
||||
";URL;true;appendingPathComponent(_:conformingTo:);;;Argument[-1..0];ReturnValue;taint",
|
||||
";URL;true;appendPathExtension(_:);;;Argument[-1..0];Argument[-1];taint",
|
||||
";URL;true;appendingPathExtension(_:);;;Argument[-1..0];ReturnValue;taint",
|
||||
";URL;true;deletingLastPathComponent();;;Argument[-1];ReturnValue;taint",
|
||||
";URL;true;deletingPathExtension();;;Argument[-1];ReturnValue;taint",
|
||||
";URL;true;bookmarkData(options:includingResourceValuesForKeys:relativeTo:);;;Argument[-1];ReturnValue;taint",
|
||||
";URL;true;bookmarkData(options:includingResourceValuesForKeys:relativeTo:);;;Argument[1..2];ReturnValue;taint",
|
||||
";URL;true;bookmarkData(withContentsOf:);;;Argument[0];ReturnValue;taint",
|
||||
";URL;true;resourceValues(forKeys:fromBookmarkData:);;;Argument[1];ReturnValue;taint",
|
||||
";URL;true;promisedItemResourceValues(forKeys:);;;Argument[-1];ReturnValue;taint",
|
||||
";URL;true;append(component:directoryHint:);;;Argument[-1..0];Argument[-1];taint",
|
||||
";URL;true;append(components:directoryHint:);;;Argument[-1..0];Argument[-1];taint",
|
||||
";URL;true;append(path:directoryHint:);;;Argument[-1..0];Argument[-1];taint",
|
||||
";URL;true;append(queryItems:);;;Argument[-1..0];Argument[-1];taint",
|
||||
";URL;true;appending(component:directoryHint:);;;Argument[-1..0];ReturnValue;taint",
|
||||
";URL;true;appending(components:directoryHint:);;;Argument[-1..0];ReturnValue;taint",
|
||||
";URL;true;appending(path:directoryHint:);;;Argument[-1..0];ReturnValue;taint",
|
||||
";URL;true;appending(queryItems:);;;Argument[-1..0];ReturnValue;taint",
|
||||
";URL;true;formatted();;;Argument[-1];ReturnValue;taint",
|
||||
";URL;true;formatted(_:);;;Argument[-1..0];ReturnValue;taint",
|
||||
";URL;true;fragment(percentEncoded:);;;Argument[-1];ReturnValue;taint",
|
||||
";URL;true;host(percentEncoded:);;;Argument[-1];ReturnValue;taint",
|
||||
";URL;true;password(percentEncoded:);;;Argument[-1];ReturnValue;taint",
|
||||
";URL;true;path(percentEncoded:);;;Argument[-1];ReturnValue;taint",
|
||||
";URL;true;query(percentEncoded:);;;Argument[-1];ReturnValue;taint",
|
||||
";URL;true;user(percentEncoded:);;;Argument[-1];ReturnValue;taint",
|
||||
";URL;true;homeDirectory(forUser:);;;Argument[0];ReturnValue;taint",
|
||||
";URLResource;true;init(name:subdirectory:locale:bundle:);;;Argument[0..1];ReturnValue;taint",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
deadEnd
|
||||
| url.swift:493:2:493:28 | call to sink(any:) |
|
||||
@@ -5,8 +5,53 @@ class NSObject
|
||||
|
||||
struct URL
|
||||
{
|
||||
typealias BookmarkResolutionOptions = NSURL.BookmarkResolutionOptions
|
||||
|
||||
struct URLResourceKey : Hashable {
|
||||
init(_ rawValue: String) { }
|
||||
init(rawValue: String) { }
|
||||
|
||||
// …
|
||||
}
|
||||
|
||||
struct URLResourceValues {
|
||||
var name: String?
|
||||
var path: String?
|
||||
var canonicalPath: String?
|
||||
var localizedLabel: String?
|
||||
var localizedName: String?
|
||||
var parentDirectory: URL?
|
||||
|
||||
// …
|
||||
}
|
||||
|
||||
struct AsyncBytes {
|
||||
// …
|
||||
}
|
||||
|
||||
enum DirectoryHint {
|
||||
case inferFromPath
|
||||
}
|
||||
|
||||
init?(string: String) {}
|
||||
init?(string: String, relativeTo: URL?) {}
|
||||
init(fileURLWithPath path: String) { }
|
||||
init(fileURLWithPath path: String, isDirectory: Bool) { }
|
||||
init(fileURLWithPath path: String, relativeTo base: URL?) { }
|
||||
init(fileURLWithPath path: String, isDirectory: Bool, relativeTo base: URL?) { }
|
||||
init(fileURLWithFileSystemRepresentation path: UnsafePointer<Int8>, isDirectory: Bool, relativeTo baseURL: URL?) { }
|
||||
init(fileReferenceLiteralResourceName name: String) { }
|
||||
init?(_ path: FilePath) { }
|
||||
init?(_ path: FilePath, isDirectory: Bool) { }
|
||||
init(resolvingBookmarkData data: Data, options: URL.BookmarkResolutionOptions = [], relativeTo url: URL? = nil, bookmarkDataIsStale: inout Bool) throws { }
|
||||
init(resolvingAliasFileAt url: URL, options: URL.BookmarkResolutionOptions = []) throws { }
|
||||
init?(resource: URLResource) { }
|
||||
init?(dataRepresentation: Data, relativeTo url: URL?, isAbsolute: Bool = false) { }
|
||||
init?(filePath path: FilePath, directoryHint: URL.DirectoryHint = .inferFromPath) { }
|
||||
init(filePath path: String, directoryHint: URL.DirectoryHint = .inferFromPath, relativeTo base: URL? = nil) { }
|
||||
|
||||
var dataRepresentation: Data { get { return Data(0) } }
|
||||
var absoluteString: String { get { return "" } }
|
||||
var absoluteURL: URL { get {return URL(string: "")!} }
|
||||
var baseURL: URL { get {return URL(string: "")!} }
|
||||
var fragment: String? { get {return nil} }
|
||||
@@ -24,6 +69,54 @@ struct URL
|
||||
var standardizedFileURL: URL { get {return URL(string: "")!} }
|
||||
var user: String? { get {return nil} }
|
||||
var password: String? { get {return nil} }
|
||||
var resourceBytes: URL.AsyncBytes { get { return (nil as AsyncBytes?)! } }
|
||||
var lines: AsyncLineSequence<URL.AsyncBytes> { get { return (nil as AsyncLineSequence<URL.AsyncBytes>?)! } }
|
||||
|
||||
func resourceValues(forKeys keys: Set<URLResourceKey>) throws -> URLResourceValues { return URLResourceValues() }
|
||||
static func resourceValues(forKeys keys: Set<URLResourceKey>, fromBookmarkData data: Data) -> URLResourceValues? { return nil }
|
||||
mutating func setResourceValues(_ values: URLResourceValues) throws { }
|
||||
mutating func setTemporaryResourceValue(_ value: Any, forKey key: URLResourceKey) { }
|
||||
func withUnsafeFileSystemRepresentation<ResultType>(_ block: (UnsafePointer<Int8>?) throws -> ResultType) rethrows -> ResultType { return (nil as ResultType?)! }
|
||||
func resolvingSymlinksInPath() -> URL { return URL(string: "")! }
|
||||
mutating func appendPathComponent(_ pathComponent: String) { }
|
||||
mutating func appendPathComponent(_ pathComponent: String, isDirectory: Bool) { }
|
||||
func appendingPathComponent(_ pathComponent: String) -> URL { return URL(string: "")! }
|
||||
func appendingPathComponent(_ pathComponent: String, isDirectory: Bool) -> URL { return URL(string: "")! }
|
||||
mutating func appendPathExtension(_ pathExtension: String) { }
|
||||
func appendingPathExtension(_ pathExtension: String) -> URL { return URL(string: "")! }
|
||||
func deletingLastPathComponent() -> URL { return URL(string: "")! }
|
||||
func deletingPathExtension() -> URL { return URL(string: "")! }
|
||||
mutating func append<S>(component: S, directoryHint: URL.DirectoryHint = .inferFromPath) where S: StringProtocol { }
|
||||
mutating func append<S>(components: S..., directoryHint: URL.DirectoryHint = .inferFromPath) where S: StringProtocol { }
|
||||
mutating func append<S>(path: S, directoryHint: URL.DirectoryHint = .inferFromPath) where S: StringProtocol { }
|
||||
mutating func append(queryItems: [URLQueryItem]) { }
|
||||
func appending<S>(component: S, directoryHint: URL.DirectoryHint = .inferFromPath) -> URL where S: StringProtocol { return URL(string: "")! }
|
||||
func appending<S>(components: S..., directoryHint: URL.DirectoryHint = .inferFromPath) -> URL where S: StringProtocol { return URL(string: "")! }
|
||||
func appending<S>(path: S, directoryHint: URL.DirectoryHint = .inferFromPath) -> URL where S: StringProtocol { return URL(string: "")! }
|
||||
func appending(queryItems: [URLQueryItem]) -> URL { return URL(string: "")! }
|
||||
func promisedItemResourceValues(forKeys keys: Set<URLResourceKey>) throws -> URLResourceValues { return (nil as URLResourceValues?)! }
|
||||
func formatted() -> String { return "" }
|
||||
func fragment(percentEncoded: Bool = true) -> String? { return nil }
|
||||
func host(percentEncoded: Bool = true) -> String? { return nil }
|
||||
func password(percentEncoded: Bool = true) -> String? { return nil }
|
||||
func path(percentEncoded: Bool = true) -> String { return "" }
|
||||
func query(percentEncoded: Bool = true) -> String? { return nil }
|
||||
func user(percentEncoded: Bool = true) -> String? { return nil }
|
||||
|
||||
// simplified:
|
||||
func bookmarkData(options: Int = 0, includingResourceValuesForKeys keys: Set<URLResourceKey>? = nil, relativeTo url: URL? = nil) throws -> Data { return Data(0) }
|
||||
static func bookmarkData(withContentsOf url: URL) throws -> Data { return Data(0) }
|
||||
|
||||
static var homeDirectory: URL { get { return URL(string: "")! } }
|
||||
static func homeDirectory(forUser user: String) -> URL? { return nil }
|
||||
}
|
||||
|
||||
class NSURL {
|
||||
struct BookmarkResolutionOptions : OptionSet {
|
||||
let rawValue: Int
|
||||
}
|
||||
|
||||
init?(string: String) {}
|
||||
}
|
||||
|
||||
class Data
|
||||
@@ -31,12 +124,36 @@ class Data
|
||||
init<S>(_ elements: S) {}
|
||||
}
|
||||
|
||||
struct FilePath {
|
||||
init(_ string: String) {}
|
||||
}
|
||||
|
||||
struct AsyncLineSequence<Base> : AsyncSequence {
|
||||
typealias Element = String
|
||||
struct AsyncIterator : AsyncIteratorProtocol {
|
||||
typealias Element = String
|
||||
mutating func next() async -> String? { return nil }
|
||||
}
|
||||
func makeAsyncIterator() -> AsyncIterator { return AsyncIterator() }
|
||||
}
|
||||
|
||||
class InputStream {}
|
||||
|
||||
struct Mirror {}
|
||||
|
||||
typealias TimeInterval = Double
|
||||
|
||||
struct URLResource {
|
||||
// simplified:
|
||||
init(name: String, subdirectory: String? = nil, locale: Int = 0, bundle: Int = 0) {
|
||||
self.name = name
|
||||
self.subdirectory = subdirectory
|
||||
}
|
||||
|
||||
let name: String
|
||||
let subdirectory: String?
|
||||
}
|
||||
|
||||
struct URLRequest {
|
||||
enum CachePolicy { case none }
|
||||
enum NetworkServiceType { case none }
|
||||
@@ -64,7 +181,9 @@ struct URLRequest {
|
||||
var requiresDNSSECValidation: Bool = false
|
||||
}
|
||||
|
||||
class URLResponse : NSObject {}
|
||||
struct URLQueryItem { }
|
||||
|
||||
class URLResponse : NSObject { }
|
||||
|
||||
class URLSessionTask : NSObject { }
|
||||
|
||||
@@ -93,54 +212,56 @@ func taintThroughURL() {
|
||||
let urlTainted = URL(string: tainted)!
|
||||
|
||||
sink(arg: urlClean)
|
||||
sink(arg: urlTainted) // $ tainted=91
|
||||
sink(arg: urlTainted) // $ tainted=210
|
||||
// Fields
|
||||
sink(arg: urlTainted.absoluteURL) // $ tainted=91
|
||||
sink(arg: urlTainted.baseURL) // $ SPURIOUS: $ tainted=91
|
||||
sink(string: urlTainted.fragment!) // $ tainted=91
|
||||
sink(string: urlTainted.host!) // $ tainted=91
|
||||
sink(string: urlTainted.lastPathComponent) // $ tainted=91
|
||||
sink(string: urlTainted.path) // $ tainted=91
|
||||
sink(string: urlTainted.pathComponents[0]) // $ tainted=91
|
||||
sink(string: urlTainted.pathExtension) // $ tainted=91
|
||||
sink(int: urlTainted.port!) // $ tainted=91
|
||||
sink(string: urlTainted.query!) // $ tainted=91
|
||||
sink(string: urlTainted.relativePath) // $ tainted=91
|
||||
sink(string: urlTainted.relativeString) // $ tainted=91
|
||||
sink(string: urlTainted.scheme!) // $ tainted=91
|
||||
sink(arg: urlTainted.standardized) // $ tainted=91
|
||||
sink(arg: urlTainted.standardizedFileURL) // $ tainted=91
|
||||
sink(string: urlTainted.user!) // $ tainted=91
|
||||
sink(string: urlTainted.password!) // $ tainted=91
|
||||
sink(data: urlTainted.dataRepresentation) // $ tainted=210
|
||||
sink(string: urlTainted.absoluteString) // $ tainted=210
|
||||
sink(arg: urlTainted.absoluteURL) // $ tainted=210
|
||||
sink(arg: urlTainted.baseURL) // $ tainted=210
|
||||
sink(string: urlTainted.fragment!) // $ tainted=210
|
||||
sink(string: urlTainted.host!) // $ tainted=210
|
||||
sink(string: urlTainted.lastPathComponent) // $ tainted=210
|
||||
sink(string: urlTainted.path) // $ tainted=210
|
||||
sink(string: urlTainted.pathComponents[0]) // $ tainted=210
|
||||
sink(string: urlTainted.pathExtension) // $ tainted=210
|
||||
sink(int: urlTainted.port!) // $ tainted=210
|
||||
sink(string: urlTainted.query!) // $ tainted=210
|
||||
sink(string: urlTainted.relativePath) // $ tainted=210
|
||||
sink(string: urlTainted.relativeString) // $ tainted=210
|
||||
sink(string: urlTainted.scheme!) // $ tainted=210
|
||||
sink(arg: urlTainted.standardized) // $ tainted=210
|
||||
sink(arg: urlTainted.standardizedFileURL) // $ tainted=210
|
||||
sink(string: urlTainted.user!) // $ tainted=210
|
||||
sink(string: urlTainted.password!) // $ tainted=210
|
||||
sink(any: urlTainted.resourceBytes) // $ tainted=210
|
||||
|
||||
sink(arg: URL(string: clean, relativeTo: nil)!)
|
||||
sink(arg: URL(string: tainted, relativeTo: nil)!) // $ tainted=91
|
||||
sink(arg: URL(string: tainted, relativeTo: nil)!) // $ tainted=210
|
||||
sink(arg: URL(string: clean, relativeTo: urlClean)!)
|
||||
// Fields (assuming `clean` was a relative path instead of a full URL)
|
||||
sink(arg: URL(string: clean, relativeTo: urlTainted)!.absoluteURL) // $ tainted=91
|
||||
sink(arg: URL(string: clean, relativeTo: urlTainted)!.baseURL) // $ tainted=91
|
||||
sink(string: URL(string: clean, relativeTo: urlTainted)!.fragment!) // $ SPURIOUS: $ tainted=91
|
||||
sink(string: URL(string: clean, relativeTo: urlTainted)!.host!) // $ tainted=91
|
||||
sink(string: URL(string: clean, relativeTo: urlTainted)!.lastPathComponent) // $ SPURIOUS: $ tainted=91
|
||||
sink(string: URL(string: clean, relativeTo: urlTainted)!.path) // $ SPURIOUS: $ tainted=91
|
||||
sink(string: URL(string: clean, relativeTo: urlTainted)!.pathComponents[0]) // $ SPURIOUS: $ tainted=91
|
||||
sink(string: URL(string: clean, relativeTo: urlTainted)!.pathExtension) // $ SPURIOUS: $ tainted=91
|
||||
sink(int: URL(string: clean, relativeTo: urlTainted)!.port!) // $ tainted=91
|
||||
sink(string: URL(string: clean, relativeTo: urlTainted)!.query!) // $ SPURIOUS: $ tainted=91
|
||||
sink(string: URL(string: clean, relativeTo: urlTainted)!.relativePath) // $ SPURIOUS: $ tainted=91
|
||||
sink(string: URL(string: clean, relativeTo: urlTainted)!.relativeString) // $ SPURIOUS: $ tainted=91
|
||||
sink(string: URL(string: clean, relativeTo: urlTainted)!.scheme!) // $ tainted=91
|
||||
sink(arg: URL(string: clean, relativeTo: urlTainted)!.standardized) // $ tainted=91
|
||||
sink(arg: URL(string: clean, relativeTo: urlTainted)!.standardizedFileURL) // $ tainted=91
|
||||
sink(string: URL(string: clean, relativeTo: urlTainted)!.user!) // $ tainted=91
|
||||
sink(string: URL(string: clean, relativeTo: urlTainted)!.password!) // $ tainted=91
|
||||
sink(arg: URL(string: clean, relativeTo: urlTainted)!.absoluteURL) // $ tainted=210
|
||||
sink(arg: URL(string: clean, relativeTo: urlTainted)!.baseURL) // $ tainted=210
|
||||
sink(string: URL(string: clean, relativeTo: urlTainted)!.fragment!) // $ $ tainted=210
|
||||
sink(string: URL(string: clean, relativeTo: urlTainted)!.host!) // $ tainted=210
|
||||
sink(string: URL(string: clean, relativeTo: urlTainted)!.lastPathComponent) // $ $ tainted=210
|
||||
sink(string: URL(string: clean, relativeTo: urlTainted)!.path) // $ $ tainted=210
|
||||
sink(string: URL(string: clean, relativeTo: urlTainted)!.pathComponents[0]) // $ $ tainted=210
|
||||
sink(string: URL(string: clean, relativeTo: urlTainted)!.pathExtension) // $ $ tainted=210
|
||||
sink(int: URL(string: clean, relativeTo: urlTainted)!.port!) // $ tainted=210
|
||||
sink(string: URL(string: clean, relativeTo: urlTainted)!.query!) // $ $ tainted=210
|
||||
sink(string: URL(string: clean, relativeTo: urlTainted)!.relativePath) // $ $ tainted=210
|
||||
sink(string: URL(string: clean, relativeTo: urlTainted)!.relativeString) // $ $ tainted=210
|
||||
sink(string: URL(string: clean, relativeTo: urlTainted)!.scheme!) // $ tainted=210
|
||||
sink(arg: URL(string: clean, relativeTo: urlTainted)!.standardized) // $ tainted=210
|
||||
sink(arg: URL(string: clean, relativeTo: urlTainted)!.standardizedFileURL) // $ tainted=210
|
||||
sink(string: URL(string: clean, relativeTo: urlTainted)!.user!) // $ tainted=210
|
||||
sink(string: URL(string: clean, relativeTo: urlTainted)!.password!) // $ tainted=210
|
||||
|
||||
if let x = URL(string: clean) {
|
||||
sink(arg: x)
|
||||
}
|
||||
|
||||
if let y = URL(string: tainted) {
|
||||
sink(arg: y) // $ tainted=91
|
||||
sink(arg: y) // $ tainted=210
|
||||
}
|
||||
|
||||
var urlClean2 : URL!
|
||||
@@ -149,11 +270,160 @@ func taintThroughURL() {
|
||||
|
||||
var urlTainted2 : URL!
|
||||
urlTainted2 = URL(string: tainted)
|
||||
sink(arg: urlTainted2) // $ tainted=91
|
||||
sink(arg: urlTainted2) // $ tainted=210
|
||||
|
||||
let task = URLSession.shared.dataTask(with: urlTainted) { (data, response, error) in
|
||||
sink(data: data!) // $ tainted=91
|
||||
let _ = URLSession.shared.dataTask(with: urlTainted) { (data, response, error) in
|
||||
sink(data: data!) // $ tainted=210
|
||||
}
|
||||
|
||||
sink(arg: URL(fileURLWithPath: tainted)) // $ tainted=210
|
||||
sink(arg: URL(fileURLWithPath: tainted, isDirectory: false)) // $ tainted=210
|
||||
sink(arg: URL(fileURLWithPath: tainted, relativeTo: urlClean)) // $ tainted=210
|
||||
sink(arg: URL(fileURLWithPath: clean, relativeTo: urlTainted)) // $ tainted=210
|
||||
sink(arg: URL(fileURLWithPath: tainted, isDirectory: false, relativeTo: urlClean)) // $ tainted=210
|
||||
sink(arg: URL(fileURLWithPath: clean, isDirectory: false, relativeTo: urlTainted)) // $ tainted=210
|
||||
sink(arg: URL(fileURLWithPath: tainted)) // $ tainted=210
|
||||
|
||||
let _ = clean.withCString({
|
||||
ptrClean in
|
||||
sink(arg: URL(fileURLWithFileSystemRepresentation: ptrClean, isDirectory: false, relativeTo: nil))
|
||||
sink(arg: URL(fileURLWithFileSystemRepresentation: ptrClean, isDirectory: false, relativeTo: urlTainted)) // $ MISSING: tainted=210
|
||||
});
|
||||
sink(arg: URL(fileURLWithFileSystemRepresentation: 0 as! UnsafePointer<Int8>, isDirectory: false, relativeTo: urlTainted)) // $ tainted=210
|
||||
let _ = tainted.withCString({
|
||||
ptrTainted in
|
||||
sink(arg: URL(fileURLWithFileSystemRepresentation: ptrTainted, isDirectory: false, relativeTo: nil)) // $ MISSING: tainted=210
|
||||
})
|
||||
|
||||
sink(arg: URL(fileReferenceLiteralResourceName: tainted)) // $ tainted=210
|
||||
sink(arg: URL(FilePath(tainted))!) // $ tainted=210
|
||||
sink(arg: URL(FilePath(tainted), isDirectory: false)!) // $ tainted=210
|
||||
|
||||
if let values = try? urlTainted.resourceValues(forKeys: []) {
|
||||
sink(any: values) // $ tainted=210
|
||||
sink(string: values.name!) // $ tainted=210
|
||||
sink(string: values.path!) // $ tainted=210
|
||||
sink(string: values.canonicalPath!) // $ tainted=210
|
||||
sink(string: values.localizedLabel!) // $ tainted=210
|
||||
sink(string: values.localizedName!) // $ tainted=210
|
||||
sink(any: values.parentDirectory!) // $ tainted=210
|
||||
}
|
||||
if let values = try? urlTainted.promisedItemResourceValues(forKeys: []) {
|
||||
sink(any: values) // $ tainted=210
|
||||
sink(string: values.name!) // $ tainted=210
|
||||
sink(string: values.path!) // $ tainted=210
|
||||
sink(string: values.canonicalPath!) // $ tainted=210
|
||||
sink(string: values.localizedLabel!) // $ tainted=210
|
||||
sink(string: values.localizedName!) // $ tainted=210
|
||||
sink(any: values.parentDirectory!) // $ tainted=210
|
||||
}
|
||||
|
||||
urlClean.withUnsafeFileSystemRepresentation({
|
||||
ptr in
|
||||
sink(any: ptr!)
|
||||
})
|
||||
urlTainted.withUnsafeFileSystemRepresentation({
|
||||
ptr in
|
||||
sink(any: ptr!) // $ MISSING: tainted=210
|
||||
})
|
||||
|
||||
sink(arg: urlTainted.resolvingSymlinksInPath()) // $ tainted=210
|
||||
sink(arg: urlTainted.appendingPathComponent(clean)) // $ tainted=210
|
||||
sink(arg: urlClean.appendingPathComponent(tainted)) // $ tainted=210
|
||||
sink(arg: urlTainted.appendingPathComponent(clean, isDirectory: false)) // $ tainted=210
|
||||
sink(arg: urlClean.appendingPathComponent(tainted, isDirectory: false)) // $ tainted=210
|
||||
sink(arg: urlTainted.appendingPathExtension(clean)) // $ tainted=210
|
||||
sink(arg: urlClean.appendingPathExtension(tainted)) // $ tainted=210
|
||||
sink(arg: urlTainted.deletingLastPathComponent()) // $ tainted=210
|
||||
sink(arg: urlTainted.deletingPathExtension()) // $ tainted=210
|
||||
sink(arg: urlTainted.appending(component: clean)) // $ tainted=210
|
||||
sink(arg: urlClean.appending(component: tainted)) // $ tainted=210
|
||||
sink(arg: urlTainted.appending(components: clean)) // $ tainted=210
|
||||
sink(arg: urlClean.appending(components: tainted)) // $ MISSING: tainted=210
|
||||
sink(arg: urlClean.appending(components: clean, tainted)) // $ MISSING: tainted=210
|
||||
sink(arg: urlTainted.appending(path: clean)) // $ tainted=210
|
||||
sink(arg: urlClean.appending(path: tainted)) // $ tainted=210
|
||||
sink(arg: urlTainted.appending(queryItems: [])) // $ tainted=210
|
||||
sink(arg: urlClean.appending(queryItems: [source() as! URLQueryItem])) // $ MISSING: tainted=210
|
||||
|
||||
sink(arg: URL(filePath: tainted)) // $ tainted=210
|
||||
sink(arg: URL(filePath: tainted, relativeTo: nil)) // $ tainted=210
|
||||
sink(arg: URL(filePath: clean, relativeTo: urlTainted)) // $ tainted=210
|
||||
sink(arg: try! URL(resolvingAliasFileAt: urlTainted)) // $ tainted=210
|
||||
sink(arg: URL(resource: URLResource(name: tainted))!) // $ tainted=210
|
||||
sink(arg: URL(resource: URLResource(name: clean, subdirectory: tainted))!) // $ tainted=210
|
||||
|
||||
let dataClean = Data(clean)
|
||||
let dataTainted = Data(tainted)
|
||||
var stale = true
|
||||
sink(arg: URL(dataRepresentation: dataTainted, relativeTo: urlClean)!) // $ tainted=210
|
||||
sink(arg: URL(dataRepresentation: dataClean, relativeTo: urlTainted)!) // $ tainted=210
|
||||
sink(arg: try! URL(resolvingBookmarkData: dataTainted, bookmarkDataIsStale: &stale)) // $ tainted=210
|
||||
sink(arg: try! URL(resolvingBookmarkData: dataClean, relativeTo: urlTainted, bookmarkDataIsStale: &stale)) // $ tainted=210
|
||||
|
||||
sink(string: urlTainted.formatted()) // $ tainted=210
|
||||
sink(string: urlTainted.fragment()!) // $ tainted=210
|
||||
sink(string: urlTainted.host()!) // $ tainted=210
|
||||
sink(string: urlTainted.password()!) // $ tainted=210
|
||||
sink(string: urlTainted.path()) // $ tainted=210
|
||||
sink(string: urlTainted.query()!) // $ tainted=210
|
||||
sink(string: urlTainted.user()!) // $ tainted=210
|
||||
|
||||
var url1 = URL(string: clean)!
|
||||
if let values = try? urlClean.resourceValues(forKeys: []) {
|
||||
try! url1.setResourceValues(values)
|
||||
}
|
||||
sink(arg: url1)
|
||||
if let values = try? urlTainted.resourceValues(forKeys: []) {
|
||||
try! url1.setResourceValues(values)
|
||||
}
|
||||
sink(arg: url1) // $ tainted=210
|
||||
|
||||
var url2 = URL(string: clean)!
|
||||
url2.setTemporaryResourceValue(source(), forKey: URL.URLResourceKey(""))
|
||||
sink(arg: url2) // $ tainted=383
|
||||
|
||||
var url3 = URL(string: clean)!
|
||||
url3.appendPathComponent(clean)
|
||||
sink(arg: url3)
|
||||
url3.appendPathComponent(tainted)
|
||||
sink(arg: url3) // $ tainted=210
|
||||
|
||||
var url4 = URL(string: clean)!
|
||||
url4.appendPathComponent(tainted, isDirectory: false)
|
||||
sink(arg: url4) // $ tainted=210
|
||||
|
||||
var url5 = URL(string: clean)!
|
||||
url5.appendPathExtension(tainted)
|
||||
sink(arg: url5) // $ tainted=210
|
||||
|
||||
var url6 = URL(string: clean)!
|
||||
url6.append(component: tainted)
|
||||
sink(arg: url6) // $ tainted=210
|
||||
|
||||
var url7 = URL(string: clean)!
|
||||
url7.append(components: tainted)
|
||||
sink(arg: url7) // $ MISSING: tainted=210
|
||||
|
||||
var url8 = URL(string: clean)!
|
||||
url8.append(components: clean, tainted)
|
||||
sink(arg: url8) // $ MISSING: tainted=210
|
||||
|
||||
var url9 = URL(string: clean)!
|
||||
url9.append(path: tainted)
|
||||
sink(arg: url9) // $ tainted=210
|
||||
|
||||
var url10 = URL(string: clean)!
|
||||
url10.append(queryItems: [source() as! URLQueryItem])
|
||||
sink(arg: url10) // $ MISSING: tainted=210
|
||||
|
||||
sink(data: try! urlTainted.bookmarkData()) // $ tainted=210
|
||||
sink(data: try! URL.bookmarkData(withContentsOf: urlTainted)) // $ tainted=210
|
||||
sink(any: URL.resourceValues(forKeys: [], fromBookmarkData: dataTainted)!) // $ tainted=210
|
||||
|
||||
sink(arg: URL.homeDirectory) // (static var, not tainted)
|
||||
sink(arg: URL.homeDirectory(forUser: clean)!)
|
||||
sink(arg: URL.homeDirectory(forUser: tainted)!) // $ tainted=210
|
||||
}
|
||||
|
||||
func taintThroughUrlRequest() {
|
||||
@@ -161,21 +431,21 @@ func taintThroughUrlRequest() {
|
||||
let tainted = source() as! URLRequest
|
||||
|
||||
sink(any: clean)
|
||||
sink(any: tainted) // $tainted=161
|
||||
sink(any: tainted) // $ tainted=431
|
||||
sink(any: clean.cachePolicy)
|
||||
sink(any: tainted.cachePolicy)
|
||||
sink(any: clean.httpMethod)
|
||||
sink(any: tainted.httpMethod)
|
||||
sink(any: clean.url)
|
||||
sink(any: tainted.url) // $tainted=161
|
||||
sink(any: tainted.url) // $ tainted=431
|
||||
sink(any: clean.httpBody)
|
||||
sink(any: tainted.httpBody) // $tainted=161
|
||||
sink(any: clean.httpBodyStream)
|
||||
sink(any: tainted.httpBodyStream) // $tainted=161
|
||||
sink(any: tainted.httpBody) // $ tainted=431
|
||||
sink(any: clean.httpBodyStream!)
|
||||
sink(any: tainted.httpBodyStream!) // $ tainted=431
|
||||
sink(any: clean.mainDocument)
|
||||
sink(any: tainted.mainDocument) // $tainted=161
|
||||
sink(any: clean.allHTTPHeaderFields)
|
||||
sink(any: tainted.allHTTPHeaderFields) // $tainted=161
|
||||
sink(any: tainted.mainDocument) // $ tainted=431
|
||||
sink(any: clean.allHTTPHeaderFields!)
|
||||
sink(any: tainted.allHTTPHeaderFields!) // $ tainted=431
|
||||
sink(any: clean.timeoutInterval)
|
||||
sink(any: tainted.timeoutInterval)
|
||||
sink(any: clean.httpShouldHandleCookies)
|
||||
@@ -204,4 +474,41 @@ func taintThroughUrlRequest() {
|
||||
sink(any: tainted.assumesHTTP3Capable)
|
||||
sink(any: clean.requiresDNSSECValidation)
|
||||
sink(any: tainted.requiresDNSSECValidation)
|
||||
}
|
||||
}
|
||||
|
||||
func taintThroughUrlResource() {
|
||||
let clean = URLResource(name: "")
|
||||
let tainted = source() as! URLResource
|
||||
|
||||
sink(string: clean.name)
|
||||
sink(string: tainted.name) // $ tainted=481
|
||||
sink(string: clean.subdirectory!)
|
||||
sink(string: tainted.subdirectory!) // $ tainted=481
|
||||
}
|
||||
|
||||
func taintUrlAsync() async throws {
|
||||
let tainted = source() as! String
|
||||
let urlTainted = URL(string: tainted)!
|
||||
|
||||
sink(any: urlTainted.lines) // $ tainted=490
|
||||
|
||||
for try await line in urlTainted.lines {
|
||||
sink(string: line) // $ MISSING: tainted=490
|
||||
}
|
||||
}
|
||||
|
||||
func closureReturnValue() {
|
||||
let url = URL(string: "http://example.com/")!
|
||||
|
||||
let r1 = url.withUnsafeFileSystemRepresentation({
|
||||
ptr in
|
||||
return "abc"
|
||||
})
|
||||
sink(string: r1)
|
||||
|
||||
let r2 = url.withUnsafeFileSystemRepresentation({
|
||||
ptr in
|
||||
return source() as! String
|
||||
})
|
||||
sink(string: r2) // $ tainted=511
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user