-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Rust: TaintedPath query #18960
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rust: TaintedPath query #18960
Changes from 11 commits
8223dde
4b5883a
0fd69ea
ecca805
f08d1d1
a3cc695
81f954a
d3e2877
5a91b94
2804c13
f5fe531
efedfa1
b10a296
bf76505
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -581,6 +581,12 @@ | |
| model = "" | ||
| or | ||
| LocalFlow::flowSummaryLocalStep(nodeFrom, nodeTo, model) | ||
| or | ||
| // Add flow through optional barriers. This step is then blocked by the barrier for queries that choose to use the barrier. | ||
| FlowSummaryImpl::Private::Steps::summaryReadStep(nodeFrom | ||
| .(Node::FlowSummaryNode) | ||
| .getSummaryNode(), TOptionalBarrier(_), nodeTo.(Node::FlowSummaryNode).getSummaryNode()) and | ||
| model = "" | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -710,7 +716,8 @@ | |
| ) | ||
| or | ||
| FlowSummaryImpl::Private::Steps::summaryReadStep(node1.(FlowSummaryNode).getSummaryNode(), cs, | ||
| node2.(FlowSummaryNode).getSummaryNode()) | ||
| node2.(FlowSummaryNode).getSummaryNode()) and | ||
| not isSpecialContentSet(cs) | ||
| } | ||
|
|
||
| pragma[nomagic] | ||
|
|
@@ -807,7 +814,8 @@ | |
| storeContentStep(node1, cs.(SingletonContentSet).getContent(), node2) | ||
| or | ||
| FlowSummaryImpl::Private::Steps::summaryStoreStep(node1.(FlowSummaryNode).getSummaryNode(), cs, | ||
| node2.(FlowSummaryNode).getSummaryNode()) | ||
| node2.(FlowSummaryNode).getSummaryNode()) and | ||
| not isSpecialContentSet(cs) | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -1093,7 +1101,24 @@ | |
| newtype TReturnKind = TNormalReturnKind() | ||
|
|
||
| cached | ||
| newtype TContentSet = TSingletonContentSet(Content c) | ||
| newtype TContentSet = | ||
| TSingletonContentSet(Content c) or | ||
| TOptionalStep(string name) { | ||
| name = any(FlowSummaryImpl::Private::AccessPathToken tok).getAnArgument("OptionalStep") | ||
| } or | ||
| TOptionalBarrier(string name) { | ||
| name = any(FlowSummaryImpl::Private::AccessPathToken tok).getAnArgument("OptionalBarrier") | ||
| } | ||
|
|
||
| /** | ||
| * Holds if `cs` is used to encode a special operation as a content component, but should not | ||
| * be treated as an ordinary content component. | ||
| */ | ||
| cached | ||
| predicate isSpecialContentSet(ContentSet cs) { | ||
|
||
| cs instanceof TOptionalStep or | ||
| cs instanceof TOptionalBarrier | ||
| } | ||
|
|
||
| /** Holds if `n` is a flow source of kind `kind`. */ | ||
| cached | ||
|
|
@@ -1105,3 +1130,29 @@ | |
| } | ||
|
|
||
| import Cached | ||
|
|
||
| cached | ||
| private module OptionalSteps { | ||
aibaars marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| /** | ||
| * A step in a flow summary defined using `OptionalStep[name]`. An `OptionalStep` is "opt-in", which means | ||
| * that by default the step is not present in the flow summary and needs to be explicitly enabled by defining | ||
| * an additional flow step. | ||
| */ | ||
|
Comment on lines
+1130
to
+1134
Check warningCode scanning / CodeQL Predicate QLDoc style Warning
The QLDoc for a predicate without a result should start with 'Holds'.
|
||
| cached | ||
| predicate optionalStep(Node node1, string name, Node node2) { | ||
| FlowSummaryImpl::Private::Steps::summaryReadStep(node1.(FlowSummaryNode).getSummaryNode(), | ||
| TOptionalStep(name), node2.(FlowSummaryNode).getSummaryNode()) | ||
| } | ||
|
|
||
| /** | ||
| * A step in a flow summary defined using `OptionalBarrier[name]`. An `OptionalBarrier` is "opt-out", by default | ||
| * data can flow freely through the step. Flow through the step can be explicity blocked by defining its node as a barrier. | ||
| */ | ||
|
Comment on lines
+1141
to
+1144
Check warningCode scanning / CodeQL Predicate QLDoc style Warning
The QLDoc for a predicate without a result should start with 'Holds'.
|
||
| cached | ||
| predicate optionalBarrier(Node node, string name) { | ||
| FlowSummaryImpl::Private::Steps::summaryReadStep(_, TOptionalBarrier(name), | ||
| node.(FlowSummaryNode).getSummaryNode()) | ||
| } | ||
| } | ||
|
|
||
| import OptionalSteps | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| /** | ||
| * Provides modeling for the `Poem` library. | ||
| */ | ||
|
|
||
| private import rust | ||
| private import codeql.rust.Concepts | ||
| private import codeql.rust.dataflow.DataFlow | ||
|
|
||
| /** | ||
| * Parameters of a handler function | ||
| */ | ||
| private class PoemHandlerParam extends RemoteSource::Range { | ||
| PoemHandlerParam() { | ||
| exists(TupleStructPat param | | ||
| param.getResolvedPath() = ["crate::web::query::Query", "crate::web::path::Path"] | ||
| | | ||
| this.asPat().getPat() = param.getAField() | ||
geoffw0 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ) | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| /** | ||
| * Provides classes modeling security-relevant aspects of the standard libraries. | ||
| */ | ||
|
|
||
| private import rust | ||
| private import codeql.rust.Concepts | ||
| private import codeql.rust.controlflow.ControlFlowGraph as Cfg | ||
| private import codeql.rust.controlflow.CfgNodes as CfgNodes | ||
| private import codeql.rust.dataflow.DataFlow | ||
|
|
||
| /** | ||
| * A call to the `starts_with` method on a `Path`. | ||
| */ | ||
| private class StartswithCall extends Path::SafeAccessCheck::Range, CfgNodes::MethodCallExprCfgNode { | ||
| StartswithCall() { | ||
| this.getAstNode().(Resolvable).getResolvedPath() = "<crate::path::Path>::starts_with" | ||
| } | ||
|
|
||
| override predicate checks(Cfg::CfgNode e, boolean branch) { | ||
| e = this.getReceiver() and | ||
| branch = true | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| extensions: | ||
| - addsTo: | ||
| pack: codeql/rust-all | ||
| extensible: sourceModel | ||
| data: [] | ||
| - addsTo: | ||
| pack: codeql/rust-all | ||
| extensible: sinkModel | ||
| data: | ||
| - ["lang:std", "crate::fs::read_to_string", "Argument[0]", "path-injection", "manual"] | ||
|
|
||
| - addsTo: | ||
| pack: codeql/rust-all | ||
| extensible: summaryModel | ||
| data: | ||
| - ["lang:std", "<crate::path::PathBuf as crate::convert::From>::from", "Argument[0]", "ReturnValue", "taint", "manual"] | ||
| - ["lang:std", "<crate::path::Path>::join", "Argument[self]", "ReturnValue", "taint", "manual"] | ||
| - ["lang:std", "<crate::path::Path>::join", "Argument[0]", "ReturnValue", "taint", "manual"] | ||
| - ["lang:std", "<crate::path::Path>::canonicalize", "Argument[self].OptionalStep[normalize-path]", "ReturnValue.Field[crate::result::Result::Ok(0)]", "taint", "manual"] | ||
| - ["lang:std", "<crate::path::Path>::canonicalize", "Argument[self].OptionalBarrier[normalize-path]", "ReturnValue.Field[crate::result::Result::Ok(0)]", "taint", "manual"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.