From 5d125572ec3daa563ff717b65432804d38036dfe Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 17 Feb 2023 18:01:45 +0000 Subject: [PATCH 1/2] Swift: Test for FileManager taint sources. --- .../dataflow/flowsources/filemanager.swift | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 swift/ql/test/library-tests/dataflow/flowsources/filemanager.swift diff --git a/swift/ql/test/library-tests/dataflow/flowsources/filemanager.swift b/swift/ql/test/library-tests/dataflow/flowsources/filemanager.swift new file mode 100644 index 00000000000..374e67e74a6 --- /dev/null +++ b/swift/ql/test/library-tests/dataflow/flowsources/filemanager.swift @@ -0,0 +1,52 @@ +// --- stubs --- + +class NSObject { +} + +struct URL { +} + +struct URLResourceKey { +} + +struct Data { +} + +class FileManager : NSObject { + struct DirectoryEnumerationOptions : OptionSet{ + let rawValue: Int + } + + func contentsOfDirectory(at url: URL, includingPropertyForKeys keys: [URLResourceKey]?, options mask: FileManager.DirectoryEnumerationOptions = []) throws -> [URL] { return [] } + func contentsOfDirectory(atPath path: String) throws -> [String] { return [] } + func directoryContents(atPath path: String) -> [Any]? { return [] } // returns array of NSString + func subpathsOfDirectory(atPath path: String) throws -> [String] { return [] } + func subpaths(atPath path: String) -> [String]? { return [] } + + func destinationOfSymbolicLink(atPath path: String) throws -> String { return "" } + func pathContentOfSymbolicLink(atPath path: String) -> String? { return "" } + + func contents(atPath path: String) -> Data? { return nil } +} + +// --- tests --- + +func testFileHandle(fm: FileManager, url: URL, path: String) { + do + { + let contents1 = try fm.contentsOfDirectory(at: url, includingPropertyForKeys: nil) // SOURCE + let content1 = contents1[0] + let contents2 = try fm.contentsOfDirectory(atPath: path) // SOURCE + let contents3 = fm.directoryContents(atPath: path)! // SOURCE + + let subpaths1 = try fm.subpathsOfDirectory(atPath: path) // SOURCE + let subpaths2 = fm.subpaths(atPath: path)! // SOURCE + + let link1 = try fm.destinationOfSymbolicLink(atPath: path) // SOURCE + let link2 = fm.pathContentOfSymbolicLink(atPath: path)! // SOURCE + + let data = fm.contents(atPath: path)! // SOURCE + } catch { + // ... + } +} From 7a9bbb1414b11c135995097389ff0869837f3478 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 17 Feb 2023 17:38:01 +0000 Subject: [PATCH 2/2] Swift: Model FileManager sources. --- .../codeql/swift/dataflow/ExternalFlow.qll | 1 + .../StandardLibrary/FileManager.qll | 25 +++++++++++++++++++ .../dataflow/flowsources/FlowSources.expected | 8 ++++++ .../dataflow/flowsources/filemanager.swift | 5 ++-- 4 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 swift/ql/lib/codeql/swift/frameworks/StandardLibrary/FileManager.qll diff --git a/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll b/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll index 1a1095dc3df..eda7d314ac3 100644 --- a/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll +++ b/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll @@ -81,6 +81,7 @@ private module Frameworks { private import codeql.swift.frameworks.StandardLibrary.Collection private import codeql.swift.frameworks.StandardLibrary.CustomUrlSchemes private import codeql.swift.frameworks.StandardLibrary.Data + private import codeql.swift.frameworks.StandardLibrary.FileManager private import codeql.swift.frameworks.StandardLibrary.FilePath private import codeql.swift.frameworks.StandardLibrary.InputStream private import codeql.swift.frameworks.StandardLibrary.NsData diff --git a/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/FileManager.qll b/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/FileManager.qll new file mode 100644 index 00000000000..931871c6538 --- /dev/null +++ b/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/FileManager.qll @@ -0,0 +1,25 @@ +/** + * Provides models for the `FileManager` Swift class. + */ + +import swift +private import codeql.swift.dataflow.ExternalFlow + +/** + * A model for `FileManager` members that are flow sources. + */ +private class FileManagerSource extends SourceModelCsv { + override predicate row(string row) { + row = + [ + ";FileManager;true;contentsOfDirectory(at:includingPropertiesForKeys:options:);;;ReturnValue;local", + ";FileManager;true;contentsOfDirectory(atPath:);;;ReturnValue;local", + ";FileManager;true;directoryContents(atPath:);;;ReturnValue;local", + ";FileManager;true;subpathsOfDirectory(atPath:);;;ReturnValue;local", + ";FileManager;true;subpaths(atPath:);;;ReturnValue;local", + ";FileManager;true;destinationOfSymbolicLink(atPath:);;;ReturnValue;local", + ";FileManager;true;pathContentOfSymbolicLink(atPath:);;;ReturnValue;local", + ";FileManager;true;contents(atPath:);;;ReturnValue;local" + ] + } +} diff --git a/swift/ql/test/library-tests/dataflow/flowsources/FlowSources.expected b/swift/ql/test/library-tests/dataflow/flowsources/FlowSources.expected index 8b872c18b11..de8dc32229e 100644 --- a/swift/ql/test/library-tests/dataflow/flowsources/FlowSources.expected +++ b/swift/ql/test/library-tests/dataflow/flowsources/FlowSources.expected @@ -38,6 +38,14 @@ | file://:0:0:0:0 | .source1 | external | | file://:0:0:0:0 | .source4 | external | | file://:0:0:0:0 | .source9 | external | +| filemanager.swift:37:23:37:86 | call to contentsOfDirectory(at:includingPropertiesForKeys:options:) | external | +| filemanager.swift:38:23:38:58 | call to contentsOfDirectory(atPath:) | external | +| filemanager.swift:39:19:39:52 | call to directoryContents(atPath:) | external | +| filemanager.swift:41:23:41:58 | call to subpathsOfDirectory(atPath:) | external | +| filemanager.swift:42:19:42:43 | call to subpaths(atPath:) | external | +| filemanager.swift:44:19:44:60 | call to destinationOfSymbolicLink(atPath:) | external | +| filemanager.swift:45:15:45:56 | call to pathContentOfSymbolicLink(atPath:) | external | +| filemanager.swift:47:14:47:38 | call to contents(atPath:) | external | | generics.swift:10:9:10:16 | .source1 | external | | generics.swift:11:9:11:16 | .source2 | external | | generics.swift:12:9:12:24 | call to source3() | external | diff --git a/swift/ql/test/library-tests/dataflow/flowsources/filemanager.swift b/swift/ql/test/library-tests/dataflow/flowsources/filemanager.swift index 374e67e74a6..af1b28664d8 100644 --- a/swift/ql/test/library-tests/dataflow/flowsources/filemanager.swift +++ b/swift/ql/test/library-tests/dataflow/flowsources/filemanager.swift @@ -17,7 +17,7 @@ class FileManager : NSObject { let rawValue: Int } - func contentsOfDirectory(at url: URL, includingPropertyForKeys keys: [URLResourceKey]?, options mask: FileManager.DirectoryEnumerationOptions = []) throws -> [URL] { return [] } + func contentsOfDirectory(at url: URL, includingPropertiesForKeys keys: [URLResourceKey]?, options mask: FileManager.DirectoryEnumerationOptions = []) throws -> [URL] { return [] } func contentsOfDirectory(atPath path: String) throws -> [String] { return [] } func directoryContents(atPath path: String) -> [Any]? { return [] } // returns array of NSString func subpathsOfDirectory(atPath path: String) throws -> [String] { return [] } @@ -34,8 +34,7 @@ class FileManager : NSObject { func testFileHandle(fm: FileManager, url: URL, path: String) { do { - let contents1 = try fm.contentsOfDirectory(at: url, includingPropertyForKeys: nil) // SOURCE - let content1 = contents1[0] + let contents1 = try fm.contentsOfDirectory(at: url, includingPropertiesForKeys: nil) // SOURCE let contents2 = try fm.contentsOfDirectory(atPath: path) // SOURCE let contents3 = fm.directoryContents(atPath: path)! // SOURCE