Merge branch 'github:main' into main

This commit is contained in:
Yunus AYDIN
2023-11-14 00:03:25 +03:00
committed by GitHub
7 changed files with 282 additions and 94 deletions

View File

@@ -103,8 +103,8 @@ private class NsStringSummaries extends SummaryModelCsv {
";NSString;true;data(using:);;;Argument[-1];ReturnValue;taint",
";NSString;true;data(using:allowLossyConversion:);;;Argument[-1];ReturnValue;taint",
";NSString;true;path(withComponents:);;;Argument[0].CollectionElement;ReturnValue;taint",
";NSString;true;completePath(into:caseSensitive:matchesInto:filterTypes:);;;Argument[-1];Argument[0];taint",
";NSString;true;completePath(into:caseSensitive:matchesInto:filterTypes:);;;Argument[-1];Argument[2];taint",
";NSString;true;completePath(into:caseSensitive:matchesInto:filterTypes:);;;Argument[-1];Argument[0].CollectionElement;taint",
";NSString;true;completePath(into:caseSensitive:matchesInto:filterTypes:);;;Argument[-1];Argument[2].CollectionElement.CollectionElement;taint",
";NSString;true;getFileSystemRepresentation(_:maxLength:);;;Argument[-1];Argument[0];taint",
";NSString;true;appendingPathComponent(_:);;;Argument[-1..0];ReturnValue;taint",
";NSString;true;appendingPathComponent(_:conformingTo:);;;Argument[-1..0];ReturnValue;taint",

View File

@@ -3,13 +3,34 @@
*/
import swift
private import codeql.swift.dataflow.DataFlow
private import codeql.swift.dataflow.ExternalFlow
private import codeql.swift.dataflow.FlowSteps
/**
* A content implying that, if an `NSURL` is tainted, then all its fields are tainted.
*/
private class NSUrlFieldsInheritTaint extends TaintInheritingContent,
DataFlow::Content::FieldContent
{
NSUrlFieldsInheritTaint() {
this.getField().getEnclosingDecl().asNominalTypeDecl().getFullName() = "NSURL"
}
}
/**
* A model for `NSURL` members that permit taint flow.
*/
private class NsUrlSummaries extends SummaryModelCsv {
override predicate row(string row) {
row = ";NSURL;true;init(string:);(String);;Argument[0];ReturnValue.OptionalSome;taint"
row =
[
";NSURL;true;init(string:);(String);;Argument[0];ReturnValue.OptionalSome;taint",
";NSURL;true;appendingPathComponent(_:);;;Argument[-1..0];ReturnValue;taint",
";NSURL;true;appendingPathComponent(_:isDirectory:);;;Argument[-1..0];ReturnValue;taint",
";NSURL;true;appendingPathComponent(_:conformingTo:);;;Argument[-1..0];ReturnValue;taint",
";NSURL;true;appendingPathExtension(_:);;;Argument[-1..0];ReturnValue;taint",
";NSURL;true;appendingPathExtension(for:);;;Argument[-1];ReturnValue;taint",
]
}
}

View File

@@ -45,8 +45,8 @@ private class StringSummaries extends SummaryModelCsv {
";StringProtocol;true;applyingTransform(_:reverse:);;;Argument[-1];ReturnValue;taint",
";StringProtocol;true;cString(using:);;;Argument[-1];ReturnValue;taint",
";StringProtocol;true;capitalized(with:);;;Argument[-1];ReturnValue;taint",
";StringProtocol;true;completePath(into:caseSensitive:matchesInto:filterTypes:);;;Argument[-1];Argument[0].OptionalSome.CollectionElement;taint",
";StringProtocol;true;completePath(into:caseSensitive:matchesInto:filterTypes:);;;Argument[-1];Argument[2].OptionalSome.CollectionElement.CollectionElement;taint",
";StringProtocol;true;completePath(into:caseSensitive:matchesInto:filterTypes:);;;Argument[-1];Argument[0].CollectionElement;taint",
";StringProtocol;true;completePath(into:caseSensitive:matchesInto:filterTypes:);;;Argument[-1];Argument[2].CollectionElement.CollectionElement;taint",
";StringProtocol;true;components(separatedBy:);;;Argument[-1];ReturnValue;taint",
";StringProtocol;true;data(using:allowLossyConversion:);;;Argument[-1];ReturnValue;taint",
";StringProtocol;true;folding(options:locale:);;;Argument[-1];ReturnValue;taint",

View File

@@ -15,8 +15,8 @@ class UrlDecl extends StructDecl {
/**
* A content implying that, if a `URL` is tainted, then all its fields are tainted.
*/
private class UriFieldsInheritTaint extends TaintInheritingContent, DataFlow::Content::FieldContent {
UriFieldsInheritTaint() {
private class UrlFieldsInheritTaint extends TaintInheritingContent, DataFlow::Content::FieldContent {
UrlFieldsInheritTaint() {
this.getField().getEnclosingDecl().asNominalTypeDecl() instanceof UrlDecl
}
}
@@ -106,6 +106,8 @@ private class UrlSummaries extends SummaryModelCsv {
";URL;true;init(dataRepresentation:relativeTo:isAbsolute:);;;Argument[0];ReturnValue;taint",
";URL;true;init(dataRepresentation:relativeTo:isAbsolute:);;;Argument[1].OptionalSome;ReturnValue;taint",
";URL;true;init(_:strategy:);;;Argument[0];ReturnValue;taint",
";URL;true;init(filePath:);;;Argument[0];ReturnValue.OptionalSome;taint",
";URL;true;init(filePath:isDirectory:);;;Argument[0];ReturnValue.OptionalSome;taint",
";URL;true;init(filePath:directoryHint:);;;Argument[0];ReturnValue.OptionalSome;taint",
";URL;true;init(filePath:directoryHint:relativeTo:);;;Argument[0];ReturnValue;taint",
";URL;true;init(filePath:directoryHint:relativeTo:);;;Argument[2].OptionalSome;ReturnValue;taint",
@@ -126,6 +128,7 @@ private class UrlSummaries extends SummaryModelCsv {
";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;appendingPathExtension(for:);;;Argument[-1];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",

View File

@@ -61,6 +61,41 @@ private class EnumConstructorPathInjectionSink extends PathInjectionSink {
}
}
/**
* A string that might be a label for a path argument.
*/
pragma[inline]
private predicate pathLikeHeuristic(string label) {
label =
[
"atFile", "atPath", "atDirectory", "toFile", "toPath", "toDirectory", "inFile", "inPath",
"inDirectory", "contentsOfFile", "contentsOfPath", "contentsOfDirectory", "filePath",
"directory", "directoryPath"
]
}
/**
* A path injection sink that is determined by imprecise methods.
*/
private class HeuristicPathInjectionSink extends PathInjectionSink {
HeuristicPathInjectionSink() {
// by parameter name
exists(CallExpr ce, int ix, ParamDecl pd |
pathLikeHeuristic(pragma[only_bind_into](pd.getName())) and
pd.getType().getUnderlyingType().getName() = ["String", "NSString"] and
pd = ce.getStaticTarget().getParam(ix) and
this.asExpr() = ce.getArgument(ix).getExpr()
)
or
// by argument name
exists(Argument a |
pathLikeHeuristic(pragma[only_bind_into](a.getLabel())) and
a.getExpr().getType().getUnderlyingType().getName() = ["String", "NSString"] and
this.asExpr() = a.getExpr()
)
}
}
private class DefaultPathInjectionBarrier extends PathInjectionBarrier {
DefaultPathInjectionBarrier() {
// This is a simplified implementation.
@@ -87,7 +122,14 @@ private class PathInjectionSinks extends SinkModelCsv {
override predicate row(string row) {
row =
[
";Data;true;init(contentsOf:options:);;;Argument[0];path-injection",
";Data;true;write(to:options:);;;Argument[0];path-injection",
";NSData;true;init(contentsOfFile:);;;Argument[0];path-injection",
";NSData;true;init(contentsOfFile:options:);;;Argument[0];path-injection",
";NSData;true;init(contentsOf:);;;Argument[0];path-injection",
";NSData;true;init(contentsOf:options:);;;Argument[0];path-injection",
";NSData;true;init(contentsOfMappedFile:);;;Argument[0];path-injection",
";NSData;true;dataWithContentsOfMappedFile(_:);;;Argument[0];path-injection",
";NSData;true;write(to:atomically:);;;Argument[0];path-injection",
";NSData;true;write(to:options:);;;Argument[0];path-injection",
";NSData;true;write(toFile:atomically:);;;Argument[0];path-injection",
@@ -118,12 +160,14 @@ private class PathInjectionSinks extends SinkModelCsv {
";FileManager;true;fileExists(atPath:);;;Argument[0];path-injection",
";FileManager;true;fileExists(atPath:isDirectory:);;;Argument[0];path-injection",
";FileManager;true;setAttributes(_:ofItemAtPath:);;;Argument[1];path-injection",
";FileManager;true;attributesOfItem(atPath:);;;Argument[0];path-injection",
";FileManager;true;contents(atPath:);;;Argument[0];path-injection",
";FileManager;true;contentsEqual(atPath:andPath:);;;Argument[0..1];path-injection",
";FileManager;true;changeCurrentDirectoryPath(_:);;;Argument[0];path-injection",
";FileManager;true;unmountVolume(at:options:completionHandler:);;;Argument[0];path-injection",
// Deprecated FileManager methods:
";FileManager;true;changeFileAttributes(_:atPath:);;;Argument[1];path-injection",
";FileManager;true;fileAttributes(atPath:traverseLink:);;;Argument[0];path-injection",
";FileManager;true;directoryContents(atPath:);;;Argument[0];path-injection",
";FileManager;true;createDirectory(atPath:attributes:);;;Argument[0];path-injection",
";FileManager;true;createSymbolicLink(atPath:pathContent:);;;Argument[0..1];path-injection",
@@ -146,6 +190,7 @@ private class PathInjectionSinks extends SinkModelCsv {
";ArchiveByteStream;true;withFileStream(path:mode:options:permissions:_:);;;Argument[0];path-injection",
";Bundle;true;init(url:);;;Argument[0];path-injection",
";Bundle;true;init(path:);;;Argument[0];path-injection",
";NSURL;writeBookmarkData(_:to:options:);;;Argument[1];path-injection",
// GRDB
";Database;true;init(path:description:configuration:);;;Argument[0];path-injection",
";DatabasePool;true;init(path:configuration:);;;Argument[0];path-injection",

View File

@@ -0,0 +1,5 @@
---
category: minorAnalysis
---
* Added additional sinks for the "Uncontrolled data used in path expression" (`swift/path-injection`) query. Some of these sinks are heuristic (imprecise) in nature.

View File

@@ -1,12 +1,32 @@
// --- stubs ---
struct URL {
enum DirectoryHint {
case inferFromPath
}
init?(string: String) {}
init(fileURLWithPath path: String, isDirectory: Bool) {}
init(filePath path: String, directoryHint: URL.DirectoryHint = .inferFromPath, relativeTo base: URL? = nil) {}
mutating func appendPathComponent(_ pathComponent: String) {}
func appendingPathComponent(_ pathComponent: String) -> URL { return self }
}
class NSURL {
init?(string: String) {}
func appendingPathComponent(_ pathComponent: String) -> URL? { return nil }
var filePathURL: URL? { get { URL(string: "") } }
}
extension StringProtocol {
func completePath(
into outputName: UnsafeMutablePointer<String>? = nil,
caseSensitive: Bool,
matchesInto outputArray: UnsafeMutablePointer<[String]>? = nil,
filterTypes: [String]? = nil) -> Int { 0 }
}
extension String {
@@ -59,6 +79,12 @@ class Data : DataProtocol {
}
class NSData {
init() { }
init?(contentsOfFile path: String) { }
init?(contentsOfMappedFile path: String) { }
init?(contentsOf url: URL) { }
class func dataWithContentsOfMappedFile(_ path: String) -> Any? { return nil }
struct WritingOptions : OptionSet { let rawValue: Int }
func write(to: URL, atomically: Bool) -> Bool { return false }
func write(to: URL, options: NSData.WritingOptions) {}
@@ -125,7 +151,9 @@ class FileManager {
func changeCurrentDirectoryPath(_: String) -> Bool { return false }
func unmountVolume(at: URL, options: FileManager.UnmountOptions, completionHandler: (Error?) -> Void) {}
// Deprecated methods
func fileAttributes(atPath path: String, traverseLink yorn: Bool) -> [AnyHashable : Any]? { nil }
func changeFileAttributes(_: [AnyHashable : Any], atPath: String) -> Bool { return false }
func attributesOfItem(atPath path: String) throws -> [FileAttributeKey : Any] { return [:] }
func directoryContents(atPath: String) -> [Any]? { return nil }
func createDirectory(atPath: String, attributes: [AnyHashable : Any]) -> Bool { return false }
func createSymbolicLink(atPath: String, pathContent: String) -> Bool { return false }
@@ -165,6 +193,14 @@ class Bundle {
init?(path: String) {}
}
class KeyPath<Root, Value> {
}
class NSSortDescriptor {
init(key: String?, ascending: Bool) { }
convenience init<Root, Value>(keyPath: KeyPath<Root, Value>, ascending: Bool) { self.init(key: nil, ascending: ascending) }
}
// GRDB
struct Configuration {}
@@ -256,115 +292,115 @@ func test(buffer1: UnsafeMutablePointer<UInt8>, buffer2: UnsafeMutablePointer<UI
let safeUrl = URL(string: "")!
let safeNsUrl = NSURL(string: "")!
Data("").write(to: remoteUrl, options: []) // $ hasPathInjection=253
Data("").write(to: remoteUrl, options: []) // $ hasPathInjection=289
let nsData = NSData()
let _ = nsData.write(to: remoteUrl, atomically: false) // $ hasPathInjection=253
nsData.write(to: remoteUrl, options: []) // $ hasPathInjection=253
let _ = nsData.write(toFile: remoteString, atomically: false) // $ hasPathInjection=253
nsData.write(toFile: remoteString, options: []) // $ hasPathInjection=253
let _ = nsData.write(to: remoteUrl, atomically: false) // $ hasPathInjection=289
nsData.write(to: remoteUrl, options: []) // $ hasPathInjection=289
let _ = nsData.write(toFile: remoteString, atomically: false) // $ hasPathInjection=289
nsData.write(toFile: remoteString, options: []) // $ hasPathInjection=289
let fm = FileManager()
let _ = fm.contentsOfDirectory(at: remoteUrl, includingPropertiesForKeys: [], options: []) // $ hasPathInjection=253
let _ = fm.contentsOfDirectory(atPath: remoteString) // $ hasPathInjection=253
let _ = fm.enumerator(at: remoteUrl, includingPropertiesForKeys: [], options: [], errorHandler: nil) // $ hasPathInjection=253
let _ = fm.enumerator(atPath: remoteString) // $ hasPathInjection=253
let _ = fm.subpathsOfDirectory(atPath: remoteString) // $ hasPathInjection=253
let _ = fm.subpaths(atPath: remoteString) // $ hasPathInjection=253
fm.createDirectory(at: remoteUrl, withIntermediateDirectories: false, attributes: [:]) // $ hasPathInjection=253
let _ = fm.createDirectory(atPath: remoteString, attributes: [:]) // $ hasPathInjection=253
let _ = fm.createFile(atPath: remoteString, contents: nil, attributes: [:]) // $ hasPathInjection=253
fm.removeItem(at: remoteUrl) // $ hasPathInjection=253
fm.removeItem(atPath: remoteString) // $ hasPathInjection=253
fm.trashItem(at: remoteUrl, resultingItemURL: AutoreleasingUnsafeMutablePointer<NSURL?>()) // $ hasPathInjection=253
let _ = fm.replaceItemAt(remoteUrl, withItemAt: safeUrl, backupItemName: nil, options: []) // $ hasPathInjection=253
let _ = fm.replaceItemAt(safeUrl, withItemAt: remoteUrl, backupItemName: nil, options: []) // $ hasPathInjection=253
fm.replaceItem(at: remoteUrl, withItemAt: safeUrl, backupItemName: nil, options: [], resultingItemURL: AutoreleasingUnsafeMutablePointer<NSURL?>()) // $ hasPathInjection=253
fm.replaceItem(at: safeUrl, withItemAt: remoteUrl, backupItemName: nil, options: [], resultingItemURL: AutoreleasingUnsafeMutablePointer<NSURL?>()) // $ hasPathInjection=253
fm.copyItem(at: remoteUrl, to: safeUrl) // $ hasPathInjection=253
fm.copyItem(at: safeUrl, to: remoteUrl) // $ hasPathInjection=253
fm.copyItem(atPath: remoteString, toPath: "") // $ hasPathInjection=253
fm.copyItem(atPath: "", toPath: remoteString) // $ hasPathInjection=253
fm.moveItem(at: remoteUrl, to: safeUrl) // $ hasPathInjection=253
fm.moveItem(at: safeUrl, to: remoteUrl) // $ hasPathInjection=253
fm.moveItem(atPath: remoteString, toPath: "") // $ hasPathInjection=253
fm.moveItem(atPath: "", toPath: remoteString) // $ hasPathInjection=253
fm.createSymbolicLink(at: remoteUrl, withDestinationURL: safeUrl) // $ hasPathInjection=253
fm.createSymbolicLink(at: safeUrl, withDestinationURL: remoteUrl) // $ hasPathInjection=253
fm.createSymbolicLink(atPath: remoteString, withDestinationPath: "") // $ hasPathInjection=253
fm.createSymbolicLink(atPath: "", withDestinationPath: remoteString) // $ hasPathInjection=253
fm.linkItem(at: remoteUrl, to: safeUrl) // $ hasPathInjection=253
fm.linkItem(at: safeUrl, to: remoteUrl) // $ hasPathInjection=253
fm.linkItem(atPath: remoteString, toPath: "") // $ hasPathInjection=253
fm.linkItem(atPath: "", toPath: remoteString) // $ hasPathInjection=253
let _ = fm.destinationOfSymbolicLink(atPath: remoteString) // $ hasPathInjection=253
let _ = fm.fileExists(atPath: remoteString) // $ hasPathInjection=253
let _ = fm.fileExists(atPath: remoteString, isDirectory: UnsafeMutablePointer<ObjCBool>.init(bitPattern: 0)) // $ hasPathInjection=253
fm.setAttributes([:], ofItemAtPath: remoteString) // $ hasPathInjection=253
let _ = fm.contents(atPath: remoteString) // $ hasPathInjection=253
let _ = fm.contentsEqual(atPath: remoteString, andPath: "") // $ hasPathInjection=253
let _ = fm.contentsEqual(atPath: "", andPath: remoteString) // $ hasPathInjection=253
let _ = fm.changeCurrentDirectoryPath(remoteString) // $ hasPathInjection=253
let _ = fm.unmountVolume(at: remoteUrl, options: [], completionHandler: { _ in }) // $ hasPathInjection=253
let _ = fm.contentsOfDirectory(at: remoteUrl, includingPropertiesForKeys: [], options: []) // $ hasPathInjection=289
let _ = fm.contentsOfDirectory(atPath: remoteString) // $ hasPathInjection=289
let _ = fm.enumerator(at: remoteUrl, includingPropertiesForKeys: [], options: [], errorHandler: nil) // $ hasPathInjection=289
let _ = fm.enumerator(atPath: remoteString) // $ hasPathInjection=289
let _ = fm.subpathsOfDirectory(atPath: remoteString) // $ hasPathInjection=289
let _ = fm.subpaths(atPath: remoteString) // $ hasPathInjection=289
fm.createDirectory(at: remoteUrl, withIntermediateDirectories: false, attributes: [:]) // $ hasPathInjection=289
let _ = fm.createDirectory(atPath: remoteString, attributes: [:]) // $ hasPathInjection=289
let _ = fm.createFile(atPath: remoteString, contents: nil, attributes: [:]) // $ hasPathInjection=289
fm.removeItem(at: remoteUrl) // $ hasPathInjection=289
fm.removeItem(atPath: remoteString) // $ hasPathInjection=289
fm.trashItem(at: remoteUrl, resultingItemURL: AutoreleasingUnsafeMutablePointer<NSURL?>()) // $ hasPathInjection=289
let _ = fm.replaceItemAt(remoteUrl, withItemAt: safeUrl, backupItemName: nil, options: []) // $ hasPathInjection=289
let _ = fm.replaceItemAt(safeUrl, withItemAt: remoteUrl, backupItemName: nil, options: []) // $ hasPathInjection=289
fm.replaceItem(at: remoteUrl, withItemAt: safeUrl, backupItemName: nil, options: [], resultingItemURL: AutoreleasingUnsafeMutablePointer<NSURL?>()) // $ hasPathInjection=289
fm.replaceItem(at: safeUrl, withItemAt: remoteUrl, backupItemName: nil, options: [], resultingItemURL: AutoreleasingUnsafeMutablePointer<NSURL?>()) // $ hasPathInjection=289
fm.copyItem(at: remoteUrl, to: safeUrl) // $ hasPathInjection=289
fm.copyItem(at: safeUrl, to: remoteUrl) // $ hasPathInjection=289
fm.copyItem(atPath: remoteString, toPath: "") // $ hasPathInjection=289
fm.copyItem(atPath: "", toPath: remoteString) // $ hasPathInjection=289
fm.moveItem(at: remoteUrl, to: safeUrl) // $ hasPathInjection=289
fm.moveItem(at: safeUrl, to: remoteUrl) // $ hasPathInjection=289
fm.moveItem(atPath: remoteString, toPath: "") // $ hasPathInjection=289
fm.moveItem(atPath: "", toPath: remoteString) // $ hasPathInjection=289
fm.createSymbolicLink(at: remoteUrl, withDestinationURL: safeUrl) // $ hasPathInjection=289
fm.createSymbolicLink(at: safeUrl, withDestinationURL: remoteUrl) // $ hasPathInjection=289
fm.createSymbolicLink(atPath: remoteString, withDestinationPath: "") // $ hasPathInjection=289
fm.createSymbolicLink(atPath: "", withDestinationPath: remoteString) // $ hasPathInjection=289
fm.linkItem(at: remoteUrl, to: safeUrl) // $ hasPathInjection=289
fm.linkItem(at: safeUrl, to: remoteUrl) // $ hasPathInjection=289
fm.linkItem(atPath: remoteString, toPath: "") // $ hasPathInjection=289
fm.linkItem(atPath: "", toPath: remoteString) // $ hasPathInjection=289
let _ = fm.destinationOfSymbolicLink(atPath: remoteString) // $ hasPathInjection=289
let _ = fm.fileExists(atPath: remoteString) // $ hasPathInjection=289
let _ = fm.fileExists(atPath: remoteString, isDirectory: UnsafeMutablePointer<ObjCBool>.init(bitPattern: 0)) // $ hasPathInjection=289
fm.setAttributes([:], ofItemAtPath: remoteString) // $ hasPathInjection=289
let _ = fm.contents(atPath: remoteString) // $ hasPathInjection=289
let _ = fm.contentsEqual(atPath: remoteString, andPath: "") // $ hasPathInjection=289
let _ = fm.contentsEqual(atPath: "", andPath: remoteString) // $ hasPathInjection=289
let _ = fm.changeCurrentDirectoryPath(remoteString) // $ hasPathInjection=289
let _ = fm.unmountVolume(at: remoteUrl, options: [], completionHandler: { _ in }) // $ hasPathInjection=289
// Deprecated methods
let _ = fm.changeFileAttributes([:], atPath: remoteString) // $ hasPathInjection=253
let _ = fm.directoryContents(atPath: remoteString) // $ hasPathInjection=253
let _ = fm.createDirectory(atPath: remoteString, attributes: [:]) // $ hasPathInjection=253
let _ = fm.createSymbolicLink(atPath: remoteString, pathContent: "") // $ hasPathInjection=253
let _ = fm.createSymbolicLink(atPath: "", pathContent: remoteString) // $ hasPathInjection=253
let _ = fm.pathContentOfSymbolicLink(atPath: remoteString) // $ hasPathInjection=253
let _ = fm.replaceItemAtURL(originalItemURL: remoteNsUrl, withItemAtURL: safeNsUrl, backupItemName: nil, options: []) // $ hasPathInjection=253
let _ = fm.replaceItemAtURL(originalItemURL: safeNsUrl, withItemAtURL: remoteNsUrl, backupItemName: nil, options: []) // $ hasPathInjection=253
let _ = fm.changeFileAttributes([:], atPath: remoteString) // $ hasPathInjection=289
let _ = fm.directoryContents(atPath: remoteString) // $ hasPathInjection=289
let _ = fm.createDirectory(atPath: remoteString, attributes: [:]) // $ hasPathInjection=289
let _ = fm.createSymbolicLink(atPath: remoteString, pathContent: "") // $ hasPathInjection=289
let _ = fm.createSymbolicLink(atPath: "", pathContent: remoteString) // $ hasPathInjection=289
let _ = fm.pathContentOfSymbolicLink(atPath: remoteString) // $ hasPathInjection=289
let _ = fm.replaceItemAtURL(originalItemURL: remoteNsUrl, withItemAtURL: safeNsUrl, backupItemName: nil, options: []) // $ hasPathInjection=289
let _ = fm.replaceItemAtURL(originalItemURL: safeNsUrl, withItemAtURL: remoteNsUrl, backupItemName: nil, options: []) // $ hasPathInjection=289
var encoding = String.Encoding.utf8
let _ = try! String(contentsOfFile: remoteString) // $ hasPathInjection=253
let _ = try! String(contentsOfFile: remoteString, encoding: String.Encoding.utf8) // $ hasPathInjection=253
let _ = try! String(contentsOfFile: remoteString, usedEncoding: &encoding) // $ hasPathInjection=253
let _ = try! String(contentsOfFile: remoteString) // $ hasPathInjection=289
let _ = try! String(contentsOfFile: remoteString, encoding: String.Encoding.utf8) // $ hasPathInjection=289
let _ = try! String(contentsOfFile: remoteString, usedEncoding: &encoding) // $ hasPathInjection=289
let _ = try! NSString(contentsOfFile: remoteString, encoding: 0) // $ hasPathInjection=253
let _ = try! NSString(contentsOfFile: remoteString, usedEncoding: nil) // $ hasPathInjection=253
NSString().write(to: remoteUrl, atomically: true, encoding: 0) // $ hasPathInjection=253
NSString().write(toFile: remoteString, atomically: true, encoding: 0) // $ hasPathInjection=253
let _ = try! NSString(contentsOfFile: remoteString, encoding: 0) // $ hasPathInjection=289
let _ = try! NSString(contentsOfFile: remoteString, usedEncoding: nil) // $ hasPathInjection=289
NSString().write(to: remoteUrl, atomically: true, encoding: 0) // $ hasPathInjection=289
NSString().write(toFile: remoteString, atomically: true, encoding: 0) // $ hasPathInjection=289
let _ = NSKeyedUnarchiver().unarchiveObject(withFile: remoteString) // $ hasPathInjection=253
let _ = ArchiveByteStream.fileStream(fd: remoteString as! FileDescriptor, automaticClose: true) // $ hasPathInjection=253
ArchiveByteStream.withFileStream(fd: remoteString as! FileDescriptor, automaticClose: true) { _ in } // $ hasPathInjection=253
let _ = ArchiveByteStream.fileStream(path: FilePath(stringLiteral: remoteString), mode: .readOnly, options: .append, permissions: .ownerRead) // $ hasPathInjection=253
ArchiveByteStream.withFileStream(path: FilePath(stringLiteral: remoteString), mode: .readOnly, options: .append, permissions: .ownerRead) { _ in } // $ hasPathInjection=253
let _ = Bundle(url: remoteUrl) // $ hasPathInjection=253
let _ = Bundle(path: remoteString) // $ hasPathInjection=253
let _ = NSKeyedUnarchiver().unarchiveObject(withFile: remoteString) // $ hasPathInjection=289
let _ = ArchiveByteStream.fileStream(fd: remoteString as! FileDescriptor, automaticClose: true) // $ hasPathInjection=289
ArchiveByteStream.withFileStream(fd: remoteString as! FileDescriptor, automaticClose: true) { _ in } // $ hasPathInjection=289
let _ = ArchiveByteStream.fileStream(path: FilePath(stringLiteral: remoteString), mode: .readOnly, options: .append, permissions: .ownerRead) // $ hasPathInjection=289
ArchiveByteStream.withFileStream(path: FilePath(stringLiteral: remoteString), mode: .readOnly, options: .append, permissions: .ownerRead) { _ in } // $ hasPathInjection=289
let _ = Bundle(url: remoteUrl) // $ hasPathInjection=289
let _ = Bundle(path: remoteString) // $ hasPathInjection=289
// GRDB
let _ = Database(path: remoteString, description: "", configuration: Configuration()) // $ hasPathInjection=253
let _ = Database(path: remoteString, description: "", configuration: Configuration()) // $ hasPathInjection=289
let _ = Database(path: "", description: "", configuration: Configuration()) // Safe
let _ = DatabasePool(path: remoteString, configuration: Configuration()) // $ hasPathInjection=253
let _ = DatabasePool(path: remoteString, configuration: Configuration()) // $ hasPathInjection=289
let _ = DatabasePool(path: "", configuration: Configuration()) // Safe
let _ = DatabaseQueue(path: remoteString, configuration: Configuration()) // $ hasPathInjection=253
let _ = DatabaseQueue(path: remoteString, configuration: Configuration()) // $ hasPathInjection=289
let _ = DatabaseQueue(path: "", configuration: Configuration()) // Safe
let _ = DatabaseSnapshotPool(path: remoteString, configuration: Configuration()) // $ hasPathInjection=253
let _ = DatabaseSnapshotPool(path: remoteString, configuration: Configuration()) // $ hasPathInjection=289
let _ = DatabaseSnapshotPool(path: "", configuration: Configuration()) // Safe
let _ = SerializedDatabase(path: remoteString, defaultLabel: "") // $ hasPathInjection=253
let _ = SerializedDatabase(path: remoteString, defaultLabel: "") // $ hasPathInjection=289
let _ = SerializedDatabase(path: "", defaultLabel: "") // Safe
let _ = SerializedDatabase(path: remoteString, defaultLabel: "", purpose: nil) // $ hasPathInjection=253
let _ = SerializedDatabase(path: remoteString, defaultLabel: "", purpose: nil) // $ hasPathInjection=289
let _ = SerializedDatabase(path: "", defaultLabel: "", purpose: nil) // Safe
let _ = SerializedDatabase(path: remoteString, configuration: Configuration(), defaultLabel: "") // $ hasPathInjection=253
let _ = SerializedDatabase(path: remoteString, configuration: Configuration(), defaultLabel: "") // $ hasPathInjection=289
let _ = SerializedDatabase(path: "", configuration: Configuration(), defaultLabel: "") // Safe
let _ = SerializedDatabase(path: remoteString, configuration: Configuration(), defaultLabel: "", purpose: nil) // $ hasPathInjection=253
let _ = SerializedDatabase(path: remoteString, configuration: Configuration(), defaultLabel: "", purpose: nil) // $ hasPathInjection=289
let _ = SerializedDatabase(path: "", configuration: Configuration(), defaultLabel: "", purpose: nil) // Safe
// Realm
_ = Realm.Configuration(fileURL: safeUrl) // GOOD
_ = Realm.Configuration(fileURL: remoteUrl) // $ hasPathInjection=253
_ = Realm.Configuration(fileURL: remoteUrl) // $ hasPathInjection=289
_ = Realm.Configuration(seedFilePath: safeUrl) // GOOD
_ = Realm.Configuration(seedFilePath: remoteUrl) // $ hasPathInjection=253
_ = Realm.Configuration(seedFilePath: remoteUrl) // $ hasPathInjection=289
var config = Realm.Configuration() // GOOD
config.fileURL = safeUrl // GOOD
config.fileURL = remoteUrl // $ hasPathInjection=253
config.fileURL = remoteUrl // $ hasPathInjection=289
config.seedFilePath = safeUrl // GOOD
config.seedFilePath = remoteUrl // $ hasPathInjection=253
config.seedFilePath = remoteUrl // $ hasPathInjection=289
// sqlite3
@@ -375,22 +411,22 @@ func test(buffer1: UnsafeMutablePointer<UInt8>, buffer2: UnsafeMutablePointer<UI
remoteData.copyBytes(to: buffer2, count: remoteData.count)
_ = sqlite3_open("myFile.sqlite3", &db) // GOOD
_ = sqlite3_open(remoteString, &db) // $ hasPathInjection=253
_ = sqlite3_open(remoteString, &db) // $ hasPathInjection=289
_ = sqlite3_open16(buffer1, &db) // GOOD
_ = sqlite3_open16(buffer2, &db) // $ hasPathInjection=373
_ = sqlite3_open16(buffer2, &db) // $ hasPathInjection=409
_ = sqlite3_open_v2("myFile.sqlite3", &db, 0, nil) // GOOD
_ = sqlite3_open_v2(remoteString, &db, 0, nil) // $ hasPathInjection=253
_ = sqlite3_open_v2(remoteString, &db, 0, nil) // $ hasPathInjection=289
sqlite3_temp_directory = UnsafeMutablePointer<CChar>(mutating: NSString(string: "myFile.sqlite3").utf8String) // GOOD
sqlite3_temp_directory = UnsafeMutablePointer<CChar>(mutating: NSString(string: remoteString).utf8String) // $ hasPathInjection=253
sqlite3_temp_directory = UnsafeMutablePointer<CChar>(mutating: NSString(string: remoteString).utf8String) // $ hasPathInjection=289
// SQLite.swift
try! _ = Connection()
try! _ = Connection(Connection.Location.uri("myFile.sqlite3")) // GOOD
try! _ = Connection(Connection.Location.uri(remoteString)) // $ hasPathInjection=253
try! _ = Connection(Connection.Location.uri(remoteString)) // $ hasPathInjection=289
try! _ = Connection("myFile.sqlite3") // GOOD
try! _ = Connection(remoteString) // $ hasPathInjection=253
try! _ = Connection(remoteString) // $ hasPathInjection=289
}
func testBarriers() {
@@ -402,5 +438,83 @@ func testBarriers() {
if (filePath.lexicallyNormalized().starts(with: "/safe")) {
let _ = fm.contents(atPath: remoteString) // Safe
}
let _ = fm.contents(atPath: remoteString) // $ hasPathInjection=397
let _ = fm.contents(atPath: remoteString) // $ hasPathInjection=433
}
func testPathInjection2(s1: UnsafeMutablePointer<String>, s2: UnsafeMutablePointer<String>, s3: UnsafeMutablePointer<String>, fm: FileManager) throws {
let remoteString = String(contentsOf: URL(string: "http://example.com/")!)
var u1 = URL(filePath: "")
_ = NSData(contentsOf: u1)
_ = NSData(contentsOf: u1.appendingPathComponent(""))
_ = NSData(contentsOf: u1.appendingPathComponent(remoteString)) // $ hasPathInjection=445
_ = NSData(contentsOf: u1.appendingPathComponent(remoteString).appendingPathComponent("")) // $ hasPathInjection=445
u1.appendPathComponent(remoteString)
_ = NSData(contentsOf: u1) // $ hasPathInjection=445
let u2 = URL(filePath: remoteString) // $ hasPathInjection=445
_ = NSData(contentsOf: u2) // $ hasPathInjection=445
let u3 = NSURL(string: "")!
Data("").write(to: u3.filePathURL!, options: [])
Data("").write(to: u3.appendingPathComponent("")!, options: [])
Data("").write(to: u3.appendingPathComponent(remoteString)!, options: []) // $ hasPathInjection=445
let u4 = NSURL(string: remoteString)!
Data("").write(to: u4.filePathURL!, options: []) // $ hasPathInjection=445
Data("").write(to: u4.appendingPathComponent("")!, options: []) // $ hasPathInjection=445
_ = NSData(contentsOfFile: remoteString)! // $ hasPathInjection=445
_ = NSData(contentsOfMappedFile: remoteString)! // $ hasPathInjection=445
_ = NSData.dataWithContentsOfMappedFile(remoteString)! // $ hasPathInjection=445
_ = NSData().write(toFile: s1.pointee, atomically: true)
s1.pointee = remoteString
_ = NSData().write(toFile: s1.pointee, atomically: true) // $ hasPathInjection=445
_ = NSData().write(toFile: s1[0], atomically: true) // $ MISSING: hasPathInjection=445
_ = "".completePath(into: s2, caseSensitive: false, matchesInto: nil, filterTypes: nil)
_ = NSData().write(toFile: s2.pointee, atomically: true)
_ = NSData().write(toFile: s2[0], atomically: true)
_ = remoteString.completePath(into: s3, caseSensitive: false, matchesInto: nil, filterTypes: nil)
_ = NSData().write(toFile: s3.pointee, atomically: true) // $ MISSING: hasPathInjection=445
_ = NSData().write(toFile: s3[0], atomically: true) // $ hasPathInjection=445
_ = fm.fileAttributes(atPath: remoteString, traverseLink: true) // $ hasPathInjection=445
_ = try fm.attributesOfItem(atPath: remoteString) // $ hasPathInjection=445
}
// ---
func myOpenFile1(atPath path: String) { }
func myOpenFile2(_ filePath: String) { }
func myFindFiles(ofType type: Int, inDirectory dir: String) { }
class MyClass {
init(contentsOfFile: String) { }
func doSomething(keyPath: String) { }
func write(toFile: String) { }
}
class MyFile {
init(path: String) { }
}
func testPathInjectionHeuristics() {
let remoteString = String(contentsOf: URL(string: "http://example.com/")!)
myOpenFile1(atPath: remoteString) // $ hasPathInjection=505
myOpenFile2(remoteString) // $ hasPathInjection=505
myFindFiles(ofType: 0, inDirectory: remoteString) // $ hasPathInjection=505
let mc = MyClass(contentsOfFile: remoteString) // $ hasPathInjection=505
mc.doSomething(keyPath: remoteString) // good - not a path
mc.write(toFile: remoteString) // $ hasPathInjection=505
let mf1 = MyFile(path: "")
let mf2 = MyFile(path: remoteString) // $ MISSING: hasPathInjection=
_ = NSSortDescriptor(key: remoteString, ascending: true) // good - not a path
_ = NSSortDescriptor(keyPath: remoteString as! KeyPath<Int, Int>, ascending: true) // good - not a path
}