Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
34 changes: 8 additions & 26 deletions rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ final class DataFlowCallable extends TDataFlowCallable {
}

/** Gets the location of this callable. */
Location getLocation() { result = this.asCfgScope().getLocation() }
Location getLocation() {
result = [this.asCfgScope().getLocation(), this.asSummarizedCallable().getLocation()]
}
}

final class DataFlowCall extends TDataFlowCall {
Expand Down Expand Up @@ -145,13 +147,9 @@ final class ArgumentPosition extends ParameterPosition {
* as the synthetic `ReceiverNode` is the argument for the `self` parameter.
*/
predicate isArgumentForCall(ExprCfgNode arg, CallCfgNode call, ParameterPosition pos) {
// TODO: Handle index expressions as calls in data flow.
not call.getCall() instanceof IndexExpr and
(
call.getPositionalArgument(pos.getPosition()) = arg
or
call.getReceiver() = arg and pos.isSelf() and not call.getCall().receiverImplicitlyBorrowed()
)
call.getPositionalArgument(pos.getPosition()) = arg
or
call.getReceiver() = arg and pos.isSelf() and not call.getCall().receiverImplicitlyBorrowed()
}

/** Provides logic related to SSA. */
Expand Down Expand Up @@ -557,12 +555,6 @@ module RustDataFlow implements InputSig<Location> {
access = c.(FieldContent).getAnAccess()
)
or
exists(IndexExprCfgNode arr |
c instanceof ElementContent and
node1.asExpr() = arr.getBase() and
node2.asExpr() = arr
)
or
exists(ForExprCfgNode for |
c instanceof ElementContent and
node1.asExpr() = for.getIterable() and
Expand All @@ -582,13 +574,6 @@ module RustDataFlow implements InputSig<Location> {
.isVariantField([any(OptionEnum o).getSome(), any(ResultEnum r).getOk()], 0)
)
or
exists(PrefixExprCfgNode deref |
c instanceof ReferenceContent and
deref.getOperatorName() = "*" and
node1.asExpr() = deref.getExpr() and
node2.asExpr() = deref
)
or
// Read from function return
exists(DataFlowCall call |
lambdaCall(call, _, node1) and
Expand Down Expand Up @@ -700,6 +685,7 @@ module RustDataFlow implements InputSig<Location> {
or
referenceAssignment(node1, node2.(PostUpdateNode).getPreUpdateNode(), c)
or
// todo: rely on flow summary
exists(AssignmentExprCfgNode assignment, IndexExprCfgNode index |
c instanceof ElementContent and
assignment.getLhs() = index and
Expand Down Expand Up @@ -983,11 +969,7 @@ private module Cached {

cached
newtype TDataFlowCall =
TCall(CallCfgNode c) {
Stages::DataFlowStage::ref() and
// TODO: Handle index expressions as calls in data flow.
not c.getCall() instanceof IndexExpr
} or
TCall(CallCfgNode c) { Stages::DataFlowStage::ref() } or
TSummaryCall(
FlowSummaryImpl::Public::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver
) {
Expand Down
8 changes: 2 additions & 6 deletions rust/ql/lib/codeql/rust/dataflow/internal/Node.qll
Original file line number Diff line number Diff line change
Expand Up @@ -467,15 +467,11 @@ newtype TNode =
any(TryExprCfgNode try).getExpr(), //
any(PrefixExprCfgNode pe | pe.getOperatorName() = "*").getExpr(), //
any(AwaitExprCfgNode a).getExpr(), //
any(MethodCallExprCfgNode mc).getReceiver(), //
any(CallCfgNode call | call.getCall().receiverImplicitlyBorrowed()).getReceiver(), //
getPostUpdateReverseStep(any(PostUpdateNode n).getPreUpdateNode().asExpr(), _)
]
} or
TReceiverNode(CallCfgNode mc, Boolean isPost) {
mc.getCall().receiverImplicitlyBorrowed() and
// TODO: Handle index expressions as calls in data flow.
not mc.getCall() instanceof IndexExpr
} or
TReceiverNode(CallCfgNode mc, Boolean isPost) { mc.getCall().receiverImplicitlyBorrowed() } or
TSsaNode(SsaImpl::DataFlowIntegration::SsaNode node) or
TFlowSummaryNode(FlowSummaryImpl::Private::SummaryNode sn) or
TClosureSelfReferenceNode(CfgScope c) { lambdaCreationExpr(c, _) } or
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,6 @@ module RustTaintTracking implements InputSig<Location, RustDataFlow> {
or
pred.asExpr() = succ.asExpr().(CastExprCfgNode).getExpr()
or
exists(IndexExprCfgNode index |
index.getIndex() instanceof RangeExprCfgNode and
pred.asExpr() = index.getBase() and
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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ private import codeql.rust.elements.internal.ExprImpl::Impl as ExprImpl
* the canonical path `path` and the method name `method`, and if it borrows its
* first `borrows` arguments.
*/
private predicate isOverloaded(string op, int arity, string path, string method, int borrows) {
predicate isOverloaded(string op, int arity, string path, string method, int borrows) {
arity = 1 and
(
// Negation
Expand Down
7 changes: 7 additions & 0 deletions rust/ql/lib/codeql/rust/elements/internal/UnionImpl.qll
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ module Impl {
* ```
*/
class Union extends Generated::Union {
/** Gets the record field named `name`, if any. */
pragma[nomagic]
StructField getStructField(string name) {
result = this.getStructFieldList().getAField() and
result.getName().getText() = name
}

override string toStringImpl() { result = "union " + this.getName().getText() }
}
}
112 changes: 112 additions & 0 deletions rust/ql/lib/codeql/rust/frameworks/stdlib/Stdlib.qll
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ private import codeql.rust.Concepts
private import codeql.rust.controlflow.ControlFlowGraph as Cfg
private import codeql.rust.controlflow.CfgNodes as CfgNodes
private import codeql.rust.dataflow.DataFlow
private import codeql.rust.dataflow.FlowSummary
private import codeql.rust.internal.PathResolution
private import codeql.rust.internal.Type
private import codeql.rust.internal.TypeInference
private import codeql.rust.internal.TypeMention

/**
* A call to the `starts_with` method on a `Path`.
Expand Down Expand Up @@ -213,3 +217,111 @@ class StringStruct extends Struct {
pragma[nomagic]
StringStruct() { this.getCanonicalPath() = "alloc::string::String" }
}

/**
* The [`Deref` trait][1].
*
* [1]: https://doc.rust-lang.org/core/ops/trait.Deref.html
*/
class DerefTrait extends Trait {
pragma[nomagic]
DerefTrait() { this.getCanonicalPath() = "core::ops::deref::Deref" }

/** Gets the `Target` associated type. */
pragma[nomagic]
TypeAlias getTargetType() {
result = this.getAssocItemList().getAnAssocItem() and
result.getName().getText() = "Target"
}
}

/**
* One of the two special
*
* ```rust
* impl<T: ?Sized> const Deref for &T
* impl<T: ?Sized> const Deref for &mut T
* ```
*
* implementations.
*/
private class CoreDerefImpl extends ImplItemNode {
pragma[nomagic]
CoreDerefImpl() {
this.resolveTraitTy() instanceof DerefTrait and
this.(Impl)
.getSelfTy()
.(TypeMention)
.resolveTypeAt(TypePath::singleton(TRefTypeParameter()))
.(TypeParamTypeParameter)
.getTypeParam() = this.getTypeParam(_)
}

Function getDeref() { result = this.getASuccessor("deref") }
}

// TODO: Use MaD when `&(mut) T` is assigned an appropriate canonical path
private class CoreDerefSummarizedCallable extends SummarizedCallable::Range {
CoreDerefSummarizedCallable() { this = any(CoreDerefImpl i).getDeref() }

override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self].Reference" and
output = "ReturnValue" and
preservesValue = true
}
}

/**
* The [`Index` trait][1].
*
* [1]: https://doc.rust-lang.org/std/ops/trait.Index.html
*/
class IndexTrait extends Trait {
pragma[nomagic]
IndexTrait() { this.getCanonicalPath() = "core::ops::index::Index" }

/** Gets the `Output` associated type. */
pragma[nomagic]
TypeAlias getOutputType() {
result = this.getAssocItemList().getAnAssocItem() and
result.getName().getText() = "Output"
}
}

/**
* One of the two special
*
* ```rust
* impl<T, I, const N: usize> Index<I> for [T; N]
* impl<T, I> ops::Index<I> for [T]
* ```
*
* implementations.
*/
private class CoreIndexImpl extends ImplItemNode {
pragma[nomagic]
CoreIndexImpl() {
this.resolveTraitTy() instanceof IndexTrait and
exists(TypeParameter tp | tp = TArrayTypeParameter() or tp = TSliceTypeParameter() |
this.(Impl)
.getSelfTy()
.(TypeMention)
.resolveTypeAt(TypePath::singleton(tp))
.(TypeParamTypeParameter)
.getTypeParam() = this.getTypeParam(_)
)
}

Function getIndex() { result = this.getASuccessor("index") }
}

// TODO: Use MaD when `[T(; N)]` is assigned an appropriate canonical path
private class CoreIndexSummarizedCallable extends SummarizedCallable::Range {
CoreIndexSummarizedCallable() { this = any(CoreIndexImpl i).getIndex() }

override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self].Reference.Element" and
output = "ReturnValue" and
preservesValue = true
}
}
13 changes: 4 additions & 9 deletions rust/ql/lib/codeql/rust/frameworks/stdlib/lang-alloc.model.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,10 @@ extensions:
- ["<alloc::boxed::Box>::pin", "Argument[0]", "ReturnValue.Reference", "value", "manual"]
- ["<alloc::boxed::Box>::new", "Argument[0]", "ReturnValue.Reference", "value", "manual"]
- ["<alloc::boxed::Box>::into_pin", "Argument[0]", "ReturnValue", "value", "manual"]
- ["<alloc::boxed::Box as core::ops::deref::Deref>::deref", "Argument[self].Reference", "ReturnValue", "value", "manual"]
# Fmt
- ["alloc::fmt::format", "Argument[0]", "ReturnValue", "taint", "manual"]
# String
- ["<core::str>::as_str", "Argument[self]", "ReturnValue", "value", "manual"]
- ["<core::str>::as_bytes", "Argument[self]", "ReturnValue", "value", "manual"]
- ["<alloc::string::String>::as_str", "Argument[self]", "ReturnValue", "value", "manual"]
- ["<alloc::string::String>::as_bytes", "Argument[self]", "ReturnValue", "value", "manual"]
- ["<alloc::str as alloc::string::ToString>::to_string", "Argument[self]", "ReturnValue", "taint", "manual"]
- ["<alloc::string::String as alloc::string::ToString>::to_string", "Argument[self]", "ReturnValue", "taint", "manual"]
- ["<core::str>::parse", "Argument[self]", "ReturnValue.Field[core::result::Result::Ok(0)]", "taint", "manual"]
- ["<core::str>::trim", "Argument[self]", "ReturnValue.Reference", "taint", "manual"]
- ["<alloc::string::String as core::convert::From>::from", "Argument[0]", "ReturnValue", "value", "manual"]
- ["<alloc::string::String>::as_str", "Argument[self].Reference", "ReturnValue.Reference", "taint", "manual"]
- ["<alloc::string::String>::as_bytes", "Argument[self].Reference", "ReturnValue.Reference", "taint", "manual"]
- ["<alloc::string::String as core::convert::From>::from", "Argument[0].Reference", "ReturnValue", "taint", "manual"]
15 changes: 8 additions & 7 deletions rust/ql/lib/codeql/rust/frameworks/stdlib/lang-core.model.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ extensions:
- ["<core::slice::iter::Iter as core::iter::traits::iterator::Iterator>::collect", "Argument[self].Element", "ReturnValue.Element", "value", "manual"]
- ["<core::slice::iter::Iter as core::iter::traits::iterator::Iterator>::map", "Argument[self].Element", "Argument[0].Parameter[0]", "value", "manual"]
- ["<_ as core::iter::traits::iterator::Iterator>::for_each", "Argument[self].Element", "Argument[0].Parameter[0]", "value", "manual"]
# Index
- ["<alloc::vec::Vec as core::ops::index::Index>::index", "Argument[self].Reference.Element", "ReturnValue", "value", "manual"]
- ["<alloc::string::String as core::ops::index::Index>::index", "Argument[self].Reference", "ReturnValue", "taint", "manual"]
# Layout
- ["<core::alloc::layout::Layout>::from_size_align", "Argument[0]", "ReturnValue.Field[core::result::Result::Ok(0)]", "taint", "manual"]
- ["<core::alloc::layout::Layout>::from_size_align_unchecked", "Argument[0]", "ReturnValue", "taint", "manual"]
Expand All @@ -48,6 +51,7 @@ extensions:
- ["<core::pin::Pin>::into_inner", "Argument[0]", "ReturnValue", "value", "manual"]
- ["<core::pin::Pin>::into_inner_unchecked", "Argument[0]", "ReturnValue", "value", "manual"]
- ["<core::pin::Pin>::set", "Argument[0]", "Argument[self]", "value", "manual"]
- ["<core::pin::Pin as core::ops::deref::Deref>::deref", "Argument[self].Reference", "ReturnValue", "value", "manual"]
# Ptr
- ["core::ptr::read", "Argument[0].Reference", "ReturnValue", "value", "manual"]
- ["core::ptr::read_unaligned", "Argument[0].Reference", "ReturnValue", "value", "manual"]
Expand All @@ -56,13 +60,10 @@ extensions:
- ["core::ptr::write_unaligned", "Argument[1]", "Argument[0].Reference", "value", "manual"]
- ["core::ptr::write_volatile", "Argument[1]", "Argument[0].Reference", "value", "manual"]
# Str
- ["<core::str>::as_str", "Argument[self]", "ReturnValue", "taint", "value"]
- ["<alloc::string::String>::as_str", "Argument[self]", "ReturnValue", "taint", "value"]
- ["<core::str>::as_bytes", "Argument[self]", "ReturnValue", "taint", "value"]
- ["<alloc::string::String>::as_bytes", "Argument[self]", "ReturnValue", "taint", "value"]
- ["<core::str>::to_string", "Argument[self]", "ReturnValue", "taint", "manual"]
- ["<core::str>::parse", "Argument[self]", "ReturnValue.Field[core::result::Result::Ok(0)]", "taint", "manual"]
- ["<core::str>::trim", "Argument[self]", "ReturnValue.Reference", "taint", "manual"]
- ["<core::str>::as_str", "Argument[self].Reference", "ReturnValue.Reference", "taint", "value"]
- ["<core::str>::as_bytes", "Argument[self].Reference", "ReturnValue.Reference", "taint", "value"]
- ["<core::str>::parse", "Argument[self].Reference", "ReturnValue.Field[core::result::Result::Ok(0)]", "taint", "manual"]
- ["<core::str>::trim", "Argument[self].Reference", "ReturnValue.Reference", "taint", "manual"]
- addsTo:
pack: codeql/rust-all
extensible: sourceModel
Expand Down
4 changes: 3 additions & 1 deletion rust/ql/lib/codeql/rust/internal/PathResolution.qll
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,8 @@ final class ImplItemNode extends ImplOrTraitItemNode instanceof Impl {

TraitItemNode resolveTraitTy() { result = resolvePath(this.getTraitPath()) }

predicate isBlanket() { this.resolveSelfTy() instanceof TypeParam }

override AssocItemNode getAnAssocItem() { result = this.getADescendant() }

override string getName() { result = "(impl)" }
Expand Down Expand Up @@ -726,7 +728,7 @@ final class ImplItemNode extends ImplOrTraitItemNode instanceof Impl {
}
}

final private class ImplTraitTypeReprItemNode extends TypeItemNode instanceof ImplTraitTypeRepr {
final class ImplTraitTypeReprItemNode extends TypeItemNode instanceof ImplTraitTypeRepr {
pragma[nomagic]
Path getABoundPath() {
result = super.getTypeBoundList().getABound().getTypeRepr().(PathTypeRepr).getPath()
Expand Down
Loading