Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rust: Query for cleartext logging of sensitive information #18582

Merged
merged 22 commits into from
Jan 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
bb3be2f
Rust: Add a test for the log crate + placeholder query.
geoffw0 Jan 21, 2025
173cfd5
Rust: Add test cases for various std:: bits.
geoffw0 Jan 21, 2025
4297d05
Rust: Implement the query.
geoffw0 Jan 21, 2025
1d2950c
Rust: Add some sinks.
geoffw0 Jan 21, 2025
484331c
Rust: Model StdoutLock, StderrLock methods and String.as_bytes.
geoffw0 Jan 22, 2025
2bbf493
Rust: Model assert_failed.
geoffw0 Jan 22, 2025
6444494
Rust: Add taint sinks for target and key-value arguments.
geoffw0 Jan 22, 2025
78c58aa
Rust: Allow implicit taint reads from tuple contents at sinks.
geoffw0 Jan 22, 2025
59c3ac6
Rust: Allow flow through reference taking (&).
geoffw0 Jan 23, 2025
e708167
Rust: Add the sinks to metrics.
geoffw0 Jan 23, 2025
ccc1243
Rust: Add .qhelp and examples.
geoffw0 Jan 23, 2025
4214c83
Rust: Clean up the query message.
geoffw0 Jan 23, 2025
613a165
Rust: Simplify QL slightly.
geoffw0 Jan 23, 2025
5570523
Update rust/ql/src/queries/security/CWE-312/CleartextLoggingBad.rs
geoffw0 Jan 23, 2025
d27a71e
Rust: Minor fixes.
geoffw0 Jan 23, 2025
951d1fc
Rust: Add missing file.
geoffw0 Jan 23, 2025
44b9a11
Rust: Another .qhelp fix.
geoffw0 Jan 23, 2025
f5459d7
Rust: Accept changes to integration test results.
geoffw0 Jan 23, 2025
814118d
Merge remote-tracking branch 'upstream/main' into logging
geoffw0 Jan 23, 2025
037d496
Rust: Fix some more tests (MaD ID changes and extraction consistency …
geoffw0 Jan 23, 2025
117db8a
Rust: Make the test runnable.
geoffw0 Jan 24, 2025
0a3d44c
Rust: Re-apply suggested changes (I accidentally force-pushed them aw…
geoffw0 Jan 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions rust/ql/integration-tests/hello-project/summary.expected
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
2 changes: 1 addition & 1 deletion rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll
Original file line number Diff line number Diff line change
Expand Up @@ -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) }
Expand Down
17 changes: 17 additions & 0 deletions rust/ql/lib/codeql/rust/frameworks/log.model.yml
Original file line number Diff line number Diff line change
@@ -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", "<crate::io::stdio::StdoutLock as crate::io::Write>::write", "Argument[0]", "log-injection", "manual"]
- ["lang:std", "<crate::io::stdio::StdoutLock as crate::io::Write>::write_all", "Argument[0]", "log-injection", "manual"]
- ["lang:std", "<crate::io::stdio::StderrLock as crate::io::Write>::write", "Argument[0]", "log-injection", "manual"]
- ["lang:std", "<crate::io::stdio::StderrLock as crate::io::Write>::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", "<crate::option::Option>::expect", "Argument[0]", "log-injection", "manual"]
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ extensions:
- ["lang:core", "<crate::result::Result>::unwrap_or", "Argument[0]", "ReturnValue", "value", "manual"]
# String
- ["lang:alloc", "<crate::string::String>::as_str", "Argument[self]", "ReturnValue", "taint", "manual"]
- ["lang:alloc", "<crate::string::String>::as_bytes", "Argument[self]", "ReturnValue", "taint", "manual"]
# Hint
- ["lang:core", "crate::hint::must_use", "Argument[0]", "ReturnValue", "value", "manual"]
# Fmt
Expand Down
40 changes: 40 additions & 0 deletions rust/ql/lib/codeql/rust/security/CleartextLoggingExtensions.qll
Original file line number Diff line number Diff line change
@@ -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%")) }
}
}
38 changes: 38 additions & 0 deletions rust/ql/src/queries/security/CWE-312/CleartextLogging.qhelp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>

<overview>
<p>
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.
</p>
</overview>

<recommendation>
<p>
Do not log sensitive data. If it is necessary to log sensitive data, encrypt it before logging.
</p>
</recommendation>

<example>
<p>
The following example code logs user credentials (in this case, their password) in plaintext:
</p>
<sample src="CleartextLoggingBad.rs"/>
<p>
Instead, you should encrypt the credentials, or better still, omit them entirely:
</p>
<sample src="CleartextLoggingGood.rs"/>
</example>

<references>

