diff --git a/rust/ql/integration-tests/hello-project/summary.expected b/rust/ql/integration-tests/hello-project/summary.expected index 20f4b216b64c..343b06a93b4c 100644 --- a/rust/ql/integration-tests/hello-project/summary.expected +++ b/rust/ql/integration-tests/hello-project/summary.expected @@ -14,11 +14,11 @@ | Macro calls - resolved | 2 | | Macro calls - total | 2 | | Macro calls - unresolved | 0 | -| Taint edges - number of edges | 2 | +| Taint edges - number of edges | 3 | | Taint reach - nodes tainted | 0 | | Taint reach - per million nodes | 0 | | Taint sinks - cryptographic operations | 0 | -| Taint sinks - query sinks | 0 | +| Taint sinks - query sinks | 1 | | Taint sources - active | 0 | | Taint sources - disabled | 0 | | Taint sources - sensitive data | 0 | diff --git a/rust/ql/integration-tests/hello-workspace/summary.cargo.expected b/rust/ql/integration-tests/hello-workspace/summary.cargo.expected index e0d5ce240a39..24a7bbf392fe 100644 --- a/rust/ql/integration-tests/hello-workspace/summary.cargo.expected +++ b/rust/ql/integration-tests/hello-workspace/summary.cargo.expected @@ -14,11 +14,11 @@ | Macro calls - resolved | 2 | | Macro calls - total | 2 | | Macro calls - unresolved | 0 | -| Taint edges - number of edges | 2 | +| Taint edges - number of edges | 3 | | Taint reach - nodes tainted | 0 | | Taint reach - per million nodes | 0 | | Taint sinks - cryptographic operations | 0 | -| Taint sinks - query sinks | 0 | +| Taint sinks - query sinks | 1 | | Taint sources - active | 0 | | Taint sources - disabled | 0 | | Taint sources - sensitive data | 0 | diff --git a/rust/ql/integration-tests/hello-workspace/summary.rust-project.expected b/rust/ql/integration-tests/hello-workspace/summary.rust-project.expected index e0d5ce240a39..24a7bbf392fe 100644 --- a/rust/ql/integration-tests/hello-workspace/summary.rust-project.expected +++ b/rust/ql/integration-tests/hello-workspace/summary.rust-project.expected @@ -14,11 +14,11 @@ | Macro calls - resolved | 2 | | Macro calls - total | 2 | | Macro calls - unresolved | 0 | -| Taint edges - number of edges | 2 | +| Taint edges - number of edges | 3 | | Taint reach - nodes tainted | 0 | | Taint reach - per million nodes | 0 | | Taint sinks - cryptographic operations | 0 | -| Taint sinks - query sinks | 0 | +| Taint sinks - query sinks | 1 | | Taint sources - active | 0 | | Taint sources - disabled | 0 | | Taint sources - sensitive data | 0 | diff --git a/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll b/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll index b4346babb53b..aa2262ab7cdc 100644 --- a/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll +++ b/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll @@ -773,7 +773,7 @@ final class ArrayElementContent extends Content, TArrayElement { * NOTE: Unlike `struct`s and `enum`s tuples are structural and not nominal, * hence we don't store a canonical path for them. */ -private class TuplePositionContent extends Content, TTuplePositionContent { +final class TuplePositionContent extends Content, TTuplePositionContent { private int pos; TuplePositionContent() { this = TTuplePositionContent(pos) } diff --git a/rust/ql/lib/codeql/rust/frameworks/log.model.yml b/rust/ql/lib/codeql/rust/frameworks/log.model.yml new file mode 100644 index 000000000000..10a530ab8f86 --- /dev/null +++ b/rust/ql/lib/codeql/rust/frameworks/log.model.yml @@ -0,0 +1,17 @@ +extensions: + - addsTo: + pack: codeql/rust-all + extensible: sinkModel + data: + - ["repo:https://github.com/rust-lang/log:log", "crate::__private_api::log", "Argument[0]", "log-injection", "manual"] # args + - ["repo:https://github.com/rust-lang/log:log", "crate::__private_api::log", "Argument[2]", "log-injection", "manual"] # target + - ["repo:https://github.com/rust-lang/log:log", "crate::__private_api::log", "Argument[3]", "log-injection", "manual"] # key value + - ["lang:std", "crate::io::stdio::_print", "Argument[0]", "log-injection", "manual"] + - ["lang:std", "crate::io::stdio::_eprint", "Argument[0]", "log-injection", "manual"] + - ["lang:std", "::write", "Argument[0]", "log-injection", "manual"] + - ["lang:std", "::write_all", "Argument[0]", "log-injection", "manual"] + - ["lang:std", "::write", "Argument[0]", "log-injection", "manual"] + - ["lang:std", "::write_all", "Argument[0]", "log-injection", "manual"] + - ["lang:core", "crate::panicking::panic_fmt", "Argument[0]", "log-injection", "manual"] + - ["lang:core", "crate::panicking::assert_failed", "Argument[3].Variant[crate::option::Option::Some(0)]", "log-injection", "manual"] + - ["lang:core", "::expect", "Argument[0]", "log-injection", "manual"] diff --git a/rust/ql/lib/codeql/rust/frameworks/stdlib/lang-core.model.yml b/rust/ql/lib/codeql/rust/frameworks/stdlib/lang-core.model.yml index 4cf937e693b8..4fad34e36b5e 100644 --- a/rust/ql/lib/codeql/rust/frameworks/stdlib/lang-core.model.yml +++ b/rust/ql/lib/codeql/rust/frameworks/stdlib/lang-core.model.yml @@ -13,6 +13,7 @@ extensions: - ["lang:core", "::unwrap_or", "Argument[0]", "ReturnValue", "value", "manual"] # String - ["lang:alloc", "::as_str", "Argument[self]", "ReturnValue", "taint", "manual"] + - ["lang:alloc", "::as_bytes", "Argument[self]", "ReturnValue", "taint", "manual"] # Hint - ["lang:core", "crate::hint::must_use", "Argument[0]", "ReturnValue", "value", "manual"] # Fmt diff --git a/rust/ql/lib/codeql/rust/security/CleartextLoggingExtensions.qll b/rust/ql/lib/codeql/rust/security/CleartextLoggingExtensions.qll new file mode 100644 index 000000000000..bfe6da7ac82c --- /dev/null +++ b/rust/ql/lib/codeql/rust/security/CleartextLoggingExtensions.qll @@ -0,0 +1,40 @@ +/** + * Provides classes and predicates for reasoning about cleartext logging + * of sensitive information vulnerabilities. + */ + +import rust +private import codeql.rust.dataflow.DataFlow +private import codeql.rust.dataflow.internal.DataFlowImpl +private import codeql.rust.security.SensitiveData + +/** + * Provides default sources, sinks and barriers for detecting cleartext logging + * vulnerabilities, as well as extension points for adding your own. + */ +module CleartextLogging { + /** + * A data flow source for cleartext logging vulnerabilities. + */ + abstract class Source extends DataFlow::Node { } + + /** + * A data flow sink for cleartext logging vulnerabilities. + */ + abstract class Sink extends DataFlow::Node { } + + /** + * A barrier for cleartext logging vulnerabilities. + */ + abstract class Barrier extends DataFlow::Node { } + + /** + * Sensitive data, considered as a flow source. + */ + private class SensitiveDataAsSource extends Source instanceof SensitiveData { } + + /** A sink for logging from model data. */ + private class ModelsAsDataSinks extends Sink { + ModelsAsDataSinks() { exists(string s | sinkNode(this, s) and s.matches("log-injection%")) } + } +} diff --git a/rust/ql/src/queries/security/CWE-312/CleartextLogging.qhelp b/rust/ql/src/queries/security/CWE-312/CleartextLogging.qhelp new file mode 100644 index 000000000000..9e30bbf180de --- /dev/null +++ b/rust/ql/src/queries/security/CWE-312/CleartextLogging.qhelp @@ -0,0 +1,38 @@ + + + + +

+Sensitive user data and system information that is logged could be exposed to an attacker when it is +displayed. Also, external processes often store the standard output and standard error streams of +an application, which will include logged sensitive information. +

+
+ + +

+Do not log sensitive data. If it is necessary to log sensitive data, encrypt it before logging. +

+
+ + +

+The following example code logs user credentials (in this case, their password) in plaintext: +

+ +

+Instead, you should encrypt the credentials, or better still, omit them entirely: +

+ +
+ + + +
  • M. Dowd, J. McDonald and J. Schuhm, The Art of Software Security Assessment, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006.
  • +
  • M. Howard and D. LeBlanc, Writing Secure Code, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002.
  • +
  • OWASP: Logging Cheat Sheet - Data to exclude.
  • + +
    +
    diff --git a/rust/ql/src/queries/security/CWE-312/CleartextLogging.ql b/rust/ql/src/queries/security/CWE-312/CleartextLogging.ql new file mode 100644 index 000000000000..d9a3fb9bc5a6 --- /dev/null +++ b/rust/ql/src/queries/security/CWE-312/CleartextLogging.ql @@ -0,0 +1,58 @@ +/** + * @name Cleartext logging of sensitive information + * @description Logging sensitive information in plaintext can + * expose it to an attacker. + * @kind path-problem + * @problem.severity error + * @security-severity 7.5 + * @precision high + * @id rust/cleartext-logging + * @tags security + * external/cwe/cwe-312 + * external/cwe/cwe-359 + * external/cwe/cwe-532 + */ + +import rust +import codeql.rust.security.CleartextLoggingExtensions +import codeql.rust.dataflow.DataFlow +import codeql.rust.dataflow.TaintTracking +import codeql.rust.dataflow.internal.DataFlowImpl + +/** + * A taint-tracking configuration for cleartext logging vulnerabilities. + */ +module CleartextLoggingConfig implements DataFlow::ConfigSig { + import CleartextLogging + + predicate isSource(DataFlow::Node source) { source instanceof Source } + + predicate isSink(DataFlow::Node sink) { sink instanceof Sink } + + predicate isBarrier(DataFlow::Node barrier) { barrier instanceof Barrier } + + predicate isBarrierIn(DataFlow::Node node) { + // make sources barriers so that we only report the closest instance + isSource(node) + } + + predicate isAdditionalFlowStep(Node node1, Node node2) { + // flow from `a` to `&a` + node2.asExpr().getExpr().(RefExpr).getExpr() = node1.asExpr().getExpr() + } + + predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) { + // flow out from tuple content at sinks. + isSink(node) and + c.getAReadContent() instanceof TuplePositionContent + } +} + +module CleartextLoggingFlow = TaintTracking::Global; + +import CleartextLoggingFlow::PathGraph + +from CleartextLoggingFlow::PathNode source, CleartextLoggingFlow::PathNode sink +where CleartextLoggingFlow::flowPath(source, sink) +select sink.getNode(), source, sink, "This operation writes $@ to a log file.", source, + source.getNode().toString() diff --git a/rust/ql/src/queries/security/CWE-312/CleartextLoggingBad.rs b/rust/ql/src/queries/security/CWE-312/CleartextLoggingBad.rs new file mode 100644 index 000000000000..15008f19c4c5 --- /dev/null +++ b/rust/ql/src/queries/security/CWE-312/CleartextLoggingBad.rs @@ -0,0 +1,2 @@ +let password = "P@ssw0rd"; +info!("User password changed to {password}"); diff --git a/rust/ql/src/queries/security/CWE-312/CleartextLoggingGood.rs b/rust/ql/src/queries/security/CWE-312/CleartextLoggingGood.rs new file mode 100644 index 000000000000..ba5fc5dac77e --- /dev/null +++ b/rust/ql/src/queries/security/CWE-312/CleartextLoggingGood.rs @@ -0,0 +1,2 @@ +let password = "P@ssw0rd"; +info!("User password changed"); diff --git a/rust/ql/src/queries/summary/Stats.qll b/rust/ql/src/queries/summary/Stats.qll index 8bdb25381bc6..4054b0bc1326 100644 --- a/rust/ql/src/queries/summary/Stats.qll +++ b/rust/ql/src/queries/summary/Stats.qll @@ -10,6 +10,7 @@ private import codeql.rust.AstConsistency as AstConsistency private import codeql.rust.controlflow.internal.CfgConsistency as CfgConsistency private import codeql.rust.dataflow.internal.DataFlowConsistency as DataFlowConsistency private import codeql.rust.security.SqlInjectionExtensions +private import codeql.rust.security.CleartextLoggingExtensions /** * Gets a count of the total number of lines of code in the database. @@ -58,7 +59,9 @@ int getTaintEdgesCount() { * Gets a kind of query for which `n` is a sink (if any). */ string getAQuerySinkKind(DataFlow::Node n) { - (n instanceof SqlInjection::Sink and result = "SqlInjection") + n instanceof SqlInjection::Sink and result = "SqlInjection" + or + n instanceof CleartextLogging::Sink and result = "CleartextLogging" } /** diff --git a/rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected b/rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected index fdb81065a0eb..776cb29c3d55 100644 --- a/rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected +++ b/rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected @@ -1,11 +1,11 @@ localStep -| file://:0:0:0:0 | [summary param] 0 in lang:core::_::::unwrap_or | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:core::_::::unwrap_or | MaD:2 | -| file://:0:0:0:0 | [summary param] 0 in lang:core::_::::unwrap_or | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:core::_::::unwrap_or | MaD:5 | -| file://:0:0:0:0 | [summary param] 0 in lang:core::_::crate::hint::must_use | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:core::_::crate::hint::must_use | MaD:7 | -| file://:0:0:0:0 | [summary] read: Argument[self].Variant[crate::option::Option::Some(0)] in lang:core::_::::unwrap | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:core::_::::unwrap | MaD:1 | -| file://:0:0:0:0 | [summary] read: Argument[self].Variant[crate::option::Option::Some(0)] in lang:core::_::::unwrap_or | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:core::_::::unwrap_or | MaD:3 | -| file://:0:0:0:0 | [summary] read: Argument[self].Variant[crate::result::Result::Ok(0)] in lang:core::_::::unwrap | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:core::_::::unwrap | MaD:4 | -| file://:0:0:0:0 | [summary] read: Argument[self].Variant[crate::result::Result::Ok(0)] in lang:core::_::::unwrap_or | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:core::_::::unwrap_or | MaD:6 | +| file://:0:0:0:0 | [summary param] 0 in lang:core::_::::unwrap_or | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:core::_::::unwrap_or | MaD:3 | +| file://:0:0:0:0 | [summary param] 0 in lang:core::_::::unwrap_or | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:core::_::::unwrap_or | MaD:6 | +| file://:0:0:0:0 | [summary param] 0 in lang:core::_::crate::hint::must_use | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:core::_::crate::hint::must_use | MaD:8 | +| file://:0:0:0:0 | [summary] read: Argument[self].Variant[crate::option::Option::Some(0)] in lang:core::_::::unwrap | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:core::_::::unwrap | MaD:2 | +| file://:0:0:0:0 | [summary] read: Argument[self].Variant[crate::option::Option::Some(0)] in lang:core::_::::unwrap_or | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:core::_::::unwrap_or | MaD:4 | +| file://:0:0:0:0 | [summary] read: Argument[self].Variant[crate::result::Result::Ok(0)] in lang:core::_::::unwrap | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:core::_::::unwrap | MaD:5 | +| file://:0:0:0:0 | [summary] read: Argument[self].Variant[crate::result::Result::Ok(0)] in lang:core::_::::unwrap_or | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:core::_::::unwrap_or | MaD:7 | | main.rs:3:11:3:11 | [SSA] i | main.rs:4:12:4:12 | i | | | main.rs:3:11:3:11 | i | main.rs:3:11:3:11 | [SSA] i | | | main.rs:3:11:3:16 | ...: i64 | main.rs:3:11:3:11 | i | | @@ -14,6 +14,7 @@ localStep | main.rs:7:9:7:9 | s | main.rs:7:9:7:9 | [SSA] s | | | main.rs:7:9:7:14 | ...: i64 | main.rs:7:9:7:9 | s | | | main.rs:8:14:8:20 | FormatArgsExpr | main.rs:8:14:8:20 | MacroExpr | | +| main.rs:8:14:8:20 | MacroExpr | main.rs:8:5:8:21 | ...::_print | MaD:1 | | main.rs:19:9:19:9 | [SSA] s | main.rs:20:10:20:10 | s | | | main.rs:19:9:19:9 | s | main.rs:19:9:19:9 | [SSA] s | | | main.rs:19:13:19:21 | source(...) | main.rs:19:9:19:9 | s | | @@ -468,13 +469,14 @@ localStep | main.rs:436:13:436:33 | result_questionmark(...) | main.rs:436:9:436:9 | _ | | | main.rs:448:36:448:41 | ...::new(...) | main.rs:448:36:448:41 | MacroExpr | | models -| 1 | Summary: lang:core; ::unwrap; Argument[self].Variant[crate::option::Option::Some(0)]; ReturnValue; value | -| 2 | Summary: lang:core; ::unwrap_or; Argument[0]; ReturnValue; value | -| 3 | Summary: lang:core; ::unwrap_or; Argument[self].Variant[crate::option::Option::Some(0)]; ReturnValue; value | -| 4 | Summary: lang:core; ::unwrap; Argument[self].Variant[crate::result::Result::Ok(0)]; ReturnValue; value | -| 5 | Summary: lang:core; ::unwrap_or; Argument[0]; ReturnValue; value | -| 6 | Summary: lang:core; ::unwrap_or; Argument[self].Variant[crate::result::Result::Ok(0)]; ReturnValue; value | -| 7 | Summary: lang:core; crate::hint::must_use; Argument[0]; ReturnValue; value | +| 1 | Sink: lang:std; crate::io::stdio::_print; log-injection; Argument[0] | +| 2 | Summary: lang:core; ::unwrap; Argument[self].Variant[crate::option::Option::Some(0)]; ReturnValue; value | +| 3 | Summary: lang:core; ::unwrap_or; Argument[0]; ReturnValue; value | +| 4 | Summary: lang:core; ::unwrap_or; Argument[self].Variant[crate::option::Option::Some(0)]; ReturnValue; value | +| 5 | Summary: lang:core; ::unwrap; Argument[self].Variant[crate::result::Result::Ok(0)]; ReturnValue; value | +| 6 | Summary: lang:core; ::unwrap_or; Argument[0]; ReturnValue; value | +| 7 | Summary: lang:core; ::unwrap_or; Argument[self].Variant[crate::result::Result::Ok(0)]; ReturnValue; value | +| 8 | Summary: lang:core; crate::hint::must_use; Argument[0]; ReturnValue; value | storeStep | file://:0:0:0:0 | [summary] to write: ReturnValue.Variant[crate::result::Result::Ok(0)] in repo:https://github.com/seanmonstar/reqwest:reqwest::_::::text | Ok | file://:0:0:0:0 | [summary] to write: ReturnValue in repo:https://github.com/seanmonstar/reqwest:reqwest::_::::text | | main.rs:94:14:94:22 | source(...) | tuple.0 | main.rs:94:13:94:26 | TupleExpr | diff --git a/rust/ql/test/library-tests/dataflow/taint/TaintFlowStep.expected b/rust/ql/test/library-tests/dataflow/taint/TaintFlowStep.expected index c42c4d0e9fc5..4ca0f8199314 100644 --- a/rust/ql/test/library-tests/dataflow/taint/TaintFlowStep.expected +++ b/rust/ql/test/library-tests/dataflow/taint/TaintFlowStep.expected @@ -1,7 +1,8 @@ additionalTaintStep -| file://:0:0:0:0 | [summary param] 0 in lang:alloc::_::crate::fmt::format | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:alloc::_::crate::fmt::format | MaD:2 | -| file://:0:0:0:0 | [summary param] self in lang:alloc::_::::as_str | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:alloc::_::::as_str | MaD:1 | -| file://:0:0:0:0 | [summary param] self in repo:https://github.com/seanmonstar/reqwest:reqwest::_::::text | file://:0:0:0:0 | [summary] to write: ReturnValue.Variant[crate::result::Result::Ok(0)] in repo:https://github.com/seanmonstar/reqwest:reqwest::_::::text | MaD:3 | +| file://:0:0:0:0 | [summary param] 0 in lang:alloc::_::crate::fmt::format | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:alloc::_::crate::fmt::format | MaD:3 | +| file://:0:0:0:0 | [summary param] self in lang:alloc::_::::as_bytes | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:alloc::_::::as_bytes | MaD:1 | +| file://:0:0:0:0 | [summary param] self in lang:alloc::_::::as_str | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:alloc::_::::as_str | MaD:2 | +| file://:0:0:0:0 | [summary param] self in repo:https://github.com/seanmonstar/reqwest:reqwest::_::::text | file://:0:0:0:0 | [summary] to write: ReturnValue.Variant[crate::result::Result::Ok(0)] in repo:https://github.com/seanmonstar/reqwest:reqwest::_::::text | MaD:4 | | main.rs:4:5:4:8 | 1000 | main.rs:4:5:4:12 | ... + ... | | | main.rs:4:12:4:12 | i | main.rs:4:5:4:12 | ... + ... | | | main.rs:8:20:8:20 | s | main.rs:8:14:8:20 | FormatArgsExpr | | @@ -19,6 +20,7 @@ additionalTaintStep | main.rs:64:24:64:27 | s[1] | main.rs:64:18:64:27 | FormatArgsExpr | | | main.rs:69:9:69:12 | arr2 | main.rs:69:9:69:15 | arr2[1] | | models -| 1 | Summary: lang:alloc; ::as_str; Argument[self]; ReturnValue; taint | -| 2 | Summary: lang:alloc; crate::fmt::format; Argument[0]; ReturnValue; taint | -| 3 | Summary: repo:https://github.com/seanmonstar/reqwest:reqwest; ::text; Argument[self]; ReturnValue.Variant[crate::result::Result::Ok(0)]; taint | +| 1 | Summary: lang:alloc; ::as_bytes; Argument[self]; ReturnValue; taint | +| 2 | Summary: lang:alloc; ::as_str; Argument[self]; ReturnValue; taint | +| 3 | Summary: lang:alloc; crate::fmt::format; Argument[0]; ReturnValue; taint | +| 4 | Summary: repo:https://github.com/seanmonstar/reqwest:reqwest; ::text; Argument[self]; ReturnValue.Variant[crate::result::Result::Ok(0)]; taint | diff --git a/rust/ql/test/query-tests/diagnostics/SummaryStats.expected b/rust/ql/test/query-tests/diagnostics/SummaryStats.expected index 5223601d625f..1d7193b6b99a 100644 --- a/rust/ql/test/query-tests/diagnostics/SummaryStats.expected +++ b/rust/ql/test/query-tests/diagnostics/SummaryStats.expected @@ -14,11 +14,11 @@ | Macro calls - resolved | 8 | | Macro calls - total | 9 | | Macro calls - unresolved | 1 | -| Taint edges - number of edges | 2 | +| Taint edges - number of edges | 3 | | Taint reach - nodes tainted | 0 | | Taint reach - per million nodes | 0 | | Taint sinks - cryptographic operations | 0 | -| Taint sinks - query sinks | 0 | +| Taint sinks - query sinks | 3 | | Taint sources - active | 0 | | Taint sources - disabled | 0 | | Taint sources - sensitive data | 0 | diff --git a/rust/ql/test/query-tests/security/CWE-312/CONSISTENCY/ExtractionConsistency.expected b/rust/ql/test/query-tests/security/CWE-312/CONSISTENCY/ExtractionConsistency.expected new file mode 100644 index 000000000000..bd41fe2245ab --- /dev/null +++ b/rust/ql/test/query-tests/security/CWE-312/CONSISTENCY/ExtractionConsistency.expected @@ -0,0 +1,3 @@ +extractionWarning +| test_logging.rs:90:12:90:30 | expected R_PAREN | +| test_logging.rs:90:12:90:30 | macro expansion failed: the macro '$crate::__private_api::format_args' expands to ERROR but a Expr was expected | \ No newline at end of file diff --git a/rust/ql/test/query-tests/security/CWE-312/CleartextLogging.expected b/rust/ql/test/query-tests/security/CWE-312/CleartextLogging.expected new file mode 100644 index 000000000000..e4feee0fd55d --- /dev/null +++ b/rust/ql/test/query-tests/security/CWE-312/CleartextLogging.expected @@ -0,0 +1,436 @@ +#select +| test_logging.rs:42:5:42:36 | ...::log | test_logging.rs:42:28:42:35 | password | test_logging.rs:42:5:42:36 | ...::log | This operation writes $@ to a log file. | test_logging.rs:42:28:42:35 | password | password | +| test_logging.rs:43:5:43:36 | ...::log | test_logging.rs:43:28:43:35 | password | test_logging.rs:43:5:43:36 | ...::log | This operation writes $@ to a log file. | test_logging.rs:43:28:43:35 | password | password | +| test_logging.rs:44:5:44:35 | ...::log | test_logging.rs:44:27:44:34 | password | test_logging.rs:44:5:44:35 | ...::log | This operation writes $@ to a log file. | test_logging.rs:44:27:44:34 | password | password | +| test_logging.rs:45:5:45:36 | ...::log | test_logging.rs:45:28:45:35 | password | test_logging.rs:45:5:45:36 | ...::log | This operation writes $@ to a log file. | test_logging.rs:45:28:45:35 | password | password | +| test_logging.rs:46:5:46:35 | ...::log | test_logging.rs:46:27:46:34 | password | test_logging.rs:46:5:46:35 | ...::log | This operation writes $@ to a log file. | test_logging.rs:46:27:46:34 | password | password | +| test_logging.rs:47:5:47:48 | ...::log | test_logging.rs:47:40:47:47 | password | test_logging.rs:47:5:47:48 | ...::log | This operation writes $@ to a log file. | test_logging.rs:47:40:47:47 | password | password | +| test_logging.rs:52:5:52:36 | ...::log | test_logging.rs:52:28:52:35 | password | test_logging.rs:52:5:52:36 | ...::log | This operation writes $@ to a log file. | test_logging.rs:52:28:52:35 | password | password | +| test_logging.rs:54:5:54:49 | ...::log | test_logging.rs:54:41:54:48 | password | test_logging.rs:54:5:54:49 | ...::log | This operation writes $@ to a log file. | test_logging.rs:54:41:54:48 | password | password | +| test_logging.rs:56:5:56:47 | ...::log | test_logging.rs:56:39:56:46 | password | test_logging.rs:56:5:56:47 | ...::log | This operation writes $@ to a log file. | test_logging.rs:56:39:56:46 | password | password | +| test_logging.rs:57:5:57:34 | ...::log | test_logging.rs:57:24:57:31 | password | test_logging.rs:57:5:57:34 | ...::log | This operation writes $@ to a log file. | test_logging.rs:57:24:57:31 | password | password | +| test_logging.rs:58:5:58:36 | ...::log | test_logging.rs:58:24:58:31 | password | test_logging.rs:58:5:58:36 | ...::log | This operation writes $@ to a log file. | test_logging.rs:58:24:58:31 | password | password | +| test_logging.rs:60:5:60:54 | ...::log | test_logging.rs:60:46:60:53 | password | test_logging.rs:60:5:60:54 | ...::log | This operation writes $@ to a log file. | test_logging.rs:60:46:60:53 | password | password | +| test_logging.rs:61:5:61:55 | ...::log | test_logging.rs:61:21:61:28 | password | test_logging.rs:61:5:61:55 | ...::log | This operation writes $@ to a log file. | test_logging.rs:61:21:61:28 | password | password | +| test_logging.rs:65:5:65:48 | ...::log | test_logging.rs:65:40:65:47 | password | test_logging.rs:65:5:65:48 | ...::log | This operation writes $@ to a log file. | test_logging.rs:65:40:65:47 | password | password | +| test_logging.rs:67:5:67:66 | ...::log | test_logging.rs:67:58:67:65 | password | test_logging.rs:67:5:67:66 | ...::log | This operation writes $@ to a log file. | test_logging.rs:67:58:67:65 | password | password | +| test_logging.rs:68:5:68:67 | ...::log | test_logging.rs:68:19:68:26 | password | test_logging.rs:68:5:68:67 | ...::log | This operation writes $@ to a log file. | test_logging.rs:68:19:68:26 | password | password | +| test_logging.rs:72:5:72:47 | ...::log::<...> | test_logging.rs:72:39:72:46 | password | test_logging.rs:72:5:72:47 | ...::log::<...> | This operation writes $@ to a log file. | test_logging.rs:72:39:72:46 | password | password | +| test_logging.rs:74:5:74:65 | ...::log::<...> | test_logging.rs:74:57:74:64 | password | test_logging.rs:74:5:74:65 | ...::log::<...> | This operation writes $@ to a log file. | test_logging.rs:74:57:74:64 | password | password | +| test_logging.rs:75:5:75:51 | ...::log::<...> | test_logging.rs:75:21:75:28 | password | test_logging.rs:75:5:75:51 | ...::log::<...> | This operation writes $@ to a log file. | test_logging.rs:75:21:75:28 | password | password | +| test_logging.rs:76:5:76:47 | ...::log::<...> | test_logging.rs:76:39:76:46 | password | test_logging.rs:76:5:76:47 | ...::log::<...> | This operation writes $@ to a log file. | test_logging.rs:76:39:76:46 | password | password | +| test_logging.rs:82:5:82:44 | ...::log::<...> | test_logging.rs:82:36:82:43 | password | test_logging.rs:82:5:82:44 | ...::log::<...> | This operation writes $@ to a log file. | test_logging.rs:82:36:82:43 | password | password | +| test_logging.rs:84:5:84:62 | ...::log::<...> | test_logging.rs:84:54:84:61 | password | test_logging.rs:84:5:84:62 | ...::log::<...> | This operation writes $@ to a log file. | test_logging.rs:84:54:84:61 | password | password | +| test_logging.rs:85:5:85:48 | ...::log::<...> | test_logging.rs:85:21:85:28 | password | test_logging.rs:85:5:85:48 | ...::log::<...> | This operation writes $@ to a log file. | test_logging.rs:85:21:85:28 | password | password | +| test_logging.rs:86:5:86:44 | ...::log::<...> | test_logging.rs:86:36:86:43 | password | test_logging.rs:86:5:86:44 | ...::log::<...> | This operation writes $@ to a log file. | test_logging.rs:86:36:86:43 | password | password | +| test_logging.rs:94:5:94:29 | ...::log | test_logging.rs:93:15:93:22 | password | test_logging.rs:94:5:94:29 | ...::log | This operation writes $@ to a log file. | test_logging.rs:93:15:93:22 | password | password | +| test_logging.rs:97:5:97:19 | ...::log | test_logging.rs:96:42:96:49 | password | test_logging.rs:97:5:97:19 | ...::log | This operation writes $@ to a log file. | test_logging.rs:96:42:96:49 | password | password | +| test_logging.rs:100:5:100:19 | ...::log | test_logging.rs:99:38:99:45 | password | test_logging.rs:100:5:100:19 | ...::log | This operation writes $@ to a log file. | test_logging.rs:99:38:99:45 | password | password | +| test_logging.rs:118:5:118:42 | ...::log | test_logging.rs:118:28:118:41 | get_password(...) | test_logging.rs:118:5:118:42 | ...::log | This operation writes $@ to a log file. | test_logging.rs:118:28:118:41 | get_password(...) | get_password(...) | +| test_logging.rs:131:5:131:32 | ...::log | test_logging.rs:129:25:129:32 | password | test_logging.rs:131:5:131:32 | ...::log | This operation writes $@ to a log file. | test_logging.rs:129:25:129:32 | password | password | +| test_logging.rs:152:5:152:38 | ...::_print | test_logging.rs:152:30:152:37 | password | test_logging.rs:152:5:152:38 | ...::_print | This operation writes $@ to a log file. | test_logging.rs:152:30:152:37 | password | password | +| test_logging.rs:153:5:153:38 | ...::_print | test_logging.rs:153:30:153:37 | password | test_logging.rs:153:5:153:38 | ...::_print | This operation writes $@ to a log file. | test_logging.rs:153:30:153:37 | password | password | +| test_logging.rs:154:5:154:39 | ...::_eprint | test_logging.rs:154:31:154:38 | password | test_logging.rs:154:5:154:39 | ...::_eprint | This operation writes $@ to a log file. | test_logging.rs:154:31:154:38 | password | password | +| test_logging.rs:155:5:155:39 | ...::_eprint | test_logging.rs:155:31:155:38 | password | test_logging.rs:155:5:155:39 | ...::_eprint | This operation writes $@ to a log file. | test_logging.rs:155:31:155:38 | password | password | +| test_logging.rs:158:16:158:47 | ...::panic_fmt | test_logging.rs:158:39:158:46 | password | test_logging.rs:158:16:158:47 | ...::panic_fmt | This operation writes $@ to a log file. | test_logging.rs:158:39:158:46 | password | password | +| test_logging.rs:159:16:159:46 | ...::panic_fmt | test_logging.rs:159:38:159:45 | password | test_logging.rs:159:16:159:46 | ...::panic_fmt | This operation writes $@ to a log file. | test_logging.rs:159:38:159:45 | password | password | +| test_logging.rs:160:16:160:55 | ...::panic_fmt | test_logging.rs:160:47:160:54 | password | test_logging.rs:160:16:160:55 | ...::panic_fmt | This operation writes $@ to a log file. | test_logging.rs:160:47:160:54 | password | password | +| test_logging.rs:161:16:161:53 | ...::panic_fmt | test_logging.rs:161:45:161:52 | password | test_logging.rs:161:16:161:53 | ...::panic_fmt | This operation writes $@ to a log file. | test_logging.rs:161:45:161:52 | password | password | +| test_logging.rs:162:16:162:55 | ...::panic_fmt | test_logging.rs:162:47:162:54 | password | test_logging.rs:162:16:162:55 | ...::panic_fmt | This operation writes $@ to a log file. | test_logging.rs:162:47:162:54 | password | password | +| test_logging.rs:163:16:163:57 | ...::assert_failed | test_logging.rs:163:49:163:56 | password | test_logging.rs:163:16:163:57 | ...::assert_failed | This operation writes $@ to a log file. | test_logging.rs:163:49:163:56 | password | password | +| test_logging.rs:164:16:164:57 | ...::assert_failed | test_logging.rs:164:49:164:56 | password | test_logging.rs:164:16:164:57 | ...::assert_failed | This operation writes $@ to a log file. | test_logging.rs:164:49:164:56 | password | password | +| test_logging.rs:165:16:165:61 | ...::panic_fmt | test_logging.rs:165:53:165:60 | password | test_logging.rs:165:16:165:61 | ...::panic_fmt | This operation writes $@ to a log file. | test_logging.rs:165:53:165:60 | password | password | +| test_logging.rs:166:16:166:63 | ...::assert_failed | test_logging.rs:166:55:166:62 | password | test_logging.rs:166:16:166:63 | ...::assert_failed | This operation writes $@ to a log file. | test_logging.rs:166:55:166:62 | password | password | +| test_logging.rs:167:17:167:64 | ...::assert_failed | test_logging.rs:167:56:167:63 | password | test_logging.rs:167:17:167:64 | ...::assert_failed | This operation writes $@ to a log file. | test_logging.rs:167:56:167:63 | password | password | +| test_logging.rs:168:27:168:32 | expect | test_logging.rs:168:58:168:65 | password | test_logging.rs:168:27:168:32 | expect | This operation writes $@ to a log file. | test_logging.rs:168:58:168:65 | password | password | +| test_logging.rs:174:30:174:34 | write | test_logging.rs:174:62:174:69 | password | test_logging.rs:174:30:174:34 | write | This operation writes $@ to a log file. | test_logging.rs:174:62:174:69 | password | password | +| test_logging.rs:175:30:175:38 | write_all | test_logging.rs:175:66:175:73 | password | test_logging.rs:175:30:175:38 | write_all | This operation writes $@ to a log file. | test_logging.rs:175:66:175:73 | password | password | +| test_logging.rs:178:9:178:13 | write | test_logging.rs:178:41:178:48 | password | test_logging.rs:178:9:178:13 | write | This operation writes $@ to a log file. | test_logging.rs:178:41:178:48 | password | password | +| test_logging.rs:181:9:181:13 | write | test_logging.rs:181:41:181:48 | password | test_logging.rs:181:9:181:13 | write | This operation writes $@ to a log file. | test_logging.rs:181:41:181:48 | password | password | +edges +| test_logging.rs:42:12:42:35 | MacroExpr | test_logging.rs:42:5:42:36 | ...::log | provenance | MaD:0 Sink:MaD:0 | +| test_logging.rs:42:28:42:35 | password | test_logging.rs:42:12:42:35 | MacroExpr | provenance | | +| test_logging.rs:43:12:43:35 | MacroExpr | test_logging.rs:43:5:43:36 | ...::log | provenance | MaD:0 Sink:MaD:0 | +| test_logging.rs:43:28:43:35 | password | test_logging.rs:43:12:43:35 | MacroExpr | provenance | | +| test_logging.rs:44:11:44:34 | MacroExpr | test_logging.rs:44:5:44:35 | ...::log | provenance | MaD:0 Sink:MaD:0 | +| test_logging.rs:44:27:44:34 | password | test_logging.rs:44:11:44:34 | MacroExpr | provenance | | +| test_logging.rs:45:12:45:35 | MacroExpr | test_logging.rs:45:5:45:36 | ...::log | provenance | MaD:0 Sink:MaD:0 | +| test_logging.rs:45:28:45:35 | password | test_logging.rs:45:12:45:35 | MacroExpr | provenance | | +| test_logging.rs:46:11:46:34 | MacroExpr | test_logging.rs:46:5:46:35 | ...::log | provenance | MaD:0 Sink:MaD:0 | +| test_logging.rs:46:27:46:34 | password | test_logging.rs:46:11:46:34 | MacroExpr | provenance | | +| test_logging.rs:47:24:47:47 | MacroExpr | test_logging.rs:47:5:47:48 | ...::log | provenance | MaD:0 Sink:MaD:0 | +| test_logging.rs:47:40:47:47 | password | test_logging.rs:47:24:47:47 | MacroExpr | provenance | | +| test_logging.rs:52:12:52:35 | MacroExpr | test_logging.rs:52:5:52:36 | ...::log | provenance | MaD:0 Sink:MaD:0 | +| test_logging.rs:52:28:52:35 | password | test_logging.rs:52:12:52:35 | MacroExpr | provenance | | +| test_logging.rs:54:12:54:48 | MacroExpr | test_logging.rs:54:5:54:49 | ...::log | provenance | MaD:0 Sink:MaD:0 | +| test_logging.rs:54:41:54:48 | password | test_logging.rs:54:12:54:48 | MacroExpr | provenance | | +| test_logging.rs:56:12:56:46 | MacroExpr | test_logging.rs:56:5:56:47 | ...::log | provenance | MaD:0 Sink:MaD:0 | +| test_logging.rs:56:39:56:46 | password | test_logging.rs:56:12:56:46 | MacroExpr | provenance | | +| test_logging.rs:57:12:57:33 | MacroExpr | test_logging.rs:57:5:57:34 | ...::log | provenance | MaD:0 Sink:MaD:0 | +| test_logging.rs:57:24:57:31 | password | test_logging.rs:57:12:57:33 | MacroExpr | provenance | | +| test_logging.rs:58:12:58:35 | MacroExpr | test_logging.rs:58:5:58:36 | ...::log | provenance | MaD:0 Sink:MaD:0 | +| test_logging.rs:58:24:58:31 | password | test_logging.rs:58:12:58:35 | MacroExpr | provenance | | +| test_logging.rs:60:30:60:53 | MacroExpr | test_logging.rs:60:5:60:54 | ...::log | provenance | MaD:0 Sink:MaD:0 | +| test_logging.rs:60:46:60:53 | password | test_logging.rs:60:30:60:53 | MacroExpr | provenance | | +| test_logging.rs:61:20:61:28 | &... [&ref, tuple.0, &ref] | test_logging.rs:61:5:61:55 | ...::log | provenance | MaD:1 Sink:MaD:1 Sink:MaD:1 | +| test_logging.rs:61:20:61:28 | &... [&ref, tuple.0, &ref] | test_logging.rs:61:5:61:55 | ...::log | provenance | MaD:1 Sink:MaD:1 Sink:MaD:1 Sink:MaD:1 | +| test_logging.rs:61:20:61:28 | &... [&ref, tuple.0] | test_logging.rs:61:5:61:55 | ...::log | provenance | MaD:1 Sink:MaD:1 Sink:MaD:1 | +| test_logging.rs:61:20:61:28 | &password | test_logging.rs:61:20:61:28 | TupleExpr [tuple.0] | provenance | | +| test_logging.rs:61:20:61:28 | &password [&ref] | test_logging.rs:61:20:61:28 | TupleExpr [tuple.0, &ref] | provenance | | +| test_logging.rs:61:20:61:28 | TupleExpr [tuple.0, &ref] | test_logging.rs:61:20:61:28 | &... [&ref, tuple.0, &ref] | provenance | | +| test_logging.rs:61:20:61:28 | TupleExpr [tuple.0] | test_logging.rs:61:20:61:28 | &... [&ref, tuple.0] | provenance | | +| test_logging.rs:61:21:61:28 | password | test_logging.rs:61:20:61:28 | &password | provenance | Config | +| test_logging.rs:61:21:61:28 | password | test_logging.rs:61:20:61:28 | &password [&ref] | provenance | | +| test_logging.rs:65:24:65:47 | MacroExpr | test_logging.rs:65:5:65:48 | ...::log | provenance | MaD:0 Sink:MaD:0 | +| test_logging.rs:65:40:65:47 | password | test_logging.rs:65:24:65:47 | MacroExpr | provenance | | +| test_logging.rs:67:42:67:65 | MacroExpr | test_logging.rs:67:5:67:66 | ...::log | provenance | MaD:0 Sink:MaD:0 | +| test_logging.rs:67:58:67:65 | password | test_logging.rs:67:42:67:65 | MacroExpr | provenance | | +| test_logging.rs:68:18:68:26 | &... [&ref, tuple.0, &ref] | test_logging.rs:68:5:68:67 | ...::log | provenance | MaD:1 Sink:MaD:1 Sink:MaD:1 | +| test_logging.rs:68:18:68:26 | &... [&ref, tuple.0, &ref] | test_logging.rs:68:5:68:67 | ...::log | provenance | MaD:1 Sink:MaD:1 Sink:MaD:1 Sink:MaD:1 | +| test_logging.rs:68:18:68:26 | &... [&ref, tuple.0] | test_logging.rs:68:5:68:67 | ...::log | provenance | MaD:1 Sink:MaD:1 Sink:MaD:1 | +| test_logging.rs:68:18:68:26 | &password | test_logging.rs:68:18:68:26 | TupleExpr [tuple.0] | provenance | | +| test_logging.rs:68:18:68:26 | &password [&ref] | test_logging.rs:68:18:68:26 | TupleExpr [tuple.0, &ref] | provenance | | +| test_logging.rs:68:18:68:26 | TupleExpr [tuple.0, &ref] | test_logging.rs:68:18:68:26 | &... [&ref, tuple.0, &ref] | provenance | | +| test_logging.rs:68:18:68:26 | TupleExpr [tuple.0] | test_logging.rs:68:18:68:26 | &... [&ref, tuple.0] | provenance | | +| test_logging.rs:68:19:68:26 | password | test_logging.rs:68:18:68:26 | &password | provenance | Config | +| test_logging.rs:68:19:68:26 | password | test_logging.rs:68:18:68:26 | &password [&ref] | provenance | | +| test_logging.rs:72:23:72:46 | MacroExpr | test_logging.rs:72:5:72:47 | ...::log::<...> | provenance | MaD:0 Sink:MaD:0 | +| test_logging.rs:72:39:72:46 | password | test_logging.rs:72:23:72:46 | MacroExpr | provenance | | +| test_logging.rs:74:41:74:64 | MacroExpr | test_logging.rs:74:5:74:65 | ...::log::<...> | provenance | MaD:0 Sink:MaD:0 | +| test_logging.rs:74:57:74:64 | password | test_logging.rs:74:41:74:64 | MacroExpr | provenance | | +| test_logging.rs:75:20:75:28 | &... [&ref, tuple.0, &ref] | test_logging.rs:75:5:75:51 | ...::log::<...> | provenance | MaD:1 Sink:MaD:1 Sink:MaD:1 | +| test_logging.rs:75:20:75:28 | &... [&ref, tuple.0, &ref] | test_logging.rs:75:5:75:51 | ...::log::<...> | provenance | MaD:1 Sink:MaD:1 Sink:MaD:1 Sink:MaD:1 | +| test_logging.rs:75:20:75:28 | &... [&ref, tuple.0] | test_logging.rs:75:5:75:51 | ...::log::<...> | provenance | MaD:1 Sink:MaD:1 Sink:MaD:1 | +| test_logging.rs:75:20:75:28 | &password | test_logging.rs:75:20:75:28 | TupleExpr [tuple.0] | provenance | | +| test_logging.rs:75:20:75:28 | &password [&ref] | test_logging.rs:75:20:75:28 | TupleExpr [tuple.0, &ref] | provenance | | +| test_logging.rs:75:20:75:28 | TupleExpr [tuple.0, &ref] | test_logging.rs:75:20:75:28 | &... [&ref, tuple.0, &ref] | provenance | | +| test_logging.rs:75:20:75:28 | TupleExpr [tuple.0] | test_logging.rs:75:20:75:28 | &... [&ref, tuple.0] | provenance | | +| test_logging.rs:75:21:75:28 | password | test_logging.rs:75:20:75:28 | &password | provenance | Config | +| test_logging.rs:75:21:75:28 | password | test_logging.rs:75:20:75:28 | &password [&ref] | provenance | | +| test_logging.rs:76:23:76:46 | MacroExpr | test_logging.rs:76:5:76:47 | ...::log::<...> | provenance | MaD:0 Sink:MaD:0 | +| test_logging.rs:76:39:76:46 | password | test_logging.rs:76:23:76:46 | MacroExpr | provenance | | +| test_logging.rs:82:20:82:43 | MacroExpr | test_logging.rs:82:5:82:44 | ...::log::<...> | provenance | MaD:0 Sink:MaD:0 | +| test_logging.rs:82:36:82:43 | password | test_logging.rs:82:20:82:43 | MacroExpr | provenance | | +| test_logging.rs:84:38:84:61 | MacroExpr | test_logging.rs:84:5:84:62 | ...::log::<...> | provenance | MaD:0 Sink:MaD:0 | +| test_logging.rs:84:54:84:61 | password | test_logging.rs:84:38:84:61 | MacroExpr | provenance | | +| test_logging.rs:85:20:85:28 | &... [&ref, tuple.0, &ref] | test_logging.rs:85:5:85:48 | ...::log::<...> | provenance | MaD:1 Sink:MaD:1 Sink:MaD:1 | +| test_logging.rs:85:20:85:28 | &... [&ref, tuple.0, &ref] | test_logging.rs:85:5:85:48 | ...::log::<...> | provenance | MaD:1 Sink:MaD:1 Sink:MaD:1 Sink:MaD:1 | +| test_logging.rs:85:20:85:28 | &... [&ref, tuple.0] | test_logging.rs:85:5:85:48 | ...::log::<...> | provenance | MaD:1 Sink:MaD:1 Sink:MaD:1 | +| test_logging.rs:85:20:85:28 | &password | test_logging.rs:85:20:85:28 | TupleExpr [tuple.0] | provenance | | +| test_logging.rs:85:20:85:28 | &password [&ref] | test_logging.rs:85:20:85:28 | TupleExpr [tuple.0, &ref] | provenance | | +| test_logging.rs:85:20:85:28 | TupleExpr [tuple.0, &ref] | test_logging.rs:85:20:85:28 | &... [&ref, tuple.0, &ref] | provenance | | +| test_logging.rs:85:20:85:28 | TupleExpr [tuple.0] | test_logging.rs:85:20:85:28 | &... [&ref, tuple.0] | provenance | | +| test_logging.rs:85:21:85:28 | password | test_logging.rs:85:20:85:28 | &password | provenance | Config | +| test_logging.rs:85:21:85:28 | password | test_logging.rs:85:20:85:28 | &password [&ref] | provenance | | +| test_logging.rs:86:20:86:43 | MacroExpr | test_logging.rs:86:5:86:44 | ...::log::<...> | provenance | MaD:0 Sink:MaD:0 | +| test_logging.rs:86:36:86:43 | password | test_logging.rs:86:20:86:43 | MacroExpr | provenance | | +| test_logging.rs:93:9:93:10 | m1 | test_logging.rs:94:11:94:28 | MacroExpr | provenance | | +| test_logging.rs:93:14:93:22 | &password | test_logging.rs:93:9:93:10 | m1 | provenance | | +| test_logging.rs:93:15:93:22 | password | test_logging.rs:93:14:93:22 | &password | provenance | Config | +| test_logging.rs:94:11:94:28 | MacroExpr | test_logging.rs:94:5:94:29 | ...::log | provenance | MaD:0 Sink:MaD:0 | +| test_logging.rs:96:9:96:10 | m2 | test_logging.rs:97:11:97:18 | MacroExpr | provenance | | +| test_logging.rs:96:41:96:49 | &password | test_logging.rs:96:9:96:10 | m2 | provenance | | +| test_logging.rs:96:42:96:49 | password | test_logging.rs:96:41:96:49 | &password | provenance | Config | +| test_logging.rs:97:11:97:18 | MacroExpr | test_logging.rs:97:5:97:19 | ...::log | provenance | MaD:0 Sink:MaD:0 | +| test_logging.rs:99:9:99:10 | m3 | test_logging.rs:100:11:100:18 | MacroExpr | provenance | | +| test_logging.rs:99:14:99:46 | res | test_logging.rs:99:22:99:45 | { ... } | provenance | | +| test_logging.rs:99:22:99:45 | ...::format(...) | test_logging.rs:99:14:99:46 | res | provenance | | +| test_logging.rs:99:22:99:45 | ...::must_use(...) | test_logging.rs:99:9:99:10 | m3 | provenance | | +| test_logging.rs:99:22:99:45 | MacroExpr | test_logging.rs:99:22:99:45 | ...::format(...) | provenance | MaD:48 | +| test_logging.rs:99:22:99:45 | { ... } | test_logging.rs:99:22:99:45 | ...::must_use(...) | provenance | MaD:47 | +| test_logging.rs:99:38:99:45 | password | test_logging.rs:99:22:99:45 | MacroExpr | provenance | | +| test_logging.rs:100:11:100:18 | MacroExpr | test_logging.rs:100:5:100:19 | ...::log | provenance | MaD:0 Sink:MaD:0 | +| test_logging.rs:118:12:118:41 | MacroExpr | test_logging.rs:118:5:118:42 | ...::log | provenance | MaD:0 Sink:MaD:0 | +| test_logging.rs:118:28:118:41 | get_password(...) | test_logging.rs:118:12:118:41 | MacroExpr | provenance | | +| test_logging.rs:129:9:129:10 | t1 [tuple.1] | test_logging.rs:131:28:131:29 | t1 [tuple.1] | provenance | | +| test_logging.rs:129:14:129:33 | TupleExpr [tuple.1] | test_logging.rs:129:9:129:10 | t1 [tuple.1] | provenance | | +| test_logging.rs:129:25:129:32 | password | test_logging.rs:129:14:129:33 | TupleExpr [tuple.1] | provenance | | +| test_logging.rs:131:12:131:31 | MacroExpr | test_logging.rs:131:5:131:32 | ...::log | provenance | MaD:0 Sink:MaD:0 | +| test_logging.rs:131:28:131:29 | t1 [tuple.1] | test_logging.rs:131:28:131:31 | t1.1 | provenance | | +| test_logging.rs:131:28:131:31 | t1.1 | test_logging.rs:131:12:131:31 | MacroExpr | provenance | | +| test_logging.rs:152:12:152:37 | MacroExpr | test_logging.rs:152:5:152:38 | ...::_print | provenance | MaD:3 Sink:MaD:3 | +| test_logging.rs:152:30:152:37 | password | test_logging.rs:152:12:152:37 | MacroExpr | provenance | | +| test_logging.rs:153:14:153:37 | MacroExpr | test_logging.rs:153:5:153:38 | ...::_print | provenance | MaD:3 Sink:MaD:3 | +| test_logging.rs:153:30:153:37 | password | test_logging.rs:153:14:153:37 | MacroExpr | provenance | | +| test_logging.rs:154:13:154:38 | MacroExpr | test_logging.rs:154:5:154:39 | ...::_eprint | provenance | MaD:4 Sink:MaD:4 | +| test_logging.rs:154:31:154:38 | password | test_logging.rs:154:13:154:38 | MacroExpr | provenance | | +| test_logging.rs:155:15:155:38 | MacroExpr | test_logging.rs:155:5:155:39 | ...::_eprint | provenance | MaD:4 Sink:MaD:4 | +| test_logging.rs:155:31:155:38 | password | test_logging.rs:155:15:155:38 | MacroExpr | provenance | | +| test_logging.rs:158:23:158:46 | MacroExpr | test_logging.rs:158:16:158:47 | ...::panic_fmt | provenance | MaD:9 Sink:MaD:9 | +| test_logging.rs:158:39:158:46 | password | test_logging.rs:158:23:158:46 | MacroExpr | provenance | | +| test_logging.rs:159:22:159:45 | MacroExpr | test_logging.rs:159:16:159:46 | ...::panic_fmt | provenance | MaD:9 Sink:MaD:9 | +| test_logging.rs:159:38:159:45 | password | test_logging.rs:159:22:159:45 | MacroExpr | provenance | | +| test_logging.rs:160:31:160:54 | MacroExpr | test_logging.rs:160:16:160:55 | ...::panic_fmt | provenance | MaD:9 Sink:MaD:9 | +| test_logging.rs:160:47:160:54 | password | test_logging.rs:160:31:160:54 | MacroExpr | provenance | | +| test_logging.rs:161:29:161:52 | MacroExpr | test_logging.rs:161:16:161:53 | ...::panic_fmt | provenance | MaD:9 Sink:MaD:9 | +| test_logging.rs:161:45:161:52 | password | test_logging.rs:161:29:161:52 | MacroExpr | provenance | | +| test_logging.rs:162:31:162:54 | MacroExpr | test_logging.rs:162:16:162:55 | ...::panic_fmt | provenance | MaD:9 Sink:MaD:9 | +| test_logging.rs:162:47:162:54 | password | test_logging.rs:162:31:162:54 | MacroExpr | provenance | | +| test_logging.rs:163:33:163:56 | ...::Some(...) [Some] | test_logging.rs:163:16:163:57 | ...::assert_failed | provenance | MaD:10 Sink:MaD:10 | +| test_logging.rs:163:33:163:56 | MacroExpr | test_logging.rs:163:33:163:56 | ...::Some(...) [Some] | provenance | | +| test_logging.rs:163:49:163:56 | password | test_logging.rs:163:33:163:56 | MacroExpr | provenance | | +| test_logging.rs:164:33:164:56 | ...::Some(...) [Some] | test_logging.rs:164:16:164:57 | ...::assert_failed | provenance | MaD:10 Sink:MaD:10 | +| test_logging.rs:164:33:164:56 | MacroExpr | test_logging.rs:164:33:164:56 | ...::Some(...) [Some] | provenance | | +| test_logging.rs:164:49:164:56 | password | test_logging.rs:164:33:164:56 | MacroExpr | provenance | | +| test_logging.rs:165:37:165:60 | MacroExpr | test_logging.rs:165:16:165:61 | ...::panic_fmt | provenance | MaD:9 Sink:MaD:9 | +| test_logging.rs:165:53:165:60 | password | test_logging.rs:165:37:165:60 | MacroExpr | provenance | | +| test_logging.rs:166:39:166:62 | ...::Some(...) [Some] | test_logging.rs:166:16:166:63 | ...::assert_failed | provenance | MaD:10 Sink:MaD:10 | +| test_logging.rs:166:39:166:62 | MacroExpr | test_logging.rs:166:39:166:62 | ...::Some(...) [Some] | provenance | | +| test_logging.rs:166:55:166:62 | password | test_logging.rs:166:39:166:62 | MacroExpr | provenance | | +| test_logging.rs:167:40:167:63 | ...::Some(...) [Some] | test_logging.rs:167:17:167:64 | ...::assert_failed | provenance | MaD:10 Sink:MaD:10 | +| test_logging.rs:167:40:167:63 | MacroExpr | test_logging.rs:167:40:167:63 | ...::Some(...) [Some] | provenance | | +| test_logging.rs:167:56:167:63 | password | test_logging.rs:167:40:167:63 | MacroExpr | provenance | | +| test_logging.rs:168:34:168:66 | MacroExpr | test_logging.rs:168:34:168:75 | ... .as_str(...) | provenance | MaD:45 | +| test_logging.rs:168:34:168:66 | res | test_logging.rs:168:42:168:65 | { ... } | provenance | | +| test_logging.rs:168:34:168:75 | ... .as_str(...) | test_logging.rs:168:27:168:32 | expect | provenance | MaD:11 Sink:MaD:11 | +| test_logging.rs:168:42:168:65 | ...::format(...) | test_logging.rs:168:34:168:66 | res | provenance | | +| test_logging.rs:168:42:168:65 | ...::must_use(...) | test_logging.rs:168:34:168:66 | MacroExpr | provenance | | +| test_logging.rs:168:42:168:65 | MacroExpr | test_logging.rs:168:42:168:65 | ...::format(...) | provenance | MaD:48 | +| test_logging.rs:168:42:168:65 | { ... } | test_logging.rs:168:42:168:65 | ...::must_use(...) | provenance | MaD:47 | +| test_logging.rs:168:58:168:65 | password | test_logging.rs:168:42:168:65 | MacroExpr | provenance | | +| test_logging.rs:174:36:174:70 | MacroExpr | test_logging.rs:174:36:174:81 | ... .as_bytes(...) | provenance | MaD:46 | +| test_logging.rs:174:36:174:70 | res | test_logging.rs:174:44:174:69 | { ... } | provenance | | +| test_logging.rs:174:36:174:81 | ... .as_bytes(...) | test_logging.rs:174:30:174:34 | write | provenance | MaD:5 Sink:MaD:5 | +| test_logging.rs:174:44:174:69 | ...::format(...) | test_logging.rs:174:36:174:70 | res | provenance | | +| test_logging.rs:174:44:174:69 | ...::must_use(...) | test_logging.rs:174:36:174:70 | MacroExpr | provenance | | +| test_logging.rs:174:44:174:69 | MacroExpr | test_logging.rs:174:44:174:69 | ...::format(...) | provenance | MaD:48 | +| test_logging.rs:174:44:174:69 | { ... } | test_logging.rs:174:44:174:69 | ...::must_use(...) | provenance | MaD:47 | +| test_logging.rs:174:62:174:69 | password | test_logging.rs:174:44:174:69 | MacroExpr | provenance | | +| test_logging.rs:175:40:175:74 | MacroExpr | test_logging.rs:175:40:175:85 | ... .as_bytes(...) | provenance | MaD:46 | +| test_logging.rs:175:40:175:74 | res | test_logging.rs:175:48:175:73 | { ... } | provenance | | +| test_logging.rs:175:40:175:85 | ... .as_bytes(...) | test_logging.rs:175:30:175:38 | write_all | provenance | MaD:6 Sink:MaD:6 | +| test_logging.rs:175:48:175:73 | ...::format(...) | test_logging.rs:175:40:175:74 | res | provenance | | +| test_logging.rs:175:48:175:73 | ...::must_use(...) | test_logging.rs:175:40:175:74 | MacroExpr | provenance | | +| test_logging.rs:175:48:175:73 | MacroExpr | test_logging.rs:175:48:175:73 | ...::format(...) | provenance | MaD:48 | +| test_logging.rs:175:48:175:73 | { ... } | test_logging.rs:175:48:175:73 | ...::must_use(...) | provenance | MaD:47 | +| test_logging.rs:175:66:175:73 | password | test_logging.rs:175:48:175:73 | MacroExpr | provenance | | +| test_logging.rs:178:15:178:49 | MacroExpr | test_logging.rs:178:15:178:60 | ... .as_bytes(...) | provenance | MaD:46 | +| test_logging.rs:178:15:178:49 | res | test_logging.rs:178:23:178:48 | { ... } | provenance | | +| test_logging.rs:178:15:178:60 | ... .as_bytes(...) | test_logging.rs:178:9:178:13 | write | provenance | MaD:5 Sink:MaD:5 | +| test_logging.rs:178:23:178:48 | ...::format(...) | test_logging.rs:178:15:178:49 | res | provenance | | +| test_logging.rs:178:23:178:48 | ...::must_use(...) | test_logging.rs:178:15:178:49 | MacroExpr | provenance | | +| test_logging.rs:178:23:178:48 | MacroExpr | test_logging.rs:178:23:178:48 | ...::format(...) | provenance | MaD:48 | +| test_logging.rs:178:23:178:48 | { ... } | test_logging.rs:178:23:178:48 | ...::must_use(...) | provenance | MaD:47 | +| test_logging.rs:178:41:178:48 | password | test_logging.rs:178:23:178:48 | MacroExpr | provenance | | +| test_logging.rs:181:15:181:49 | MacroExpr | test_logging.rs:181:15:181:60 | ... .as_bytes(...) | provenance | MaD:46 | +| test_logging.rs:181:15:181:49 | res | test_logging.rs:181:23:181:48 | { ... } | provenance | | +| test_logging.rs:181:15:181:60 | ... .as_bytes(...) | test_logging.rs:181:9:181:13 | write | provenance | MaD:7 Sink:MaD:7 | +| test_logging.rs:181:23:181:48 | ...::format(...) | test_logging.rs:181:15:181:49 | res | provenance | | +| test_logging.rs:181:23:181:48 | ...::must_use(...) | test_logging.rs:181:15:181:49 | MacroExpr | provenance | | +| test_logging.rs:181:23:181:48 | MacroExpr | test_logging.rs:181:23:181:48 | ...::format(...) | provenance | MaD:48 | +| test_logging.rs:181:23:181:48 | { ... } | test_logging.rs:181:23:181:48 | ...::must_use(...) | provenance | MaD:47 | +| test_logging.rs:181:41:181:48 | password | test_logging.rs:181:23:181:48 | MacroExpr | provenance | | +nodes +| test_logging.rs:42:5:42:36 | ...::log | semmle.label | ...::log | +| test_logging.rs:42:12:42:35 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:42:28:42:35 | password | semmle.label | password | +| test_logging.rs:43:5:43:36 | ...::log | semmle.label | ...::log | +| test_logging.rs:43:12:43:35 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:43:28:43:35 | password | semmle.label | password | +| test_logging.rs:44:5:44:35 | ...::log | semmle.label | ...::log | +| test_logging.rs:44:11:44:34 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:44:27:44:34 | password | semmle.label | password | +| test_logging.rs:45:5:45:36 | ...::log | semmle.label | ...::log | +| test_logging.rs:45:12:45:35 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:45:28:45:35 | password | semmle.label | password | +| test_logging.rs:46:5:46:35 | ...::log | semmle.label | ...::log | +| test_logging.rs:46:11:46:34 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:46:27:46:34 | password | semmle.label | password | +| test_logging.rs:47:5:47:48 | ...::log | semmle.label | ...::log | +| test_logging.rs:47:24:47:47 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:47:40:47:47 | password | semmle.label | password | +| test_logging.rs:52:5:52:36 | ...::log | semmle.label | ...::log | +| test_logging.rs:52:12:52:35 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:52:28:52:35 | password | semmle.label | password | +| test_logging.rs:54:5:54:49 | ...::log | semmle.label | ...::log | +| test_logging.rs:54:12:54:48 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:54:41:54:48 | password | semmle.label | password | +| test_logging.rs:56:5:56:47 | ...::log | semmle.label | ...::log | +| test_logging.rs:56:12:56:46 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:56:39:56:46 | password | semmle.label | password | +| test_logging.rs:57:5:57:34 | ...::log | semmle.label | ...::log | +| test_logging.rs:57:12:57:33 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:57:24:57:31 | password | semmle.label | password | +| test_logging.rs:58:5:58:36 | ...::log | semmle.label | ...::log | +| test_logging.rs:58:12:58:35 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:58:24:58:31 | password | semmle.label | password | +| test_logging.rs:60:5:60:54 | ...::log | semmle.label | ...::log | +| test_logging.rs:60:30:60:53 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:60:46:60:53 | password | semmle.label | password | +| test_logging.rs:61:5:61:55 | ...::log | semmle.label | ...::log | +| test_logging.rs:61:20:61:28 | &... [&ref, tuple.0, &ref] | semmle.label | &... [&ref, tuple.0, &ref] | +| test_logging.rs:61:20:61:28 | &... [&ref, tuple.0] | semmle.label | &... [&ref, tuple.0] | +| test_logging.rs:61:20:61:28 | &password | semmle.label | &password | +| test_logging.rs:61:20:61:28 | &password [&ref] | semmle.label | &password [&ref] | +| test_logging.rs:61:20:61:28 | TupleExpr [tuple.0, &ref] | semmle.label | TupleExpr [tuple.0, &ref] | +| test_logging.rs:61:20:61:28 | TupleExpr [tuple.0] | semmle.label | TupleExpr [tuple.0] | +| test_logging.rs:61:21:61:28 | password | semmle.label | password | +| test_logging.rs:65:5:65:48 | ...::log | semmle.label | ...::log | +| test_logging.rs:65:24:65:47 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:65:40:65:47 | password | semmle.label | password | +| test_logging.rs:67:5:67:66 | ...::log | semmle.label | ...::log | +| test_logging.rs:67:42:67:65 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:67:58:67:65 | password | semmle.label | password | +| test_logging.rs:68:5:68:67 | ...::log | semmle.label | ...::log | +| test_logging.rs:68:18:68:26 | &... [&ref, tuple.0, &ref] | semmle.label | &... [&ref, tuple.0, &ref] | +| test_logging.rs:68:18:68:26 | &... [&ref, tuple.0] | semmle.label | &... [&ref, tuple.0] | +| test_logging.rs:68:18:68:26 | &password | semmle.label | &password | +| test_logging.rs:68:18:68:26 | &password [&ref] | semmle.label | &password [&ref] | +| test_logging.rs:68:18:68:26 | TupleExpr [tuple.0, &ref] | semmle.label | TupleExpr [tuple.0, &ref] | +| test_logging.rs:68:18:68:26 | TupleExpr [tuple.0] | semmle.label | TupleExpr [tuple.0] | +| test_logging.rs:68:19:68:26 | password | semmle.label | password | +| test_logging.rs:72:5:72:47 | ...::log::<...> | semmle.label | ...::log::<...> | +| test_logging.rs:72:23:72:46 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:72:39:72:46 | password | semmle.label | password | +| test_logging.rs:74:5:74:65 | ...::log::<...> | semmle.label | ...::log::<...> | +| test_logging.rs:74:41:74:64 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:74:57:74:64 | password | semmle.label | password | +| test_logging.rs:75:5:75:51 | ...::log::<...> | semmle.label | ...::log::<...> | +| test_logging.rs:75:20:75:28 | &... [&ref, tuple.0, &ref] | semmle.label | &... [&ref, tuple.0, &ref] | +| test_logging.rs:75:20:75:28 | &... [&ref, tuple.0] | semmle.label | &... [&ref, tuple.0] | +| test_logging.rs:75:20:75:28 | &password | semmle.label | &password | +| test_logging.rs:75:20:75:28 | &password [&ref] | semmle.label | &password [&ref] | +| test_logging.rs:75:20:75:28 | TupleExpr [tuple.0, &ref] | semmle.label | TupleExpr [tuple.0, &ref] | +| test_logging.rs:75:20:75:28 | TupleExpr [tuple.0] | semmle.label | TupleExpr [tuple.0] | +| test_logging.rs:75:21:75:28 | password | semmle.label | password | +| test_logging.rs:76:5:76:47 | ...::log::<...> | semmle.label | ...::log::<...> | +| test_logging.rs:76:23:76:46 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:76:39:76:46 | password | semmle.label | password | +| test_logging.rs:82:5:82:44 | ...::log::<...> | semmle.label | ...::log::<...> | +| test_logging.rs:82:20:82:43 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:82:36:82:43 | password | semmle.label | password | +| test_logging.rs:84:5:84:62 | ...::log::<...> | semmle.label | ...::log::<...> | +| test_logging.rs:84:38:84:61 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:84:54:84:61 | password | semmle.label | password | +| test_logging.rs:85:5:85:48 | ...::log::<...> | semmle.label | ...::log::<...> | +| test_logging.rs:85:20:85:28 | &... [&ref, tuple.0, &ref] | semmle.label | &... [&ref, tuple.0, &ref] | +| test_logging.rs:85:20:85:28 | &... [&ref, tuple.0] | semmle.label | &... [&ref, tuple.0] | +| test_logging.rs:85:20:85:28 | &password | semmle.label | &password | +| test_logging.rs:85:20:85:28 | &password [&ref] | semmle.label | &password [&ref] | +| test_logging.rs:85:20:85:28 | TupleExpr [tuple.0, &ref] | semmle.label | TupleExpr [tuple.0, &ref] | +| test_logging.rs:85:20:85:28 | TupleExpr [tuple.0] | semmle.label | TupleExpr [tuple.0] | +| test_logging.rs:85:21:85:28 | password | semmle.label | password | +| test_logging.rs:86:5:86:44 | ...::log::<...> | semmle.label | ...::log::<...> | +| test_logging.rs:86:20:86:43 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:86:36:86:43 | password | semmle.label | password | +| test_logging.rs:93:9:93:10 | m1 | semmle.label | m1 | +| test_logging.rs:93:14:93:22 | &password | semmle.label | &password | +| test_logging.rs:93:15:93:22 | password | semmle.label | password | +| test_logging.rs:94:5:94:29 | ...::log | semmle.label | ...::log | +| test_logging.rs:94:11:94:28 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:96:9:96:10 | m2 | semmle.label | m2 | +| test_logging.rs:96:41:96:49 | &password | semmle.label | &password | +| test_logging.rs:96:42:96:49 | password | semmle.label | password | +| test_logging.rs:97:5:97:19 | ...::log | semmle.label | ...::log | +| test_logging.rs:97:11:97:18 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:99:9:99:10 | m3 | semmle.label | m3 | +| test_logging.rs:99:14:99:46 | res | semmle.label | res | +| test_logging.rs:99:22:99:45 | ...::format(...) | semmle.label | ...::format(...) | +| test_logging.rs:99:22:99:45 | ...::must_use(...) | semmle.label | ...::must_use(...) | +| test_logging.rs:99:22:99:45 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:99:22:99:45 | { ... } | semmle.label | { ... } | +| test_logging.rs:99:38:99:45 | password | semmle.label | password | +| test_logging.rs:100:5:100:19 | ...::log | semmle.label | ...::log | +| test_logging.rs:100:11:100:18 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:118:5:118:42 | ...::log | semmle.label | ...::log | +| test_logging.rs:118:12:118:41 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:118:28:118:41 | get_password(...) | semmle.label | get_password(...) | +| test_logging.rs:129:9:129:10 | t1 [tuple.1] | semmle.label | t1 [tuple.1] | +| test_logging.rs:129:14:129:33 | TupleExpr [tuple.1] | semmle.label | TupleExpr [tuple.1] | +| test_logging.rs:129:25:129:32 | password | semmle.label | password | +| test_logging.rs:131:5:131:32 | ...::log | semmle.label | ...::log | +| test_logging.rs:131:12:131:31 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:131:28:131:29 | t1 [tuple.1] | semmle.label | t1 [tuple.1] | +| test_logging.rs:131:28:131:31 | t1.1 | semmle.label | t1.1 | +| test_logging.rs:152:5:152:38 | ...::_print | semmle.label | ...::_print | +| test_logging.rs:152:12:152:37 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:152:30:152:37 | password | semmle.label | password | +| test_logging.rs:153:5:153:38 | ...::_print | semmle.label | ...::_print | +| test_logging.rs:153:14:153:37 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:153:30:153:37 | password | semmle.label | password | +| test_logging.rs:154:5:154:39 | ...::_eprint | semmle.label | ...::_eprint | +| test_logging.rs:154:13:154:38 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:154:31:154:38 | password | semmle.label | password | +| test_logging.rs:155:5:155:39 | ...::_eprint | semmle.label | ...::_eprint | +| test_logging.rs:155:15:155:38 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:155:31:155:38 | password | semmle.label | password | +| test_logging.rs:158:16:158:47 | ...::panic_fmt | semmle.label | ...::panic_fmt | +| test_logging.rs:158:23:158:46 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:158:39:158:46 | password | semmle.label | password | +| test_logging.rs:159:16:159:46 | ...::panic_fmt | semmle.label | ...::panic_fmt | +| test_logging.rs:159:22:159:45 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:159:38:159:45 | password | semmle.label | password | +| test_logging.rs:160:16:160:55 | ...::panic_fmt | semmle.label | ...::panic_fmt | +| test_logging.rs:160:31:160:54 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:160:47:160:54 | password | semmle.label | password | +| test_logging.rs:161:16:161:53 | ...::panic_fmt | semmle.label | ...::panic_fmt | +| test_logging.rs:161:29:161:52 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:161:45:161:52 | password | semmle.label | password | +| test_logging.rs:162:16:162:55 | ...::panic_fmt | semmle.label | ...::panic_fmt | +| test_logging.rs:162:31:162:54 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:162:47:162:54 | password | semmle.label | password | +| test_logging.rs:163:16:163:57 | ...::assert_failed | semmle.label | ...::assert_failed | +| test_logging.rs:163:33:163:56 | ...::Some(...) [Some] | semmle.label | ...::Some(...) [Some] | +| test_logging.rs:163:33:163:56 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:163:49:163:56 | password | semmle.label | password | +| test_logging.rs:164:16:164:57 | ...::assert_failed | semmle.label | ...::assert_failed | +| test_logging.rs:164:33:164:56 | ...::Some(...) [Some] | semmle.label | ...::Some(...) [Some] | +| test_logging.rs:164:33:164:56 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:164:49:164:56 | password | semmle.label | password | +| test_logging.rs:165:16:165:61 | ...::panic_fmt | semmle.label | ...::panic_fmt | +| test_logging.rs:165:37:165:60 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:165:53:165:60 | password | semmle.label | password | +| test_logging.rs:166:16:166:63 | ...::assert_failed | semmle.label | ...::assert_failed | +| test_logging.rs:166:39:166:62 | ...::Some(...) [Some] | semmle.label | ...::Some(...) [Some] | +| test_logging.rs:166:39:166:62 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:166:55:166:62 | password | semmle.label | password | +| test_logging.rs:167:17:167:64 | ...::assert_failed | semmle.label | ...::assert_failed | +| test_logging.rs:167:40:167:63 | ...::Some(...) [Some] | semmle.label | ...::Some(...) [Some] | +| test_logging.rs:167:40:167:63 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:167:56:167:63 | password | semmle.label | password | +| test_logging.rs:168:27:168:32 | expect | semmle.label | expect | +| test_logging.rs:168:34:168:66 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:168:34:168:66 | res | semmle.label | res | +| test_logging.rs:168:34:168:75 | ... .as_str(...) | semmle.label | ... .as_str(...) | +| test_logging.rs:168:42:168:65 | ...::format(...) | semmle.label | ...::format(...) | +| test_logging.rs:168:42:168:65 | ...::must_use(...) | semmle.label | ...::must_use(...) | +| test_logging.rs:168:42:168:65 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:168:42:168:65 | { ... } | semmle.label | { ... } | +| test_logging.rs:168:58:168:65 | password | semmle.label | password | +| test_logging.rs:174:30:174:34 | write | semmle.label | write | +| test_logging.rs:174:36:174:70 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:174:36:174:70 | res | semmle.label | res | +| test_logging.rs:174:36:174:81 | ... .as_bytes(...) | semmle.label | ... .as_bytes(...) | +| test_logging.rs:174:44:174:69 | ...::format(...) | semmle.label | ...::format(...) | +| test_logging.rs:174:44:174:69 | ...::must_use(...) | semmle.label | ...::must_use(...) | +| test_logging.rs:174:44:174:69 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:174:44:174:69 | { ... } | semmle.label | { ... } | +| test_logging.rs:174:62:174:69 | password | semmle.label | password | +| test_logging.rs:175:30:175:38 | write_all | semmle.label | write_all | +| test_logging.rs:175:40:175:74 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:175:40:175:74 | res | semmle.label | res | +| test_logging.rs:175:40:175:85 | ... .as_bytes(...) | semmle.label | ... .as_bytes(...) | +| test_logging.rs:175:48:175:73 | ...::format(...) | semmle.label | ...::format(...) | +| test_logging.rs:175:48:175:73 | ...::must_use(...) | semmle.label | ...::must_use(...) | +| test_logging.rs:175:48:175:73 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:175:48:175:73 | { ... } | semmle.label | { ... } | +| test_logging.rs:175:66:175:73 | password | semmle.label | password | +| test_logging.rs:178:9:178:13 | write | semmle.label | write | +| test_logging.rs:178:15:178:49 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:178:15:178:49 | res | semmle.label | res | +| test_logging.rs:178:15:178:60 | ... .as_bytes(...) | semmle.label | ... .as_bytes(...) | +| test_logging.rs:178:23:178:48 | ...::format(...) | semmle.label | ...::format(...) | +| test_logging.rs:178:23:178:48 | ...::must_use(...) | semmle.label | ...::must_use(...) | +| test_logging.rs:178:23:178:48 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:178:23:178:48 | { ... } | semmle.label | { ... } | +| test_logging.rs:178:41:178:48 | password | semmle.label | password | +| test_logging.rs:181:9:181:13 | write | semmle.label | write | +| test_logging.rs:181:15:181:49 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:181:15:181:49 | res | semmle.label | res | +| test_logging.rs:181:15:181:60 | ... .as_bytes(...) | semmle.label | ... .as_bytes(...) | +| test_logging.rs:181:23:181:48 | ...::format(...) | semmle.label | ...::format(...) | +| test_logging.rs:181:23:181:48 | ...::must_use(...) | semmle.label | ...::must_use(...) | +| test_logging.rs:181:23:181:48 | MacroExpr | semmle.label | MacroExpr | +| test_logging.rs:181:23:181:48 | { ... } | semmle.label | { ... } | +| test_logging.rs:181:41:181:48 | password | semmle.label | password | +subpaths diff --git a/rust/ql/test/query-tests/security/CWE-312/CleartextLogging.qlref b/rust/ql/test/query-tests/security/CWE-312/CleartextLogging.qlref new file mode 100644 index 000000000000..01a435da9202 --- /dev/null +++ b/rust/ql/test/query-tests/security/CWE-312/CleartextLogging.qlref @@ -0,0 +1,3 @@ +query: queries/security/CWE-312/CleartextLogging.ql +postprocess: + - utils/test/InlineExpectationsTestQuery.ql diff --git a/rust/ql/test/query-tests/security/CWE-312/options.yml b/rust/ql/test/query-tests/security/CWE-312/options.yml new file mode 100644 index 000000000000..439af840b902 --- /dev/null +++ b/rust/ql/test/query-tests/security/CWE-312/options.yml @@ -0,0 +1,4 @@ +qltest_cargo_check: true +qltest_dependencies: + - log = { version = "0.4.25", features = ["kv"] } + - simple_logger = { version = "5.0.0" } diff --git a/rust/ql/test/query-tests/security/CWE-312/test_logging.rs b/rust/ql/test/query-tests/security/CWE-312/test_logging.rs new file mode 100644 index 000000000000..ab8013689906 --- /dev/null +++ b/rust/ql/test/query-tests/security/CWE-312/test_logging.rs @@ -0,0 +1,189 @@ + +use log::{debug, error, info, trace, warn, log, Level}; +use std::io::Write as _; +use std::fmt::Write as _; + +// --- tests --- + +fn get_password() -> String { + "123456".to_string() +} + +fn use_password(password: &String) { + // ... +} + +#[derive(Debug)] +struct MyStruct1 { + harmless: String, + password: String, +} + +impl std::fmt::Display for MyStruct1 { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{} {}", self.harmless, self.password) + } +} + +#[derive(Debug)] +struct MyStruct2 { + harmless: String, + password: String, +} + +impl std::fmt::Display for MyStruct2 { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{} [REDACTED]", self.harmless) // doesn't output password + } +} + +fn test_log(harmless: String, password: String, encrypted_password: String) { + // logging macros + debug!("message = {}", password); // $ Source Alert[rust/cleartext-logging] + error!("message = {}", password); // $ Source Alert[rust/cleartext-logging] + info!("message = {}", password); // $ Source Alert[rust/cleartext-logging] + trace!("message = {}", password); // $ Source Alert[rust/cleartext-logging] + warn!("message = {}", password); // $ Source Alert[rust/cleartext-logging] + log!(Level::Error, "message = {}", password); // $ Source Alert[rust/cleartext-logging] + + // debug! macro, various formatting + debug!("message"); + debug!("message = {}", harmless); + debug!("message = {}", password); // $ Source Alert[rust/cleartext-logging] + debug!("message = {}", encrypted_password); + debug!("message = {} {}", harmless, password); // $ Source Alert[rust/cleartext-logging] + debug!("message = {harmless}"); + debug!("message = {harmless} {}", password); // $ Source Alert[rust/cleartext-logging] + debug!("message = {password}"); // $ Source Alert[rust/cleartext-logging] + debug!("message = {password:?}"); // $ Source Alert[rust/cleartext-logging] + debug!(target: "target", "message = {}", harmless); + debug!(target: "target", "message = {}", password); // $ Source Alert[rust/cleartext-logging] + debug!(target: &password, "message = {}", harmless); // $ Source Alert[rust/cleartext-logging] + + // log! macro, various formatting + log!(Level::Error, "message = {}", harmless); + log!(Level::Error, "message = {}", password); // $ Source Alert[rust/cleartext-logging] + log!(target: "target", Level::Error, "message = {}", harmless); + log!(target: "target", Level::Error, "message = {}", password); // $ Source Alert[rust/cleartext-logging] + log!(target: &password, Level::Error, "message = {}", harmless); // $ Source Alert[rust/cleartext-logging] + + // structured logging + error!(value = 1; "message = {}", harmless); + error!(value = 1; "message = {}", password); // $ Source Alert[rust/cleartext-logging] + error!(target: "target", value = 1; "message"); + error!(target: "target", value = 1; "message = {}", password); // $ Source Alert[rust/cleartext-logging] + error!(target: &password, value = 1; "message"); // $ Source Alert[rust/cleartext-logging] + error!(value = 1; "message = {}", password); // $ Source Alert[rust/cleartext-logging] + error!(value = password.as_str(); "message"); // $ MISSING: Alert[rust/cleartext-logging] + error!(value:? = password.as_str(); "message"); // $ MISSING: Alert[rust/cleartext-logging] + + let value1 = 1; + error!(value1; "message = {}", harmless); + error!(value1; "message = {}", password); // $ Source Alert[rust/cleartext-logging] + error!(target: "target", value1; "message"); + error!(target: "target", value1; "message = {}", password); // $ Source Alert[rust/cleartext-logging] + error!(target: &password, value1; "message"); // $ Source Alert[rust/cleartext-logging] + error!(value1; "message = {}", password); // $ Source Alert[rust/cleartext-logging] + + let value2 = password.as_str(); + error!(value2; "message"); // $ MISSING: Alert[rust/cleartext-logging] + error!(value2:?; "message"); // $ MISSING: Alert[rust/cleartext-logging] + + // pre-formatted + let m1 = &password; // $ Source=m1 + info!("message = {}", m1); // $ Alert[rust/cleartext-logging]=m1 + + let m2 = "message = ".to_string() + &password; // $ Source=m2 + info!("{}", m2); // $ Alert[rust/cleartext-logging]=m2 + + let m3 = format!("message = {}", password); // $ Source=m3 + info!("{}", m3); // $ Alert[rust/cleartext-logging]=m3 + + let mut m4 = String::new(); + write!(&mut m4, "message = {}", password); // $ MISSING: Source=m4 + info!("{}", m4); // $ MISSING: Alert[rust/cleartext-logging]=m4 + + let mut m5 = String::new(); + writeln!(&mut m5, "message = {}", password); // $ MISSING: Source=m5 + info!("{}", m5); // $ MISSING: Alert[rust/cleartext-logging]=m5 + + let mut m6 = Vec::new(); + write!(&mut m6, "message = {}", password); // $ MISSING: Source=m6 + info!("{}", std::str::from_utf8(&m6).unwrap()); // $ MISSING: Alert[rust/cleartext-logging]=m6 + unsafe { + info!("{}", std::str::from_utf8_unchecked(&m6)); // $ MISSING: Alert[rust/cleartext-logging]=m6 + } + + // logging with a call + trace!("message = {}", get_password()); // $ Source Alert[rust/cleartext-logging] + + let str1 = "123456".to_string(); + trace!("message = {}", &str1); // $ MISSING: Alert[rust/cleartext-logging] + use_password(&str1); // (proves that `str1` is a password) + trace!("message = {}", &str1); // $ MISSING: Alert[rust/cleartext-logging] + + let str2 = "123456".to_string(); + trace!("message = {}", &str2); + + // logging from a tuple + let t1 = (harmless, password); // $ Source=t1 + trace!("message = {}", t1.0); + trace!("message = {}", t1.1); // $ Alert[rust/cleartext-logging]=t1 + trace!("message = {:?}", t1); // $ MISSING: Alert[rust/cleartext-logging]=t1 + trace!("message = {:#?}", t1); // $ MISSING: Alert[rust/cleartext-logging]=t1 + + // logging from a struct + let s1 = MyStruct1 { harmless: "foo".to_string(), password: "123456".to_string() }; // $ MISSING: Source=s1 + warn!("message = {}", s1.harmless); + warn!("message = {}", s1.password); // $ MISSING: Alert[rust/cleartext-logging] + warn!("message = {}", s1); // $ MISSING: Alert[rust/cleartext-logging]=s1 + warn!("message = {:?}", s1); // $ MISSING: Alert[rust/cleartext-logging]=s1 + warn!("message = {:#?}", s1); // $ MISSING: Alert[rust/cleartext-logging]=s1 + + let s2 = MyStruct2 { harmless: "foo".to_string(), password: "123456".to_string() }; // $ MISSING: Source=s2 + warn!("message = {}", s2.harmless); + warn!("message = {}", s2.password); // $ MISSING: Alert[rust/cleartext-logging] + warn!("message = {}", s2); // (this implementation does not output the password field) + warn!("message = {:?}", s2); // $ MISSING: Alert[rust/cleartext-logging]=s2 + warn!("message = {:#?}", s2); // $ MISSING: Alert[rust/cleartext-logging]=s2 +} + +fn test_std(password: String, i: i32, opt_i: Option) { + print!("message = {}\n", password); // $ Source Alert[rust/cleartext-logging] + println!("message = {}", password); // $ Source Alert[rust/cleartext-logging] + eprint!("message = {}\n", password); // $ Source Alert[rust/cleartext-logging] + eprintln!("message = {}", password); // $ Source Alert[rust/cleartext-logging] + + match i { + 1 => { panic!("message = {}", password); } // $ Source Alert[rust/cleartext-logging] + 2 => { todo!("message = {}", password); } // $ Source Alert[rust/cleartext-logging] + 3 => { unimplemented!("message = {}", password); } // $ Source Alert[rust/cleartext-logging] + 4 => { unreachable!("message = {}", password); } // $ Source Alert[rust/cleartext-logging] + 5 => { assert!(false, "message = {}", password); } // $ Source Alert[rust/cleartext-logging] + 6 => { assert_eq!(1, 2, "message = {}", password); } // $ Source Alert[rust/cleartext-logging] + 7 => { assert_ne!(1, 1, "message = {}", password); } // $ Source Alert[rust/cleartext-logging] + 8 => { debug_assert!(false, "message = {}", password); } // $ Source Alert[rust/cleartext-logging] + 9 => { debug_assert_eq!(1, 2, "message = {}", password); } // $ Source Alert[rust/cleartext-logging] + 10 => { debug_assert_ne!(1, 1, "message = {}", password); } // $ Source Alert[rust/cleartext-logging] + 11 => { _ = opt_i.expect(format!("message = {}", password).as_str()); } // $ Source Alert[rust/cleartext-logging] + _ => {} + } + + std::io::stdout().lock().write_fmt(format_args!("message = {}\n", password)); // $ MISSING: Alert[rust/cleartext-logging] + std::io::stderr().lock().write_fmt(format_args!("message = {}\n", password)); // $ MISSING: Alert[rust/cleartext-logging] + std::io::stdout().lock().write(format!("message = {}\n", password).as_bytes()); // $ Source Alert[rust/cleartext-logging] + std::io::stdout().lock().write_all(format!("message = {}\n", password).as_bytes()); // $ Source Alert[rust/cleartext-logging] + + let mut out = std::io::stdout().lock(); + out.write(format!("message = {}\n", password).as_bytes()); // $ Source Alert[rust/cleartext-logging] + + let mut err = std::io::stderr().lock(); + err.write(format!("message = {}\n", password).as_bytes()); // $ Source Alert[rust/cleartext-logging] +} + +fn main() { + simple_logger::SimpleLogger::new().init().unwrap(); + + test_log("harmless".to_string(), "123456".to_string(), "[encrypted]".to_string()); + test_std("123456".to_string(), 0, None); +}