mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
Merge pull request #16210 from aschackmull/dataflow/provenance-for-tests
Dataflow: Add support for pretty-printed alert provenance in tests
This commit is contained in:
@@ -98,6 +98,44 @@ private import semmle.code.csharp.dispatch.OverridableCallable
|
||||
private import semmle.code.csharp.frameworks.System
|
||||
private import codeql.mad.ModelValidation as SharedModelVal
|
||||
|
||||
/**
|
||||
* Holds if the given extension tuple `madId` should pretty-print as `model`.
|
||||
*
|
||||
* This predicate should only be used in tests.
|
||||
*/
|
||||
predicate interpretModelForTest(QlBuiltins::ExtensionId madId, string model) {
|
||||
exists(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string output, string kind, string provenance
|
||||
|
|
||||
sourceModel(namespace, type, subtypes, name, signature, ext, output, kind, provenance, madId) and
|
||||
model =
|
||||
"Source: " + namespace + "; " + type + "; " + subtypes + "; " + name + "; " + signature + "; "
|
||||
+ ext + "; " + output + "; " + kind + "; " + provenance
|
||||
)
|
||||
or
|
||||
exists(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string input, string kind, string provenance
|
||||
|
|
||||
sinkModel(namespace, type, subtypes, name, signature, ext, input, kind, provenance, madId) and
|
||||
model =
|
||||
"Sink: " + namespace + "; " + type + "; " + subtypes + "; " + name + "; " + signature + "; " +
|
||||
ext + "; " + input + "; " + kind + "; " + provenance
|
||||
)
|
||||
or
|
||||
exists(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string input, string output, string kind, string provenance
|
||||
|
|
||||
summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind, provenance,
|
||||
madId) and
|
||||
model =
|
||||
"Summary: " + namespace + "; " + type + "; " + subtypes + "; " + name + "; " + signature +
|
||||
"; " + ext + "; " + input + "; " + output + "; " + kind + "; " + provenance
|
||||
)
|
||||
}
|
||||
|
||||
private predicate relevantNamespace(string namespace) {
|
||||
sourceModel(namespace, _, _, _, _, _, _, _, _, _) or
|
||||
sinkModel(namespace, _, _, _, _, _, _, _, _, _) or
|
||||
|
||||
@@ -1,28 +1,32 @@
|
||||
models
|
||||
| 1 | Summary: System.Net; IPHostEntry; false; get_HostName; (); ; Argument[this]; ReturnValue; taint; manual |
|
||||
| 2 | Summary: System.Web; HttpCookie; false; get_Value; (); ; Argument[this]; ReturnValue; taint; manual |
|
||||
| 3 | Summary: System.Collections.Specialized; NameValueCollection; false; get_Item; (System.String); ; Argument[this]; ReturnValue; taint; df-generated |
|
||||
edges
|
||||
| ConditionalBypass.cs:12:16:12:22 | access to local variable isAdmin : String | ConditionalBypass.cs:16:13:16:30 | ... == ... | provenance | |
|
||||
| ConditionalBypass.cs:12:26:12:48 | access to property QueryString : NameValueCollection | ConditionalBypass.cs:12:16:12:22 | access to local variable isAdmin : String | provenance | |
|
||||
| ConditionalBypass.cs:12:26:12:48 | access to property QueryString : NameValueCollection | ConditionalBypass.cs:12:26:12:59 | access to indexer : String | provenance | MaD:11390 |
|
||||
| ConditionalBypass.cs:12:26:12:48 | access to property QueryString : NameValueCollection | ConditionalBypass.cs:12:26:12:59 | access to indexer : String | provenance | MaD:3 |
|
||||
| ConditionalBypass.cs:12:26:12:59 | access to indexer : String | ConditionalBypass.cs:12:16:12:22 | access to local variable isAdmin : String | provenance | |
|
||||
| ConditionalBypass.cs:19:20:19:30 | access to local variable adminCookie : HttpCookie | ConditionalBypass.cs:22:13:22:23 | access to local variable adminCookie : HttpCookie | provenance | |
|
||||
| ConditionalBypass.cs:19:20:19:30 | access to local variable adminCookie : HttpCookie | ConditionalBypass.cs:27:13:27:23 | access to local variable adminCookie : HttpCookie | provenance | |
|
||||
| ConditionalBypass.cs:19:34:19:52 | access to property Cookies : HttpCookieCollection | ConditionalBypass.cs:19:20:19:30 | access to local variable adminCookie : HttpCookie | provenance | |
|
||||
| ConditionalBypass.cs:22:13:22:23 | access to local variable adminCookie : HttpCookie | ConditionalBypass.cs:22:13:22:29 | access to property Value : String | provenance | MaD:2161 |
|
||||
| ConditionalBypass.cs:22:13:22:23 | access to local variable adminCookie : HttpCookie | ConditionalBypass.cs:22:13:22:29 | access to property Value : String | provenance | MaD:2 |
|
||||
| ConditionalBypass.cs:22:13:22:29 | access to property Value : String | ConditionalBypass.cs:22:13:22:45 | call to method Equals | provenance | |
|
||||
| ConditionalBypass.cs:27:13:27:23 | access to local variable adminCookie : HttpCookie | ConditionalBypass.cs:27:13:27:29 | access to property Value : String | provenance | MaD:2161 |
|
||||
| ConditionalBypass.cs:27:13:27:23 | access to local variable adminCookie : HttpCookie | ConditionalBypass.cs:27:13:27:29 | access to property Value : String | provenance | MaD:2 |
|
||||
| ConditionalBypass.cs:27:13:27:29 | access to property Value : String | ConditionalBypass.cs:27:13:27:40 | ... == ... | provenance | |
|
||||
| ConditionalBypass.cs:42:21:42:28 | access to local variable hostInfo : IPHostEntry | ConditionalBypass.cs:44:13:44:20 | access to local variable hostInfo : IPHostEntry | provenance | |
|
||||
| ConditionalBypass.cs:42:21:42:28 | access to local variable hostInfo : IPHostEntry | ConditionalBypass.cs:49:13:49:20 | access to local variable hostInfo : IPHostEntry | provenance | |
|
||||
| ConditionalBypass.cs:42:32:42:66 | call to method GetHostByAddress : IPHostEntry | ConditionalBypass.cs:42:21:42:28 | access to local variable hostInfo : IPHostEntry | provenance | |
|
||||
| ConditionalBypass.cs:44:13:44:20 | access to local variable hostInfo : IPHostEntry | ConditionalBypass.cs:44:13:44:29 | access to property HostName : String | provenance | MaD:1827 |
|
||||
| ConditionalBypass.cs:44:13:44:20 | access to local variable hostInfo : IPHostEntry | ConditionalBypass.cs:44:13:44:29 | access to property HostName : String | provenance | MaD:1 |
|
||||
| ConditionalBypass.cs:44:13:44:29 | access to property HostName : String | ConditionalBypass.cs:44:13:44:46 | ... == ... | provenance | |
|
||||
| ConditionalBypass.cs:49:13:49:20 | access to local variable hostInfo : IPHostEntry | ConditionalBypass.cs:49:13:49:29 | access to property HostName | provenance | MaD:1827 |
|
||||
| ConditionalBypass.cs:49:13:49:20 | access to local variable hostInfo : IPHostEntry | ConditionalBypass.cs:49:13:49:29 | access to property HostName | provenance | MaD:1 |
|
||||
| ConditionalBypass.cs:70:20:70:30 | access to local variable adminCookie : HttpCookie | ConditionalBypass.cs:72:13:72:23 | access to local variable adminCookie : HttpCookie | provenance | |
|
||||
| ConditionalBypass.cs:70:34:70:52 | access to property Cookies : HttpCookieCollection | ConditionalBypass.cs:70:20:70:30 | access to local variable adminCookie : HttpCookie | provenance | |
|
||||
| ConditionalBypass.cs:72:13:72:23 | access to local variable adminCookie : HttpCookie | ConditionalBypass.cs:72:13:72:29 | access to property Value : String | provenance | MaD:2161 |
|
||||
| ConditionalBypass.cs:72:13:72:23 | access to local variable adminCookie : HttpCookie | ConditionalBypass.cs:72:13:72:29 | access to property Value : String | provenance | MaD:2 |
|
||||
| ConditionalBypass.cs:72:13:72:29 | access to property Value : String | ConditionalBypass.cs:72:13:72:40 | ... == ... | provenance | |
|
||||
| ConditionalBypass.cs:83:20:83:30 | access to local variable adminCookie : HttpCookie | ConditionalBypass.cs:84:13:84:23 | access to local variable adminCookie : HttpCookie | provenance | |
|
||||
| ConditionalBypass.cs:83:34:83:52 | access to property Cookies : HttpCookieCollection | ConditionalBypass.cs:83:20:83:30 | access to local variable adminCookie : HttpCookie | provenance | |
|
||||
| ConditionalBypass.cs:84:13:84:23 | access to local variable adminCookie : HttpCookie | ConditionalBypass.cs:84:13:84:29 | access to property Value : String | provenance | MaD:2161 |
|
||||
| ConditionalBypass.cs:84:13:84:23 | access to local variable adminCookie : HttpCookie | ConditionalBypass.cs:84:13:84:29 | access to property Value : String | provenance | MaD:2 |
|
||||
| ConditionalBypass.cs:84:13:84:29 | access to property Value : String | ConditionalBypass.cs:84:13:84:40 | ... == ... | provenance | |
|
||||
nodes
|
||||
| ConditionalBypass.cs:12:16:12:22 | access to local variable isAdmin : String | semmle.label | access to local variable isAdmin : String |
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* @kind path-problem
|
||||
*/
|
||||
|
||||
import csharp
|
||||
import semmle.code.csharp.security.dataflow.ConditionalBypassQuery
|
||||
import codeql.dataflow.test.ProvenancePathGraph
|
||||
import semmle.code.csharp.dataflow.internal.ExternalFlow
|
||||
import ShowProvenance<interpretModelForTest/2, ConditionalBypass::PathNode, ConditionalBypass::PathGraph>
|
||||
|
||||
from ConditionalBypass::PathNode source, ConditionalBypass::PathNode sink
|
||||
where ConditionalBypass::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "This condition guards a sensitive $@, but a $@ controls it.",
|
||||
sink.getNode().(Sink).getSensitiveMethodCall(), "action", source.getNode(), "user-provided value"
|
||||
@@ -1 +0,0 @@
|
||||
Security Features/CWE-807/ConditionalBypass.ql
|
||||
@@ -84,6 +84,44 @@ private import internal.FlowSummaryImpl::Private
|
||||
private import internal.FlowSummaryImpl::Private::External
|
||||
private import codeql.mad.ModelValidation as SharedModelVal
|
||||
|
||||
/**
|
||||
* Holds if the given extension tuple `madId` should pretty-print as `model`.
|
||||
*
|
||||
* This predicate should only be used in tests.
|
||||
*/
|
||||
predicate interpretModelForTest(QlBuiltins::ExtensionId madId, string model) {
|
||||
exists(
|
||||
string package, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string output, string kind, string provenance
|
||||
|
|
||||
sourceModel(package, type, subtypes, name, signature, ext, output, kind, provenance, madId) and
|
||||
model =
|
||||
"Source: " + package + "; " + type + "; " + subtypes + "; " + name + "; " + signature + "; " +
|
||||
ext + "; " + output + "; " + kind + "; " + provenance
|
||||
)
|
||||
or
|
||||
exists(
|
||||
string package, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string input, string kind, string provenance
|
||||
|
|
||||
sinkModel(package, type, subtypes, name, signature, ext, input, kind, provenance, madId) and
|
||||
model =
|
||||
"Sink: " + package + "; " + type + "; " + subtypes + "; " + name + "; " + signature + "; " +
|
||||
ext + "; " + input + "; " + kind + "; " + provenance
|
||||
)
|
||||
or
|
||||
exists(
|
||||
string package, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string input, string output, string kind, string provenance
|
||||
|
|
||||
summaryModel(package, type, subtypes, name, signature, ext, input, output, kind, provenance,
|
||||
madId) and
|
||||
model =
|
||||
"Summary: " + package + "; " + type + "; " + subtypes + "; " + name + "; " + signature + "; " +
|
||||
ext + "; " + input + "; " + output + "; " + kind + "; " + provenance
|
||||
)
|
||||
}
|
||||
|
||||
private predicate relevantPackage(string package) {
|
||||
sourceModel(package, _, _, _, _, _, _, _, _, _) or
|
||||
sinkModel(package, _, _, _, _, _, _, _, _, _) or
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
models
|
||||
| 1 | Summary: net/url; URL; true; Query; ; ; Argument[receiver]; ReturnValue; taint; manual |
|
||||
| 2 | Summary: path; ; false; Clean; ; ; Argument[0]; ReturnValue; taint; manual |
|
||||
edges
|
||||
| TaintedPath.go:14:18:14:22 | selection of URL | TaintedPath.go:14:18:14:30 | call to Query | provenance | MaD:735 |
|
||||
| TaintedPath.go:14:18:14:22 | selection of URL | TaintedPath.go:14:18:14:30 | call to Query | provenance | MaD:1 |
|
||||
| TaintedPath.go:14:18:14:30 | call to Query | TaintedPath.go:17:29:17:40 | tainted_path | provenance | |
|
||||
| TaintedPath.go:14:18:14:30 | call to Query | TaintedPath.go:21:57:21:68 | tainted_path | provenance | |
|
||||
| TaintedPath.go:14:18:14:30 | call to Query | TaintedPath.go:68:39:68:56 | ...+... | provenance | |
|
||||
| TaintedPath.go:21:57:21:68 | tainted_path | TaintedPath.go:21:28:21:69 | call to Join | provenance | FunctionModel |
|
||||
| TaintedPath.go:68:39:68:56 | ...+... | TaintedPath.go:68:28:68:57 | call to Clean | provenance | MaD:761 |
|
||||
| TaintedPath.go:68:39:68:56 | ...+... | TaintedPath.go:68:28:68:57 | call to Clean | provenance | MaD:2 |
|
||||
nodes
|
||||
| TaintedPath.go:14:18:14:22 | selection of URL | semmle.label | selection of URL |
|
||||
| TaintedPath.go:14:18:14:30 | call to Query | semmle.label | call to Query |
|
||||
|
||||
14
go/ql/test/query-tests/Security/CWE-022/TaintedPath.ql
Normal file
14
go/ql/test/query-tests/Security/CWE-022/TaintedPath.ql
Normal file
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* @kind path-problem
|
||||
*/
|
||||
|
||||
import go
|
||||
import semmle.go.security.TaintedPath
|
||||
import codeql.dataflow.test.ProvenancePathGraph
|
||||
import semmle.go.dataflow.ExternalFlow
|
||||
import ShowProvenance<interpretModelForTest/2, TaintedPath::Flow::PathNode, TaintedPath::Flow::PathGraph>
|
||||
|
||||
from TaintedPath::Flow::PathNode source, TaintedPath::Flow::PathNode sink
|
||||
where TaintedPath::Flow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "This path depends on a $@.", source.getNode(),
|
||||
"user-provided value"
|
||||
@@ -1 +0,0 @@
|
||||
Security/CWE-022/TaintedPath.ql
|
||||
@@ -185,6 +185,44 @@ predicate summaryModel(
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the given extension tuple `madId` should pretty-print as `model`.
|
||||
*
|
||||
* This predicate should only be used in tests.
|
||||
*/
|
||||
predicate interpretModelForTest(QlBuiltins::ExtensionId madId, string model) {
|
||||
exists(
|
||||
string package, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string output, string kind, string provenance
|
||||
|
|
||||
sourceModel(package, type, subtypes, name, signature, ext, output, kind, provenance, madId) and
|
||||
model =
|
||||
"Source: " + package + "; " + type + "; " + subtypes + "; " + name + "; " + signature + "; " +
|
||||
ext + "; " + output + "; " + kind + "; " + provenance
|
||||
)
|
||||
or
|
||||
exists(
|
||||
string package, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string input, string kind, string provenance
|
||||
|
|
||||
sinkModel(package, type, subtypes, name, signature, ext, input, kind, provenance, madId) and
|
||||
model =
|
||||
"Sink: " + package + "; " + type + "; " + subtypes + "; " + name + "; " + signature + "; " +
|
||||
ext + "; " + input + "; " + kind + "; " + provenance
|
||||
)
|
||||
or
|
||||
exists(
|
||||
string package, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string input, string output, string kind, string provenance
|
||||
|
|
||||
summaryModel(package, type, subtypes, name, signature, ext, input, output, kind, provenance,
|
||||
madId) and
|
||||
model =
|
||||
"Summary: " + package + "; " + type + "; " + subtypes + "; " + name + "; " + signature + "; " +
|
||||
ext + "; " + input + "; " + output + "; " + kind + "; " + provenance
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if a neutral model exists for the given parameters. */
|
||||
predicate neutralModel = Extensions::neutralModel/6;
|
||||
|
||||
|
||||
@@ -1,17 +1,21 @@
|
||||
models
|
||||
| 1 | Sink: java.net; URL; false; openConnection; ; ; Argument[this]; request-forgery; manual |
|
||||
| 2 | Summary: java.net; URL; false; URL; (String); ; Argument[0]; Argument[this]; taint; manual |
|
||||
| 3 | Summary: java.net; URL; false; URL; (URL,String); ; Argument[1]; Argument[this]; taint; ai-manual |
|
||||
edges
|
||||
| HttpsUrlsTest.java:23:23:23:31 | "http://" : String | HttpsUrlsTest.java:24:21:24:56 | ... + ... : String | provenance | |
|
||||
| HttpsUrlsTest.java:24:13:24:57 | new URL(...) : URL | HttpsUrlsTest.java:28:50:28:50 | u | provenance | Sink:MaD:42944 |
|
||||
| HttpsUrlsTest.java:24:13:24:57 | new URL(...) : URL | HttpsUrlsTest.java:28:50:28:50 | u | provenance | Sink:MaD:1 |
|
||||
| HttpsUrlsTest.java:24:21:24:56 | ... + ... : String | HttpsUrlsTest.java:24:13:24:57 | new URL(...) : URL | provenance | Config |
|
||||
| HttpsUrlsTest.java:24:21:24:56 | ... + ... : String | HttpsUrlsTest.java:24:13:24:57 | new URL(...) : URL | provenance | MaD:42977 |
|
||||
| HttpsUrlsTest.java:24:21:24:56 | ... + ... : String | HttpsUrlsTest.java:24:13:24:57 | new URL(...) : URL | provenance | MaD:2 |
|
||||
| HttpsUrlsTest.java:36:23:36:28 | "http" : String | HttpsUrlsTest.java:37:21:37:28 | protocol : String | provenance | |
|
||||
| HttpsUrlsTest.java:37:13:37:62 | new URL(...) : URL | HttpsUrlsTest.java:41:50:41:50 | u | provenance | Sink:MaD:42944 |
|
||||
| HttpsUrlsTest.java:37:13:37:62 | new URL(...) : URL | HttpsUrlsTest.java:41:50:41:50 | u | provenance | Sink:MaD:1 |
|
||||
| HttpsUrlsTest.java:37:21:37:28 | protocol : String | HttpsUrlsTest.java:37:13:37:62 | new URL(...) : URL | provenance | Config |
|
||||
| HttpsUrlsTest.java:49:23:49:31 | "http://" : String | HttpsUrlsTest.java:51:64:51:98 | ... + ... : String | provenance | |
|
||||
| HttpsUrlsTest.java:51:13:51:99 | new URL(...) : URL | HttpsUrlsTest.java:55:50:55:50 | u | provenance | Sink:MaD:42944 |
|
||||
| HttpsUrlsTest.java:51:13:51:99 | new URL(...) : URL | HttpsUrlsTest.java:55:50:55:50 | u | provenance | Sink:MaD:1 |
|
||||
| HttpsUrlsTest.java:51:64:51:98 | ... + ... : String | HttpsUrlsTest.java:51:13:51:99 | new URL(...) : URL | provenance | Config |
|
||||
| HttpsUrlsTest.java:51:64:51:98 | ... + ... : String | HttpsUrlsTest.java:51:13:51:99 | new URL(...) : URL | provenance | MaD:42985 |
|
||||
| HttpsUrlsTest.java:51:64:51:98 | ... + ... : String | HttpsUrlsTest.java:51:13:51:99 | new URL(...) : URL | provenance | MaD:3 |
|
||||
| HttpsUrlsTest.java:87:23:87:28 | "http" : String | HttpsUrlsTest.java:88:21:88:28 | protocol : String | provenance | |
|
||||
| HttpsUrlsTest.java:88:13:88:52 | new URL(...) : URL | HttpsUrlsTest.java:92:50:92:50 | u | provenance | Sink:MaD:42944 |
|
||||
| HttpsUrlsTest.java:88:13:88:52 | new URL(...) : URL | HttpsUrlsTest.java:92:50:92:50 | u | provenance | Sink:MaD:1 |
|
||||
| HttpsUrlsTest.java:88:21:88:28 | protocol : String | HttpsUrlsTest.java:88:13:88:52 | new URL(...) : URL | provenance | Config |
|
||||
nodes
|
||||
| HttpsUrlsTest.java:23:23:23:31 | "http://" : String | semmle.label | "http://" : String |
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* @kind path-problem
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.security.HttpsUrlsQuery
|
||||
import codeql.dataflow.test.ProvenancePathGraph
|
||||
import semmle.code.java.dataflow.ExternalFlow
|
||||
import ShowProvenance<interpretModelForTest/2, HttpStringToUrlOpenMethodFlow::PathNode, HttpStringToUrlOpenMethodFlow::PathGraph>
|
||||
|
||||
from HttpStringToUrlOpenMethodFlow::PathNode source, HttpStringToUrlOpenMethodFlow::PathNode sink
|
||||
where HttpStringToUrlOpenMethodFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "URL may have been constructed with HTTP protocol, using $@.",
|
||||
source.getNode(), "this HTTP URL"
|
||||
@@ -1 +0,0 @@
|
||||
Security/CWE/CWE-319/HttpsUrls.ql
|
||||
@@ -369,6 +369,28 @@ private predicate typeVariableModel(string name, string path) {
|
||||
Extensions::typeVariableModel(name, path)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the given extension tuple `madId` should pretty-print as `model`.
|
||||
*
|
||||
* This predicate should only be used in tests.
|
||||
*/
|
||||
predicate interpretModelForTest(QlBuiltins::ExtensionId madId, string model) {
|
||||
exists(string type, string path, string kind |
|
||||
Extensions::sourceModel(type, path, kind, madId) and
|
||||
model = "Source: " + type + "; " + path + "; " + kind
|
||||
)
|
||||
or
|
||||
exists(string type, string path, string kind |
|
||||
Extensions::sinkModel(type, path, kind, madId) and
|
||||
model = "Sink: " + type + "; " + path + "; " + kind
|
||||
)
|
||||
or
|
||||
exists(string type, string path, string input, string output, string kind |
|
||||
Extensions::summaryModel(type, path, input, output, kind, madId) and
|
||||
model = "Summary: " + type + "; " + path + "; " + input + "; " + output + "; " + kind
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if rows involving `type` might be relevant for the analysis of this database.
|
||||
*/
|
||||
|
||||
@@ -369,6 +369,28 @@ private predicate typeVariableModel(string name, string path) {
|
||||
Extensions::typeVariableModel(name, path)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the given extension tuple `madId` should pretty-print as `model`.
|
||||
*
|
||||
* This predicate should only be used in tests.
|
||||
*/
|
||||
predicate interpretModelForTest(QlBuiltins::ExtensionId madId, string model) {
|
||||
exists(string type, string path, string kind |
|
||||
Extensions::sourceModel(type, path, kind, madId) and
|
||||
model = "Source: " + type + "; " + path + "; " + kind
|
||||
)
|
||||
or
|
||||
exists(string type, string path, string kind |
|
||||
Extensions::sinkModel(type, path, kind, madId) and
|
||||
model = "Sink: " + type + "; " + path + "; " + kind
|
||||
)
|
||||
or
|
||||
exists(string type, string path, string input, string output, string kind |
|
||||
Extensions::summaryModel(type, path, input, output, kind, madId) and
|
||||
model = "Summary: " + type + "; " + path + "; " + input + "; " + output + "; " + kind
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if rows involving `type` might be relevant for the analysis of this database.
|
||||
*/
|
||||
|
||||
@@ -369,6 +369,28 @@ private predicate typeVariableModel(string name, string path) {
|
||||
Extensions::typeVariableModel(name, path)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the given extension tuple `madId` should pretty-print as `model`.
|
||||
*
|
||||
* This predicate should only be used in tests.
|
||||
*/
|
||||
predicate interpretModelForTest(QlBuiltins::ExtensionId madId, string model) {
|
||||
exists(string type, string path, string kind |
|
||||
Extensions::sourceModel(type, path, kind, madId) and
|
||||
model = "Source: " + type + "; " + path + "; " + kind
|
||||
)
|
||||
or
|
||||
exists(string type, string path, string kind |
|
||||
Extensions::sinkModel(type, path, kind, madId) and
|
||||
model = "Sink: " + type + "; " + path + "; " + kind
|
||||
)
|
||||
or
|
||||
exists(string type, string path, string input, string output, string kind |
|
||||
Extensions::summaryModel(type, path, input, output, kind, madId) and
|
||||
model = "Summary: " + type + "; " + path + "; " + input + "; " + output + "; " + kind
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if rows involving `type` might be relevant for the analysis of this database.
|
||||
*/
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
models
|
||||
| 1 | Sink: Terrapin::CommandLine!; Method[new].Argument[0]; command-injection |
|
||||
| 2 | Sink: Terrapin::CommandLine!; Method[new].Argument[1]; command-injection |
|
||||
edges
|
||||
| CommandInjection.rb:6:9:6:11 | cmd | CommandInjection.rb:7:10:7:15 | #{...} | provenance | |
|
||||
| CommandInjection.rb:6:9:6:11 | cmd | CommandInjection.rb:8:16:8:18 | cmd | provenance | |
|
||||
@@ -21,9 +24,9 @@ edges
|
||||
| CommandInjection.rb:103:9:103:12 | file | CommandInjection.rb:104:16:104:28 | "cat #{...}" | provenance | AdditionalTaintStep |
|
||||
| CommandInjection.rb:103:16:103:21 | call to params | CommandInjection.rb:103:16:103:28 | ...[...] | provenance | |
|
||||
| CommandInjection.rb:103:16:103:28 | ...[...] | CommandInjection.rb:103:9:103:12 | file | provenance | |
|
||||
| CommandInjection.rb:111:33:111:38 | call to params | CommandInjection.rb:111:33:111:44 | ...[...] | provenance | Sink:MaD:46 |
|
||||
| CommandInjection.rb:111:33:111:38 | call to params | CommandInjection.rb:111:33:111:44 | ...[...] | provenance | Sink:MaD:1 |
|
||||
| CommandInjection.rb:113:44:113:49 | call to params | CommandInjection.rb:113:44:113:54 | ...[...] | provenance | |
|
||||
| CommandInjection.rb:113:44:113:54 | ...[...] | CommandInjection.rb:113:41:113:56 | "#{...}" | provenance | AdditionalTaintStep Sink:MaD:47 |
|
||||
| CommandInjection.rb:113:44:113:54 | ...[...] | CommandInjection.rb:113:41:113:56 | "#{...}" | provenance | AdditionalTaintStep Sink:MaD:2 |
|
||||
nodes
|
||||
| CommandInjection.rb:6:9:6:11 | cmd | semmle.label | cmd |
|
||||
| CommandInjection.rb:6:15:6:20 | call to params | semmle.label | call to params |
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* @kind path-problem
|
||||
*/
|
||||
|
||||
import codeql.ruby.AST
|
||||
import codeql.ruby.security.CommandInjectionQuery
|
||||
import codeql.dataflow.test.ProvenancePathGraph
|
||||
import codeql.ruby.frameworks.data.internal.ApiGraphModels
|
||||
import ShowProvenance<interpretModelForTest/2, CommandInjectionFlow::PathNode, CommandInjectionFlow::PathGraph>
|
||||
|
||||
from CommandInjectionFlow::PathNode source, CommandInjectionFlow::PathNode sink, Source sourceNode
|
||||
where
|
||||
CommandInjectionFlow::flowPath(source, sink) and
|
||||
sourceNode = source.getNode()
|
||||
select sink.getNode(), source, sink, "This command depends on a $@.", sourceNode,
|
||||
sourceNode.getSourceType()
|
||||
@@ -1 +0,0 @@
|
||||
queries/security/cwe-078/CommandInjection.ql
|
||||
@@ -3905,10 +3905,12 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group) }
|
||||
}
|
||||
|
||||
private import codeql.dataflow.test.ProvenancePathGraph as ProvenancePathGraph
|
||||
|
||||
/**
|
||||
* Provides the query predicates needed to include a graph in a path-problem query.
|
||||
*/
|
||||
module PathGraph implements PathGraphSig<PathNode> {
|
||||
module PathGraph implements PathGraphSig<PathNode>, ProvenancePathGraph::PathGraphSig<PathNode> {
|
||||
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
|
||||
query predicate edges(PathNode a, PathNode b, string key, string val) {
|
||||
a.(PathNodeImpl).getANonHiddenSuccessor(val) = b and
|
||||
|
||||
83
shared/dataflow/codeql/dataflow/test/ProvenancePathGraph.qll
Normal file
83
shared/dataflow/codeql/dataflow/test/ProvenancePathGraph.qll
Normal file
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* Provides a module for renumbering MaD IDs in data flow path explanations in
|
||||
* order to produce more stable test output.
|
||||
*
|
||||
* In addition to the `PathGraph`, a `query predicate models` is provided to
|
||||
* list the contents of the referenced MaD rows.
|
||||
*/
|
||||
signature predicate interpretModelForTestSig(QlBuiltins::ExtensionId madId, string model);
|
||||
|
||||
signature class PathNodeSig {
|
||||
string toString();
|
||||
}
|
||||
|
||||
signature module PathGraphSig<PathNodeSig PathNode> {
|
||||
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
|
||||
predicate edges(PathNode a, PathNode b, string key, string val);
|
||||
|
||||
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||
predicate nodes(PathNode n, string key, string val);
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out);
|
||||
}
|
||||
|
||||
/** Transforms a `PathGraph` by printing the provenance information. */
|
||||
module ShowProvenance<
|
||||
interpretModelForTestSig/2 interpretModelForTest, PathNodeSig PathNode,
|
||||
PathGraphSig<PathNode> PathGraph>
|
||||
{
|
||||
private predicate madIds(string madId) {
|
||||
exists(string model |
|
||||
PathGraph::edges(_, _, _, model) and
|
||||
model.regexpFind("(?<=MaD:)[0-9]*", _, _) = madId
|
||||
)
|
||||
}
|
||||
|
||||
private predicate rankedMadIds(string madId, int r) {
|
||||
madId = rank[r](string madId0 | madIds(madId0) | madId0 order by madId0.toInt())
|
||||
}
|
||||
|
||||
query predicate models(int r, string model) {
|
||||
exists(QlBuiltins::ExtensionId madId |
|
||||
rankedMadIds(madId.toString(), r) and interpretModelForTest(madId, model)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate translateModelsPart(string model1, string model2, int i) {
|
||||
PathGraph::edges(_, _, _, model1) and
|
||||
exists(string s | model1.splitAt("MaD:", i) = s |
|
||||
model2 = s and i = 0
|
||||
or
|
||||
exists(string part, string madId, string rest, int r |
|
||||
translateModelsPart(model1, part, i - 1) and
|
||||
madId = s.regexpCapture("([0-9]*)(.*)", 1) and
|
||||
rest = s.regexpCapture("([0-9]*)(.*)", 2) and
|
||||
rankedMadIds(madId, r) and
|
||||
model2 = part + "MaD:" + r + rest
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate translateModels(string model1, string model2) {
|
||||
exists(int i |
|
||||
translateModelsPart(model1, model2, i) and
|
||||
not translateModelsPart(model1, _, i + 1)
|
||||
)
|
||||
}
|
||||
|
||||
query predicate edges(PathNode a, PathNode b, string key, string val) {
|
||||
exists(string model |
|
||||
PathGraph::edges(a, b, key, model) and
|
||||
translateModels(model, val)
|
||||
)
|
||||
}
|
||||
|
||||
query predicate nodes = PathGraph::nodes/3;
|
||||
|
||||
query predicate subpaths = PathGraph::subpaths/4;
|
||||
}
|
||||
Reference in New Issue
Block a user