<li>M. Dowd, J. McDonald and J. Schuhm, <i>The Art of Software Security Assessment</i>, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006.</li>
<li>M. Howard and D. LeBlanc, <i>Writing Secure Code</i>, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002.</li>
<li>OWASP: <a href="https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html#data-to-exclude">Logging Cheat Sheet - Data to exclude</a>.</li>

</references>
</qhelp>
58 changes: 58 additions & 0 deletions rust/ql/src/queries/security/CWE-312/CleartextLogging.ql
Original file line number Diff line number Diff line change
@@ -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()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We possibly want something like this as a general flow step. It matters for basically all the test cases that mention &password in the source I think. @paldepind what do you think?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree that adding this as an additional flow step shouldn't be necessary.

I actually would've thought that this should work. If password is tainted then &password should have taint stored in the reference and this implicit read step at the sink should ensure that it is read. I can look into it and see why it doesn't work.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, please do look into this, it looks like it should work to me as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've written up an issue for this as I think it's worth investigating and there are definitely some improvements we can make.

}

predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
// flow out from tuple content at sinks.
isSink(node) and
c.getAReadContent() instanceof TuplePositionContent
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't get tuple content to work in the models-as-data sink itself, so this might have to do for now.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Tuple[i] notation should work for summaries (there's a test here). But I'm not sure if it's also expected to work for sinks.

Copy link
Contributor Author

@geoffw0 geoffw0 Jan 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried the Tuple[i] notation and couldn't get it to work. I'm not sure I could've messed up the syntax, it's pretty simple. So best guess, it doesn't work on sinks at the moment???

}
}

module CleartextLoggingFlow = TaintTracking::Global<CleartextLoggingConfig>;

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()
2 changes: 2 additions & 0 deletions rust/ql/src/queries/security/CWE-312/CleartextLoggingBad.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
let password = "P@ssw0rd";
info!("User password changed to {password}");
2 changes: 2 additions & 0 deletions rust/ql/src/queries/security/CWE-312/CleartextLoggingGood.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
let password = "P@ssw0rd";
info!("User password changed");
5 changes: 4 additions & 1 deletion rust/ql/src/queries/summary/Stats.qll
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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"
}

