mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
Merge branch 'ruby-framework-grape' of github.com:felickz/codeql into ruby-framework-grape
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* Added predicates `getTransitiveNumberOfVlaDimensionStmts`, `getTransitiveVlaDimensionStmt`, and `getParentVlaDecl` to `VlaDeclStmt` for handling `VlaDeclStmt`s whose base type defined in terms of an other `VlaDeclStmt` via a `typedef`.
|
||||
* Added predicates `getTransitiveNumberOfVlaDimensionStmts`, `getTransitiveVlaDimensionStmt`, and `getParentVlaDecl` to `VlaDeclStmt` for handling `VlaDeclStmt`s whose base type is defined in terms of another `VlaDeclStmt` via a `typedef`.
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<example>
|
||||
<p>In this example, we are incrementing/decrementing the current date by one year when creating a new <code>System.DateTime</code> object. This may work most of the time, but on any given February 29th, the resulting value will be invalid.</p>
|
||||
<sample src="UnsafeYearConstructionBad.cs" />
|
||||
<p>To fix this bug, we add/substract years to the current date by calling <code>AddYears</code> method on it.</p>
|
||||
<p>To fix this bug, we add/subtract years to the current date by calling <code>AddYears</code> method on it.</p>
|
||||
<sample src="UnsafeYearConstructionGood.cs" />
|
||||
</example>
|
||||
<references>
|
||||
|
||||
@@ -33,6 +33,18 @@ ConditionGuardNode getLengthLEGuard(Variable index, Variable array) {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a condition that checks that `index` is less than `array.length`.
|
||||
*/
|
||||
ConditionGuardNode getLengthLTGuard(Variable index, Variable array) {
|
||||
exists(RelationalComparison cmp | cmp instanceof GTExpr or cmp instanceof LTExpr |
|
||||
cmp = result.getTest() and
|
||||
result.getOutcome() = true and
|
||||
cmp.getGreaterOperand() = arrayLen(array) and
|
||||
cmp.getLesserOperand() = index.getAnAccess()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a condition that checks that `index` is not equal to `array.length`.
|
||||
*/
|
||||
@@ -62,7 +74,8 @@ where
|
||||
elementRead(ea, array, index, bb) and
|
||||
// and the read is guarded by the comparison
|
||||
cond.dominates(bb) and
|
||||
// but the read is not guarded by another check that `index != array.length`
|
||||
not getLengthNEGuard(index, array).dominates(bb)
|
||||
// but the read is not guarded by another check that `index != array.length` or `index < array.length`
|
||||
not getLengthNEGuard(index, array).dominates(bb) and
|
||||
not getLengthLTGuard(index, array).dominates(bb)
|
||||
select cond.getTest(), "Off-by-one index comparison against length may lead to out-of-bounds $@.",
|
||||
ea, "read"
|
||||
|
||||
@@ -108,7 +108,7 @@ str.replace(/\.\.\//g, "");
|
||||
</sample>
|
||||
|
||||
<p>
|
||||
The regular expression attempts to strip out all occurences of <code>/../</code> from <code>str</code>.
|
||||
The regular expression attempts to strip out all occurrences of <code>/../</code> from <code>str</code>.
|
||||
This will not work as expected: for the string <code>/./.././</code>, for example, it will remove the single
|
||||
occurrence of <code>/../</code> in the middle, but the remainder of the string then becomes
|
||||
<code>/../</code>, which is another instance of the substring we were trying to remove.
|
||||
|
||||
4
javascript/ql/src/change-notes/2025-09-12-off-by-one.md
Normal file
4
javascript/ql/src/change-notes/2025-09-12-off-by-one.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Query `js/index-out-of-bounds` no longer produces a false-positive when a strictly-less-than check overrides a previous less-than-or-equal test.
|
||||
@@ -55,3 +55,11 @@ function badContains(a, elt) {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// OK - incorrect upper bound, but extra check
|
||||
function badContains2(a, elt) {
|
||||
for (let i = 0; i <= a.length; ++i)
|
||||
if (i < a.length && a[i] === elt)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -136,7 +136,9 @@ private class GrapeParamsCall extends ParamsCallImpl {
|
||||
this.getParent+() = api.getADeclaration()
|
||||
)
|
||||
}
|
||||
}/**
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `headers` from within a Grape API endpoint or headers block.
|
||||
* Headers can also be a source of user input.
|
||||
*/
|
||||
|
||||
@@ -19,6 +19,7 @@ ql/rust/ql/src/queries/security/CWE-328/WeakSensitiveDataHashing.ql
|
||||
ql/rust/ql/src/queries/security/CWE-770/UncontrolledAllocationSize.ql
|
||||
ql/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql
|
||||
ql/rust/ql/src/queries/security/CWE-825/AccessInvalidPointer.ql
|
||||
ql/rust/ql/src/queries/security/CWE-918/RequestForgery.ql
|
||||
ql/rust/ql/src/queries/summary/LinesOfCode.ql
|
||||
ql/rust/ql/src/queries/summary/LinesOfUserCode.ql
|
||||
ql/rust/ql/src/queries/summary/NodesWithTypeAtLengthLimit.ql
|
||||
|
||||
@@ -22,6 +22,7 @@ ql/rust/ql/src/queries/security/CWE-770/UncontrolledAllocationSize.ql
|
||||
ql/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql
|
||||
ql/rust/ql/src/queries/security/CWE-825/AccessAfterLifetime.ql
|
||||
ql/rust/ql/src/queries/security/CWE-825/AccessInvalidPointer.ql
|
||||
ql/rust/ql/src/queries/security/CWE-918/RequestForgery.ql
|
||||
ql/rust/ql/src/queries/summary/LinesOfCode.ql
|
||||
ql/rust/ql/src/queries/summary/LinesOfUserCode.ql
|
||||
ql/rust/ql/src/queries/summary/NodesWithTypeAtLengthLimit.ql
|
||||
|
||||
@@ -21,6 +21,7 @@ ql/rust/ql/src/queries/security/CWE-770/UncontrolledAllocationSize.ql
|
||||
ql/rust/ql/src/queries/security/CWE-798/HardcodedCryptographicValue.ql
|
||||
ql/rust/ql/src/queries/security/CWE-825/AccessAfterLifetime.ql
|
||||
ql/rust/ql/src/queries/security/CWE-825/AccessInvalidPointer.ql
|
||||
ql/rust/ql/src/queries/security/CWE-918/RequestForgery.ql
|
||||
ql/rust/ql/src/queries/summary/LinesOfCode.ql
|
||||
ql/rust/ql/src/queries/summary/LinesOfUserCode.ql
|
||||
ql/rust/ql/src/queries/summary/NodesWithTypeAtLengthLimit.ql
|
||||
|
||||
4
rust/ql/lib/change-notes/2025-09-12-cookie.md
Normal file
4
rust/ql/lib/change-notes/2025-09-12-cookie.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Added cryptography related models for the `cookie` and `biscotti` crates.
|
||||
7
rust/ql/lib/codeql/rust/frameworks/biscotti.model.yml
Normal file
7
rust/ql/lib/codeql/rust/frameworks/biscotti.model.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
# Models for the `biscotti` crate.
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/rust-all
|
||||
extensible: sinkModel
|
||||
data:
|
||||
- ["<biscotti::crypto::master::Key>::from", "Argument[0]", "credentials-key", "manual"]
|
||||
7
rust/ql/lib/codeql/rust/frameworks/cookie.model.yml
Normal file
7
rust/ql/lib/codeql/rust/frameworks/cookie.model.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
# Models for the `cookie` crate.
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/rust-all
|
||||
extensible: sinkModel
|
||||
data:
|
||||
- ["<cookie::secure::key::Key>::from", "Argument[0].Reference", "credentials-key", "manual"]
|
||||
@@ -9,8 +9,8 @@ extensions:
|
||||
pack: codeql/rust-all
|
||||
extensible: sinkModel
|
||||
data:
|
||||
- ["<reqwest::async_impl::client::Client>::request", "Argument[1]", "transmission", "manual"]
|
||||
- ["<reqwest::blocking::client::Client>::request", "Argument[1]", "transmission", "manual"]
|
||||
- ["<reqwest::async_impl::client::Client>::request", "Argument[1]", "request-url", "manual"]
|
||||
- ["<reqwest::blocking::client::Client>::request", "Argument[1]", "request-url", "manual"]
|
||||
- addsTo:
|
||||
pack: codeql/rust-all
|
||||
extensible: summaryModel
|
||||
|
||||
@@ -45,7 +45,6 @@ extensions:
|
||||
data:
|
||||
- ["std::fs::canonicalize", "Argument[0].OptionalStep[normalize-path]", "ReturnValue.Field[core::result::Result::Ok(0)]", "taint", "manual"]
|
||||
- ["std::fs::canonicalize", "Argument[0].OptionalBarrier[normalize-path]", "ReturnValue.Field[core::result::Result::Ok(0)]", "taint", "manual"]
|
||||
- ["<std::path::PathBuf as core::convert::From>::from", "Argument[0]", "ReturnValue", "value", "manual"]
|
||||
- ["<std::path::PathBuf>::as_path", "Argument[Self]", "ReturnValue.Reference", "value", "manual"]
|
||||
- ["<std::path::PathBuf>::as_mut_os_string", "Argument[Self].Reference", "ReturnValue.Reference", "value", "manual"]
|
||||
- ["<std::path::PathBuf>::into_os_string", "Argument[Self]", "ReturnValue", "value", "manual"]
|
||||
|
||||
@@ -46,4 +46,5 @@ extensions:
|
||||
- ["<alloc::string::String as alloc::string::ToString>::to_string", "Argument[self]", "ReturnValue", "taint", "manual"]
|
||||
- ["<core::str>::parse", "Argument[self]", "ReturnValue.Field[core::result::Result::Ok(0)]", "taint", "manual"]
|
||||
- ["<core::str>::trim", "Argument[self]", "ReturnValue.Reference", "taint", "manual"]
|
||||
- ["<alloc::string::String as core::convert::From>::from", "Argument[0]", "ReturnValue", "value", "manual"]
|
||||
# Vec
|
||||
- ["alloc::vec::from_elem", "Argument[0]", "ReturnValue.Element", "value", "manual"]
|
||||
|
||||
@@ -11,6 +11,8 @@ extensions:
|
||||
- ["<_ as core::convert::Into>::into", "Argument[self].Reference.Element", "ReturnValue.Element", "taint", "manual"]
|
||||
- ["<alloc::string::String as core::convert::Into>::into", "Argument[self].Element", "ReturnValue.Element", "taint", "manual"]
|
||||
- ["<alloc::string::String as core::convert::Into>::into", "Argument[self].Reference.Element", "ReturnValue.Element", "taint", "manual"]
|
||||
# From
|
||||
- ["<_ as core::convert::From>::from", "Argument[0]", "ReturnValue", "value", "manual"]
|
||||
# Iterator
|
||||
- ["<core::result::Result>::iter", "Argument[self].Element", "ReturnValue.Element", "value", "manual"]
|
||||
- ["<alloc::vec::Vec as value_trait::array::Array>::iter", "Argument[self].Element", "ReturnValue.Element", "value", "manual"]
|
||||
|
||||
@@ -648,6 +648,18 @@ final class ImplItemNode extends ImplOrTraitItemNode instanceof Impl {
|
||||
|
||||
override Visibility getVisibility() { result = Impl.super.getVisibility() }
|
||||
|
||||
TypeParamItemNode getBlanketImplementationTypeParam() {
|
||||
result = this.resolveSelfTy() and
|
||||
// This impl block is not superseded by the expansion of an attribute macro.
|
||||
not exists(super.getAttributeMacroExpansion())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this impl block is a blanket implementation. That is, the
|
||||
* implementation targets a generic parameter of the impl block.
|
||||
*/
|
||||
predicate isBlanketImplementation() { exists(this.getBlanketImplementationTypeParam()) }
|
||||
|
||||
override predicate hasCanonicalPath(Crate c) { this.resolveSelfTy().hasCanonicalPathPrefix(c) }
|
||||
|
||||
/**
|
||||
@@ -1006,6 +1018,14 @@ final class TypeParamItemNode extends TypeItemNode instanceof TypeParam {
|
||||
Path getABoundPath() { result = this.getTypeBoundAt(_, _).getTypeRepr().(PathTypeRepr).getPath() }
|
||||
|
||||
pragma[nomagic]
|
||||
ItemNode resolveBound(int index) {
|
||||
result =
|
||||
rank[index + 1](int i, int j |
|
||||
|
|
||||
resolvePath(this.getTypeBoundAt(i, j).getTypeRepr().(PathTypeRepr).getPath()) order by i, j
|
||||
)
|
||||
}
|
||||
|
||||
ItemNode resolveABound() { result = resolvePath(this.getABoundPath()) }
|
||||
|
||||
/**
|
||||
|
||||
@@ -1915,6 +1915,10 @@ private predicate methodCandidateTrait(Type type, Trait trait, string name, int
|
||||
methodCandidate(type, name, arity, impl)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `mc` has `rootType` as the root type of the receiver and the target
|
||||
* method is named `name` and has arity `arity`
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate isMethodCall(MethodCall mc, Type rootType, string name, int arity) {
|
||||
rootType = mc.getTypeAt(TypePath::nil()) and
|
||||
@@ -2153,6 +2157,130 @@ private predicate methodCallHasImplCandidate(MethodCall mc, Impl impl) {
|
||||
else any()
|
||||
}
|
||||
|
||||
private module BlanketImplementation {
|
||||
private ImplItemNode getPotentialDuplicated(
|
||||
string fileName, string traitName, int arity, string tpName
|
||||
) {
|
||||
tpName = result.getBlanketImplementationTypeParam().getName() and
|
||||
fileName = result.getLocation().getFile().getBaseName() and
|
||||
traitName = result.resolveTraitTy().getName() and
|
||||
arity = result.resolveTraitTy().(Trait).getNumberOfGenericParams()
|
||||
}
|
||||
|
||||
private predicate duplicatedImpl(Impl impl1, Impl impl2) {
|
||||
exists(string fileName, string traitName, int arity, string tpName |
|
||||
impl1 = getPotentialDuplicated(fileName, traitName, arity, tpName) and
|
||||
impl2 = getPotentialDuplicated(fileName, traitName, arity, tpName) and
|
||||
impl1.getLocation().getFile().getAbsolutePath() <
|
||||
impl2.getLocation().getFile().getAbsolutePath()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `impl` is a canonical blanket implementation.
|
||||
*
|
||||
* Libraries can often occur several times in the database for different
|
||||
* library versions. This causes the same blanket implementations to exist
|
||||
* multiple times, and these add no useful information.
|
||||
*
|
||||
* We detect these duplicates based on some simple heuristics (same trait
|
||||
* name, file name, etc.). For these duplicates we select the one with the
|
||||
* greatest file name (which usually is also the one with the greatest library
|
||||
* version in the path) as the "canonical" implementation.
|
||||
*/
|
||||
private predicate isCanonicalImpl(Impl impl) {
|
||||
not duplicatedImpl(impl, _) and impl.(ImplItemNode).isBlanketImplementation()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `impl` is a blanket implementation for a type parameter and
|
||||
* `traitBound` is the first non-trivial trait bound of that type parameter.
|
||||
*/
|
||||
private predicate blanketImplementationTraitBound(ImplItemNode impl, Trait traitBound) {
|
||||
traitBound =
|
||||
min(Trait trait, int i |
|
||||
trait = impl.getBlanketImplementationTypeParam().resolveBound(i) and
|
||||
// Exclude traits that are known to not narrow things down very much.
|
||||
not trait.getName().getText() =
|
||||
[
|
||||
"Sized", "Clone",
|
||||
// The auto traits
|
||||
"Send", "Sync", "Unpin", "UnwindSafe", "RefUnwindSafe"
|
||||
]
|
||||
|
|
||||
trait order by i
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `impl` is a relevant blanket implementation that requires the
|
||||
* trait `traitBound` and provides `f`, a method with name `name` and arity
|
||||
* `arity`.
|
||||
*/
|
||||
private predicate blanketImplementationMethod(
|
||||
ImplItemNode impl, Trait traitBound, string name, int arity, Function f
|
||||
) {
|
||||
isCanonicalImpl(impl) and
|
||||
blanketImplementationTraitBound(impl, traitBound) and
|
||||
f.getParamList().hasSelfParam() and
|
||||
arity = f.getParamList().getNumberOfParams() and
|
||||
(
|
||||
f = impl.getAssocItem(name)
|
||||
or
|
||||
// If the trait has a method with a default implementation, then that
|
||||
// target is interesting as well.
|
||||
not exists(impl.getAssocItem(name)) and
|
||||
f = impl.resolveTraitTy().getAssocItem(name)
|
||||
) and
|
||||
// If the method is already available through one of the trait bounds on the
|
||||
// type parameter (because they implement the trait targeted by the impl
|
||||
// block) then ignore it.
|
||||
not impl.getBlanketImplementationTypeParam().resolveABound().(TraitItemNode).getASuccessor(name) =
|
||||
f
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate methodCallMatchesBlanketImpl(
|
||||
MethodCall mc, Type t, ImplItemNode impl, Trait traitBound, Trait traitImpl, Function f
|
||||
) {
|
||||
// Only check method calls where we have ruled out inherent method targets.
|
||||
// Ideally we would also check if non-blanket method targets have been ruled
|
||||
// out.
|
||||
methodCallHasNoInherentTarget(mc) and
|
||||
exists(string name, int arity |
|
||||
isMethodCall(mc, t, name, arity) and
|
||||
blanketImplementationMethod(impl, traitBound, name, arity, f)
|
||||
) and
|
||||
traitImpl = impl.resolveTraitTy()
|
||||
}
|
||||
|
||||
private predicate relevantTraitVisible(Element mc, Trait trait) {
|
||||
methodCallMatchesBlanketImpl(mc, _, _, _, trait, _)
|
||||
}
|
||||
|
||||
module SatisfiesConstraintInput implements SatisfiesConstraintInputSig<MethodCall> {
|
||||
pragma[nomagic]
|
||||
predicate relevantConstraint(MethodCall mc, Type constraint) {
|
||||
exists(Trait traitBound, Trait traitImpl |
|
||||
methodCallMatchesBlanketImpl(mc, _, _, traitBound, traitImpl, _) and
|
||||
TraitIsVisible<relevantTraitVisible/2>::traitIsVisible(mc, traitImpl) and
|
||||
traitBound = constraint.(TraitType).getTrait()
|
||||
)
|
||||
}
|
||||
|
||||
predicate useUniversalConditions() { none() }
|
||||
}
|
||||
|
||||
predicate hasBlanketImpl(MethodCall mc, Type t, Impl impl, Trait traitBound, Function f) {
|
||||
SatisfiesConstraint<MethodCall, SatisfiesConstraintInput>::satisfiesConstraintType(mc,
|
||||
TTrait(traitBound), _, _) and
|
||||
methodCallMatchesBlanketImpl(mc, t, impl, traitBound, _, f)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
Function getMethodFromBlanketImpl(MethodCall mc) { hasBlanketImpl(mc, _, _, _, result) }
|
||||
}
|
||||
|
||||
/** Gets a method from an `impl` block that matches the method call `mc`. */
|
||||
pragma[nomagic]
|
||||
private Function getMethodFromImpl(MethodCall mc) {
|
||||
@@ -2188,6 +2316,8 @@ private Function resolveMethodCallTarget(MethodCall mc) {
|
||||
// The method comes from an `impl` block targeting the type of the receiver.
|
||||
result = getMethodFromImpl(mc)
|
||||
or
|
||||
result = BlanketImplementation::getMethodFromBlanketImpl(mc)
|
||||
or
|
||||
// The type of the receiver is a type parameter and the method comes from a
|
||||
// trait bound on the type parameter.
|
||||
result = getTypeParameterMethod(mc.getTypeAt(TypePath::nil()), mc.getMethodName())
|
||||
|
||||
@@ -53,6 +53,6 @@ module CleartextTransmission {
|
||||
* A sink defined through MaD.
|
||||
*/
|
||||
private class ModelsAsDataSink extends Sink {
|
||||
ModelsAsDataSink() { sinkNode(this, "transmission") }
|
||||
ModelsAsDataSink() { sinkNode(this, ["transmission", "request-url"]) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Provides classes and predicates for reasoning about request forgery
|
||||
* vulnerabilities.
|
||||
*/
|
||||
|
||||
import rust
|
||||
private import codeql.rust.dataflow.DataFlow
|
||||
private import codeql.rust.dataflow.FlowSink
|
||||
private import codeql.rust.dataflow.FlowSource
|
||||
private import codeql.rust.Concepts
|
||||
|
||||
/**
|
||||
* Provides default sources, sinks and barriers for detecting request forgery
|
||||
* vulnerabilities, as well as extension points for adding your own.
|
||||
*/
|
||||
module RequestForgery {
|
||||
/**
|
||||
* A data flow source for request forgery vulnerabilities.
|
||||
*/
|
||||
abstract class Source extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A data flow sink for request forgery vulnerabilities.
|
||||
*/
|
||||
abstract class Sink extends QuerySink::Range {
|
||||
/**
|
||||
* Gets the name of a part of the request that may be tainted by this sink,
|
||||
* such as the URL or the host.
|
||||
*/
|
||||
override string getSinkType() { result = "RequestForgery" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A barrier for request forgery vulnerabilities.
|
||||
*/
|
||||
abstract class Barrier extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* An active threat-model source, considered as a flow source.
|
||||
*/
|
||||
private class ActiveThreatModelSourceAsSource extends Source, ActiveThreatModelSource { }
|
||||
|
||||
/**
|
||||
* A sink for request forgery from model data.
|
||||
*/
|
||||
private class ModelsAsDataSink extends Sink {
|
||||
ModelsAsDataSink() { sinkNode(this, "request-url") }
|
||||
}
|
||||
}
|
||||
@@ -424,21 +424,21 @@ extensions:
|
||||
pack: codeql/rust-all
|
||||
extensible: sinkModel
|
||||
data:
|
||||
- ["<reqwest::async_impl::client::Client>::delete", "Argument[0]", "transmission", "df-generated"]
|
||||
- ["<reqwest::async_impl::client::Client>::get", "Argument[0]", "transmission", "df-generated"]
|
||||
- ["<reqwest::async_impl::client::Client>::head", "Argument[0]", "transmission", "df-generated"]
|
||||
- ["<reqwest::async_impl::client::Client>::patch", "Argument[0]", "transmission", "df-generated"]
|
||||
- ["<reqwest::async_impl::client::Client>::post", "Argument[0]", "transmission", "df-generated"]
|
||||
- ["<reqwest::async_impl::client::Client>::put", "Argument[0]", "transmission", "df-generated"]
|
||||
- ["<reqwest::async_impl::client::Client>::delete", "Argument[0]", "request-url", "df-generated"]
|
||||
- ["<reqwest::async_impl::client::Client>::get", "Argument[0]", "request-url", "df-generated"]
|
||||
- ["<reqwest::async_impl::client::Client>::head", "Argument[0]", "request-url", "df-generated"]
|
||||
- ["<reqwest::async_impl::client::Client>::patch", "Argument[0]", "request-url", "df-generated"]
|
||||
- ["<reqwest::async_impl::client::Client>::post", "Argument[0]", "request-url", "df-generated"]
|
||||
- ["<reqwest::async_impl::client::Client>::put", "Argument[0]", "request-url", "df-generated"]
|
||||
- ["<reqwest::async_impl::multipart::Form>::into_stream", "Argument[self]", "log-injection", "df-generated"]
|
||||
- ["<reqwest::async_impl::multipart::Form>::stream", "Argument[self]", "log-injection", "df-generated"]
|
||||
- ["<reqwest::async_impl::request::RequestBuilder>::multipart", "Argument[0]", "log-injection", "df-generated"]
|
||||
- ["<reqwest::blocking::client::Client>::delete", "Argument[0]", "transmission", "df-generated"]
|
||||
- ["<reqwest::blocking::client::Client>::get", "Argument[0]", "transmission", "df-generated"]
|
||||
- ["<reqwest::blocking::client::Client>::head", "Argument[0]", "transmission", "df-generated"]
|
||||
- ["<reqwest::blocking::client::Client>::patch", "Argument[0]", "transmission", "df-generated"]
|
||||
- ["<reqwest::blocking::client::Client>::post", "Argument[0]", "transmission", "df-generated"]
|
||||
- ["<reqwest::blocking::client::Client>::put", "Argument[0]", "transmission", "df-generated"]
|
||||
- ["<reqwest::blocking::client::Client>::delete", "Argument[0]", "request-url", "df-generated"]
|
||||
- ["<reqwest::blocking::client::Client>::get", "Argument[0]", "request-url", "df-generated"]
|
||||
- ["<reqwest::blocking::client::Client>::head", "Argument[0]", "request-url", "df-generated"]
|
||||
- ["<reqwest::blocking::client::Client>::patch", "Argument[0]", "request-url", "df-generated"]
|
||||
- ["<reqwest::blocking::client::Client>::post", "Argument[0]", "request-url", "df-generated"]
|
||||
- ["<reqwest::blocking::client::Client>::put", "Argument[0]", "request-url", "df-generated"]
|
||||
- ["<reqwest::blocking::multipart::Form>::into_reader", "Argument[self]", "log-injection", "df-generated"]
|
||||
- ["<reqwest::blocking::multipart::Form>::reader", "Argument[self]", "log-injection", "df-generated"]
|
||||
- ["<reqwest::blocking::multipart::Reader as std::io::Read>::read", "Argument[self]", "log-injection", "df-generated"]
|
||||
@@ -450,9 +450,9 @@ extensions:
|
||||
- ["<reqwest::blocking::response::Response>::text_with_charset", "Argument[self]", "pointer-access", "df-generated"]
|
||||
- ["<reqwest::connect::ConnectorService as tower_service::Service>::call", "Argument[0]", "log-injection", "df-generated"]
|
||||
- ["<reqwest::error::Error>::new", "Argument[1]", "pointer-access", "df-generated"]
|
||||
- ["reqwest::blocking::get", "Argument[0]", "transmission", "df-generated"]
|
||||
- ["reqwest::blocking::get", "Argument[0]", "request-url", "df-generated"]
|
||||
- ["reqwest::blocking::wait::timeout", "Argument[1]", "pointer-access", "df-generated"]
|
||||
- ["reqwest::get", "Argument[0]", "transmission", "df-generated"]
|
||||
- ["reqwest::get", "Argument[0]", "request-url", "df-generated"]
|
||||
- addsTo:
|
||||
pack: codeql/rust-all
|
||||
extensible: sourceModel
|
||||
|
||||
4
rust/ql/src/change-notes/2025-09-09-request-forgery.md
Normal file
4
rust/ql/src/change-notes/2025-09-09-request-forgery.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: newQuery
|
||||
---
|
||||
* Added a new query, `rust/request-forgery`, for detecting server-side request forgery vulnerabilities.
|
||||
48
rust/ql/src/queries/security/CWE-918/RequestForgery.qhelp
Normal file
48
rust/ql/src/queries/security/CWE-918/RequestForgery.qhelp
Normal file
@@ -0,0 +1,48 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>
|
||||
Directly incorporating user input into an HTTP request without validating the
|
||||
input can facilitate server-side request forgery (SSRF) attacks. In these
|
||||
attacks, the server may be tricked into making a request to an unintended API
|
||||
endpoint or resource.
|
||||
|
||||
If the server is connected to an internal network, attackers can bypass security
|
||||
boundaries to target internal services.
|
||||
|
||||
Forged requests can execute unintended actions, leak data if redirected to an
|
||||
external server, or compromise the server if responses are handled insecurely.
|
||||
</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>
|
||||
To guard against SSRF attacks, you should avoid putting user-provided input
|
||||
directly into a request URL. Instead, maintain a list of authorized URLs on the
|
||||
server; then choose from that list based on the input provided. Alternatively,
|
||||
ensure requests constructed from user input are limited to a particular host or
|
||||
a more restrictive URL prefix.
|
||||
</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>
|
||||
The following example shows an HTTP request parameter being used directly to
|
||||
form a new request without validating the input, which facilitates SSRF attacks.
|
||||
It also shows how to remedy the problem by validating the user input against a
|
||||
known fixed string.
|
||||
</p>
|
||||
|
||||
<sample src="RequestForgery.rs" />
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>
|
||||
<a href="https://owasp.org/www-community/attacks/Server_Side_Request_Forgery">OWASP Server Side Request Forgery</a>.
|
||||
</li>
|
||||
</references>
|
||||
|
||||
</qhelp>
|
||||
38
rust/ql/src/queries/security/CWE-918/RequestForgery.ql
Normal file
38
rust/ql/src/queries/security/CWE-918/RequestForgery.ql
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* @name Server-side request forgery
|
||||
* @description Making a network request with user-controlled data in the URL allows for request forgery attacks.
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @security-severity 9.1
|
||||
* @precision high
|
||||
* @id rust/request-forgery
|
||||
* @tags security
|
||||
* external/cwe/cwe-918
|
||||
*/
|
||||
|
||||
private import rust
|
||||
private import codeql.rust.dataflow.TaintTracking
|
||||
private import codeql.rust.dataflow.DataFlow
|
||||
private import codeql.rust.security.RequestForgeryExtensions
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for detecting request forgery vulnerabilities.
|
||||
*/
|
||||
module RequestForgeryConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RequestForgery::Source }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof RequestForgery::Sink }
|
||||
|
||||
predicate isBarrier(DataFlow::Node barrier) { barrier instanceof RequestForgery::Barrier }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
}
|
||||
|
||||
module RequestForgeryFlow = TaintTracking::Global<RequestForgeryConfig>;
|
||||
|
||||
import RequestForgeryFlow::PathGraph
|
||||
|
||||
from RequestForgeryFlow::PathNode source, RequestForgeryFlow::PathNode sink
|
||||
where RequestForgeryFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "The URL of this request depends on a $@.", source.getNode(),
|
||||
"user-provided value"
|
||||
39
rust/ql/src/queries/security/CWE-918/RequestForgery.rs
Normal file
39
rust/ql/src/queries/security/CWE-918/RequestForgery.rs
Normal file
@@ -0,0 +1,39 @@
|
||||
// BAD: Endpoint handler that makes requests based on user input
|
||||
async fn vulnerable_endpoint_handler(req: Request) -> Result<Response> {
|
||||
// This request is vulnerable to SSRF attacks as the user controls the
|
||||
// entire URL
|
||||
let response = reqwest::get(&req.user_url).await;
|
||||
|
||||
match response {
|
||||
Ok(resp) => {
|
||||
let body = resp.text().await.unwrap_or_default();
|
||||
Ok(Response {
|
||||
message: "Success".to_string(),
|
||||
data: body,
|
||||
})
|
||||
}
|
||||
Err(_) => Err("Request failed")
|
||||
}
|
||||
}
|
||||
|
||||
// GOOD: Validate user input against an allowlist
|
||||
async fn secure_endpoint_handler(req: Request) -> Result<Response> {
|
||||
// Allow list of specific, known-safe URLs
|
||||
let allowed_hosts = ["api.example.com", "trusted-service.com"];
|
||||
|
||||
if !allowed_hosts.contains(&req.user_url) {
|
||||
return Err("Untrusted domain");
|
||||
}
|
||||
// This request is safe as the user input has been validated
|
||||
let response = reqwest::get(&req.user_url).await;
|
||||
match response {
|
||||
Ok(resp) => {
|
||||
let body = resp.text().await.unwrap_or_default();
|
||||
Ok(Response {
|
||||
message: "Success".to_string(),
|
||||
data: body,
|
||||
})
|
||||
}
|
||||
Err(_) => Err("Request failed")
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ private import codeql.rust.security.AccessInvalidPointerExtensions
|
||||
private import codeql.rust.security.CleartextLoggingExtensions
|
||||
private import codeql.rust.security.CleartextStorageDatabaseExtensions
|
||||
private import codeql.rust.security.CleartextTransmissionExtensions
|
||||
private import codeql.rust.security.RequestForgeryExtensions
|
||||
private import codeql.rust.security.LogInjectionExtensions
|
||||
private import codeql.rust.security.SqlInjectionExtensions
|
||||
private import codeql.rust.security.TaintedPathExtensions
|
||||
|
||||
@@ -1005,12 +1005,15 @@ readStep
|
||||
| main.rs:458:5:458:11 | mut_arr | file://:0:0:0:0 | element | main.rs:458:5:458:14 | mut_arr[1] |
|
||||
| main.rs:459:13:459:19 | mut_arr | file://:0:0:0:0 | element | main.rs:459:13:459:22 | mut_arr[1] |
|
||||
| main.rs:461:10:461:16 | mut_arr | file://:0:0:0:0 | element | main.rs:461:10:461:19 | mut_arr[0] |
|
||||
| main.rs:467:24:467:33 | [post] receiver for source(...) | file://:0:0:0:0 | &ref | main.rs:467:24:467:33 | [post] source(...) |
|
||||
| main.rs:468:9:468:20 | TuplePat | file://:0:0:0:0 | tuple.0 | main.rs:468:10:468:13 | cond |
|
||||
| main.rs:468:9:468:20 | TuplePat | file://:0:0:0:0 | tuple.1 | main.rs:468:16:468:19 | name |
|
||||
| main.rs:468:25:468:29 | names | file://:0:0:0:0 | element | main.rs:468:9:468:20 | TuplePat |
|
||||
| main.rs:470:41:470:67 | [post] \|...\| ... | main.rs:467:9:467:20 | captured default_name | main.rs:470:41:470:67 | [post] default_name |
|
||||
| main.rs:470:44:470:55 | [post] receiver for default_name | file://:0:0:0:0 | &ref | main.rs:470:44:470:55 | [post] default_name |
|
||||
| main.rs:470:44:470:55 | this | main.rs:467:9:467:20 | captured default_name | main.rs:470:44:470:55 | default_name |
|
||||
| main.rs:471:18:471:18 | [post] receiver for n | file://:0:0:0:0 | &ref | main.rs:471:18:471:18 | [post] n |
|
||||
| main.rs:494:13:494:13 | [post] receiver for a | file://:0:0:0:0 | &ref | main.rs:494:13:494:13 | [post] a |
|
||||
| main.rs:495:13:495:13 | [post] receiver for b | file://:0:0:0:0 | &ref | main.rs:495:13:495:13 | [post] b |
|
||||
| main.rs:496:18:496:18 | [post] receiver for b | file://:0:0:0:0 | &ref | main.rs:496:18:496:18 | [post] b |
|
||||
| main.rs:507:10:507:11 | vs | file://:0:0:0:0 | element | main.rs:507:10:507:14 | vs[0] |
|
||||
@@ -1110,8 +1113,11 @@ storeStep
|
||||
| main.rs:455:27:455:27 | 2 | file://:0:0:0:0 | element | main.rs:455:23:455:31 | [...] |
|
||||
| main.rs:455:30:455:30 | 3 | file://:0:0:0:0 | element | main.rs:455:23:455:31 | [...] |
|
||||
| main.rs:458:18:458:27 | source(...) | file://:0:0:0:0 | element | main.rs:458:5:458:11 | [post] mut_arr |
|
||||
| main.rs:467:24:467:33 | source(...) | file://:0:0:0:0 | &ref | main.rs:467:24:467:33 | receiver for source(...) |
|
||||
| main.rs:470:41:470:67 | default_name | main.rs:467:9:467:20 | captured default_name | main.rs:470:41:470:67 | \|...\| ... |
|
||||
| main.rs:470:44:470:55 | default_name | file://:0:0:0:0 | &ref | main.rs:470:44:470:55 | receiver for default_name |
|
||||
| main.rs:471:18:471:18 | n | file://:0:0:0:0 | &ref | main.rs:471:18:471:18 | receiver for n |
|
||||
| main.rs:494:13:494:13 | a | file://:0:0:0:0 | &ref | main.rs:494:13:494:13 | receiver for a |
|
||||
| main.rs:495:13:495:13 | b | file://:0:0:0:0 | &ref | main.rs:495:13:495:13 | receiver for b |
|
||||
| main.rs:496:18:496:18 | b | file://:0:0:0:0 | &ref | main.rs:496:18:496:18 | receiver for b |
|
||||
| main.rs:505:15:505:24 | source(...) | file://:0:0:0:0 | element | main.rs:505:14:505:34 | [...] |
|
||||
|
||||
@@ -73,6 +73,18 @@ multipleCallTargets
|
||||
| test.rs:977:14:977:29 | ...::_print(...) |
|
||||
| test.rs:979:27:979:36 | ...::_print(...) |
|
||||
| test.rs:980:28:980:41 | ...::_print(...) |
|
||||
| test_futures_io.rs:45:27:45:84 | ...::read(...) |
|
||||
| test_futures_io.rs:49:27:49:51 | reader.read(...) |
|
||||
| test_futures_io.rs:83:22:83:39 | reader2.fill_buf() |
|
||||
| test_futures_io.rs:103:27:103:85 | ...::read(...) |
|
||||
| test_futures_io.rs:107:27:107:52 | reader2.read(...) |
|
||||
| test_futures_io.rs:125:22:125:39 | reader2.fill_buf() |
|
||||
| test_futures_io.rs:132:27:132:62 | reader2.read_until(...) |
|
||||
| test_futures_io.rs:139:27:139:54 | reader2.read_line(...) |
|
||||
| test_futures_io.rs:146:27:146:58 | reader2.read_to_end(...) |
|
||||
| test_futures_io.rs:152:32:152:46 | reader2.lines() |
|
||||
| test_futures_io.rs:153:14:153:32 | lines_stream.next() |
|
||||
| test_futures_io.rs:154:32:154:50 | lines_stream.next() |
|
||||
| web_frameworks.rs:13:14:13:22 | a.as_str() |
|
||||
| web_frameworks.rs:13:14:13:23 | a.as_str() |
|
||||
| web_frameworks.rs:14:14:14:24 | a.as_bytes() |
|
||||
|
||||
@@ -309,28 +309,28 @@ async fn test_tokio_stdin() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut stdin = tokio::io::stdin(); // $ Alert[rust/summary/taint-sources]
|
||||
let mut buffer = [0u8; 100];
|
||||
let _bytes = stdin.read(&mut buffer).await?;
|
||||
sink(&buffer); // $ MISSING: hasTaintFlow -- we cannot resolve the `read` call above, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
|
||||
sink(&buffer); // $ hasTaintFlow
|
||||
}
|
||||
|
||||
{
|
||||
let mut stdin = tokio::io::stdin(); // $ Alert[rust/summary/taint-sources]
|
||||
let mut buffer = Vec::<u8>::new();
|
||||
let _bytes = stdin.read_to_end(&mut buffer).await?;
|
||||
sink(&buffer); // $ MISSING: hasTaintFlow -- we cannot resolve the `read_to_end` call above, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
|
||||
sink(&buffer); // $ hasTaintFlow
|
||||
}
|
||||
|
||||
{
|
||||
let mut stdin = tokio::io::stdin(); // $ Alert[rust/summary/taint-sources]
|
||||
let mut buffer = String::new();
|
||||
let _bytes = stdin.read_to_string(&mut buffer).await?;
|
||||
sink(&buffer); // $ MISSING: hasTaintFlow -- we cannot resolve the `read_to_string` call above, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
|
||||
sink(&buffer); // $ hasTaintFlow
|
||||
}
|
||||
|
||||
{
|
||||
let mut stdin = tokio::io::stdin(); // $ Alert[rust/summary/taint-sources]
|
||||
let mut buffer = [0; 100];
|
||||
stdin.read_exact(&mut buffer).await?;
|
||||
sink(&buffer); // $ MISSING: hasTaintFlow -- we cannot resolve the `read_exact` call above, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
|
||||
sink(&buffer); // $ hasTaintFlow
|
||||
}
|
||||
|
||||
{
|
||||
@@ -339,17 +339,17 @@ async fn test_tokio_stdin() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let v2 = stdin.read_i16().await?;
|
||||
let v3 = stdin.read_f32().await?;
|
||||
let v4 = stdin.read_i64_le().await?;
|
||||
sink(v1); // $ MISSING: hasTaintFlow -- we cannot resolve the `read_u8` call above, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
|
||||
sink(v2); // $ MISSING: hasTaintFlow -- we cannot resolve the `read_i16` call above, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
|
||||
sink(v3); // $ MISSING: hasTaintFlow -- we cannot resolve the `read_f32` call above, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
|
||||
sink(v4); // $ MISSING: hasTaintFlow -- we cannot resolve the `read_i64_le` call above, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
|
||||
sink(v1); // $ hasTaintFlow
|
||||
sink(v2); // $ hasTaintFlow
|
||||
sink(v3); // $ hasTaintFlow
|
||||
sink(v4); // $ hasTaintFlow
|
||||
}
|
||||
|
||||
{
|
||||
let mut stdin = tokio::io::stdin(); // $ Alert[rust/summary/taint-sources]
|
||||
let mut buffer = bytes::BytesMut::new();
|
||||
stdin.read_buf(&mut buffer).await?;
|
||||
sink(&buffer); // $ MISSING: hasTaintFlow -- we cannot resolve the `read_buf` call above, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
|
||||
sink(&buffer); // $ hasTaintFlow
|
||||
}
|
||||
|
||||
// --- async reading from stdin (BufReader) ---
|
||||
@@ -357,7 +357,7 @@ async fn test_tokio_stdin() -> Result<(), Box<dyn std::error::Error>> {
|
||||
{
|
||||
let mut reader = tokio::io::BufReader::new(tokio::io::stdin()); // $ Alert[rust/summary/taint-sources]
|
||||
let data = reader.fill_buf().await?;
|
||||
sink(&data); // $ MISSING: hasTaintFlow -- we cannot resolve the `fill_buf` call above, which comes from `impl<R: AsyncBufRead + ?Sized> AsyncBufReadExt for R {}` in `async_buf_read_ext.rs`
|
||||
sink(&data); // $ hasTaintFlow
|
||||
}
|
||||
|
||||
{
|
||||
@@ -370,31 +370,31 @@ async fn test_tokio_stdin() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut buffer = String::new();
|
||||
let mut reader = tokio::io::BufReader::new(tokio::io::stdin()); // $ Alert[rust/summary/taint-sources]
|
||||
reader.read_line(&mut buffer).await?;
|
||||
sink(&buffer); // $ MISSING: hasTaintFlow -- we cannot resolve the `read_line` call above, which comes from `impl<R: AsyncBufRead + ?Sized> AsyncBufReadExt for R {}` in `async_buf_read_ext.rs`
|
||||
sink(&buffer); // $ hasTaintFlow
|
||||
}
|
||||
|
||||
{
|
||||
let mut buffer = Vec::<u8>::new();
|
||||
let mut reader = tokio::io::BufReader::new(tokio::io::stdin()); // $ Alert[rust/summary/taint-sources]
|
||||
reader.read_until(b',', &mut buffer).await?;
|
||||
sink(&buffer); // $ MISSING: hasTaintFlow -- we cannot resolve the `read_until` call above, which comes from `impl<R: AsyncBufRead + ?Sized> AsyncBufReadExt for R {}` in `async_buf_read_ext.rs`
|
||||
sink(buffer[0]); // $ MISSING: hasTaintFlow -- we cannot resolve the `read_until` call above, which comes from `impl<R: AsyncBufRead + ?Sized> AsyncBufReadExt for R {}` in `async_buf_read_ext.rs`
|
||||
sink(&buffer); // $ hasTaintFlow
|
||||
sink(buffer[0]); // $ hasTaintFlow
|
||||
}
|
||||
|
||||
{
|
||||
let mut reader_split = tokio::io::BufReader::new(tokio::io::stdin()).split(b','); // $ Alert[rust/summary/taint-sources]
|
||||
sink(reader_split.next_segment().await?.unwrap()); // $ MISSING: hasTaintFlow -- we cannot resolve the `split` call above, which comes from `impl<R: AsyncBufRead + ?Sized> AsyncBufReadExt for R {}` in `async_buf_read_ext.rs`
|
||||
sink(reader_split.next_segment().await?.unwrap()); // $ hasTaintFlow
|
||||
while let Some(chunk) = reader_split.next_segment().await? {
|
||||
sink(chunk); // $ MISSING: hasTaintFlow
|
||||
sink(chunk); // $ hasTaintFlow
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let reader = tokio::io::BufReader::new(tokio::io::stdin()); // $ Alert[rust/summary/taint-sources]
|
||||
let mut lines = reader.lines();
|
||||
sink(lines.next_line().await?.unwrap()); // $ MISSING: hasTaintFlow -- we cannot resolve the `lines` call above, which comes from `impl<R: AsyncBufRead + ?Sized> AsyncBufReadExt for R {}` in `async_buf_read_ext.rs`
|
||||
sink(lines.next_line().await?.unwrap()); // $ hasTaintFlow
|
||||
while let Some(line) = lines.next_line().await? {
|
||||
sink(line); // $ MISSING: hasTaintFlow
|
||||
sink(line); // $ hasTaintFlow
|
||||
}
|
||||
}
|
||||
|
||||
@@ -583,25 +583,25 @@ async fn test_tokio_file() -> std::io::Result<()> {
|
||||
{
|
||||
let mut buffer = [0u8; 100];
|
||||
let _bytes = file.read(&mut buffer).await?;
|
||||
sink(&buffer); // $ MISSING: hasTaintFlow="file.txt" -- we cannot resolve the `read` call above, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
|
||||
sink(&buffer); // $ hasTaintFlow="file.txt"
|
||||
}
|
||||
|
||||
{
|
||||
let mut buffer = Vec::<u8>::new();
|
||||
let _bytes = file.read_to_end(&mut buffer).await?;
|
||||
sink(&buffer); // $ MISSING: hasTaintFlow="file.txt" -- we cannot resolve the `read_to_end` call above, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
|
||||
sink(&buffer); // $ hasTaintFlow="file.txt"
|
||||
}
|
||||
|
||||
{
|
||||
let mut buffer = String::new();
|
||||
let _bytes = file.read_to_string(&mut buffer).await?;
|
||||
sink(&buffer); // $ MISSING: hasTaintFlow="file.txt" -- we cannot resolve the `read_to_string` call above, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
|
||||
sink(&buffer); // $ hasTaintFlow="file.txt"
|
||||
}
|
||||
|
||||
{
|
||||
let mut buffer = [0; 100];
|
||||
file.read_exact(&mut buffer).await?;
|
||||
sink(&buffer); // $ MISSING: hasTaintFlow="file.txt" -- we cannot resolve the `read_exact` call above, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
|
||||
sink(&buffer); // $ hasTaintFlow="file.txt"
|
||||
}
|
||||
|
||||
{
|
||||
@@ -609,16 +609,16 @@ async fn test_tokio_file() -> std::io::Result<()> {
|
||||
let v2 = file.read_i16().await?;
|
||||
let v3 = file.read_f32().await?;
|
||||
let v4 = file.read_i64_le().await?;
|
||||
sink(v1); // $ MISSING: hasTaintFlow="file.txt" -- we cannot resolve the `read_u8` call above, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
|
||||
sink(v2); // $ MISSING: hasTaintFlow="file.txt" -- we cannot resolve the `read_i16` call above, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
|
||||
sink(v3); // $ MISSING: hasTaintFlow="file.txt" -- we cannot resolve the `read_f32` call above, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
|
||||
sink(v4); // $ MISSING: hasTaintFlow="file.txt" -- we cannot resolve the `read_i64_le` call above, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
|
||||
sink(v1); // $ hasTaintFlow="file.txt"
|
||||
sink(v2); // $ hasTaintFlow="file.txt"
|
||||
sink(v3); // $ hasTaintFlow="file.txt"
|
||||
sink(v4); // $ hasTaintFlow="file.txt"
|
||||
}
|
||||
|
||||
{
|
||||
let mut buffer = bytes::BytesMut::new();
|
||||
file.read_buf(&mut buffer).await?;
|
||||
sink(&buffer); // $ MISSING: hasTaintFlow="file.txt" -- we cannot resolve the `read_buf` call above, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
|
||||
sink(&buffer); // $ hasTaintFlow="file.txt"
|
||||
}
|
||||
|
||||
// --- OpenOptions ---
|
||||
@@ -627,7 +627,7 @@ async fn test_tokio_file() -> std::io::Result<()> {
|
||||
let mut f1 = tokio::fs::OpenOptions::new().open("f1.txt").await?; // $ Alert[rust/summary/taint-sources]
|
||||
let mut buffer = [0u8; 1024];
|
||||
let _bytes = f1.read(&mut buffer).await?;
|
||||
sink(&buffer); // $ MISSING: hasTaintFlow="f1.txt"
|
||||
sink(&buffer); // $ hasTaintFlow="f1.txt"
|
||||
}
|
||||
|
||||
// --- misc operations ---
|
||||
@@ -775,8 +775,8 @@ async fn test_tokio_tcpstream(case: i64) -> std::io::Result<()> {
|
||||
sink(buffer1[0]); // $ hasTaintFlow=address
|
||||
|
||||
println!("buffer2 = {:?}", buffer2);
|
||||
sink(&buffer2); // $ MISSING: hasTaintFlow=address -- we cannot resolve the `read` call above, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
|
||||
sink(buffer2[0]); // $ MISSING: hasTaintFlow=address -- we cannot resolve the `read` call above, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
|
||||
sink(&buffer2); // $ hasTaintFlow=address
|
||||
sink(buffer2[0]); // $ hasTaintFlow=address
|
||||
|
||||
let buffer_string = String::from_utf8_lossy(&buffer2[..n2]);
|
||||
println!("string = {}", buffer_string);
|
||||
|
||||
@@ -43,12 +43,12 @@ async fn test_futures_rustls_futures_io() -> io::Result<()> {
|
||||
// using the `AsyncReadExt::read` extension method (higher-level)
|
||||
let mut buffer1 = [0u8; 64];
|
||||
let bytes_read1 = futures::io::AsyncReadExt::read(&mut reader, &mut buffer1).await?; // we cannot resolve the `read` call, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
|
||||
sink(&buffer1[..bytes_read1]); // $ MISSING: hasTaintFlow=url
|
||||
sink(&buffer1[..bytes_read1]); // $ hasTaintFlow=url
|
||||
|
||||
let mut buffer2 = [0u8; 64];
|
||||
let bytes_read2 = reader.read(&mut buffer2).await?; // we cannot resolve the `read` call, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
|
||||
|
||||
sink(&buffer2[..bytes_read2]); // $ MISSING: hasTaintFlow=url
|
||||
sink(&buffer2[..bytes_read2]); // $ hasTaintFlow=url
|
||||
}
|
||||
|
||||
let mut reader2 = futures::io::BufReader::new(reader);
|
||||
@@ -81,7 +81,7 @@ async fn test_futures_rustls_futures_io() -> io::Result<()> {
|
||||
{
|
||||
// using the `AsyncBufReadExt::fill_buf` extension method (higher-level)
|
||||
let buffer = reader2.fill_buf().await?; // we cannot resolve the `fill_buf` call, which comes from `impl<R: AsyncBufRead + ?Sized> AsyncBufReadExt for R {}` in `async_buf_read_ext.rs`
|
||||
sink(buffer); // $ MISSING: hasTaintFlow=url
|
||||
sink(buffer); // $ hasTaintFlow=url
|
||||
}
|
||||
|
||||
{
|
||||
@@ -101,11 +101,11 @@ async fn test_futures_rustls_futures_io() -> io::Result<()> {
|
||||
// using the `AsyncReadExt::read` extension method (higher-level)
|
||||
let mut buffer1 = [0u8; 64];
|
||||
let bytes_read1 = futures::io::AsyncReadExt::read(&mut reader2, &mut buffer1).await?; // we cannot resolve the `read` call, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
|
||||
sink(&buffer1[..bytes_read1]); // $ MISSING: hasTaintFlow=url
|
||||
sink(&buffer1[..bytes_read1]); // $ hasTaintFlow=url
|
||||
|
||||
let mut buffer2 = [0u8; 64];
|
||||
let bytes_read2 = reader2.read(&mut buffer2).await?; // we cannot resolve the `read` call, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
|
||||
sink(&buffer2[..bytes_read2]); // $ MISSING: hasTaintFlow=url
|
||||
sink(&buffer2[..bytes_read2]); // $ hasTaintFlow=url
|
||||
}
|
||||
|
||||
{
|
||||
@@ -123,28 +123,28 @@ async fn test_futures_rustls_futures_io() -> io::Result<()> {
|
||||
{
|
||||
// using the `AsyncBufReadExt::fill_buf` extension method (higher-level)
|
||||
let buffer = reader2.fill_buf().await?; // we cannot resolve the `fill_buf` call, which comes from `impl<R: AsyncBufRead + ?Sized> AsyncBufReadExt for R {}` in `async_buf_read_ext.rs`
|
||||
sink(buffer); // $ MISSING: hasTaintFlow=url
|
||||
sink(buffer); // $ hasTaintFlow=url
|
||||
}
|
||||
|
||||
{
|
||||
// using the `AsyncBufReadExt::read_until` extension method
|
||||
let mut line = Vec::new();
|
||||
let _bytes_read = reader2.read_until(b'\n', &mut line).await?; // we cannot resolve the `read_until` call, which comes from `impl<R: AsyncBufRead + ?Sized> AsyncBufReadExt for R {}` in `async_buf_read_ext.rs`
|
||||
sink(&line); // $ MISSING: hasTaintFlow=url
|
||||
sink(&line); // $ hasTaintFlow=url
|
||||
}
|
||||
|
||||
{
|
||||
// using the `AsyncBufReadExt::read_line` extension method
|
||||
let mut line = String::new();
|
||||
let _bytes_read = reader2.read_line(&mut line).await?; // we cannot resolve the `read_line` call, which comes from `impl<R: AsyncBufRead + ?Sized> AsyncBufReadExt for R {}` in `async_buf_read_ext.rs`
|
||||
sink(&line); // $ MISSING: hasTaintFlow=url
|
||||
sink(&line); // $ hasTaintFlow=url
|
||||
}
|
||||
|
||||
{
|
||||
// using the `AsyncBufReadExt::read_to_end` extension method
|
||||
let mut buffer = Vec::with_capacity(1024);
|
||||
let _bytes_read = reader2.read_to_end(&mut buffer).await?; // we cannot resolve the `read` call, which comes from `impl<R: AsyncRead + ?Sized> AsyncReadExt for R {}` in `async_read_ext.rs`
|
||||
sink(&buffer); // $ MISSING: hasTaintFlow=url
|
||||
sink(&buffer); // $ hasTaintFlow=url
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
models
|
||||
| 1 | Summary: <alloc::string::String as core::convert::From>::from; Argument[0].Reference; ReturnValue; value |
|
||||
| 2 | Summary: <alloc::string::String as core::convert::From>::from; Argument[0]; ReturnValue; value |
|
||||
| 1 | Summary: <_ as core::convert::From>::from; Argument[0]; ReturnValue; value |
|
||||
| 2 | Summary: <alloc::string::String as core::convert::From>::from; Argument[0].Reference; ReturnValue; value |
|
||||
| 3 | Summary: <alloc::string::String as core::ops::arith::Add>::add; Argument[self]; ReturnValue; value |
|
||||
| 4 | Summary: <alloc::string::String>::as_str; Argument[self]; ReturnValue; value |
|
||||
| 5 | Summary: <core::str>::as_str; Argument[self]; ReturnValue; value |
|
||||
|
||||
@@ -30,7 +30,7 @@ fn int_div(
|
||||
) -> Result<i32> // $ item=my::Result $ item=i32
|
||||
{
|
||||
if y == 0 {
|
||||
return Err("Div by zero".to_string()); // $ item=Err
|
||||
return Err("Div by zero".to_string()); // $ item=Err item=to_string
|
||||
}
|
||||
Ok(x / y) // $ item=Ok
|
||||
}
|
||||
|
||||
161
rust/ql/test/library-tests/type-inference/blanket_impl.rs
Normal file
161
rust/ql/test/library-tests/type-inference/blanket_impl.rs
Normal file
@@ -0,0 +1,161 @@
|
||||
// Tests for method resolution targeting blanket trait implementations
|
||||
|
||||
mod basic_blanket_impl {
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
struct S1;
|
||||
|
||||
trait Clone1 {
|
||||
fn clone1(&self) -> Self;
|
||||
}
|
||||
|
||||
trait Duplicatable {
|
||||
fn duplicate(&self) -> Self
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
|
||||
impl Clone1 for S1 {
|
||||
// S1::clone1
|
||||
fn clone1(&self) -> Self {
|
||||
*self // $ target=deref
|
||||
}
|
||||
}
|
||||
|
||||
// Blanket implementation for all types that implement Display and Clone
|
||||
impl<T: Clone1> Duplicatable for T {
|
||||
// Clone1duplicate
|
||||
fn duplicate(&self) -> Self {
|
||||
self.clone1() // $ target=clone1
|
||||
}
|
||||
}
|
||||
|
||||
pub fn test_basic_blanket() {
|
||||
let x = S1.clone1(); // $ target=S1::clone1
|
||||
println!("{x:?}");
|
||||
let y = S1.duplicate(); // $ target=Clone1duplicate
|
||||
println!("{y:?}");
|
||||
}
|
||||
}
|
||||
|
||||
mod extension_trait_blanket_impl {
|
||||
// This tests:
|
||||
// 1. A trait that is implemented for a type parameter
|
||||
// 2. An extension trait
|
||||
// 3. A blanket implementation of the extension trait for a type parameter
|
||||
|
||||
trait Flag {
|
||||
fn read_flag(&self) -> bool;
|
||||
}
|
||||
|
||||
trait TryFlag {
|
||||
fn try_read_flag(&self) -> Option<bool>;
|
||||
}
|
||||
|
||||
impl<Fl> TryFlag for Fl
|
||||
where
|
||||
Fl: Flag,
|
||||
{
|
||||
fn try_read_flag(&self) -> Option<bool> {
|
||||
Some(self.read_flag()) // $ target=read_flag
|
||||
}
|
||||
}
|
||||
|
||||
trait TryFlagExt: TryFlag {
|
||||
// TryFlagExt::try_read_flag_twice
|
||||
fn try_read_flag_twice(&self) -> Option<bool> {
|
||||
self.try_read_flag() // $ target=try_read_flag
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TryFlag> TryFlagExt for T {}
|
||||
|
||||
trait AnotherTryFlag {
|
||||
// AnotherTryFlag::try_read_flag_twice
|
||||
fn try_read_flag_twice(&self) -> Option<bool>;
|
||||
}
|
||||
|
||||
struct MyTryFlag {
|
||||
flag: bool,
|
||||
}
|
||||
|
||||
impl TryFlag for MyTryFlag {
|
||||
// MyTryFlag::try_read_flag
|
||||
fn try_read_flag(&self) -> Option<bool> {
|
||||
Some(self.flag) // $ fieldof=MyTryFlag
|
||||
}
|
||||
}
|
||||
|
||||
struct MyFlag {
|
||||
flag: bool,
|
||||
}
|
||||
|
||||
impl Flag for MyFlag {
|
||||
// MyFlag::read_flag
|
||||
fn read_flag(&self) -> bool {
|
||||
self.flag // $ fieldof=MyFlag
|
||||
}
|
||||
}
|
||||
|
||||
struct MyOtherFlag {
|
||||
flag: bool,
|
||||
}
|
||||
|
||||
impl AnotherTryFlag for MyOtherFlag {
|
||||
// MyOtherFlag::try_read_flag_twice
|
||||
fn try_read_flag_twice(&self) -> Option<bool> {
|
||||
Some(self.flag) // $ fieldof=MyOtherFlag
|
||||
}
|
||||
}
|
||||
|
||||
fn test() {
|
||||
let my_try_flag = MyTryFlag { flag: true };
|
||||
let result = my_try_flag.try_read_flag_twice(); // $ target=TryFlagExt::try_read_flag_twice
|
||||
|
||||
let my_flag = MyFlag { flag: true };
|
||||
// Here `TryFlagExt::try_read_flag_twice` is a target since there is a
|
||||
// blanket implementaton of `TryFlag` for `Flag`.
|
||||
let result = my_flag.try_read_flag_twice(); // $ MISSING: target=TryFlagExt::try_read_flag_twice
|
||||
|
||||
let my_other_flag = MyOtherFlag { flag: true };
|
||||
// Here `TryFlagExt::try_read_flag_twice` is _not_ a target since
|
||||
// `MyOtherFlag` does not implement `TryFlag`.
|
||||
let result = my_other_flag.try_read_flag_twice(); // $ target=MyOtherFlag::try_read_flag_twice
|
||||
}
|
||||
}
|
||||
|
||||
pub mod sql_exec {
|
||||
// a highly simplified model of `MySqlConnection.execute` in SQLx
|
||||
|
||||
trait Connection {}
|
||||
|
||||
trait Executor {
|
||||
fn execute1(&self);
|
||||
fn execute2<E>(&self, query: E);
|
||||
}
|
||||
|
||||
impl<T: Connection> Executor for T {
|
||||
fn execute1(&self) {
|
||||
println!("Executor::execute1");
|
||||
}
|
||||
|
||||
fn execute2<E>(&self, _query: E) {
|
||||
println!("Executor::execute2");
|
||||
}
|
||||
}
|
||||
|
||||
struct MySqlConnection {}
|
||||
|
||||
impl Connection for MySqlConnection {}
|
||||
|
||||
pub fn f() {
|
||||
let c = MySqlConnection {}; // $ certainType=c:MySqlConnection
|
||||
|
||||
c.execute1(); // $ target=execute1
|
||||
MySqlConnection::execute1(&c); // $ MISSING: target=execute1
|
||||
|
||||
c.execute2("SELECT * FROM users"); // $ target=execute2
|
||||
c.execute2::<&str>("SELECT * FROM users"); // $ target=execute2
|
||||
MySqlConnection::execute2(&c, "SELECT * FROM users"); // $ MISSING: target=execute2
|
||||
MySqlConnection::execute2::<&str>(&c, "SELECT * FROM users"); // $ MISSING: target=execute2
|
||||
}
|
||||
}
|
||||
@@ -101,7 +101,7 @@ fn test_assoc_type(obj: &dyn AssocTrait<i64, AP = bool>) {
|
||||
pub fn test() {
|
||||
test_basic_dyn_trait(&MyStruct { value: 42 }); // $ target=test_basic_dyn_trait
|
||||
test_generic_dyn_trait(&GenStruct {
|
||||
value: "".to_string(),
|
||||
value: "".to_string(), // $ target=to_string
|
||||
}); // $ target=test_generic_dyn_trait
|
||||
test_poly_dyn_trait(); // $ target=test_poly_dyn_trait
|
||||
test_assoc_type(&GenStruct { value: 100 }); // $ target=test_assoc_type
|
||||
|
||||
@@ -365,7 +365,7 @@ mod method_non_parametric_trait_impl {
|
||||
|
||||
fn type_bound_type_parameter_impl<TP: MyTrait<S1>>(thing: TP) -> S1 {
|
||||
// The trait bound on `TP` makes the implementation of `ConvertTo` valid
|
||||
thing.convert_to() // $ MISSING: target=T::convert_to
|
||||
thing.convert_to() // $ target=T::convert_to
|
||||
}
|
||||
|
||||
pub fn f() {
|
||||
@@ -437,7 +437,7 @@ mod method_non_parametric_trait_impl {
|
||||
let x = get_snd_fst(c); // $ type=x:S1 target=get_snd_fst
|
||||
|
||||
let thing = MyThing { a: S1 };
|
||||
let i = thing.convert_to(); // $ MISSING: type=i:S1 target=T::convert_to
|
||||
let i = thing.convert_to(); // $ type=i:S1 target=T::convert_to
|
||||
let j = convert_to(thing); // $ type=j:S1 target=convert_to
|
||||
}
|
||||
}
|
||||
@@ -1376,7 +1376,7 @@ mod method_call_type_conversion {
|
||||
let t = x7.m1(); // $ target=m1 type=t:& type=t:&T.S2
|
||||
println!("{:?}", x7);
|
||||
|
||||
let x9: String = "Hello".to_string(); // $ certainType=x9:String
|
||||
let x9: String = "Hello".to_string(); // $ certainType=x9:String target=to_string
|
||||
|
||||
// Implicit `String` -> `str` conversion happens via the `Deref` trait:
|
||||
// https://doc.rust-lang.org/std/string/struct.String.html#deref.
|
||||
@@ -2569,43 +2569,6 @@ pub mod pattern_matching_experimental {
|
||||
}
|
||||
}
|
||||
|
||||
pub mod exec {
|
||||
// a highly simplified model of `MySqlConnection.execute` in SQLx
|
||||
|
||||
trait Connection {}
|
||||
|
||||
trait Executor {
|
||||
fn execute1(&self);
|
||||
fn execute2<E>(&self, query: E);
|
||||
}
|
||||
|
||||
impl<T: Connection> Executor for T {
|
||||
fn execute1(&self) {
|
||||
println!("Executor::execute1");
|
||||
}
|
||||
|
||||
fn execute2<E>(&self, _query: E) {
|
||||
println!("Executor::execute2");
|
||||
}
|
||||
}
|
||||
|
||||
struct MySqlConnection {}
|
||||
|
||||
impl Connection for MySqlConnection {}
|
||||
|
||||
pub fn f() {
|
||||
let c = MySqlConnection {}; // $ certainType=c:MySqlConnection
|
||||
|
||||
c.execute1(); // $ MISSING: target=execute1
|
||||
MySqlConnection::execute1(&c); // $ MISSING: target=execute1
|
||||
|
||||
c.execute2("SELECT * FROM users"); // $ MISSING: target=execute2
|
||||
c.execute2::<&str>("SELECT * FROM users"); // $ MISSING: target=execute2
|
||||
MySqlConnection::execute2(&c, "SELECT * FROM users"); // $ MISSING: target=execute2
|
||||
MySqlConnection::execute2::<&str>(&c, "SELECT * FROM users"); // $ MISSING: target=execute2
|
||||
}
|
||||
}
|
||||
|
||||
pub mod path_buf {
|
||||
// a highly simplified model of `PathBuf::canonicalize`
|
||||
|
||||
@@ -2655,6 +2618,7 @@ pub mod path_buf {
|
||||
mod closure;
|
||||
mod dereference;
|
||||
mod dyn_type;
|
||||
mod blanket_impl;
|
||||
|
||||
fn main() {
|
||||
field_access::f(); // $ target=f
|
||||
@@ -2683,7 +2647,6 @@ fn main() {
|
||||
macros::f(); // $ target=f
|
||||
method_determined_by_argument_type::f(); // $ target=f
|
||||
tuples::f(); // $ target=f
|
||||
exec::f(); // $ target=f
|
||||
path_buf::f(); // $ target=f
|
||||
dereference::test(); // $ target=test
|
||||
pattern_matching::test_all_patterns(); // $ target=test_all_patterns
|
||||
|
||||
@@ -1,4 +1,143 @@
|
||||
inferType
|
||||
| blanket_impl.rs:8:19:8:23 | SelfParam | | file://:0:0:0:0 | & |
|
||||
| blanket_impl.rs:8:19:8:23 | SelfParam | &T | blanket_impl.rs:7:5:9:5 | Self [trait Clone1] |
|
||||
| blanket_impl.rs:12:22:12:26 | SelfParam | | file://:0:0:0:0 | & |
|
||||
| blanket_impl.rs:12:22:12:26 | SelfParam | &T | blanket_impl.rs:11:5:15:5 | Self [trait Duplicatable] |
|
||||
| blanket_impl.rs:19:19:19:23 | SelfParam | | file://:0:0:0:0 | & |
|
||||
| blanket_impl.rs:19:19:19:23 | SelfParam | &T | blanket_impl.rs:4:5:5:14 | S1 |
|
||||
| blanket_impl.rs:19:34:21:9 | { ... } | | blanket_impl.rs:4:5:5:14 | S1 |
|
||||
| blanket_impl.rs:20:13:20:17 | * ... | | blanket_impl.rs:4:5:5:14 | S1 |
|
||||
| blanket_impl.rs:20:14:20:17 | self | | file://:0:0:0:0 | & |
|
||||
| blanket_impl.rs:20:14:20:17 | self | &T | blanket_impl.rs:4:5:5:14 | S1 |
|
||||
| blanket_impl.rs:27:22:27:26 | SelfParam | | file://:0:0:0:0 | & |
|
||||
| blanket_impl.rs:27:22:27:26 | SelfParam | &T | blanket_impl.rs:25:10:25:18 | T |
|
||||
| blanket_impl.rs:27:37:29:9 | { ... } | | blanket_impl.rs:25:10:25:18 | T |
|
||||
| blanket_impl.rs:28:13:28:16 | self | | file://:0:0:0:0 | & |
|
||||
| blanket_impl.rs:28:13:28:16 | self | &T | blanket_impl.rs:25:10:25:18 | T |
|
||||
| blanket_impl.rs:28:13:28:25 | self.clone1() | | blanket_impl.rs:25:10:25:18 | T |
|
||||
| blanket_impl.rs:33:13:33:13 | x | | blanket_impl.rs:4:5:5:14 | S1 |
|
||||
| blanket_impl.rs:33:17:33:18 | S1 | | blanket_impl.rs:4:5:5:14 | S1 |
|
||||
| blanket_impl.rs:33:17:33:27 | S1.clone1() | | blanket_impl.rs:4:5:5:14 | S1 |
|
||||
| blanket_impl.rs:34:18:34:24 | "{x:?}\\n" | | file://:0:0:0:0 | & |
|
||||
| blanket_impl.rs:34:18:34:24 | "{x:?}\\n" | &T | {EXTERNAL LOCATION} | str |
|
||||
| blanket_impl.rs:34:18:34:24 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments |
|
||||
| blanket_impl.rs:34:18:34:24 | MacroExpr | | {EXTERNAL LOCATION} | Arguments |
|
||||
| blanket_impl.rs:34:20:34:20 | x | | blanket_impl.rs:4:5:5:14 | S1 |
|
||||
| blanket_impl.rs:35:13:35:13 | y | | blanket_impl.rs:4:5:5:14 | S1 |
|
||||
| blanket_impl.rs:35:17:35:18 | S1 | | blanket_impl.rs:4:5:5:14 | S1 |
|
||||
| blanket_impl.rs:35:17:35:30 | S1.duplicate() | | blanket_impl.rs:4:5:5:14 | S1 |
|
||||
| blanket_impl.rs:36:18:36:24 | "{y:?}\\n" | | file://:0:0:0:0 | & |
|
||||
| blanket_impl.rs:36:18:36:24 | "{y:?}\\n" | &T | {EXTERNAL LOCATION} | str |
|
||||
| blanket_impl.rs:36:18:36:24 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments |
|
||||
| blanket_impl.rs:36:18:36:24 | MacroExpr | | {EXTERNAL LOCATION} | Arguments |
|
||||
| blanket_impl.rs:36:20:36:20 | y | | blanket_impl.rs:4:5:5:14 | S1 |
|
||||
| blanket_impl.rs:47:22:47:26 | SelfParam | | file://:0:0:0:0 | & |
|
||||
| blanket_impl.rs:47:22:47:26 | SelfParam | &T | blanket_impl.rs:46:5:48:5 | Self [trait Flag] |
|
||||
| blanket_impl.rs:51:26:51:30 | SelfParam | | file://:0:0:0:0 | & |
|
||||
| blanket_impl.rs:51:26:51:30 | SelfParam | &T | blanket_impl.rs:50:5:52:5 | Self [trait TryFlag] |
|
||||
| blanket_impl.rs:58:26:58:30 | SelfParam | | file://:0:0:0:0 | & |
|
||||
| blanket_impl.rs:58:26:58:30 | SelfParam | &T | blanket_impl.rs:54:10:54:11 | Fl |
|
||||
| blanket_impl.rs:58:49:60:9 | { ... } | | {EXTERNAL LOCATION} | Option |
|
||||
| blanket_impl.rs:58:49:60:9 | { ... } | T | {EXTERNAL LOCATION} | bool |
|
||||
| blanket_impl.rs:59:13:59:34 | Some(...) | | {EXTERNAL LOCATION} | Option |
|
||||
| blanket_impl.rs:59:13:59:34 | Some(...) | T | {EXTERNAL LOCATION} | bool |
|
||||
| blanket_impl.rs:59:18:59:21 | self | | file://:0:0:0:0 | & |
|
||||
| blanket_impl.rs:59:18:59:21 | self | &T | blanket_impl.rs:54:10:54:11 | Fl |
|
||||
| blanket_impl.rs:59:18:59:33 | self.read_flag() | | {EXTERNAL LOCATION} | bool |
|
||||
| blanket_impl.rs:65:32:65:36 | SelfParam | | file://:0:0:0:0 | & |
|
||||
| blanket_impl.rs:65:32:65:36 | SelfParam | &T | blanket_impl.rs:63:5:68:5 | Self [trait TryFlagExt] |
|
||||
| blanket_impl.rs:65:55:67:9 | { ... } | | {EXTERNAL LOCATION} | Option |
|
||||
| blanket_impl.rs:65:55:67:9 | { ... } | T | {EXTERNAL LOCATION} | bool |
|
||||
| blanket_impl.rs:66:13:66:16 | self | | file://:0:0:0:0 | & |
|
||||
| blanket_impl.rs:66:13:66:16 | self | &T | blanket_impl.rs:63:5:68:5 | Self [trait TryFlagExt] |
|
||||
| blanket_impl.rs:66:13:66:32 | self.try_read_flag() | | {EXTERNAL LOCATION} | Option |
|
||||
| blanket_impl.rs:66:13:66:32 | self.try_read_flag() | T | {EXTERNAL LOCATION} | bool |
|
||||
| blanket_impl.rs:74:32:74:36 | SelfParam | | file://:0:0:0:0 | & |
|
||||
| blanket_impl.rs:74:32:74:36 | SelfParam | &T | blanket_impl.rs:72:5:75:5 | Self [trait AnotherTryFlag] |
|
||||
| blanket_impl.rs:83:26:83:30 | SelfParam | | file://:0:0:0:0 | & |
|
||||
| blanket_impl.rs:83:26:83:30 | SelfParam | &T | blanket_impl.rs:77:5:79:5 | MyTryFlag |
|
||||
| blanket_impl.rs:83:49:85:9 | { ... } | | {EXTERNAL LOCATION} | Option |
|
||||
| blanket_impl.rs:83:49:85:9 | { ... } | T | {EXTERNAL LOCATION} | bool |
|
||||
| blanket_impl.rs:84:13:84:27 | Some(...) | | {EXTERNAL LOCATION} | Option |
|
||||
| blanket_impl.rs:84:13:84:27 | Some(...) | T | {EXTERNAL LOCATION} | bool |
|
||||
| blanket_impl.rs:84:18:84:21 | self | | file://:0:0:0:0 | & |
|
||||
| blanket_impl.rs:84:18:84:21 | self | &T | blanket_impl.rs:77:5:79:5 | MyTryFlag |
|
||||
| blanket_impl.rs:84:18:84:26 | self.flag | | {EXTERNAL LOCATION} | bool |
|
||||
| blanket_impl.rs:94:22:94:26 | SelfParam | | file://:0:0:0:0 | & |
|
||||
| blanket_impl.rs:94:22:94:26 | SelfParam | &T | blanket_impl.rs:88:5:90:5 | MyFlag |
|
||||
| blanket_impl.rs:94:37:96:9 | { ... } | | {EXTERNAL LOCATION} | bool |
|
||||
| blanket_impl.rs:95:13:95:16 | self | | file://:0:0:0:0 | & |
|
||||
| blanket_impl.rs:95:13:95:16 | self | &T | blanket_impl.rs:88:5:90:5 | MyFlag |
|
||||
| blanket_impl.rs:95:13:95:21 | self.flag | | {EXTERNAL LOCATION} | bool |
|
||||
| blanket_impl.rs:105:32:105:36 | SelfParam | | file://:0:0:0:0 | & |
|
||||
| blanket_impl.rs:105:32:105:36 | SelfParam | &T | blanket_impl.rs:99:5:101:5 | MyOtherFlag |
|
||||
| blanket_impl.rs:105:55:107:9 | { ... } | | {EXTERNAL LOCATION} | Option |
|
||||
| blanket_impl.rs:105:55:107:9 | { ... } | T | {EXTERNAL LOCATION} | bool |
|
||||
| blanket_impl.rs:106:13:106:27 | Some(...) | | {EXTERNAL LOCATION} | Option |
|
||||
| blanket_impl.rs:106:13:106:27 | Some(...) | T | {EXTERNAL LOCATION} | bool |
|
||||
| blanket_impl.rs:106:18:106:21 | self | | file://:0:0:0:0 | & |
|
||||
| blanket_impl.rs:106:18:106:21 | self | &T | blanket_impl.rs:99:5:101:5 | MyOtherFlag |
|
||||
| blanket_impl.rs:106:18:106:26 | self.flag | | {EXTERNAL LOCATION} | bool |
|
||||
| blanket_impl.rs:111:13:111:23 | my_try_flag | | blanket_impl.rs:77:5:79:5 | MyTryFlag |
|
||||
| blanket_impl.rs:111:27:111:50 | MyTryFlag {...} | | blanket_impl.rs:77:5:79:5 | MyTryFlag |
|
||||
| blanket_impl.rs:111:45:111:48 | true | | {EXTERNAL LOCATION} | bool |
|
||||
| blanket_impl.rs:112:13:112:18 | result | | {EXTERNAL LOCATION} | Option |
|
||||
| blanket_impl.rs:112:13:112:18 | result | T | {EXTERNAL LOCATION} | bool |
|
||||
| blanket_impl.rs:112:22:112:32 | my_try_flag | | blanket_impl.rs:77:5:79:5 | MyTryFlag |
|
||||
| blanket_impl.rs:112:22:112:54 | my_try_flag.try_read_flag_twice() | | {EXTERNAL LOCATION} | Option |
|
||||
| blanket_impl.rs:112:22:112:54 | my_try_flag.try_read_flag_twice() | T | {EXTERNAL LOCATION} | bool |
|
||||
| blanket_impl.rs:114:13:114:19 | my_flag | | blanket_impl.rs:88:5:90:5 | MyFlag |
|
||||
| blanket_impl.rs:114:23:114:43 | MyFlag {...} | | blanket_impl.rs:88:5:90:5 | MyFlag |
|
||||
| blanket_impl.rs:114:38:114:41 | true | | {EXTERNAL LOCATION} | bool |
|
||||
| blanket_impl.rs:117:22:117:28 | my_flag | | blanket_impl.rs:88:5:90:5 | MyFlag |
|
||||
| blanket_impl.rs:119:13:119:25 | my_other_flag | | blanket_impl.rs:99:5:101:5 | MyOtherFlag |
|
||||
| blanket_impl.rs:119:29:119:54 | MyOtherFlag {...} | | blanket_impl.rs:99:5:101:5 | MyOtherFlag |
|
||||
| blanket_impl.rs:119:49:119:52 | true | | {EXTERNAL LOCATION} | bool |
|
||||
| blanket_impl.rs:122:13:122:18 | result | | {EXTERNAL LOCATION} | Option |
|
||||
| blanket_impl.rs:122:13:122:18 | result | T | {EXTERNAL LOCATION} | bool |
|
||||
| blanket_impl.rs:122:22:122:34 | my_other_flag | | blanket_impl.rs:99:5:101:5 | MyOtherFlag |
|
||||
| blanket_impl.rs:122:22:122:56 | my_other_flag.try_read_flag_twice() | | {EXTERNAL LOCATION} | Option |
|
||||
| blanket_impl.rs:122:22:122:56 | my_other_flag.try_read_flag_twice() | T | {EXTERNAL LOCATION} | bool |
|
||||
| blanket_impl.rs:132:21:132:25 | SelfParam | | file://:0:0:0:0 | & |
|
||||
| blanket_impl.rs:132:21:132:25 | SelfParam | &T | blanket_impl.rs:131:5:134:5 | Self [trait Executor] |
|
||||
| blanket_impl.rs:133:24:133:28 | SelfParam | | file://:0:0:0:0 | & |
|
||||
| blanket_impl.rs:133:24:133:28 | SelfParam | &T | blanket_impl.rs:131:5:134:5 | Self [trait Executor] |
|
||||
| blanket_impl.rs:133:31:133:35 | query | | blanket_impl.rs:133:21:133:21 | E |
|
||||
| blanket_impl.rs:137:21:137:25 | SelfParam | | file://:0:0:0:0 | & |
|
||||
| blanket_impl.rs:137:21:137:25 | SelfParam | &T | blanket_impl.rs:136:10:136:22 | T |
|
||||
| blanket_impl.rs:138:22:138:41 | "Executor::execute1\\n" | | file://:0:0:0:0 | & |
|
||||
| blanket_impl.rs:138:22:138:41 | "Executor::execute1\\n" | &T | {EXTERNAL LOCATION} | str |
|
||||
| blanket_impl.rs:138:22:138:41 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments |
|
||||
| blanket_impl.rs:138:22:138:41 | MacroExpr | | {EXTERNAL LOCATION} | Arguments |
|
||||
| blanket_impl.rs:141:24:141:28 | SelfParam | | file://:0:0:0:0 | & |
|
||||
| blanket_impl.rs:141:24:141:28 | SelfParam | &T | blanket_impl.rs:136:10:136:22 | T |
|
||||
| blanket_impl.rs:141:31:141:36 | _query | | blanket_impl.rs:141:21:141:21 | E |
|
||||
| blanket_impl.rs:142:22:142:41 | "Executor::execute2\\n" | | file://:0:0:0:0 | & |
|
||||
| blanket_impl.rs:142:22:142:41 | "Executor::execute2\\n" | &T | {EXTERNAL LOCATION} | str |
|
||||
| blanket_impl.rs:142:22:142:41 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments |
|
||||
| blanket_impl.rs:142:22:142:41 | MacroExpr | | {EXTERNAL LOCATION} | Arguments |
|
||||
| blanket_impl.rs:151:13:151:13 | c | | blanket_impl.rs:146:5:146:29 | MySqlConnection |
|
||||
| blanket_impl.rs:151:17:151:34 | MySqlConnection {...} | | blanket_impl.rs:146:5:146:29 | MySqlConnection |
|
||||
| blanket_impl.rs:153:9:153:9 | c | | blanket_impl.rs:146:5:146:29 | MySqlConnection |
|
||||
| blanket_impl.rs:154:35:154:36 | &c | | file://:0:0:0:0 | & |
|
||||
| blanket_impl.rs:154:35:154:36 | &c | &T | blanket_impl.rs:146:5:146:29 | MySqlConnection |
|
||||
| blanket_impl.rs:154:36:154:36 | c | | blanket_impl.rs:146:5:146:29 | MySqlConnection |
|
||||
| blanket_impl.rs:156:9:156:9 | c | | blanket_impl.rs:146:5:146:29 | MySqlConnection |
|
||||
| blanket_impl.rs:156:20:156:40 | "SELECT * FROM users" | | file://:0:0:0:0 | & |
|
||||
| blanket_impl.rs:156:20:156:40 | "SELECT * FROM users" | &T | {EXTERNAL LOCATION} | str |
|
||||
| blanket_impl.rs:157:9:157:9 | c | | blanket_impl.rs:146:5:146:29 | MySqlConnection |
|
||||
| blanket_impl.rs:157:28:157:48 | "SELECT * FROM users" | | file://:0:0:0:0 | & |
|
||||
| blanket_impl.rs:157:28:157:48 | "SELECT * FROM users" | &T | {EXTERNAL LOCATION} | str |
|
||||
| blanket_impl.rs:158:35:158:36 | &c | | file://:0:0:0:0 | & |
|
||||
| blanket_impl.rs:158:35:158:36 | &c | &T | blanket_impl.rs:146:5:146:29 | MySqlConnection |
|
||||
| blanket_impl.rs:158:36:158:36 | c | | blanket_impl.rs:146:5:146:29 | MySqlConnection |
|
||||
| blanket_impl.rs:158:39:158:59 | "SELECT * FROM users" | | file://:0:0:0:0 | & |
|
||||
| blanket_impl.rs:158:39:158:59 | "SELECT * FROM users" | &T | {EXTERNAL LOCATION} | str |
|
||||
| blanket_impl.rs:159:43:159:44 | &c | | file://:0:0:0:0 | & |
|
||||
| blanket_impl.rs:159:43:159:44 | &c | &T | blanket_impl.rs:146:5:146:29 | MySqlConnection |
|
||||
| blanket_impl.rs:159:44:159:44 | c | | blanket_impl.rs:146:5:146:29 | MySqlConnection |
|
||||
| blanket_impl.rs:159:47:159:67 | "SELECT * FROM users" | | file://:0:0:0:0 | & |
|
||||
| blanket_impl.rs:159:47:159:67 | "SELECT * FROM users" | &T | {EXTERNAL LOCATION} | str |
|
||||
| closure.rs:6:13:6:22 | my_closure | | {EXTERNAL LOCATION} | dyn FnOnce |
|
||||
| closure.rs:6:13:6:22 | my_closure | dyn(Args) | file://:0:0:0:0 | (T_2) |
|
||||
| closure.rs:6:13:6:22 | my_closure | dyn(Args).0(2) | {EXTERNAL LOCATION} | bool |
|
||||
@@ -624,10 +763,13 @@ inferType
|
||||
| dyn_type.rs:103:28:105:5 | &... | | file://:0:0:0:0 | & |
|
||||
| dyn_type.rs:103:28:105:5 | &... | &T | dyn_type.rs:10:1:13:1 | dyn GenericGet |
|
||||
| dyn_type.rs:103:28:105:5 | &... | &T | dyn_type.rs:33:1:36:1 | GenStruct |
|
||||
| dyn_type.rs:103:28:105:5 | &... | &T.A | {EXTERNAL LOCATION} | String |
|
||||
| dyn_type.rs:103:28:105:5 | &... | &T.dyn(A) | {EXTERNAL LOCATION} | String |
|
||||
| dyn_type.rs:103:29:105:5 | GenStruct {...} | | dyn_type.rs:33:1:36:1 | GenStruct |
|
||||
| dyn_type.rs:103:29:105:5 | GenStruct {...} | A | {EXTERNAL LOCATION} | String |
|
||||
| dyn_type.rs:104:16:104:17 | "" | | file://:0:0:0:0 | & |
|
||||
| dyn_type.rs:104:16:104:17 | "" | &T | {EXTERNAL LOCATION} | str |
|
||||
| dyn_type.rs:104:16:104:29 | "".to_string() | | {EXTERNAL LOCATION} | String |
|
||||
| dyn_type.rs:107:21:107:45 | &... | | file://:0:0:0:0 | & |
|
||||
| dyn_type.rs:107:21:107:45 | &... | &T | dyn_type.rs:15:1:19:1 | dyn AssocTrait |
|
||||
| dyn_type.rs:107:21:107:45 | &... | &T | dyn_type.rs:33:1:36:1 | GenStruct |
|
||||
@@ -1260,8 +1402,10 @@ inferType
|
||||
| main.rs:439:21:439:37 | MyThing {...} | | main.rs:224:5:227:5 | MyThing |
|
||||
| main.rs:439:21:439:37 | MyThing {...} | A | main.rs:235:5:236:14 | S1 |
|
||||
| main.rs:439:34:439:35 | S1 | | main.rs:235:5:236:14 | S1 |
|
||||
| main.rs:440:13:440:13 | i | | main.rs:235:5:236:14 | S1 |
|
||||
| main.rs:440:17:440:21 | thing | | main.rs:224:5:227:5 | MyThing |
|
||||
| main.rs:440:17:440:21 | thing | A | main.rs:235:5:236:14 | S1 |
|
||||
| main.rs:440:17:440:34 | thing.convert_to() | | main.rs:235:5:236:14 | S1 |
|
||||
| main.rs:441:13:441:13 | j | | main.rs:235:5:236:14 | S1 |
|
||||
| main.rs:441:17:441:33 | convert_to(...) | | main.rs:235:5:236:14 | S1 |
|
||||
| main.rs:441:28:441:32 | thing | | main.rs:224:5:227:5 | MyThing |
|
||||
@@ -3187,14 +3331,22 @@ inferType
|
||||
| main.rs:1706:13:1709:13 | Vec2 {...} | | main.rs:1586:5:1591:5 | Vec2 |
|
||||
| main.rs:1707:20:1707:23 | self | | main.rs:1586:5:1591:5 | Vec2 |
|
||||
| main.rs:1707:20:1707:25 | self.x | | {EXTERNAL LOCATION} | i64 |
|
||||
| main.rs:1707:20:1707:33 | ... \| ... | | {EXTERNAL LOCATION} | NonZero |
|
||||
| main.rs:1707:20:1707:33 | ... \| ... | | {EXTERNAL LOCATION} | i64 |
|
||||
| main.rs:1707:20:1707:33 | ... \| ... | T | {EXTERNAL LOCATION} | i64 |
|
||||
| main.rs:1707:29:1707:31 | rhs | | main.rs:1586:5:1591:5 | Vec2 |
|
||||
| main.rs:1707:29:1707:33 | rhs.x | | {EXTERNAL LOCATION} | NonZero |
|
||||
| main.rs:1707:29:1707:33 | rhs.x | | {EXTERNAL LOCATION} | i64 |
|
||||
| main.rs:1707:29:1707:33 | rhs.x | T | {EXTERNAL LOCATION} | i64 |
|
||||
| main.rs:1708:20:1708:23 | self | | main.rs:1586:5:1591:5 | Vec2 |
|
||||
| main.rs:1708:20:1708:25 | self.y | | {EXTERNAL LOCATION} | i64 |
|
||||
| main.rs:1708:20:1708:33 | ... \| ... | | {EXTERNAL LOCATION} | NonZero |
|
||||
| main.rs:1708:20:1708:33 | ... \| ... | | {EXTERNAL LOCATION} | i64 |
|
||||
| main.rs:1708:20:1708:33 | ... \| ... | T | {EXTERNAL LOCATION} | i64 |
|
||||
| main.rs:1708:29:1708:31 | rhs | | main.rs:1586:5:1591:5 | Vec2 |
|
||||
| main.rs:1708:29:1708:33 | rhs.y | | {EXTERNAL LOCATION} | NonZero |
|
||||
| main.rs:1708:29:1708:33 | rhs.y | | {EXTERNAL LOCATION} | i64 |
|
||||
| main.rs:1708:29:1708:33 | rhs.y | T | {EXTERNAL LOCATION} | i64 |
|
||||
| main.rs:1714:25:1714:33 | SelfParam | | file://:0:0:0:0 | & |
|
||||
| main.rs:1714:25:1714:33 | SelfParam | &T | main.rs:1586:5:1591:5 | Vec2 |
|
||||
| main.rs:1714:36:1714:38 | rhs | | main.rs:1586:5:1591:5 | Vec2 |
|
||||
@@ -3532,9 +3684,13 @@ inferType
|
||||
| main.rs:1857:26:1857:30 | 33i64 | | {EXTERNAL LOCATION} | i64 |
|
||||
| main.rs:1857:26:1857:38 | ... & ... | | {EXTERNAL LOCATION} | i64 |
|
||||
| main.rs:1857:34:1857:38 | 34i64 | | {EXTERNAL LOCATION} | i64 |
|
||||
| main.rs:1858:13:1858:21 | i64_bitor | | {EXTERNAL LOCATION} | NonZero |
|
||||
| main.rs:1858:13:1858:21 | i64_bitor | | {EXTERNAL LOCATION} | i64 |
|
||||
| main.rs:1858:13:1858:21 | i64_bitor | T | {EXTERNAL LOCATION} | i64 |
|
||||
| main.rs:1858:25:1858:29 | 35i64 | | {EXTERNAL LOCATION} | i64 |
|
||||
| main.rs:1858:25:1858:37 | ... \| ... | | {EXTERNAL LOCATION} | NonZero |
|
||||
| main.rs:1858:25:1858:37 | ... \| ... | | {EXTERNAL LOCATION} | i64 |
|
||||
| main.rs:1858:25:1858:37 | ... \| ... | T | {EXTERNAL LOCATION} | i64 |
|
||||
| main.rs:1858:33:1858:37 | 36i64 | | {EXTERNAL LOCATION} | i64 |
|
||||
| main.rs:1859:13:1859:22 | i64_bitxor | | {EXTERNAL LOCATION} | i64 |
|
||||
| main.rs:1859:26:1859:30 | 37i64 | | {EXTERNAL LOCATION} | i64 |
|
||||
@@ -4922,89 +5078,49 @@ inferType
|
||||
| main.rs:2566:26:2566:43 | "Nested boxed: {}\\n" | &T | {EXTERNAL LOCATION} | str |
|
||||
| main.rs:2566:26:2566:59 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments |
|
||||
| main.rs:2566:26:2566:59 | MacroExpr | | {EXTERNAL LOCATION} | Arguments |
|
||||
| main.rs:2578:21:2578:25 | SelfParam | | file://:0:0:0:0 | & |
|
||||
| main.rs:2578:21:2578:25 | SelfParam | &T | main.rs:2577:5:2580:5 | Self [trait Executor] |
|
||||
| main.rs:2579:24:2579:28 | SelfParam | | file://:0:0:0:0 | & |
|
||||
| main.rs:2579:24:2579:28 | SelfParam | &T | main.rs:2577:5:2580:5 | Self [trait Executor] |
|
||||
| main.rs:2579:31:2579:35 | query | | main.rs:2579:21:2579:21 | E |
|
||||
| main.rs:2583:21:2583:25 | SelfParam | | file://:0:0:0:0 | & |
|
||||
| main.rs:2583:21:2583:25 | SelfParam | &T | main.rs:2582:10:2582:22 | T |
|
||||
| main.rs:2584:22:2584:41 | "Executor::execute1\\n" | | file://:0:0:0:0 | & |
|
||||
| main.rs:2584:22:2584:41 | "Executor::execute1\\n" | &T | {EXTERNAL LOCATION} | str |
|
||||
| main.rs:2584:22:2584:41 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments |
|
||||
| main.rs:2584:22:2584:41 | MacroExpr | | {EXTERNAL LOCATION} | Arguments |
|
||||
| main.rs:2587:24:2587:28 | SelfParam | | file://:0:0:0:0 | & |
|
||||
| main.rs:2587:24:2587:28 | SelfParam | &T | main.rs:2582:10:2582:22 | T |
|
||||
| main.rs:2587:31:2587:36 | _query | | main.rs:2587:21:2587:21 | E |
|
||||
| main.rs:2588:22:2588:41 | "Executor::execute2\\n" | | file://:0:0:0:0 | & |
|
||||
| main.rs:2588:22:2588:41 | "Executor::execute2\\n" | &T | {EXTERNAL LOCATION} | str |
|
||||
| main.rs:2588:22:2588:41 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments |
|
||||
| main.rs:2588:22:2588:41 | MacroExpr | | {EXTERNAL LOCATION} | Arguments |
|
||||
| main.rs:2597:13:2597:13 | c | | main.rs:2592:5:2592:29 | MySqlConnection |
|
||||
| main.rs:2597:17:2597:34 | MySqlConnection {...} | | main.rs:2592:5:2592:29 | MySqlConnection |
|
||||
| main.rs:2599:9:2599:9 | c | | main.rs:2592:5:2592:29 | MySqlConnection |
|
||||
| main.rs:2600:35:2600:36 | &c | | file://:0:0:0:0 | & |
|
||||
| main.rs:2600:35:2600:36 | &c | &T | main.rs:2592:5:2592:29 | MySqlConnection |
|
||||
| main.rs:2600:36:2600:36 | c | | main.rs:2592:5:2592:29 | MySqlConnection |
|
||||
| main.rs:2602:9:2602:9 | c | | main.rs:2592:5:2592:29 | MySqlConnection |
|
||||
| main.rs:2602:20:2602:40 | "SELECT * FROM users" | | file://:0:0:0:0 | & |
|
||||
| main.rs:2602:20:2602:40 | "SELECT * FROM users" | &T | {EXTERNAL LOCATION} | str |
|
||||
| main.rs:2603:9:2603:9 | c | | main.rs:2592:5:2592:29 | MySqlConnection |
|
||||
| main.rs:2603:28:2603:48 | "SELECT * FROM users" | | file://:0:0:0:0 | & |
|
||||
| main.rs:2603:28:2603:48 | "SELECT * FROM users" | &T | {EXTERNAL LOCATION} | str |
|
||||
| main.rs:2604:35:2604:36 | &c | | file://:0:0:0:0 | & |
|
||||
| main.rs:2604:35:2604:36 | &c | &T | main.rs:2592:5:2592:29 | MySqlConnection |
|
||||
| main.rs:2604:36:2604:36 | c | | main.rs:2592:5:2592:29 | MySqlConnection |
|
||||
| main.rs:2604:39:2604:59 | "SELECT * FROM users" | | file://:0:0:0:0 | & |
|
||||
| main.rs:2604:39:2604:59 | "SELECT * FROM users" | &T | {EXTERNAL LOCATION} | str |
|
||||
| main.rs:2605:43:2605:44 | &c | | file://:0:0:0:0 | & |
|
||||
| main.rs:2605:43:2605:44 | &c | &T | main.rs:2592:5:2592:29 | MySqlConnection |
|
||||
| main.rs:2605:44:2605:44 | c | | main.rs:2592:5:2592:29 | MySqlConnection |
|
||||
| main.rs:2605:47:2605:67 | "SELECT * FROM users" | | file://:0:0:0:0 | & |
|
||||
| main.rs:2605:47:2605:67 | "SELECT * FROM users" | &T | {EXTERNAL LOCATION} | str |
|
||||
| main.rs:2615:36:2617:9 | { ... } | | main.rs:2612:5:2612:22 | Path |
|
||||
| main.rs:2616:13:2616:19 | Path {...} | | main.rs:2612:5:2612:22 | Path |
|
||||
| main.rs:2619:29:2619:33 | SelfParam | | file://:0:0:0:0 | & |
|
||||
| main.rs:2619:29:2619:33 | SelfParam | &T | main.rs:2612:5:2612:22 | Path |
|
||||
| main.rs:2619:59:2621:9 | { ... } | | {EXTERNAL LOCATION} | Result |
|
||||
| main.rs:2619:59:2621:9 | { ... } | E | file://:0:0:0:0 | () |
|
||||
| main.rs:2619:59:2621:9 | { ... } | T | main.rs:2624:5:2624:25 | PathBuf |
|
||||
| main.rs:2620:13:2620:30 | Ok(...) | | {EXTERNAL LOCATION} | Result |
|
||||
| main.rs:2620:13:2620:30 | Ok(...) | E | file://:0:0:0:0 | () |
|
||||
| main.rs:2620:13:2620:30 | Ok(...) | T | main.rs:2624:5:2624:25 | PathBuf |
|
||||
| main.rs:2620:16:2620:29 | ...::new(...) | | main.rs:2624:5:2624:25 | PathBuf |
|
||||
| main.rs:2627:39:2629:9 | { ... } | | main.rs:2624:5:2624:25 | PathBuf |
|
||||
| main.rs:2628:13:2628:22 | PathBuf {...} | | main.rs:2624:5:2624:25 | PathBuf |
|
||||
| main.rs:2637:18:2637:22 | SelfParam | | file://:0:0:0:0 | & |
|
||||
| main.rs:2637:18:2637:22 | SelfParam | &T | main.rs:2624:5:2624:25 | PathBuf |
|
||||
| main.rs:2637:34:2641:9 | { ... } | | file://:0:0:0:0 | & |
|
||||
| main.rs:2637:34:2641:9 | { ... } | &T | main.rs:2612:5:2612:22 | Path |
|
||||
| main.rs:2639:33:2639:43 | ...::new(...) | | main.rs:2612:5:2612:22 | Path |
|
||||
| main.rs:2640:13:2640:17 | &path | | file://:0:0:0:0 | & |
|
||||
| main.rs:2640:13:2640:17 | &path | &T | main.rs:2612:5:2612:22 | Path |
|
||||
| main.rs:2640:14:2640:17 | path | | main.rs:2612:5:2612:22 | Path |
|
||||
| main.rs:2645:13:2645:17 | path1 | | main.rs:2612:5:2612:22 | Path |
|
||||
| main.rs:2645:21:2645:31 | ...::new(...) | | main.rs:2612:5:2612:22 | Path |
|
||||
| main.rs:2646:13:2646:17 | path2 | | {EXTERNAL LOCATION} | Result |
|
||||
| main.rs:2646:13:2646:17 | path2 | E | file://:0:0:0:0 | () |
|
||||
| main.rs:2646:13:2646:17 | path2 | T | main.rs:2624:5:2624:25 | PathBuf |
|
||||
| main.rs:2646:21:2646:25 | path1 | | main.rs:2612:5:2612:22 | Path |
|
||||
| main.rs:2646:21:2646:40 | path1.canonicalize() | | {EXTERNAL LOCATION} | Result |
|
||||
| main.rs:2646:21:2646:40 | path1.canonicalize() | E | file://:0:0:0:0 | () |
|
||||
| main.rs:2646:21:2646:40 | path1.canonicalize() | T | main.rs:2624:5:2624:25 | PathBuf |
|
||||
| main.rs:2647:13:2647:17 | path3 | | main.rs:2624:5:2624:25 | PathBuf |
|
||||
| main.rs:2647:21:2647:25 | path2 | | {EXTERNAL LOCATION} | Result |
|
||||
| main.rs:2647:21:2647:25 | path2 | E | file://:0:0:0:0 | () |
|
||||
| main.rs:2647:21:2647:25 | path2 | T | main.rs:2624:5:2624:25 | PathBuf |
|
||||
| main.rs:2647:21:2647:34 | path2.unwrap() | | main.rs:2624:5:2624:25 | PathBuf |
|
||||
| main.rs:2649:13:2649:20 | pathbuf1 | | main.rs:2624:5:2624:25 | PathBuf |
|
||||
| main.rs:2649:24:2649:37 | ...::new(...) | | main.rs:2624:5:2624:25 | PathBuf |
|
||||
| main.rs:2650:24:2650:31 | pathbuf1 | | main.rs:2624:5:2624:25 | PathBuf |
|
||||
| main.rs:2661:5:2661:20 | ...::f(...) | | main.rs:72:5:72:21 | Foo |
|
||||
| main.rs:2662:5:2662:60 | ...::g(...) | | main.rs:72:5:72:21 | Foo |
|
||||
| main.rs:2662:20:2662:38 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo |
|
||||
| main.rs:2662:41:2662:59 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo |
|
||||
| main.rs:2678:5:2678:15 | ...::f(...) | | {EXTERNAL LOCATION} | trait Future |
|
||||
| main.rs:2578:36:2580:9 | { ... } | | main.rs:2575:5:2575:22 | Path |
|
||||
| main.rs:2579:13:2579:19 | Path {...} | | main.rs:2575:5:2575:22 | Path |
|
||||
| main.rs:2582:29:2582:33 | SelfParam | | file://:0:0:0:0 | & |
|
||||
| main.rs:2582:29:2582:33 | SelfParam | &T | main.rs:2575:5:2575:22 | Path |
|
||||
| main.rs:2582:59:2584:9 | { ... } | | {EXTERNAL LOCATION} | Result |
|
||||
| main.rs:2582:59:2584:9 | { ... } | E | file://:0:0:0:0 | () |
|
||||
| main.rs:2582:59:2584:9 | { ... } | T | main.rs:2587:5:2587:25 | PathBuf |
|
||||
| main.rs:2583:13:2583:30 | Ok(...) | | {EXTERNAL LOCATION} | Result |
|
||||
| main.rs:2583:13:2583:30 | Ok(...) | E | file://:0:0:0:0 | () |
|
||||
| main.rs:2583:13:2583:30 | Ok(...) | T | main.rs:2587:5:2587:25 | PathBuf |
|
||||
| main.rs:2583:16:2583:29 | ...::new(...) | | main.rs:2587:5:2587:25 | PathBuf |
|
||||
| main.rs:2590:39:2592:9 | { ... } | | main.rs:2587:5:2587:25 | PathBuf |
|
||||
| main.rs:2591:13:2591:22 | PathBuf {...} | | main.rs:2587:5:2587:25 | PathBuf |
|
||||
| main.rs:2600:18:2600:22 | SelfParam | | file://:0:0:0:0 | & |
|
||||
| main.rs:2600:18:2600:22 | SelfParam | &T | main.rs:2587:5:2587:25 | PathBuf |
|
||||
| main.rs:2600:34:2604:9 | { ... } | | file://:0:0:0:0 | & |
|
||||
| main.rs:2600:34:2604:9 | { ... } | &T | main.rs:2575:5:2575:22 | Path |
|
||||
| main.rs:2602:33:2602:43 | ...::new(...) | | main.rs:2575:5:2575:22 | Path |
|
||||
| main.rs:2603:13:2603:17 | &path | | file://:0:0:0:0 | & |
|
||||
| main.rs:2603:13:2603:17 | &path | &T | main.rs:2575:5:2575:22 | Path |
|
||||
| main.rs:2603:14:2603:17 | path | | main.rs:2575:5:2575:22 | Path |
|
||||
| main.rs:2608:13:2608:17 | path1 | | main.rs:2575:5:2575:22 | Path |
|
||||
| main.rs:2608:21:2608:31 | ...::new(...) | | main.rs:2575:5:2575:22 | Path |
|
||||
| main.rs:2609:13:2609:17 | path2 | | {EXTERNAL LOCATION} | Result |
|
||||
| main.rs:2609:13:2609:17 | path2 | E | file://:0:0:0:0 | () |
|
||||
| main.rs:2609:13:2609:17 | path2 | T | main.rs:2587:5:2587:25 | PathBuf |
|
||||
| main.rs:2609:21:2609:25 | path1 | | main.rs:2575:5:2575:22 | Path |
|
||||
| main.rs:2609:21:2609:40 | path1.canonicalize() | | {EXTERNAL LOCATION} | Result |
|
||||
| main.rs:2609:21:2609:40 | path1.canonicalize() | E | file://:0:0:0:0 | () |
|
||||
| main.rs:2609:21:2609:40 | path1.canonicalize() | T | main.rs:2587:5:2587:25 | PathBuf |
|
||||
| main.rs:2610:13:2610:17 | path3 | | main.rs:2587:5:2587:25 | PathBuf |
|
||||
| main.rs:2610:21:2610:25 | path2 | | {EXTERNAL LOCATION} | Result |
|
||||
| main.rs:2610:21:2610:25 | path2 | E | file://:0:0:0:0 | () |
|
||||
| main.rs:2610:21:2610:25 | path2 | T | main.rs:2587:5:2587:25 | PathBuf |
|
||||
| main.rs:2610:21:2610:34 | path2.unwrap() | | main.rs:2587:5:2587:25 | PathBuf |
|
||||
| main.rs:2612:13:2612:20 | pathbuf1 | | main.rs:2587:5:2587:25 | PathBuf |
|
||||
| main.rs:2612:24:2612:37 | ...::new(...) | | main.rs:2587:5:2587:25 | PathBuf |
|
||||
| main.rs:2613:24:2613:31 | pathbuf1 | | main.rs:2587:5:2587:25 | PathBuf |
|
||||
| main.rs:2625:5:2625:20 | ...::f(...) | | main.rs:72:5:72:21 | Foo |
|
||||
| main.rs:2626:5:2626:60 | ...::g(...) | | main.rs:72:5:72:21 | Foo |
|
||||
| main.rs:2626:20:2626:38 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo |
|
||||
| main.rs:2626:41:2626:59 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo |
|
||||
| main.rs:2642:5:2642:15 | ...::f(...) | | {EXTERNAL LOCATION} | trait Future |
|
||||
| pattern_matching.rs:13:26:133:1 | { ... } | | {EXTERNAL LOCATION} | Option |
|
||||
| pattern_matching.rs:13:26:133:1 | { ... } | T | file://:0:0:0:0 | () |
|
||||
| pattern_matching.rs:14:9:14:13 | value | | {EXTERNAL LOCATION} | Option |
|
||||
|
||||
@@ -18,30 +18,31 @@ edges
|
||||
| src/main.rs:7:11:7:19 | file_name | src/main.rs:9:35:9:43 | file_name | provenance | |
|
||||
| src/main.rs:9:9:9:17 | file_path | src/main.rs:11:24:11:32 | file_path | provenance | |
|
||||
| src/main.rs:9:21:9:44 | ...::from(...) | src/main.rs:9:9:9:17 | file_path | provenance | |
|
||||
| src/main.rs:9:35:9:43 | file_name | src/main.rs:9:21:9:44 | ...::from(...) | provenance | MaD:13 |
|
||||
| src/main.rs:9:35:9:43 | file_name | src/main.rs:9:21:9:44 | ...::from(...) | provenance | MaD:9 |
|
||||
| src/main.rs:9:35:9:43 | file_name | src/main.rs:9:21:9:44 | ...::from(...) | provenance | MaD:14 |
|
||||
| src/main.rs:11:24:11:32 | file_path | src/main.rs:11:5:11:22 | ...::read_to_string | provenance | MaD:6 Sink:MaD:6 |
|
||||
| src/main.rs:50:51:50:59 | file_path | src/main.rs:52:32:52:40 | file_path | provenance | |
|
||||
| src/main.rs:52:9:52:17 | file_path [&ref] | src/main.rs:53:21:53:44 | file_path.canonicalize() [Ok] | provenance | Config |
|
||||
| src/main.rs:52:21:52:41 | ...::new(...) [&ref] | src/main.rs:52:9:52:17 | file_path [&ref] | provenance | |
|
||||
| src/main.rs:52:31:52:40 | &file_path [&ref] | src/main.rs:52:21:52:41 | ...::new(...) [&ref] | provenance | MaD:12 |
|
||||
| src/main.rs:52:31:52:40 | &file_path [&ref] | src/main.rs:52:21:52:41 | ...::new(...) [&ref] | provenance | MaD:13 |
|
||||
| src/main.rs:52:32:52:40 | file_path | src/main.rs:52:31:52:40 | &file_path [&ref] | provenance | |
|
||||
| src/main.rs:53:9:53:17 | file_path | src/main.rs:58:24:58:32 | file_path | provenance | |
|
||||
| src/main.rs:53:21:53:44 | file_path.canonicalize() [Ok] | src/main.rs:53:21:53:53 | ... .unwrap() | provenance | MaD:11 |
|
||||
| src/main.rs:53:21:53:44 | file_path.canonicalize() [Ok] | src/main.rs:53:21:53:53 | ... .unwrap() | provenance | MaD:12 |
|
||||
| src/main.rs:53:21:53:53 | ... .unwrap() | src/main.rs:53:9:53:17 | file_path | provenance | |
|
||||
| src/main.rs:58:24:58:32 | file_path | src/main.rs:58:5:58:22 | ...::read_to_string | provenance | MaD:6 Sink:MaD:6 |
|
||||
| src/main.rs:63:11:63:19 | file_path | src/main.rs:66:32:66:40 | file_path | provenance | |
|
||||
| src/main.rs:66:9:66:17 | file_path [&ref] | src/main.rs:71:24:71:32 | file_path [&ref] | provenance | |
|
||||
| src/main.rs:66:21:66:41 | ...::new(...) [&ref] | src/main.rs:66:9:66:17 | file_path [&ref] | provenance | |
|
||||
| src/main.rs:66:31:66:40 | &file_path [&ref] | src/main.rs:66:21:66:41 | ...::new(...) [&ref] | provenance | MaD:12 |
|
||||
| src/main.rs:66:31:66:40 | &file_path [&ref] | src/main.rs:66:21:66:41 | ...::new(...) [&ref] | provenance | MaD:13 |
|
||||
| src/main.rs:66:32:66:40 | file_path | src/main.rs:66:31:66:40 | &file_path [&ref] | provenance | |
|
||||
| src/main.rs:71:24:71:32 | file_path [&ref] | src/main.rs:71:5:71:22 | ...::read_to_string | provenance | MaD:6 Sink:MaD:6 |
|
||||
| src/main.rs:90:11:90:19 | file_path | src/main.rs:93:32:93:40 | file_path | provenance | |
|
||||
| src/main.rs:93:9:93:17 | file_path [&ref] | src/main.rs:98:21:98:44 | file_path.canonicalize() [Ok] | provenance | Config |
|
||||
| src/main.rs:93:21:93:41 | ...::new(...) [&ref] | src/main.rs:93:9:93:17 | file_path [&ref] | provenance | |
|
||||
| src/main.rs:93:31:93:40 | &file_path [&ref] | src/main.rs:93:21:93:41 | ...::new(...) [&ref] | provenance | MaD:12 |
|
||||
| src/main.rs:93:31:93:40 | &file_path [&ref] | src/main.rs:93:21:93:41 | ...::new(...) [&ref] | provenance | MaD:13 |
|
||||
| src/main.rs:93:32:93:40 | file_path | src/main.rs:93:31:93:40 | &file_path [&ref] | provenance | |
|
||||
| src/main.rs:98:9:98:17 | file_path | src/main.rs:99:24:99:32 | file_path | provenance | |
|
||||
| src/main.rs:98:21:98:44 | file_path.canonicalize() [Ok] | src/main.rs:98:21:98:53 | ... .unwrap() | provenance | MaD:11 |
|
||||
| src/main.rs:98:21:98:44 | file_path.canonicalize() [Ok] | src/main.rs:98:21:98:53 | ... .unwrap() | provenance | MaD:12 |
|
||||
| src/main.rs:98:21:98:53 | ... .unwrap() | src/main.rs:98:9:98:17 | file_path | provenance | |
|
||||
| src/main.rs:99:24:99:32 | file_path | src/main.rs:99:5:99:22 | ...::read_to_string | provenance | MaD:6 Sink:MaD:6 |
|
||||
| src/main.rs:103:9:103:13 | path1 | src/main.rs:104:33:104:37 | path1 | provenance | |
|
||||
@@ -58,39 +59,39 @@ edges
|
||||
| src/main.rs:103:9:103:13 | path1 | src/main.rs:123:37:123:41 | path1 | provenance | |
|
||||
| src/main.rs:103:9:103:13 | path1 | src/main.rs:123:37:123:49 | path1.clone() | provenance | MaD:8 |
|
||||
| src/main.rs:103:17:103:30 | ...::args | src/main.rs:103:17:103:32 | ...::args(...) [element] | provenance | Src:MaD:7 |
|
||||
| src/main.rs:103:17:103:32 | ...::args(...) [element] | src/main.rs:103:17:103:39 | ... .nth(...) [Some] | provenance | MaD:9 |
|
||||
| src/main.rs:103:17:103:39 | ... .nth(...) [Some] | src/main.rs:103:17:103:48 | ... .unwrap() | provenance | MaD:10 |
|
||||
| src/main.rs:103:17:103:32 | ...::args(...) [element] | src/main.rs:103:17:103:39 | ... .nth(...) [Some] | provenance | MaD:10 |
|
||||
| src/main.rs:103:17:103:39 | ... .nth(...) [Some] | src/main.rs:103:17:103:48 | ... .unwrap() | provenance | MaD:11 |
|
||||
| src/main.rs:103:17:103:48 | ... .unwrap() | src/main.rs:103:9:103:13 | path1 | provenance | |
|
||||
| src/main.rs:104:33:104:37 | path1 | src/main.rs:104:33:104:45 | path1.clone() | provenance | MaD:8 |
|
||||
| src/main.rs:104:33:104:45 | path1.clone() | src/main.rs:104:13:104:31 | ...::open | provenance | MaD:2 Sink:MaD:2 |
|
||||
| src/main.rs:106:9:106:13 | path2 | src/main.rs:107:33:107:37 | path2 | provenance | |
|
||||
| src/main.rs:106:17:106:52 | ...::canonicalize(...) [Ok] | src/main.rs:106:17:106:61 | ... .unwrap() | provenance | MaD:11 |
|
||||
| src/main.rs:106:17:106:52 | ...::canonicalize(...) [Ok] | src/main.rs:106:17:106:61 | ... .unwrap() | provenance | MaD:12 |
|
||||
| src/main.rs:106:17:106:61 | ... .unwrap() | src/main.rs:106:9:106:13 | path2 | provenance | |
|
||||
| src/main.rs:106:39:106:43 | path1 | src/main.rs:106:39:106:51 | path1.clone() | provenance | MaD:8 |
|
||||
| src/main.rs:106:39:106:51 | path1.clone() | src/main.rs:106:17:106:52 | ...::canonicalize(...) [Ok] | provenance | Config |
|
||||
| src/main.rs:107:33:107:37 | path2 | src/main.rs:107:13:107:31 | ...::open | provenance | MaD:2 Sink:MaD:2 |
|
||||
| src/main.rs:109:9:109:13 | path3 | src/main.rs:110:35:110:39 | path3 | provenance | |
|
||||
| src/main.rs:109:17:109:54 | ...::canonicalize(...) [future, Ok] | src/main.rs:109:17:109:60 | await ... [Ok] | provenance | |
|
||||
| src/main.rs:109:17:109:60 | await ... [Ok] | src/main.rs:109:17:109:69 | ... .unwrap() | provenance | MaD:11 |
|
||||
| src/main.rs:109:17:109:60 | await ... [Ok] | src/main.rs:109:17:109:69 | ... .unwrap() | provenance | MaD:12 |
|
||||
| src/main.rs:109:17:109:69 | ... .unwrap() | src/main.rs:109:9:109:13 | path3 | provenance | |
|
||||
| src/main.rs:109:41:109:45 | path1 | src/main.rs:109:41:109:53 | path1.clone() | provenance | MaD:8 |
|
||||
| src/main.rs:109:41:109:53 | path1.clone() | src/main.rs:109:17:109:54 | ...::canonicalize(...) [future, Ok] | provenance | Config |
|
||||
| src/main.rs:110:35:110:39 | path3 | src/main.rs:110:13:110:33 | ...::open | provenance | MaD:4 Sink:MaD:4 |
|
||||
| src/main.rs:112:9:112:13 | path4 | src/main.rs:113:39:113:43 | path4 | provenance | |
|
||||
| src/main.rs:112:17:112:58 | ...::canonicalize(...) [future, Ok] | src/main.rs:112:17:112:64 | await ... [Ok] | provenance | |
|
||||
| src/main.rs:112:17:112:64 | await ... [Ok] | src/main.rs:112:17:112:73 | ... .unwrap() | provenance | MaD:11 |
|
||||
| src/main.rs:112:17:112:64 | await ... [Ok] | src/main.rs:112:17:112:73 | ... .unwrap() | provenance | MaD:12 |
|
||||
| src/main.rs:112:17:112:73 | ... .unwrap() | src/main.rs:112:9:112:13 | path4 | provenance | |
|
||||
| src/main.rs:112:45:112:49 | path1 | src/main.rs:112:45:112:57 | path1.clone() | provenance | MaD:8 |
|
||||
| src/main.rs:112:45:112:57 | path1.clone() | src/main.rs:112:17:112:58 | ...::canonicalize(...) [future, Ok] | provenance | Config |
|
||||
| src/main.rs:113:39:113:43 | path4 | src/main.rs:113:13:113:37 | ...::open | provenance | MaD:1 Sink:MaD:1 |
|
||||
| src/main.rs:115:9:115:13 | path5 [&ref] | src/main.rs:116:33:116:37 | path5 [&ref] | provenance | |
|
||||
| src/main.rs:115:17:115:44 | ...::new(...) [&ref] | src/main.rs:115:9:115:13 | path5 [&ref] | provenance | |
|
||||
| src/main.rs:115:38:115:43 | &path1 [&ref] | src/main.rs:115:17:115:44 | ...::new(...) [&ref] | provenance | MaD:12 |
|
||||
| src/main.rs:115:38:115:43 | &path1 [&ref] | src/main.rs:115:17:115:44 | ...::new(...) [&ref] | provenance | MaD:13 |
|
||||
| src/main.rs:115:39:115:43 | path1 | src/main.rs:115:38:115:43 | &path1 [&ref] | provenance | |
|
||||
| src/main.rs:116:33:116:37 | path5 [&ref] | src/main.rs:116:13:116:31 | ...::open | provenance | MaD:2 Sink:MaD:2 |
|
||||
| src/main.rs:116:33:116:37 | path5 [&ref] | src/main.rs:118:17:118:36 | path5.canonicalize() [Ok] | provenance | Config |
|
||||
| src/main.rs:118:9:118:13 | path6 | src/main.rs:119:33:119:37 | path6 | provenance | |
|
||||
| src/main.rs:118:17:118:36 | path5.canonicalize() [Ok] | src/main.rs:118:17:118:45 | ... .unwrap() | provenance | MaD:11 |
|
||||
| src/main.rs:118:17:118:36 | path5.canonicalize() [Ok] | src/main.rs:118:17:118:45 | ... .unwrap() | provenance | MaD:12 |
|
||||
| src/main.rs:118:17:118:45 | ... .unwrap() | src/main.rs:118:9:118:13 | path6 | provenance | |
|
||||
| src/main.rs:119:33:119:37 | path6 | src/main.rs:119:13:119:31 | ...::open | provenance | MaD:2 Sink:MaD:2 |
|
||||
| src/main.rs:122:27:122:31 | path1 | src/main.rs:122:27:122:39 | path1.clone() | provenance | MaD:8 |
|
||||
@@ -101,15 +102,15 @@ edges
|
||||
| src/main.rs:170:16:170:29 | ...: ... [&ref] | src/main.rs:174:36:174:43 | path_str [&ref] | provenance | |
|
||||
| src/main.rs:172:9:172:12 | path [&ref] | src/main.rs:173:8:173:11 | path [&ref] | provenance | |
|
||||
| src/main.rs:172:16:172:34 | ...::new(...) [&ref] | src/main.rs:172:9:172:12 | path [&ref] | provenance | |
|
||||
| src/main.rs:172:26:172:33 | path_str [&ref] | src/main.rs:172:16:172:34 | ...::new(...) [&ref] | provenance | MaD:12 |
|
||||
| src/main.rs:172:26:172:33 | path_str [&ref] | src/main.rs:172:16:172:34 | ...::new(...) [&ref] | provenance | MaD:13 |
|
||||
| src/main.rs:173:8:173:11 | path [&ref] | src/main.rs:173:13:173:18 | exists | provenance | MaD:3 Sink:MaD:3 |
|
||||
| src/main.rs:173:8:173:11 | path [&ref] | src/main.rs:177:36:177:39 | path [&ref] | provenance | |
|
||||
| src/main.rs:174:36:174:43 | path_str [&ref] | src/main.rs:174:25:174:34 | ...::open | provenance | MaD:2 Sink:MaD:2 |
|
||||
| src/main.rs:177:36:177:39 | path [&ref] | src/main.rs:177:25:177:34 | ...::open | provenance | MaD:2 Sink:MaD:2 |
|
||||
| src/main.rs:185:9:185:13 | path1 | src/main.rs:186:18:186:22 | path1 | provenance | |
|
||||
| src/main.rs:185:17:185:30 | ...::args | src/main.rs:185:17:185:32 | ...::args(...) [element] | provenance | Src:MaD:7 |
|
||||
| src/main.rs:185:17:185:32 | ...::args(...) [element] | src/main.rs:185:17:185:39 | ... .nth(...) [Some] | provenance | MaD:9 |
|
||||
| src/main.rs:185:17:185:39 | ... .nth(...) [Some] | src/main.rs:185:17:185:48 | ... .unwrap() | provenance | MaD:10 |
|
||||
| src/main.rs:185:17:185:32 | ...::args(...) [element] | src/main.rs:185:17:185:39 | ... .nth(...) [Some] | provenance | MaD:10 |
|
||||
| src/main.rs:185:17:185:39 | ... .nth(...) [Some] | src/main.rs:185:17:185:48 | ... .unwrap() | provenance | MaD:11 |
|
||||
| src/main.rs:185:17:185:48 | ... .unwrap() | src/main.rs:185:9:185:13 | path1 | provenance | |
|
||||
| src/main.rs:186:17:186:22 | &path1 [&ref] | src/main.rs:170:16:170:29 | ...: ... [&ref] | provenance | |
|
||||
| src/main.rs:186:18:186:22 | path1 | src/main.rs:186:17:186:22 | &path1 [&ref] | provenance | |
|
||||
@@ -122,11 +123,12 @@ models
|
||||
| 6 | Sink: std::fs::read_to_string; Argument[0]; path-injection |
|
||||
| 7 | Source: std::env::args; ReturnValue.Element; commandargs |
|
||||
| 8 | Summary: <_ as core::clone::Clone>::clone; Argument[self].Reference; ReturnValue; value |
|
||||
| 9 | Summary: <_ as core::iter::traits::iterator::Iterator>::nth; Argument[self].Element; ReturnValue.Field[core::option::Option::Some(0)]; value |
|
||||
| 10 | Summary: <core::option::Option>::unwrap; Argument[self].Field[core::option::Option::Some(0)]; ReturnValue; value |
|
||||
| 11 | Summary: <core::result::Result>::unwrap; Argument[self].Field[core::result::Result::Ok(0)]; ReturnValue; value |
|
||||
| 12 | Summary: <std::path::Path>::new; Argument[0].Reference; ReturnValue.Reference; value |
|
||||
| 13 | Summary: <std::path::PathBuf as core::convert::From>::from; Argument[0]; ReturnValue; value |
|
||||
| 9 | Summary: <_ as core::convert::From>::from; Argument[0]; ReturnValue; value |
|
||||
| 10 | Summary: <_ as core::iter::traits::iterator::Iterator>::nth; Argument[self].Element; ReturnValue.Field[core::option::Option::Some(0)]; value |
|
||||
| 11 | Summary: <core::option::Option>::unwrap; Argument[self].Field[core::option::Option::Some(0)]; ReturnValue; value |
|
||||
| 12 | Summary: <core::result::Result>::unwrap; Argument[self].Field[core::result::Result::Ok(0)]; ReturnValue; value |
|
||||
| 13 | Summary: <std::path::Path>::new; Argument[0].Reference; ReturnValue.Reference; value |
|
||||
| 14 | Summary: <std::path::PathBuf as core::convert::From>::from; Argument[0]; ReturnValue; taint |
|
||||
nodes
|
||||
| src/main.rs:7:11:7:19 | file_name | semmle.label | file_name |
|
||||
| src/main.rs:9:9:9:17 | file_path | semmle.label | file_path |
|
||||
|
||||
@@ -12,12 +12,14 @@ multipleCallTargets
|
||||
| sqlx.rs:67:26:67:48 | unsafe_query_1.as_str() |
|
||||
| sqlx.rs:69:30:69:52 | unsafe_query_2.as_str() |
|
||||
| sqlx.rs:70:30:70:52 | unsafe_query_3.as_str() |
|
||||
| sqlx.rs:71:30:71:52 | unsafe_query_4.as_str() |
|
||||
| sqlx.rs:75:25:75:45 | safe_query_1.as_str() |
|
||||
| sqlx.rs:76:25:76:45 | safe_query_2.as_str() |
|
||||
| sqlx.rs:77:25:77:45 | safe_query_3.as_str() |
|
||||
| sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() |
|
||||
| sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() |
|
||||
| sqlx.rs:81:29:81:51 | unsafe_query_3.as_str() |
|
||||
| sqlx.rs:82:29:82:51 | unsafe_query_4.as_str() |
|
||||
| sqlx.rs:84:25:84:49 | prepared_query_1.as_str() |
|
||||
| sqlx.rs:85:25:85:49 | prepared_query_1.as_str() |
|
||||
| sqlx.rs:87:29:87:53 | prepared_query_1.as_str() |
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
| sqlx.rs:77:13:77:23 | ...::query | sqlx.rs:48:25:48:46 | ...::get | sqlx.rs:77:13:77:23 | ...::query | This query depends on a $@. | sqlx.rs:48:25:48:46 | ...::get | user-provided value |
|
||||
| sqlx.rs:78:13:78:23 | ...::query | sqlx.rs:47:22:47:35 | ...::args | sqlx.rs:78:13:78:23 | ...::query | This query depends on a $@. | sqlx.rs:47:22:47:35 | ...::args | user-provided value |
|
||||
| sqlx.rs:80:17:80:27 | ...::query | sqlx.rs:48:25:48:46 | ...::get | sqlx.rs:80:17:80:27 | ...::query | This query depends on a $@. | sqlx.rs:48:25:48:46 | ...::get | user-provided value |
|
||||
| sqlx.rs:82:17:82:27 | ...::query | sqlx.rs:48:25:48:46 | ...::get | sqlx.rs:82:17:82:27 | ...::query | This query depends on a $@. | sqlx.rs:48:25:48:46 | ...::get | user-provided value |
|
||||
edges
|
||||
| sqlx.rs:47:9:47:18 | arg_string | sqlx.rs:53:27:53:36 | arg_string | provenance | |
|
||||
| sqlx.rs:47:22:47:35 | ...::args | sqlx.rs:47:22:47:37 | ...::args(...) [element] | provenance | Src:MaD:3 |
|
||||
@@ -11,6 +12,7 @@ edges
|
||||
| sqlx.rs:48:9:48:21 | remote_string | sqlx.rs:49:25:49:52 | remote_string.parse() [Ok] | provenance | MaD:10 |
|
||||
| sqlx.rs:48:9:48:21 | remote_string | sqlx.rs:49:25:49:52 | remote_string.parse() [Ok] | provenance | MaD:10 |
|
||||
| sqlx.rs:48:9:48:21 | remote_string | sqlx.rs:54:27:54:39 | remote_string | provenance | |
|
||||
| sqlx.rs:48:9:48:21 | remote_string | sqlx.rs:59:17:59:72 | MacroExpr | provenance | |
|
||||
| sqlx.rs:48:25:48:46 | ...::get | sqlx.rs:48:25:48:69 | ...::get(...) [Ok] | provenance | Src:MaD:2 |
|
||||
| sqlx.rs:48:25:48:69 | ...::get(...) [Ok] | sqlx.rs:48:25:48:78 | ... .unwrap() | provenance | MaD:7 |
|
||||
| sqlx.rs:48:25:48:78 | ... .unwrap() | sqlx.rs:48:25:48:85 | ... .text() [Ok] | provenance | MaD:11 |
|
||||
@@ -38,6 +40,15 @@ edges
|
||||
| sqlx.rs:54:9:54:22 | unsafe_query_2 [&ref] | sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() [&ref] | provenance | MaD:9 |
|
||||
| sqlx.rs:54:26:54:39 | &remote_string [&ref] | sqlx.rs:54:9:54:22 | unsafe_query_2 [&ref] | provenance | |
|
||||
| sqlx.rs:54:27:54:39 | remote_string | sqlx.rs:54:26:54:39 | &remote_string [&ref] | provenance | |
|
||||
| sqlx.rs:56:9:56:22 | unsafe_query_4 | sqlx.rs:82:29:82:42 | unsafe_query_4 | provenance | |
|
||||
| sqlx.rs:56:9:56:22 | unsafe_query_4 | sqlx.rs:82:29:82:51 | unsafe_query_4.as_str() | provenance | MaD:9 |
|
||||
| sqlx.rs:56:9:56:22 | unsafe_query_4 | sqlx.rs:82:29:82:51 | unsafe_query_4.as_str() | provenance | MaD:5 |
|
||||
| sqlx.rs:56:9:56:22 | unsafe_query_4 | sqlx.rs:82:29:82:51 | unsafe_query_4.as_str() | provenance | MaD:9 |
|
||||
| sqlx.rs:59:9:59:15 | res | sqlx.rs:59:17:59:72 | { ... } | provenance | |
|
||||
| sqlx.rs:59:17:59:72 | ...::format(...) | sqlx.rs:59:9:59:15 | res | provenance | |
|
||||
| sqlx.rs:59:17:59:72 | ...::must_use(...) | sqlx.rs:56:9:56:22 | unsafe_query_4 | provenance | |
|
||||
| sqlx.rs:59:17:59:72 | MacroExpr | sqlx.rs:59:17:59:72 | ...::format(...) | provenance | MaD:12 |
|
||||
| sqlx.rs:59:17:59:72 | { ... } | sqlx.rs:59:17:59:72 | ...::must_use(...) | provenance | MaD:13 |
|
||||
| sqlx.rs:77:25:77:36 | safe_query_3 | sqlx.rs:77:25:77:45 | safe_query_3.as_str() [&ref] | provenance | MaD:9 |
|
||||
| sqlx.rs:77:25:77:36 | safe_query_3 | sqlx.rs:77:25:77:45 | safe_query_3.as_str() [&ref] | provenance | MaD:5 |
|
||||
| sqlx.rs:77:25:77:36 | safe_query_3 | sqlx.rs:77:25:77:45 | safe_query_3.as_str() [&ref] | provenance | MaD:9 |
|
||||
@@ -45,6 +56,11 @@ edges
|
||||
| sqlx.rs:77:25:77:45 | safe_query_3.as_str() [&ref] | sqlx.rs:77:13:77:23 | ...::query | provenance | MaD:1 Sink:MaD:1 |
|
||||
| sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() [&ref] | sqlx.rs:78:13:78:23 | ...::query | provenance | MaD:1 Sink:MaD:1 |
|
||||
| sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() [&ref] | sqlx.rs:80:17:80:27 | ...::query | provenance | MaD:1 Sink:MaD:1 |
|
||||
| sqlx.rs:82:29:82:42 | unsafe_query_4 | sqlx.rs:82:29:82:51 | unsafe_query_4.as_str() [&ref] | provenance | MaD:9 |
|
||||
| sqlx.rs:82:29:82:42 | unsafe_query_4 | sqlx.rs:82:29:82:51 | unsafe_query_4.as_str() [&ref] | provenance | MaD:5 |
|
||||
| sqlx.rs:82:29:82:42 | unsafe_query_4 | sqlx.rs:82:29:82:51 | unsafe_query_4.as_str() [&ref] | provenance | MaD:9 |
|
||||
| sqlx.rs:82:29:82:51 | unsafe_query_4.as_str() | sqlx.rs:82:17:82:27 | ...::query | provenance | MaD:1 Sink:MaD:1 |
|
||||
| sqlx.rs:82:29:82:51 | unsafe_query_4.as_str() [&ref] | sqlx.rs:82:17:82:27 | ...::query | provenance | MaD:1 Sink:MaD:1 |
|
||||
models
|
||||
| 1 | Sink: sqlx_core::query::query; Argument[0]; sql-injection |
|
||||
| 2 | Source: reqwest::blocking::get; ReturnValue.Field[core::result::Result::Ok(0)]; remote |
|
||||
@@ -86,6 +102,12 @@ nodes
|
||||
| sqlx.rs:54:9:54:22 | unsafe_query_2 [&ref] | semmle.label | unsafe_query_2 [&ref] |
|
||||
| sqlx.rs:54:26:54:39 | &remote_string [&ref] | semmle.label | &remote_string [&ref] |
|
||||
| sqlx.rs:54:27:54:39 | remote_string | semmle.label | remote_string |
|
||||
| sqlx.rs:56:9:56:22 | unsafe_query_4 | semmle.label | unsafe_query_4 |
|
||||
| sqlx.rs:59:9:59:15 | res | semmle.label | res |
|
||||
| sqlx.rs:59:17:59:72 | ...::format(...) | semmle.label | ...::format(...) |
|
||||
| sqlx.rs:59:17:59:72 | ...::must_use(...) | semmle.label | ...::must_use(...) |
|
||||
| sqlx.rs:59:17:59:72 | MacroExpr | semmle.label | MacroExpr |
|
||||
| sqlx.rs:59:17:59:72 | { ... } | semmle.label | { ... } |
|
||||
| sqlx.rs:77:13:77:23 | ...::query | semmle.label | ...::query |
|
||||
| sqlx.rs:77:25:77:36 | safe_query_3 | semmle.label | safe_query_3 |
|
||||
| sqlx.rs:77:25:77:45 | safe_query_3.as_str() | semmle.label | safe_query_3.as_str() |
|
||||
@@ -94,4 +116,8 @@ nodes
|
||||
| sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() [&ref] | semmle.label | unsafe_query_1.as_str() [&ref] |
|
||||
| sqlx.rs:80:17:80:27 | ...::query | semmle.label | ...::query |
|
||||
| sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() [&ref] | semmle.label | unsafe_query_2.as_str() [&ref] |
|
||||
| sqlx.rs:82:17:82:27 | ...::query | semmle.label | ...::query |
|
||||
| sqlx.rs:82:29:82:42 | unsafe_query_4 | semmle.label | unsafe_query_4 |
|
||||
| sqlx.rs:82:29:82:51 | unsafe_query_4.as_str() | semmle.label | unsafe_query_4.as_str() |
|
||||
| sqlx.rs:82:29:82:51 | unsafe_query_4.as_str() [&ref] | semmle.label | unsafe_query_4.as_str() [&ref] |
|
||||
subpaths
|
||||
|
||||
@@ -79,7 +79,7 @@ async fn test_sqlx_mysql(url: &str, enable_remote: bool) -> Result<(), sqlx::Err
|
||||
if enable_remote {
|
||||
let _ = sqlx::query(unsafe_query_2.as_str()).execute(&pool).await?; // $ sql-sink Alert[rust/sql-injection]=remote1
|
||||
let _ = sqlx::query(unsafe_query_3.as_str()).execute(&pool).await?; // $ sql-sink MISSING: Alert[rust/sql-injection]=remote1
|
||||
let _ = sqlx::query(unsafe_query_4.as_str()).execute(&pool).await?; // $ sql-sink MISSING: Alert[rust/sql-injection]=remote1
|
||||
let _ = sqlx::query(unsafe_query_4.as_str()).execute(&pool).await?; // $ sql-sink Alert[rust/sql-injection]=remote1
|
||||
}
|
||||
let _ = sqlx::query(prepared_query_1.as_str()).bind(const_string).execute(&pool).await?; // $ sql-sink
|
||||
let _ = sqlx::query(prepared_query_1.as_str()).bind(arg_string).execute(&pool).await?; // $ sql-sink
|
||||
|
||||
@@ -51,10 +51,10 @@ edges
|
||||
| main.rs:33:50:33:57 | password | main.rs:33:23:33:57 | MacroExpr | provenance | |
|
||||
| main.rs:35:33:35:35 | url | main.rs:35:12:35:18 | request | provenance | MaD:2 Sink:MaD:2 |
|
||||
models
|
||||
| 1 | Sink: <reqwest::async_impl::client::Client>::post; Argument[0]; transmission |
|
||||
| 2 | Sink: <reqwest::async_impl::client::Client>::request; Argument[1]; transmission |
|
||||
| 3 | Sink: <reqwest::blocking::client::Client>::request; Argument[1]; transmission |
|
||||
| 4 | Sink: reqwest::blocking::get; Argument[0]; transmission |
|
||||
| 1 | Sink: <reqwest::async_impl::client::Client>::post; Argument[0]; request-url |
|
||||
| 2 | Sink: <reqwest::async_impl::client::Client>::request; Argument[1]; request-url |
|
||||
| 3 | Sink: <reqwest::blocking::client::Client>::request; Argument[1]; request-url |
|
||||
| 4 | Sink: reqwest::blocking::get; Argument[0]; request-url |
|
||||
| 5 | Summary: <core::result::Result>::unwrap; Argument[self].Field[core::result::Result::Ok(0)]; ReturnValue; value |
|
||||
| 6 | Summary: <url::Url>::parse; Argument[0].Reference; ReturnValue.Field[core::result::Result::Ok(0)]; taint |
|
||||
| 7 | Summary: alloc::fmt::format; Argument[0]; ReturnValue; taint |
|
||||
|
||||
@@ -12,60 +12,87 @@
|
||||
| test_cipher.rs:50:37:50:52 | ...::zeroed | test_cipher.rs:50:37:50:52 | ...::zeroed | test_cipher.rs:51:31:51:48 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:51:31:51:48 | ...::new | a key |
|
||||
| test_cipher.rs:50:37:50:52 | ...::zeroed | test_cipher.rs:50:37:50:52 | ...::zeroed | test_cipher.rs:51:31:51:48 | ...::new | This hard-coded value is used as $@. | test_cipher.rs:51:31:51:48 | ...::new | a key |
|
||||
| test_cipher.rs:73:20:73:22 | 0u8 | test_cipher.rs:73:20:73:22 | 0u8 | test_cipher.rs:74:23:74:44 | ...::new_from_slice | This hard-coded value is used as $@. | test_cipher.rs:74:23:74:44 | ...::new_from_slice | a key |
|
||||
| test_cookie.rs:17:29:17:29 | 0 | test_cookie.rs:17:29:17:29 | 0 | test_cookie.rs:18:16:18:24 | ...::from | This hard-coded value is used as $@. | test_cookie.rs:18:16:18:24 | ...::from | a key |
|
||||
| test_cookie.rs:21:29:21:29 | 0 | test_cookie.rs:21:29:21:29 | 0 | test_cookie.rs:22:16:22:24 | ...::from | This hard-coded value is used as $@. | test_cookie.rs:22:16:22:24 | ...::from | a key |
|
||||
| test_cookie.rs:38:29:38:31 | 0u8 | test_cookie.rs:38:29:38:31 | 0u8 | test_cookie.rs:42:14:42:32 | ...::from | This hard-coded value is used as $@. | test_cookie.rs:42:14:42:32 | ...::from | a key |
|
||||
| test_cookie.rs:49:23:49:25 | 0u8 | test_cookie.rs:49:23:49:25 | 0u8 | test_cookie.rs:53:14:53:32 | ...::from | This hard-coded value is used as $@. | test_cookie.rs:53:14:53:32 | ...::from | a key |
|
||||
edges
|
||||
| test_cipher.rs:18:9:18:14 | const1 [&ref, element] | test_cipher.rs:19:73:19:78 | const1 [&ref, element] | provenance | |
|
||||
| test_cipher.rs:18:28:18:36 | &... [&ref, element] | test_cipher.rs:18:9:18:14 | const1 [&ref, element] | provenance | |
|
||||
| test_cipher.rs:18:29:18:36 | [0u8; 16] [element] | test_cipher.rs:18:28:18:36 | &... [&ref, element] | provenance | |
|
||||
| test_cipher.rs:18:30:18:32 | 0u8 | test_cipher.rs:18:29:18:36 | [0u8; 16] [element] | provenance | |
|
||||
| test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref, element] | test_cipher.rs:19:30:19:47 | ...::new | provenance | MaD:2 Sink:MaD:2 Sink:MaD:2 |
|
||||
| test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref, element] | test_cipher.rs:19:30:19:47 | ...::new | provenance | MaD:4 Sink:MaD:4 Sink:MaD:4 |
|
||||
| test_cipher.rs:19:73:19:78 | const1 [&ref, element] | test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref, element] | provenance | MaD:7 |
|
||||
| test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref, element] | test_cipher.rs:19:30:19:47 | ...::new | provenance | MaD:3 Sink:MaD:3 Sink:MaD:3 |
|
||||
| test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref, element] | test_cipher.rs:19:30:19:47 | ...::new | provenance | MaD:5 Sink:MaD:5 Sink:MaD:5 |
|
||||
| test_cipher.rs:19:73:19:78 | const1 [&ref, element] | test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref, element] | provenance | MaD:10 |
|
||||
| test_cipher.rs:25:9:25:14 | const4 [&ref, element] | test_cipher.rs:26:66:26:71 | const4 [&ref, element] | provenance | |
|
||||
| test_cipher.rs:25:28:25:36 | &... [&ref, element] | test_cipher.rs:25:9:25:14 | const4 [&ref, element] | provenance | |
|
||||
| test_cipher.rs:25:29:25:36 | [0u8; 16] [element] | test_cipher.rs:25:28:25:36 | &... [&ref, element] | provenance | |
|
||||
| test_cipher.rs:25:30:25:32 | 0u8 | test_cipher.rs:25:29:25:36 | [0u8; 16] [element] | provenance | |
|
||||
| test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref, element] | test_cipher.rs:26:30:26:40 | ...::new | provenance | MaD:2 Sink:MaD:2 Sink:MaD:2 |
|
||||
| test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref, element] | test_cipher.rs:26:30:26:40 | ...::new | provenance | MaD:4 Sink:MaD:4 Sink:MaD:4 |
|
||||
| test_cipher.rs:26:66:26:71 | const4 [&ref, element] | test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref, element] | provenance | MaD:7 |
|
||||
| test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref, element] | test_cipher.rs:26:30:26:40 | ...::new | provenance | MaD:3 Sink:MaD:3 Sink:MaD:3 |
|
||||
| test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref, element] | test_cipher.rs:26:30:26:40 | ...::new | provenance | MaD:5 Sink:MaD:5 Sink:MaD:5 |
|
||||
| test_cipher.rs:26:66:26:71 | const4 [&ref, element] | test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref, element] | provenance | MaD:10 |
|
||||
| test_cipher.rs:29:9:29:14 | const5 [&ref, element] | test_cipher.rs:30:95:30:100 | const5 [&ref, element] | provenance | |
|
||||
| test_cipher.rs:29:28:29:36 | &... [&ref, element] | test_cipher.rs:29:9:29:14 | const5 [&ref, element] | provenance | |
|
||||
| test_cipher.rs:29:29:29:36 | [0u8; 16] [element] | test_cipher.rs:29:28:29:36 | &... [&ref, element] | provenance | |
|
||||
| test_cipher.rs:29:30:29:32 | 0u8 | test_cipher.rs:29:29:29:36 | [0u8; 16] [element] | provenance | |
|
||||
| test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | test_cipher.rs:30:30:30:40 | ...::new | provenance | MaD:3 Sink:MaD:3 Sink:MaD:3 |
|
||||
| test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | test_cipher.rs:30:30:30:40 | ...::new | provenance | MaD:5 Sink:MaD:5 Sink:MaD:5 |
|
||||
| test_cipher.rs:30:95:30:100 | const5 [&ref, element] | test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | provenance | MaD:7 |
|
||||
| test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | test_cipher.rs:30:30:30:40 | ...::new | provenance | MaD:4 Sink:MaD:4 Sink:MaD:4 |
|
||||
| test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | test_cipher.rs:30:30:30:40 | ...::new | provenance | MaD:6 Sink:MaD:6 Sink:MaD:6 |
|
||||
| test_cipher.rs:30:95:30:100 | const5 [&ref, element] | test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref, element] | provenance | MaD:10 |
|
||||
| test_cipher.rs:37:9:37:14 | const7 | test_cipher.rs:38:74:38:79 | const7 | provenance | |
|
||||
| test_cipher.rs:37:27:37:74 | [...] | test_cipher.rs:37:9:37:14 | const7 | provenance | |
|
||||
| test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | test_cipher.rs:38:30:38:47 | ...::new | provenance | MaD:2 Sink:MaD:2 |
|
||||
| test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | test_cipher.rs:38:30:38:47 | ...::new | provenance | MaD:4 Sink:MaD:4 |
|
||||
| test_cipher.rs:38:73:38:79 | &const7 [&ref] | test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | provenance | MaD:7 |
|
||||
| test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | test_cipher.rs:38:30:38:47 | ...::new | provenance | MaD:3 Sink:MaD:3 |
|
||||
| test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | test_cipher.rs:38:30:38:47 | ...::new | provenance | MaD:5 Sink:MaD:5 |
|
||||
| test_cipher.rs:38:73:38:79 | &const7 [&ref] | test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | provenance | MaD:10 |
|
||||
| test_cipher.rs:38:74:38:79 | const7 | test_cipher.rs:38:73:38:79 | &const7 [&ref] | provenance | |
|
||||
| test_cipher.rs:41:9:41:14 | const8 [&ref] | test_cipher.rs:42:73:42:78 | const8 [&ref] | provenance | |
|
||||
| test_cipher.rs:41:28:41:76 | &... [&ref] | test_cipher.rs:41:9:41:14 | const8 [&ref] | provenance | |
|
||||
| test_cipher.rs:41:29:41:76 | [...] | test_cipher.rs:41:28:41:76 | &... [&ref] | provenance | |
|
||||
| test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | test_cipher.rs:42:30:42:47 | ...::new | provenance | MaD:2 Sink:MaD:2 |
|
||||
| test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | test_cipher.rs:42:30:42:47 | ...::new | provenance | MaD:4 Sink:MaD:4 |
|
||||
| test_cipher.rs:42:73:42:78 | const8 [&ref] | test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | provenance | MaD:7 |
|
||||
| test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | test_cipher.rs:42:30:42:47 | ...::new | provenance | MaD:3 Sink:MaD:3 |
|
||||
| test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | test_cipher.rs:42:30:42:47 | ...::new | provenance | MaD:5 Sink:MaD:5 |
|
||||
| test_cipher.rs:42:73:42:78 | const8 [&ref] | test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | provenance | MaD:10 |
|
||||
| test_cipher.rs:50:9:50:15 | const10 [element] | test_cipher.rs:51:75:51:81 | const10 [element] | provenance | |
|
||||
| test_cipher.rs:50:37:50:52 | ...::zeroed | test_cipher.rs:50:37:50:54 | ...::zeroed(...) [element] | provenance | Src:MaD:6 |
|
||||
| test_cipher.rs:50:37:50:52 | ...::zeroed | test_cipher.rs:50:37:50:54 | ...::zeroed(...) [element] | provenance | Src:MaD:8 |
|
||||
| test_cipher.rs:50:37:50:54 | ...::zeroed(...) [element] | test_cipher.rs:50:9:50:15 | const10 [element] | provenance | |
|
||||
| test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | test_cipher.rs:51:31:51:48 | ...::new | provenance | MaD:2 Sink:MaD:2 Sink:MaD:2 |
|
||||
| test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | test_cipher.rs:51:31:51:48 | ...::new | provenance | MaD:4 Sink:MaD:4 Sink:MaD:4 |
|
||||
| test_cipher.rs:51:74:51:81 | &const10 [&ref, element] | test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | provenance | MaD:7 |
|
||||
| test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | test_cipher.rs:51:31:51:48 | ...::new | provenance | MaD:3 Sink:MaD:3 Sink:MaD:3 |
|
||||
| test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | test_cipher.rs:51:31:51:48 | ...::new | provenance | MaD:5 Sink:MaD:5 Sink:MaD:5 |
|
||||
| test_cipher.rs:51:74:51:81 | &const10 [&ref, element] | test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | provenance | MaD:10 |
|
||||
| test_cipher.rs:51:75:51:81 | const10 [element] | test_cipher.rs:51:74:51:81 | &const10 [&ref, element] | provenance | |
|
||||
| test_cipher.rs:73:9:73:14 | const2 [&ref, element] | test_cipher.rs:74:46:74:51 | const2 [&ref, element] | provenance | |
|
||||
| test_cipher.rs:73:18:73:26 | &... [&ref, element] | test_cipher.rs:73:9:73:14 | const2 [&ref, element] | provenance | |
|
||||
| test_cipher.rs:73:19:73:26 | [0u8; 32] [element] | test_cipher.rs:73:18:73:26 | &... [&ref, element] | provenance | |
|
||||
| test_cipher.rs:73:20:73:22 | 0u8 | test_cipher.rs:73:19:73:26 | [0u8; 32] [element] | provenance | |
|
||||
| test_cipher.rs:74:46:74:51 | const2 [&ref, element] | test_cipher.rs:74:23:74:44 | ...::new_from_slice | provenance | MaD:1 Sink:MaD:1 Sink:MaD:1 |
|
||||
| test_cookie.rs:17:9:17:14 | array1 [element] | test_cookie.rs:18:27:18:32 | array1 [element] | provenance | |
|
||||
| test_cookie.rs:17:28:17:34 | [0; 64] [element] | test_cookie.rs:17:9:17:14 | array1 [element] | provenance | |
|
||||
| test_cookie.rs:17:29:17:29 | 0 | test_cookie.rs:17:28:17:34 | [0; 64] [element] | provenance | |
|
||||
| test_cookie.rs:18:26:18:32 | &array1 [&ref, element] | test_cookie.rs:18:16:18:24 | ...::from | provenance | MaD:7 Sink:MaD:7 |
|
||||
| test_cookie.rs:18:27:18:32 | array1 [element] | test_cookie.rs:18:26:18:32 | &array1 [&ref, element] | provenance | |
|
||||
| test_cookie.rs:21:9:21:14 | array2 [element] | test_cookie.rs:22:27:22:32 | array2 [element] | provenance | |
|
||||
| test_cookie.rs:21:28:21:34 | [0; 64] [element] | test_cookie.rs:21:9:21:14 | array2 [element] | provenance | |
|
||||
| test_cookie.rs:21:29:21:29 | 0 | test_cookie.rs:21:28:21:34 | [0; 64] [element] | provenance | |
|
||||
| test_cookie.rs:22:26:22:32 | &array2 [&ref, element] | test_cookie.rs:22:16:22:24 | ...::from | provenance | MaD:7 Sink:MaD:7 |
|
||||
| test_cookie.rs:22:27:22:32 | array2 [element] | test_cookie.rs:22:26:22:32 | &array2 [&ref, element] | provenance | |
|
||||
| test_cookie.rs:38:9:38:14 | array2 [element] | test_cookie.rs:42:34:42:39 | array2 [element] | provenance | |
|
||||
| test_cookie.rs:38:18:38:37 | ...::from(...) [element] | test_cookie.rs:38:9:38:14 | array2 [element] | provenance | |
|
||||
| test_cookie.rs:38:28:38:36 | [0u8; 64] [element] | test_cookie.rs:38:18:38:37 | ...::from(...) [element] | provenance | MaD:9 |
|
||||
| test_cookie.rs:38:29:38:31 | 0u8 | test_cookie.rs:38:28:38:36 | [0u8; 64] [element] | provenance | |
|
||||
| test_cookie.rs:42:34:42:39 | array2 [element] | test_cookie.rs:42:14:42:32 | ...::from | provenance | MaD:2 Sink:MaD:2 |
|
||||
| test_cookie.rs:49:9:49:14 | array3 [element] | test_cookie.rs:53:34:53:39 | array3 [element] | provenance | |
|
||||
| test_cookie.rs:49:23:49:25 | 0u8 | test_cookie.rs:49:23:49:29 | ...::from_elem(...) [element] | provenance | MaD:11 |
|
||||
| test_cookie.rs:49:23:49:29 | ...::from_elem(...) [element] | test_cookie.rs:49:9:49:14 | array3 [element] | provenance | |
|
||||
| test_cookie.rs:53:34:53:39 | array3 [element] | test_cookie.rs:53:14:53:32 | ...::from | provenance | MaD:2 Sink:MaD:2 |
|
||||
models
|
||||
| 1 | Sink: <_ as crypto_common::KeyInit>::new_from_slice; Argument[0]; credentials-key |
|
||||
| 2 | Sink: <cipher::stream_wrapper::StreamCipherCoreWrapper as crypto_common::KeyInit>::new; Argument[0]; credentials-key |
|
||||
| 3 | Sink: <cipher::stream_wrapper::StreamCipherCoreWrapper as crypto_common::KeyInit>::new; Argument[1]; credentials-iv |
|
||||
| 4 | Sink: <cipher::stream_wrapper::StreamCipherCoreWrapper as crypto_common::KeyIvInit>::new; Argument[0]; credentials-key |
|
||||
| 5 | Sink: <cipher::stream_wrapper::StreamCipherCoreWrapper as crypto_common::KeyIvInit>::new; Argument[1]; credentials-iv |
|
||||
| 6 | Source: core::mem::zeroed; ReturnValue.Element; constant-source |
|
||||
| 7 | Summary: <generic_array::GenericArray>::from_slice; Argument[0].Reference; ReturnValue.Reference; value |
|
||||
| 2 | Sink: <biscotti::crypto::master::Key>::from; Argument[0]; credentials-key |
|
||||
| 3 | Sink: <cipher::stream_wrapper::StreamCipherCoreWrapper as crypto_common::KeyInit>::new; Argument[0]; credentials-key |
|
||||
| 4 | Sink: <cipher::stream_wrapper::StreamCipherCoreWrapper as crypto_common::KeyInit>::new; Argument[1]; credentials-iv |
|
||||
| 5 | Sink: <cipher::stream_wrapper::StreamCipherCoreWrapper as crypto_common::KeyIvInit>::new; Argument[0]; credentials-key |
|
||||
| 6 | Sink: <cipher::stream_wrapper::StreamCipherCoreWrapper as crypto_common::KeyIvInit>::new; Argument[1]; credentials-iv |
|
||||
| 7 | Sink: <cookie::secure::key::Key>::from; Argument[0].Reference; credentials-key |
|
||||
| 8 | Source: core::mem::zeroed; ReturnValue.Element; constant-source |
|
||||
| 9 | Summary: <_ as core::convert::From>::from; Argument[0]; ReturnValue; value |
|
||||
| 10 | Summary: <generic_array::GenericArray>::from_slice; Argument[0].Reference; ReturnValue.Reference; value |
|
||||
| 11 | Summary: alloc::vec::from_elem; Argument[0]; ReturnValue.Element; value |
|
||||
nodes
|
||||
| test_cipher.rs:18:9:18:14 | const1 [&ref, element] | semmle.label | const1 [&ref, element] |
|
||||
| test_cipher.rs:18:28:18:36 | &... [&ref, element] | semmle.label | &... [&ref, element] |
|
||||
@@ -119,4 +146,27 @@ nodes
|
||||
| test_cipher.rs:73:20:73:22 | 0u8 | semmle.label | 0u8 |
|
||||
| test_cipher.rs:74:23:74:44 | ...::new_from_slice | semmle.label | ...::new_from_slice |
|
||||
| test_cipher.rs:74:46:74:51 | const2 [&ref, element] | semmle.label | const2 [&ref, element] |
|
||||
| test_cookie.rs:17:9:17:14 | array1 [element] | semmle.label | array1 [element] |
|
||||
| test_cookie.rs:17:28:17:34 | [0; 64] [element] | semmle.label | [0; 64] [element] |
|
||||
| test_cookie.rs:17:29:17:29 | 0 | semmle.label | 0 |
|
||||
| test_cookie.rs:18:16:18:24 | ...::from | semmle.label | ...::from |
|
||||
| test_cookie.rs:18:26:18:32 | &array1 [&ref, element] | semmle.label | &array1 [&ref, element] |
|
||||
| test_cookie.rs:18:27:18:32 | array1 [element] | semmle.label | array1 [element] |
|
||||
| test_cookie.rs:21:9:21:14 | array2 [element] | semmle.label | array2 [element] |
|
||||
| test_cookie.rs:21:28:21:34 | [0; 64] [element] | semmle.label | [0; 64] [element] |
|
||||
| test_cookie.rs:21:29:21:29 | 0 | semmle.label | 0 |
|
||||
| test_cookie.rs:22:16:22:24 | ...::from | semmle.label | ...::from |
|
||||
| test_cookie.rs:22:26:22:32 | &array2 [&ref, element] | semmle.label | &array2 [&ref, element] |
|
||||
| test_cookie.rs:22:27:22:32 | array2 [element] | semmle.label | array2 [element] |
|
||||
| test_cookie.rs:38:9:38:14 | array2 [element] | semmle.label | array2 [element] |
|
||||
| test_cookie.rs:38:18:38:37 | ...::from(...) [element] | semmle.label | ...::from(...) [element] |
|
||||
| test_cookie.rs:38:28:38:36 | [0u8; 64] [element] | semmle.label | [0u8; 64] [element] |
|
||||
| test_cookie.rs:38:29:38:31 | 0u8 | semmle.label | 0u8 |
|
||||
| test_cookie.rs:42:14:42:32 | ...::from | semmle.label | ...::from |
|
||||
| test_cookie.rs:42:34:42:39 | array2 [element] | semmle.label | array2 [element] |
|
||||
| test_cookie.rs:49:9:49:14 | array3 [element] | semmle.label | array3 [element] |
|
||||
| test_cookie.rs:49:23:49:25 | 0u8 | semmle.label | 0u8 |
|
||||
| test_cookie.rs:49:23:49:29 | ...::from_elem(...) [element] | semmle.label | ...::from_elem(...) [element] |
|
||||
| test_cookie.rs:53:14:53:32 | ...::from | semmle.label | ...::from |
|
||||
| test_cookie.rs:53:34:53:39 | array3 [element] | semmle.label | array3 [element] |
|
||||
subpaths
|
||||
|
||||
@@ -8,3 +8,5 @@ qltest_dependencies:
|
||||
- base64 = { version = "0.22.1" }
|
||||
- getrandom = { version = "0.3.1" }
|
||||
- getrandom2 = { package = "getrandom", version = "0.2.15" }
|
||||
- cookie = { version = "0.18.1", features = ["signed", "private"] }
|
||||
- biscotti = { version = "0.4.3" }
|
||||
|
||||
58
rust/ql/test/query-tests/security/CWE-798/test_cookie.rs
Normal file
58
rust/ql/test/query-tests/security/CWE-798/test_cookie.rs
Normal file
@@ -0,0 +1,58 @@
|
||||
|
||||
use cookie::{CookieJar, SignedJar, PrivateJar, Key};
|
||||
|
||||
// --- tests ---
|
||||
|
||||
fn test_cookie_jar(array_var: &[u8]) {
|
||||
let mut jar = CookieJar::new();
|
||||
|
||||
let key_generate = Key::generate(); // good
|
||||
_ = jar.signed_mut(&key_generate);
|
||||
_ = jar.private_mut(&key_generate);
|
||||
|
||||
let key_var = Key::from(array_var); // good
|
||||
_ = jar.signed_mut(&key_var);
|
||||
_ = jar.private_mut(&key_var);
|
||||
|
||||
let array1: [u8; 64] = [0; 64]; // $ Alert[rust/hard-coded-cryptographic-value]
|
||||
let key1 = Key::from(&array1); // $ Sink
|
||||
_ = jar.signed_mut(&key1);
|
||||
|
||||
let array2: [u8; 64] = [0; 64]; // $ Alert[rust/hard-coded-cryptographic-value]
|
||||
let key2 = Key::from(&array2); // $ Sink
|
||||
_ = jar.private_mut(&key2);
|
||||
}
|
||||
|
||||
fn test_biscotti_crypto(array_var: &[u8]) {
|
||||
let mut config1 = biscotti::ProcessorConfig::default();
|
||||
let crypto_rules1 = biscotti::config::CryptoRule {
|
||||
cookie_names: vec!["name".to_string()],
|
||||
algorithm: biscotti::config::CryptoAlgorithm::Signing,
|
||||
key: biscotti::Key::generate(), // good
|
||||
fallbacks: vec![],
|
||||
};
|
||||
config1.crypto_rules.push(crypto_rules1);
|
||||
let processor1: biscotti::Processor = config1.into();
|
||||
|
||||
let mut config2 = biscotti::ProcessorConfig::default();
|
||||
let array2 = Vec::from([0u8; 64]); // $ Alert[rust/hard-coded-cryptographic-value]
|
||||
let crypto_rules2 = biscotti::config::CryptoRule {
|
||||
cookie_names: vec!["name".to_string()],
|
||||
algorithm: biscotti::config::CryptoAlgorithm::Signing,
|
||||
key: biscotti::Key::from(array2), // $ Sink
|
||||
fallbacks: vec![],
|
||||
};
|
||||
config2.crypto_rules.push(crypto_rules2);
|
||||
let processor2: biscotti::Processor = config2.into();
|
||||
|
||||
let mut config3 = biscotti::ProcessorConfig::default();
|
||||
let array3 = vec![0u8; 64]; // $ Alert[rust/hard-coded-cryptographic-value]
|
||||
let crypto_rules3 = biscotti::config::CryptoRule {
|
||||
cookie_names: vec!["name".to_string()],
|
||||
algorithm: biscotti::config::CryptoAlgorithm::Signing,
|
||||
key: biscotti::Key::from(array3), // $ Sink
|
||||
fallbacks: vec![],
|
||||
};
|
||||
config3.crypto_rules.push(crypto_rules3);
|
||||
let processor3: biscotti::Processor = config3.into();
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
multipleCallTargets
|
||||
| request_forgery_tests.rs:30:36:30:51 | user_url.as_str() |
|
||||
| request_forgery_tests.rs:30:36:30:52 | user_url.as_str() |
|
||||
1997
rust/ql/test/query-tests/security/CWE-918/Cargo.lock
generated
Normal file
1997
rust/ql/test/query-tests/security/CWE-918/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,105 @@
|
||||
#select
|
||||
| request_forgery_tests.rs:8:24:8:35 | ...::get | request_forgery_tests.rs:5:29:5:36 | user_url | request_forgery_tests.rs:8:24:8:35 | ...::get | The URL of this request depends on a $@. | request_forgery_tests.rs:5:29:5:36 | user_url | user-provided value |
|
||||
| request_forgery_tests.rs:8:24:8:35 | ...::get | request_forgery_tests.rs:5:29:5:36 | user_url | request_forgery_tests.rs:8:24:8:35 | ...::get | The URL of this request depends on a $@. | request_forgery_tests.rs:5:29:5:36 | user_url | user-provided value |
|
||||
| request_forgery_tests.rs:17:25:17:36 | ...::get | request_forgery_tests.rs:5:29:5:36 | user_url | request_forgery_tests.rs:17:25:17:36 | ...::get | The URL of this request depends on a $@. | request_forgery_tests.rs:5:29:5:36 | user_url | user-provided value |
|
||||
| request_forgery_tests.rs:21:25:21:36 | ...::get | request_forgery_tests.rs:5:29:5:36 | user_url | request_forgery_tests.rs:21:25:21:36 | ...::get | The URL of this request depends on a $@. | request_forgery_tests.rs:5:29:5:36 | user_url | user-provided value |
|
||||
| request_forgery_tests.rs:25:25:25:36 | ...::get | request_forgery_tests.rs:5:29:5:36 | user_url | request_forgery_tests.rs:25:25:25:36 | ...::get | The URL of this request depends on a $@. | request_forgery_tests.rs:5:29:5:36 | user_url | user-provided value |
|
||||
| request_forgery_tests.rs:31:29:31:40 | ...::get | request_forgery_tests.rs:5:29:5:36 | user_url | request_forgery_tests.rs:31:29:31:40 | ...::get | The URL of this request depends on a $@. | request_forgery_tests.rs:5:29:5:36 | user_url | user-provided value |
|
||||
| request_forgery_tests.rs:31:29:31:40 | ...::get | request_forgery_tests.rs:5:29:5:36 | user_url | request_forgery_tests.rs:31:29:31:40 | ...::get | The URL of this request depends on a $@. | request_forgery_tests.rs:5:29:5:36 | user_url | user-provided value |
|
||||
| request_forgery_tests.rs:37:37:37:48 | ...::get | request_forgery_tests.rs:5:29:5:36 | user_url | request_forgery_tests.rs:37:37:37:48 | ...::get | The URL of this request depends on a $@. | request_forgery_tests.rs:5:29:5:36 | user_url | user-provided value |
|
||||
| request_forgery_tests.rs:37:37:37:48 | ...::get | request_forgery_tests.rs:5:29:5:36 | user_url | request_forgery_tests.rs:37:37:37:48 | ...::get | The URL of this request depends on a $@. | request_forgery_tests.rs:5:29:5:36 | user_url | user-provided value |
|
||||
edges
|
||||
| request_forgery_tests.rs:4:5:4:14 | res | request_forgery_tests.rs:16:27:16:49 | { ... } | provenance | |
|
||||
| request_forgery_tests.rs:4:5:4:14 | res | request_forgery_tests.rs:20:27:20:57 | { ... } | provenance | |
|
||||
| request_forgery_tests.rs:4:5:4:14 | res | request_forgery_tests.rs:24:27:24:70 | { ... } | provenance | |
|
||||
| request_forgery_tests.rs:5:29:5:36 | user_url | request_forgery_tests.rs:8:38:8:45 | user_url | provenance | |
|
||||
| request_forgery_tests.rs:5:29:5:36 | user_url | request_forgery_tests.rs:8:38:8:45 | user_url | provenance | |
|
||||
| request_forgery_tests.rs:5:29:5:36 | user_url | request_forgery_tests.rs:16:27:16:49 | MacroExpr | provenance | |
|
||||
| request_forgery_tests.rs:5:29:5:36 | user_url | request_forgery_tests.rs:20:27:20:57 | MacroExpr | provenance | |
|
||||
| request_forgery_tests.rs:5:29:5:36 | user_url | request_forgery_tests.rs:24:27:24:70 | MacroExpr | provenance | |
|
||||
| request_forgery_tests.rs:5:29:5:36 | user_url | request_forgery_tests.rs:31:43:31:50 | user_url | provenance | |
|
||||
| request_forgery_tests.rs:5:29:5:36 | user_url | request_forgery_tests.rs:31:43:31:50 | user_url | provenance | |
|
||||
| request_forgery_tests.rs:5:29:5:36 | user_url | request_forgery_tests.rs:37:51:37:58 | user_url | provenance | |
|
||||
| request_forgery_tests.rs:5:29:5:36 | user_url | request_forgery_tests.rs:37:51:37:58 | user_url | provenance | |
|
||||
| request_forgery_tests.rs:8:37:8:45 | &user_url [&ref] | request_forgery_tests.rs:8:24:8:35 | ...::get | provenance | MaD:3680 Sink:MaD:3680 |
|
||||
| request_forgery_tests.rs:8:37:8:45 | &user_url [&ref] | request_forgery_tests.rs:8:24:8:35 | ...::get | provenance | MaD:3680 Sink:MaD:3680 |
|
||||
| request_forgery_tests.rs:8:38:8:45 | user_url | request_forgery_tests.rs:8:37:8:45 | &user_url [&ref] | provenance | |
|
||||
| request_forgery_tests.rs:8:38:8:45 | user_url | request_forgery_tests.rs:8:37:8:45 | &user_url [&ref] | provenance | |
|
||||
| request_forgery_tests.rs:16:13:16:15 | url | request_forgery_tests.rs:17:39:17:41 | url | provenance | |
|
||||
| request_forgery_tests.rs:16:27:16:49 | ...::format(...) | request_forgery_tests.rs:4:5:4:14 | res | provenance | |
|
||||
| request_forgery_tests.rs:16:27:16:49 | ...::must_use(...) | request_forgery_tests.rs:16:13:16:15 | url | provenance | |
|
||||
| request_forgery_tests.rs:16:27:16:49 | MacroExpr | request_forgery_tests.rs:16:27:16:49 | ...::format(...) | provenance | MaD:291 |
|
||||
| request_forgery_tests.rs:16:27:16:49 | { ... } | request_forgery_tests.rs:16:27:16:49 | ...::must_use(...) | provenance | MaD:10629 |
|
||||
| request_forgery_tests.rs:17:38:17:41 | &url [&ref] | request_forgery_tests.rs:17:25:17:36 | ...::get | provenance | MaD:3680 Sink:MaD:3680 |
|
||||
| request_forgery_tests.rs:17:39:17:41 | url | request_forgery_tests.rs:17:38:17:41 | &url [&ref] | provenance | |
|
||||
| request_forgery_tests.rs:20:13:20:15 | url | request_forgery_tests.rs:21:39:21:41 | url | provenance | |
|
||||
| request_forgery_tests.rs:20:27:20:57 | ...::format(...) | request_forgery_tests.rs:4:5:4:14 | res | provenance | |
|
||||
| request_forgery_tests.rs:20:27:20:57 | ...::must_use(...) | request_forgery_tests.rs:20:13:20:15 | url | provenance | |
|
||||
| request_forgery_tests.rs:20:27:20:57 | MacroExpr | request_forgery_tests.rs:20:27:20:57 | ...::format(...) | provenance | MaD:291 |
|
||||
| request_forgery_tests.rs:20:27:20:57 | { ... } | request_forgery_tests.rs:20:27:20:57 | ...::must_use(...) | provenance | MaD:10629 |
|
||||
| request_forgery_tests.rs:21:38:21:41 | &url [&ref] | request_forgery_tests.rs:21:25:21:36 | ...::get | provenance | MaD:3680 Sink:MaD:3680 |
|
||||
| request_forgery_tests.rs:21:39:21:41 | url | request_forgery_tests.rs:21:38:21:41 | &url [&ref] | provenance | |
|
||||
| request_forgery_tests.rs:24:13:24:15 | url | request_forgery_tests.rs:25:39:25:41 | url | provenance | |
|
||||
| request_forgery_tests.rs:24:27:24:70 | ...::format(...) | request_forgery_tests.rs:4:5:4:14 | res | provenance | |
|
||||
| request_forgery_tests.rs:24:27:24:70 | ...::must_use(...) | request_forgery_tests.rs:24:13:24:15 | url | provenance | |
|
||||
| request_forgery_tests.rs:24:27:24:70 | MacroExpr | request_forgery_tests.rs:24:27:24:70 | ...::format(...) | provenance | MaD:291 |
|
||||
| request_forgery_tests.rs:24:27:24:70 | { ... } | request_forgery_tests.rs:24:27:24:70 | ...::must_use(...) | provenance | MaD:10629 |
|
||||
| request_forgery_tests.rs:25:38:25:41 | &url [&ref] | request_forgery_tests.rs:25:25:25:36 | ...::get | provenance | MaD:3680 Sink:MaD:3680 |
|
||||
| request_forgery_tests.rs:25:39:25:41 | url | request_forgery_tests.rs:25:38:25:41 | &url [&ref] | provenance | |
|
||||
| request_forgery_tests.rs:31:42:31:50 | &user_url [&ref] | request_forgery_tests.rs:31:29:31:40 | ...::get | provenance | MaD:3680 Sink:MaD:3680 |
|
||||
| request_forgery_tests.rs:31:42:31:50 | &user_url [&ref] | request_forgery_tests.rs:31:29:31:40 | ...::get | provenance | MaD:3680 Sink:MaD:3680 |
|
||||
| request_forgery_tests.rs:31:43:31:50 | user_url | request_forgery_tests.rs:31:42:31:50 | &user_url [&ref] | provenance | |
|
||||
| request_forgery_tests.rs:31:43:31:50 | user_url | request_forgery_tests.rs:31:42:31:50 | &user_url [&ref] | provenance | |
|
||||
| request_forgery_tests.rs:37:50:37:58 | &user_url [&ref] | request_forgery_tests.rs:37:37:37:48 | ...::get | provenance | MaD:3680 Sink:MaD:3680 |
|
||||
| request_forgery_tests.rs:37:50:37:58 | &user_url [&ref] | request_forgery_tests.rs:37:37:37:48 | ...::get | provenance | MaD:3680 Sink:MaD:3680 |
|
||||
| request_forgery_tests.rs:37:51:37:58 | user_url | request_forgery_tests.rs:37:50:37:58 | &user_url [&ref] | provenance | |
|
||||
| request_forgery_tests.rs:37:51:37:58 | user_url | request_forgery_tests.rs:37:50:37:58 | &user_url [&ref] | provenance | |
|
||||
nodes
|
||||
| request_forgery_tests.rs:4:5:4:14 | res | semmle.label | res |
|
||||
| request_forgery_tests.rs:4:5:4:14 | res | semmle.label | res |
|
||||
| request_forgery_tests.rs:4:5:4:14 | res | semmle.label | res |
|
||||
| request_forgery_tests.rs:5:29:5:36 | user_url | semmle.label | user_url |
|
||||
| request_forgery_tests.rs:5:29:5:36 | user_url | semmle.label | user_url |
|
||||
| request_forgery_tests.rs:8:24:8:35 | ...::get | semmle.label | ...::get |
|
||||
| request_forgery_tests.rs:8:24:8:35 | ...::get | semmle.label | ...::get |
|
||||
| request_forgery_tests.rs:8:37:8:45 | &user_url [&ref] | semmle.label | &user_url [&ref] |
|
||||
| request_forgery_tests.rs:8:37:8:45 | &user_url [&ref] | semmle.label | &user_url [&ref] |
|
||||
| request_forgery_tests.rs:8:38:8:45 | user_url | semmle.label | user_url |
|
||||
| request_forgery_tests.rs:8:38:8:45 | user_url | semmle.label | user_url |
|
||||
| request_forgery_tests.rs:16:13:16:15 | url | semmle.label | url |
|
||||
| request_forgery_tests.rs:16:27:16:49 | ...::format(...) | semmle.label | ...::format(...) |
|
||||
| request_forgery_tests.rs:16:27:16:49 | ...::must_use(...) | semmle.label | ...::must_use(...) |
|
||||
| request_forgery_tests.rs:16:27:16:49 | MacroExpr | semmle.label | MacroExpr |
|
||||
| request_forgery_tests.rs:16:27:16:49 | { ... } | semmle.label | { ... } |
|
||||
| request_forgery_tests.rs:17:25:17:36 | ...::get | semmle.label | ...::get |
|
||||
| request_forgery_tests.rs:17:38:17:41 | &url [&ref] | semmle.label | &url [&ref] |
|
||||
| request_forgery_tests.rs:17:39:17:41 | url | semmle.label | url |
|
||||
| request_forgery_tests.rs:20:13:20:15 | url | semmle.label | url |
|
||||
| request_forgery_tests.rs:20:27:20:57 | ...::format(...) | semmle.label | ...::format(...) |
|
||||
| request_forgery_tests.rs:20:27:20:57 | ...::must_use(...) | semmle.label | ...::must_use(...) |
|
||||
| request_forgery_tests.rs:20:27:20:57 | MacroExpr | semmle.label | MacroExpr |
|
||||
| request_forgery_tests.rs:20:27:20:57 | { ... } | semmle.label | { ... } |
|
||||
| request_forgery_tests.rs:21:25:21:36 | ...::get | semmle.label | ...::get |
|
||||
| request_forgery_tests.rs:21:38:21:41 | &url [&ref] | semmle.label | &url [&ref] |
|
||||
| request_forgery_tests.rs:21:39:21:41 | url | semmle.label | url |
|
||||
| request_forgery_tests.rs:24:13:24:15 | url | semmle.label | url |
|
||||
| request_forgery_tests.rs:24:27:24:70 | ...::format(...) | semmle.label | ...::format(...) |
|
||||
| request_forgery_tests.rs:24:27:24:70 | ...::must_use(...) | semmle.label | ...::must_use(...) |
|
||||
| request_forgery_tests.rs:24:27:24:70 | MacroExpr | semmle.label | MacroExpr |
|
||||
| request_forgery_tests.rs:24:27:24:70 | { ... } | semmle.label | { ... } |
|
||||
| request_forgery_tests.rs:25:25:25:36 | ...::get | semmle.label | ...::get |
|
||||
| request_forgery_tests.rs:25:38:25:41 | &url [&ref] | semmle.label | &url [&ref] |
|
||||
| request_forgery_tests.rs:25:39:25:41 | url | semmle.label | url |
|
||||
| request_forgery_tests.rs:31:29:31:40 | ...::get | semmle.label | ...::get |
|
||||
| request_forgery_tests.rs:31:29:31:40 | ...::get | semmle.label | ...::get |
|
||||
| request_forgery_tests.rs:31:42:31:50 | &user_url [&ref] | semmle.label | &user_url [&ref] |
|
||||
| request_forgery_tests.rs:31:42:31:50 | &user_url [&ref] | semmle.label | &user_url [&ref] |
|
||||
| request_forgery_tests.rs:31:43:31:50 | user_url | semmle.label | user_url |
|
||||
| request_forgery_tests.rs:31:43:31:50 | user_url | semmle.label | user_url |
|
||||
| request_forgery_tests.rs:37:37:37:48 | ...::get | semmle.label | ...::get |
|
||||
| request_forgery_tests.rs:37:37:37:48 | ...::get | semmle.label | ...::get |
|
||||
| request_forgery_tests.rs:37:50:37:58 | &user_url [&ref] | semmle.label | &user_url [&ref] |
|
||||
| request_forgery_tests.rs:37:50:37:58 | &user_url [&ref] | semmle.label | &user_url [&ref] |
|
||||
| request_forgery_tests.rs:37:51:37:58 | user_url | semmle.label | user_url |
|
||||
| request_forgery_tests.rs:37:51:37:58 | user_url | semmle.label | user_url |
|
||||
subpaths
|
||||
@@ -0,0 +1,2 @@
|
||||
query: queries/security/CWE-918/RequestForgery.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
5
rust/ql/test/query-tests/security/CWE-918/main.rs
Normal file
5
rust/ql/test/query-tests/security/CWE-918/main.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
use test::request_forgery_tests;
|
||||
|
||||
fn main() {
|
||||
request_forgery_tests::start();
|
||||
}
|
||||
5
rust/ql/test/query-tests/security/CWE-918/options.yml
Normal file
5
rust/ql/test/query-tests/security/CWE-918/options.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
qltest_cargo_check: true
|
||||
qltest_dependencies:
|
||||
- reqwest = { version = "0.12.23", features = ["blocking", "json"] }
|
||||
- tokio = { version = "1.0", features = ["full"] }
|
||||
- poem = { version = "3.1.12", features = ["server"] }
|
||||
@@ -0,0 +1,63 @@
|
||||
mod poem_server {
|
||||
use poem::{handler, web::Query, Route, Server};
|
||||
|
||||
#[handler]
|
||||
async fn endpoint(Query(user_url): Query<String>, // $ Source=user_url
|
||||
) -> String {
|
||||
// BAD: The user can control the entire URL
|
||||
let response = reqwest::get(&user_url).await; // $ Alert[rust/request-forgery]=user_url
|
||||
|
||||
// If this example is actually executed, forward the response text
|
||||
if let Ok(resp) = response {
|
||||
return resp.text().await.unwrap_or_default();
|
||||
}
|
||||
|
||||
// BAD: The user can control a prefix of the URL
|
||||
let url = format!("{}/resource", user_url);
|
||||
let _response = reqwest::get(&url).await; // $ Alert[rust/request-forgery]=user_url
|
||||
|
||||
// BAD: The user can control a prefix of the URL - only the protocol is restricted
|
||||
let url = format!("https://{}/resource", user_url);
|
||||
let _response = reqwest::get(&url).await; // $ Alert[rust/request-forgery]=user_url
|
||||
|
||||
// GOOD: The user can only control a suffix after the hostname, this is likely ok
|
||||
let url = format!("https://hostname.com/resource/{}", user_url);
|
||||
let _response = reqwest::get(&url).await; // $ SPURIOUS: Alert[rust/request-forgery]=user_url
|
||||
|
||||
let allowed_hosts = ["api.example.com", "trusted-service.com"];
|
||||
|
||||
// GOOD: The URL is guaranteed to be in the allowlist
|
||||
if allowed_hosts.contains(&user_url.as_str()) {
|
||||
let _response = reqwest::get(&user_url).await; // $ SPURIOUS: Alert[rust/request-forgery]=user_url
|
||||
}
|
||||
|
||||
if let Ok(url) = reqwest::Url::parse(&user_url) {
|
||||
if let Some(host) = url.host_str() {
|
||||
if allowed_hosts.contains(&host) {
|
||||
let _response = reqwest::get(&user_url).await; // $ SPURIOUS: Alert[rust/request-forgery]=user_url
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"".to_string()
|
||||
}
|
||||
|
||||
// Function to create the Poem application
|
||||
pub async fn create_app() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let app = Route::new().at("/fetch", poem::get(endpoint));
|
||||
|
||||
Server::new(poem::listener::TcpListener::bind("127.0.0.1:8080"))
|
||||
.run(app)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Start the Poem web application
|
||||
pub fn start() {
|
||||
tokio::runtime::Runtime::new()
|
||||
.unwrap()
|
||||
.block_on(poem_server::create_app())
|
||||
.unwrap();
|
||||
}
|
||||
@@ -919,6 +919,15 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
|
||||
signature module SatisfiesConstraintInputSig<HasTypeTreeSig HasTypeTree> {
|
||||
/** Holds if it is relevant to know if `term` satisfies `constraint`. */
|
||||
predicate relevantConstraint(HasTypeTree term, Type constraint);
|
||||
|
||||
/**
|
||||
* Holds if constraints that are satisfied through conditions that are
|
||||
* universally quantified type parameters should be used. Such type
|
||||
* parameters might have type parameter constraints, and these are _not_
|
||||
* checked. Hence using these represent a trade-off between too many
|
||||
* constraints and too few constraints being satisfied.
|
||||
*/
|
||||
default predicate useUniversalConditions() { any() }
|
||||
}
|
||||
|
||||
module SatisfiesConstraint<
|
||||
@@ -961,6 +970,7 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
|
||||
TypeMention constraintMention
|
||||
) {
|
||||
exists(Type type | hasTypeConstraint(tt, type, constraint) |
|
||||
useUniversalConditions() and
|
||||
not exists(countConstraintImplementations(type, constraint)) and
|
||||
conditionSatisfiesConstraintTypeAt(abs, condition, constraintMention, _, _) and
|
||||
resolveTypeMentionRoot(condition) = abs.getATypeParameter() and
|
||||
|
||||
Reference in New Issue
Block a user