Rust: Lift content reads as taint steps

This commit is contained in:
Simon Friis Vindum
2025-11-20 17:12:25 +01:00
parent cd721b85e9
commit 8a0e5b5675

View File

@@ -7,6 +7,9 @@ private import Node as Node
private import Content
private import FlowSummaryImpl as FlowSummaryImpl
private import codeql.rust.internal.CachedStages
private import codeql.rust.internal.TypeInference as TypeInference
private import codeql.rust.internal.Type as Type
private import codeql.rust.frameworks.stdlib.Builtins as Builtins
module RustTaintTracking implements InputSig<Location, RustDataFlow> {
predicate defaultTaintSanitizer(DataFlow::Node node) { none() }
@@ -28,11 +31,22 @@ module RustTaintTracking implements InputSig<Location, RustDataFlow> {
succ.asExpr() = index
)
or
// Although data flow through collections and references is modeled using
// stores/reads, we also allow taint to flow out of a tainted collection
// or reference.
// This is needed in order to support taint-tracking configurations where
// the source is a collection or reference.
// Read steps give rise to taint steps. This has the effect that if `foo`
// is tainted and an operation reads from `foo` (e.g., `foo.bar`) then
// taint is propagated. We limit this to not apply if the type of the
// operation is a small primitive type as these are often uninteresting
// (for instance in the case of an injection query).
RustDataFlow::readContentStep(pred, _, succ) and
not exists(Struct s |
s = TypeInference::inferType(succ.asExpr()).(Type::StructType).getStruct()
|
s instanceof Builtins::NumericType or
s instanceof Builtins::Bool or
s instanceof Builtins::Char
)
or
// Let all read steps (including those from flow summaries and those that
// result in small primitive types) give rise to taint steps.
exists(SingletonContentSet cs | RustDataFlow::readStep(pred, cs, succ) |
cs.getContent() instanceof ElementContent
or