/**
Expand Down
30 changes: 16 additions & 14 deletions rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
localStep
| file://:0:0:0:0 | [summary param] 0 in lang:core::_::<crate::option::Option>::unwrap_or | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:core::_::<crate::option::Option>::unwrap_or | MaD:2 |
| file://:0:0:0:0 | [summary param] 0 in lang:core::_::<crate::result::Result>::unwrap_or | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:core::_::<crate::result::Result>::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::_::<crate::option::Option>::unwrap | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:core::_::<crate::option::Option>::unwrap | MaD:1 |
| file://:0:0:0:0 | [summary] read: Argument[self].Variant[crate::option::Option::Some(0)] in lang:core::_::<crate::option::Option>::unwrap_or | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:core::_::<crate::option::Option>::unwrap_or | MaD:3 |
| file://:0:0:0:0 | [summary] read: Argument[self].Variant[crate::result::Result::Ok(0)] in lang:core::_::<crate::result::Result>::unwrap | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:core::_::<crate::result::Result>::unwrap | MaD:4 |
| file://:0:0:0:0 | [summary] read: Argument[self].Variant[crate::result::Result::Ok(0)] in lang:core::_::<crate::result::Result>::unwrap_or | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:core::_::<crate::result::Result>::unwrap_or | MaD:6 |
| file://:0:0:0:0 | [summary param] 0 in lang:core::_::<crate::option::Option>::unwrap_or | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:core::_::<crate::option::Option>::unwrap_or | MaD:3 |
| file://:0:0:0:0 | [summary param] 0 in lang:core::_::<crate::result::Result>::unwrap_or | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:core::_::<crate::result::Result>::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::_::<crate::option::Option>::unwrap | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:core::_::<crate::option::Option>::unwrap | MaD:2 |
| file://:0:0:0:0 | [summary] read: Argument[self].Variant[crate::option::Option::Some(0)] in lang:core::_::<crate::option::Option>::unwrap_or | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:core::_::<crate::option::Option>::unwrap_or | MaD:4 |
| file://:0:0:0:0 | [summary] read: Argument[self].Variant[crate::result::Result::Ok(0)] in lang:core::_::<crate::result::Result>::unwrap | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:core::_::<crate::result::Result>::unwrap | MaD:5 |
| file://:0:0:0:0 | [summary] read: Argument[self].Variant[crate::result::Result::Ok(0)] in lang:core::_::<crate::result::Result>::unwrap_or | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:core::_::<crate::result::Result>::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 | |
Expand All @@ -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 | |
Expand Down Expand Up @@ -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; <crate::option::Option>::unwrap; Argument[self].Variant[crate::option::Option::Some(0)]; ReturnValue; value |
| 2 | Summary: lang:core; <crate::option::Option>::unwrap_or; Argument[0]; ReturnValue; value |
| 3 | Summary: lang:core; <crate::option::Option>::unwrap_or; Argument[self].Variant[crate::option::Option::Some(0)]; ReturnValue; value |
| 4 | Summary: lang:core; <crate::result::Result>::unwrap; Argument[self].Variant[crate::result::Result::Ok(0)]; ReturnValue; value |
| 5 | Summary: lang:core; <crate::result::Result>::unwrap_or; Argument[0]; ReturnValue; value |
| 6 | Summary: lang:core; <crate::result::Result>::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; <crate::option::Option>::unwrap; Argument[self].Variant[crate::option::Option::Some(0)]; ReturnValue; value |
| 3 | Summary: lang:core; <crate::option::Option>::unwrap_or; Argument[0]; ReturnValue; value |
| 4 | Summary: lang:core; <crate::option::Option>::unwrap_or; Argument[self].Variant[crate::option::Option::Some(0)]; ReturnValue; value |
| 5 | Summary: lang:core; <crate::result::Result>::unwrap; Argument[self].Variant[crate::result::Result::Ok(0)]; ReturnValue; value |
| 6 | Summary: lang:core; <crate::result::Result>::unwrap_or; Argument[0]; ReturnValue; value |
| 7 | Summary: lang:core; <crate::result::Result>::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::_::<crate::blocking::response::Response>::text | Ok | file://:0:0:0:0 | [summary] to write: ReturnValue in repo:https://github.com/seanmonstar/reqwest:reqwest::_::<crate::blocking::response::Response>::text |
| main.rs:94:14:94:22 | source(...) | tuple.0 | main.rs:94:13:94:26 | TupleExpr |
Expand Down
14 changes: 8 additions & 6 deletions rust/ql/test/library-tests/dataflow/taint/TaintFlowStep.expected
Original file line number Diff line number Diff line change
@@ -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::_::<crate::string::String>::as_str | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:alloc::_::<crate::string::String>::as_str | MaD:1 |
| file://:0:0:0:0 | [summary param] self in repo:https://github.com/seanmonstar/reqwest:reqwest::_::<crate::blocking::response::Response>::text | file://:0:0:0:0 | [summary] to write: ReturnValue.Variant[crate::result::Result::Ok(0)] in repo:https://github.com/seanmonstar/reqwest:reqwest::_::<crate::blocking::response::Response>::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::_::<crate::string::String>::as_bytes | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:alloc::_::<crate::string::String>::as_bytes | MaD:1 |
| file://:0:0:0:0 | [summary param] self in lang:alloc::_::<crate::string::String>::as_str | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:alloc::_::<crate::string::String>::as_str | MaD:2 |
| file://:0:0:0:0 | [summary param] self in repo:https://github.com/seanmonstar/reqwest:reqwest::_::<crate::blocking::response::Response>::text | file://:0:0:0:0 | [summary] to write: ReturnValue.Variant[crate::result::Result::Ok(0)] in repo:https://github.com/seanmonstar/reqwest:reqwest::_::<crate::blocking::response::Response>::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 | |
Expand All @@ -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; <crate::string::String>::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; <crate::blocking::response::Response>::text; Argument[self]; ReturnValue.Variant[crate::result::Result::Ok(0)]; taint |
| 1 | Summary: lang:alloc; <crate::string::String>::as_bytes; Argument[self]; ReturnValue; taint |
| 2 | Summary: lang:alloc; <crate::string::String>::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; <crate::blocking::response::Response>::text; Argument[self]; ReturnValue.Variant[crate::result::Result::Ok(0)]; taint |
4 changes: 2 additions & 2 deletions rust/ql/test/query-tests/diagnostics/SummaryStats.expected
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Original file line number Diff line number Diff line change
@@ -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 |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like there's an error on line 90. Maybe it's the :?? I'm not familiar with the error! macro.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I had assumed this must be an extractor bug, but I never actually ran rustc on this code...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've made the test runnable, and ran it. The syntax on line 90 is accepted by the compiler and produces the expected output (well, I think SimpleLogger is discarding the keys / values / structured part, presumably a more sophisticated logger would use it).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. Maybe it's because the key-value syntax requires the kv feature to be turned on, but the extractor always uses the default features.

Copy link
Contributor Author

@geoffw0 geoffw0 Jan 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds like there's nothing wrong with the test then (it does turn the kv feature on). This probably explains why I couldn't get the results on lines 77 and 78 (which use the kv feature).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think you're right :)

Loading