Merge branch 'main' of https://github.com/github/codeql into post-release-prep/codeql-cli-2.25.1

This commit is contained in:
Óscar San José
2026-03-30 10:51:12 +02:00
765 changed files with 13826 additions and 27987 deletions

View File

@@ -0,0 +1,85 @@
/**
* Provides classes and predicates for defining barriers and barrier guards.
*
* Flow barriers and barrier guards defined here feed into data flow configurations as follows:
*
* ```text
* data from *.model.yml | QL extensions of FlowBarrier::Range
* v v
* FlowBarrier (associated with a models-as-data kind string)
* v
* barrierNode predicate | other QL defined barriers, for example using concepts
* v v
* various Barrier classes for specific data flow configurations
*
* data from *.model.yml | QL extensions of FlowBarrierGuard::Range
* v v
* FlowBarrierGuard (associated with a models-as-data kind string)
* v
* barrierNode predicate | other QL defined barrier guards, for example using concepts
* v v
* various Barrier classes for specific data flow configurations
* ```
*
* New barriers and barrier guards should be defined using models-as-data, QL extensions of
* `FlowBarrier::Range`/`FlowBarrierGuard::Range`, or concepts. Data flow configurations should use the
* `barrierNode` predicate and/or concepts to define their barriers.
*/
private import rust
private import internal.FlowSummaryImpl as Impl
private import internal.DataFlowImpl as DataFlowImpl
// import all instances below
private module Barriers {
private import codeql.rust.Frameworks
private import codeql.rust.dataflow.internal.ModelsAsData
}
/** Provides the `Range` class used to define the extent of `FlowBarrier`. */
module FlowBarrier {
/** A flow barrier. */
abstract class Range extends Impl::Public::BarrierElement {
bindingset[this]
Range() { any() }
override predicate isBarrier(
string output, string kind, Impl::Public::Provenance provenance, string model
) {
this.isBarrier(output, kind) and provenance = "manual" and model = ""
}
/**
* Holds if this element is a flow barrier of kind `kind`, where data
* flows out as described by `output`.
*/
predicate isBarrier(string output, string kind) { none() }
}
}
final class FlowBarrier = FlowBarrier::Range;
/** Provides the `Range` class used to define the extent of `FlowBarrierGuard`. */
module FlowBarrierGuard {
/** A flow barrier guard. */
abstract class Range extends Impl::Public::BarrierGuardElement {
bindingset[this]
Range() { any() }
override predicate isBarrierGuard(
string input, string branch, string kind, Impl::Public::Provenance provenance, string model
) {
this.isBarrierGuard(input, branch, kind) and provenance = "manual" and model = ""
}
/**
* Holds if this element is a flow barrier guard of kind `kind`, for data
* flowing in as described by `input`, when `this` evaluates to `branch`.
*/
predicate isBarrierGuard(string input, string branch, string kind) { none() }
}
}
final class FlowBarrierGuard = FlowBarrierGuard::Range;
predicate barrierNode = DataFlowImpl::barrierNode/2;

View File

@@ -1157,6 +1157,64 @@ private module Cached {
cached
predicate sinkNode(Node n, string kind) { n.(FlowSummaryNode).isSink(kind, _) }
private newtype TKindModelPair =
TMkPair(string kind, string model) {
FlowSummaryImpl::Private::barrierGuardSpec(_, _, _, kind, model)
}
private boolean convertAcceptingValue(FlowSummaryImpl::Public::AcceptingValue av) {
av.isTrue() and result = true
or
av.isFalse() and result = false
// Remaining cases are not supported yet, they depend on the shared Guards library.
// or
// av.isNoException() and result.getDualValue().isThrowsException()
// or
// av.isZero() and result.asIntValue() = 0
// or
// av.isNotZero() and result.getDualValue().asIntValue() = 0
// or
// av.isNull() and result.isNullValue()
// or
// av.isNotNull() and result.isNonNullValue()
}
private predicate barrierGuardChecks(AstNode g, Expr e, boolean gv, TKindModelPair kmp) {
exists(
FlowSummaryImpl::Public::BarrierGuardElement b,
FlowSummaryImpl::Private::SummaryComponentStack stack,
FlowSummaryImpl::Public::AcceptingValue acceptingvalue, string kind, string model
|
FlowSummaryImpl::Private::barrierGuardSpec(b, stack, acceptingvalue, kind, model) and
e = FlowSummaryImpl::StepsInput::getSinkNode(b, stack.headOfSingleton()).asExpr() and
kmp = TMkPair(kind, model) and
gv = convertAcceptingValue(acceptingvalue) and
g = b.getCall()
)
}
/** Holds if `n` is a flow barrier of kind `kind` and model `model`. */
cached
predicate barrierNode(Node n, string kind, string model) {
exists(
FlowSummaryImpl::Public::BarrierElement b,
FlowSummaryImpl::Private::SummaryComponentStack stack
|
FlowSummaryImpl::Private::barrierSpec(b, stack, kind, model)
|
n = FlowSummaryImpl::StepsInput::getSourceNode(b, stack, false)
or
// For barriers like `Argument[0]` we want to target the pre-update node
n =
FlowSummaryImpl::StepsInput::getSourceNode(b, stack, true)
.(PostUpdateNode)
.getPreUpdateNode()
)
or
ParameterizedBarrierGuard<TKindModelPair, barrierGuardChecks/4>::getABarrierNode(TMkPair(kind,
model)) = n
}
/**
* A step in a flow summary defined using `OptionalStep[name]`. An `OptionalStep` is "opt-in", which means
* that by default the step is not present in the flow summary and needs to be explicitly enabled by defining
@@ -1180,3 +1238,34 @@ private module Cached {
}
import Cached
/** Holds if `n` is a flow barrier of kind `kind`. */
predicate barrierNode(Node n, string kind) { barrierNode(n, kind, _) }
bindingset[this]
private signature class ParamSig;
private module WithParam<ParamSig P> {
/**
* Holds if the guard `g` validates the expression `e` upon evaluating to `gv`.
*
* The expression `e` is expected to be a syntactic part of the guard `g`.
* For example, the guard `g` might be a call `isSafe(x)` and the expression `e`
* the argument `x`.
*/
signature predicate guardChecksSig(AstNode g, Expr e, boolean branch, P param);
}
/**
* Provides a set of barrier nodes for a guard that validates an expression.
*
* This is expected to be used in `isBarrier`/`isSanitizer` definitions
* in data flow and taint tracking.
*/
module ParameterizedBarrierGuard<ParamSig P, WithParam<P>::guardChecksSig/4 guardChecks> {
/** Gets a node that is safely guarded by the given guard check. */
Node getABarrierNode(P param) {
SsaFlow::asNode(result) =
SsaImpl::DataFlowIntegration::ParameterizedBarrierGuard<P, guardChecks/4>::getABarrierNode(param)
}
}

View File

@@ -143,7 +143,7 @@ module Input implements InputSig<Location, RustDataFlow> {
private import Make<Location, RustDataFlow, Input> as Impl
private module StepsInput implements Impl::Private::StepsInputSig {
module StepsInput implements Impl::Private::StepsInputSig {
DataFlowCall getACall(Public::SummarizedCallable sc) { result.asCall().getStaticTarget() = sc }
/** Gets the argument of `source` described by `sc`, if any. */
@@ -171,18 +171,27 @@ private module StepsInput implements Impl::Private::StepsInputSig {
result.asCfgScope() = source.getEnclosingCfgScope()
}
RustDataFlow::Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponentStack s) {
additional RustDataFlow::Node getSourceNode(
Input::SourceBase source, Impl::Private::SummaryComponentStack s, boolean isArgPostUpdate
) {
s.head() = Impl::Private::SummaryComponent::return(_) and
result.asExpr() = source.getCall()
result.asExpr() = source.getCall() and
isArgPostUpdate = false
or
exists(RustDataFlow::ArgumentPosition pos, Expr arg |
s.head() = Impl::Private::SummaryComponent::parameter(pos) and
arg = getSourceNodeArgument(source, s.tail().headOfSingleton()) and
result.asParameter() = getCallable(arg).getParam(pos.getPosition())
result.asParameter() = getCallable(arg).getParam(pos.getPosition()) and
isArgPostUpdate = false
)
or
result.(RustDataFlow::PostUpdateNode).getPreUpdateNode().asExpr() =
getSourceNodeArgument(source, s.headOfSingleton())
getSourceNodeArgument(source, s.headOfSingleton()) and
isArgPostUpdate = true
}
RustDataFlow::Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponentStack s) {
result = getSourceNode(source, s, _)
}
RustDataFlow::Node getSinkNode(Input::SinkBase sink, Impl::Private::SummaryComponent sc) {

View File

@@ -44,6 +44,7 @@
*/
private import rust
private import codeql.rust.dataflow.FlowBarrier
private import codeql.rust.dataflow.FlowSummary
private import codeql.rust.dataflow.FlowSource
private import codeql.rust.dataflow.FlowSink
@@ -98,6 +99,29 @@ extensible predicate neutralModel(
string path, string kind, string provenance, QlBuiltins::ExtensionId madId
);
/**
* Holds if in a call to the function with canonical path `path`, the value referred
* to by `output` is a barrier of the given `kind` and `madId` is the data
* extension row number.
*/
extensible predicate barrierModel(
string path, string output, string kind, string provenance, QlBuiltins::ExtensionId madId
);
/**
* Holds if in a call to the function with canonical path `path`, the value referred
* to by `input` is a barrier guard of the given `kind` and `madId` is the data
* extension row number.
*
* The value referred to by `input` is assumed to lead to an argument of a call
* (possibly `self`), and the call is guarding the argument. `branch` is either `true`
* or `false`, indicating which branch of the guard is protecting the argument.
*/
extensible predicate barrierGuardModel(
string path, string input, string branch, string kind, string provenance,
QlBuiltins::ExtensionId madId
);
/**
* Holds if the given extension tuple `madId` should pretty-print as `model`.
*
@@ -123,6 +147,16 @@ predicate interpretModelForTest(QlBuiltins::ExtensionId madId, string model) {
neutralModel(path, kind, _, madId) and
model = "Neutral: " + path + "; " + kind
)
or
exists(string path, string output, string kind |
barrierModel(path, output, kind, _, madId) and
model = "Barrier: " + path + "; " + output + "; " + kind
)
or
exists(string path, string input, string branch, string kind |
barrierGuardModel(path, input, branch, kind, _, madId) and
model = "Barrier guard: " + path + "; " + input + "; " + branch + "; " + kind
)
}
private class SummarizedCallableFromModel extends SummarizedCallable::Range {
@@ -206,6 +240,40 @@ private class FlowSinkFromModel extends FlowSink::Range {
}
}
private class FlowBarrierFromModel extends FlowBarrier::Range {
private string path;
FlowBarrierFromModel() {
barrierModel(path, _, _, _, _) and
this.callResolvesTo(path)
}
override predicate isBarrier(string output, string kind, Provenance provenance, string model) {
exists(QlBuiltins::ExtensionId madId |
barrierModel(path, output, kind, provenance, madId) and
model = "MaD:" + madId.toString()
)
}
}
private class FlowBarrierGuardFromModel extends FlowBarrierGuard::Range {
private string path;
FlowBarrierGuardFromModel() {
barrierGuardModel(path, _, _, _, _, _) and
this.callResolvesTo(path)
}
override predicate isBarrierGuard(
string input, string branch, string kind, Provenance provenance, string model
) {
exists(QlBuiltins::ExtensionId madId |
barrierGuardModel(path, input, branch, kind, provenance, madId) and
model = "MaD:" + madId.toString()
)
}
}
private module Debug {
private import FlowSummaryImpl
private import Private

View File

@@ -82,12 +82,12 @@ class FlowSummaryNode extends Node, TFlowSummaryNode {
result = this.getSummaryNode().getSinkElement()
}
/** Holds is this node is a source node of kind `kind`. */
/** Holds if this node is a source node of kind `kind`. */
predicate isSource(string kind, string model) {
this.getSummaryNode().(FlowSummaryImpl::Private::SourceOutputNode).isEntry(kind, model)
}
/** Holds is this node is a sink node of kind `kind`. */
/** Holds if this node is a sink node of kind `kind`. */
predicate isSink(string kind, string model) {
this.getSummaryNode().(FlowSummaryImpl::Private::SinkInputNode).isExit(kind, model)
}

View File

@@ -305,6 +305,31 @@ private module Cached {
predicate getABarrierNode = getABarrierNodeImpl/0;
}
bindingset[this]
private signature class ParamSig;
private module WithParam<ParamSig P> {
signature predicate guardChecksSig(AstNode g, Expr e, boolean branch, P param);
}
overlay[global]
cached // nothing is actually cached
module ParameterizedBarrierGuard<ParamSig P, WithParam<P>::guardChecksSig/4 guardChecks> {
private predicate guardChecksAdjTypes(
DataFlowIntegrationInput::Guard g, DataFlowIntegrationInput::Expr e,
DataFlowIntegrationInput::GuardValue branch, P param
) {
guardChecks(g, e, branch, param)
}
private Node getABarrierNodeImpl(P param) {
result =
DataFlowIntegrationImpl::BarrierGuardWithState<P, guardChecksAdjTypes/4>::getABarrierNode(param)
}
predicate getABarrierNode = getABarrierNodeImpl/1;
}
}
}

View File

@@ -15,3 +15,13 @@ extensions:
pack: codeql/rust-all
extensible: summaryModel
data: []
- addsTo:
pack: codeql/rust-all
extensible: barrierModel
data: []
- addsTo:
pack: codeql/rust-all
extensible: barrierGuardModel
data: []

View File

@@ -33,5 +33,11 @@ module Impl {
result = "impl " + trait + this.getSelfTy().toAbbreviatedString() + " { ... }"
)
}
/**
* Holds if this is an inherent `impl` block, that is, one that does not implement a trait.
*/
pragma[nomagic]
predicate isInherent() { not this.hasTrait() }
}
}

View File

@@ -6,7 +6,15 @@ module Impl {
private newtype TArgumentPosition =
TPositionalArgumentPosition(int i) {
i in [0 .. max([any(ParamList l).getNumberOfParams(), any(ArgList l).getNumberOfArgs()]) - 1]
// For the type `FunctionPosition` used by type inference, we work with function-call syntax
// adjusted positions, so a call like `x.m(a, b, c)` needs positions `0` through `3`; for this
// reason, there is no `- 1` after `max(...)` below.
i in [0 .. max([
any(ParamList l).getNumberOfParams(),
any(ArgList l).getNumberOfArgs(),
any(StructFieldList l).getNumberOfFields() // Positions are used for struct expressions in type inference
]
)]
} or
TSelfArgumentPosition() or
TTypeQualifierArgumentPosition()

View File

@@ -50,5 +50,10 @@ module Impl {
or
result = this.getVariant().getStructField(name)
}
/** Gets the `i`th struct field of the instantiated struct or variant. */
StructField getNthStructField(int i) {
result = [this.getStruct().getNthStructField(i), this.getVariant().getNthStructField(i)]
}
}
}

View File

@@ -35,6 +35,12 @@ module Impl {
/** Gets a record field, if any. */
StructField getAStructField() { result = this.getStructField(_) }
/** Gets the `i`th struct field, if any. */
pragma[nomagic]
StructField getNthStructField(int i) {
result = this.getFieldList().(StructFieldList).getField(i)
}
/** Gets the `i`th tuple field, if any. */
pragma[nomagic]
TupleField getTupleField(int i) { result = this.getFieldList().(TupleFieldList).getField(i) }

View File

@@ -42,6 +42,13 @@ module Impl {
)
}
/** Gets the `i`th struct field of the instantiated struct or variant. */
StructField getNthStructField(int i) {
exists(PathResolution::ItemNode item | item = this.getResolvedPath(_) |
result = [item.(Struct).getNthStructField(i), item.(Variant).getNthStructField(i)]
)
}
/** Gets the struct pattern for the field `name`. */
pragma[nomagic]
StructPatField getPatField(string name) {

View File

@@ -32,7 +32,8 @@ module Impl {
* Gets the `index`th type bound of this type parameter, if any.
*
* This includes type bounds directly on this type parameter and bounds from
* any `where` clauses for this type parameter.
* any `where` clauses for this type parameter, but restricted to `where`
* clauses from the item that declares this type parameter.
*/
TypeBound getTypeBound(int index) {
result =
@@ -43,13 +44,36 @@ module Impl {
* Gets a type bound of this type parameter.
*
* This includes type bounds directly on this type parameter and bounds from
* any `where` clauses for this type parameter.
* any `where` clauses for this type parameter, but restricted to `where`
* clauses from the item that declares this type parameter.
*/
TypeBound getATypeBound() { result = this.getTypeBound(_) }
/** Holds if this type parameter has at least one type bound. */
predicate hasTypeBound() { exists(this.getATypeBound()) }
/**
* Gets the `index`th additional type bound of this type parameter,
* which applies to `constrainingItem`, if any.
*
* For example, in
*
* ```rust
* impl<T> SomeType<T> where T: Clone {
* fn foo() where T: Debug { }
* }
* ```
*
* The constraint `Debug` additionally applies to `T` in `foo`.
*/
TypeBound getAdditionalTypeBound(Item constrainingItem, int index) {
result =
rank[index + 1](int i, int j |
|
this.(TypeParamItemNode).getAdditionalTypeBoundAt(constrainingItem, i, j) order by i, j
)
}
override string toAbbreviatedString() { result = this.getName().getText() }
override string toStringImpl() { result = this.getName().getText() }

View File

@@ -32,6 +32,12 @@ module Impl {
result.getName().getText() = name
}
/** Gets the `i`th struct field, if any. */
pragma[nomagic]
StructField getNthStructField(int i) {
result = this.getFieldList().(StructFieldList).getField(i)
}
/** Gets the `i`th tuple field, if any. */
pragma[nomagic]
TupleField getTupleField(int i) { result = this.getFieldList().(TupleFieldList).getField(i) }

View File

@@ -1162,21 +1162,39 @@ private Path getWherePredPath(WherePred wp) { result = wp.getTypeRepr().(PathTyp
final class TypeParamItemNode extends NamedItemNode, TypeItemNode instanceof TypeParam {
/** Gets a where predicate for this type parameter, if any */
pragma[nomagic]
private WherePred getAWherePred() {
private WherePred getAWherePred(ItemNode constrainingItem, boolean isAdditional) {
exists(ItemNode declaringItem |
this = declaringItem.getTypeParam(_) and
this = resolvePath(getWherePredPath(result)) and
result = declaringItem.getADescendant() and
this = declaringItem.getADescendant()
result = constrainingItem.getADescendant()
|
constrainingItem = declaringItem and
isAdditional = false
or
constrainingItem = declaringItem.getADescendant() and
isAdditional = true
)
}
pragma[nomagic]
TypeBound getTypeBoundAt(int i, int j) {
exists(TypeBoundList tbl | result = tbl.getBound(j) |
tbl = super.getTypeBoundList() and i = 0
tbl = super.getTypeBoundList() and
i = 0
or
exists(WherePred wp |
wp = this.getAWherePred() and
wp = this.getAWherePred(_, false) and
tbl = wp.getTypeBoundList() and
wp = any(WhereClause wc).getPredicate(i)
)
)
}
pragma[nomagic]
TypeBound getAdditionalTypeBoundAt(Item constrainingItem, int i, int j) {
exists(TypeBoundList tbl | result = tbl.getBound(j) |
exists(WherePred wp |
wp = this.getAWherePred(constrainingItem, true) and
tbl = wp.getTypeBoundList() and
wp = any(WhereClause wc).getPredicate(i)
)
@@ -1197,6 +1215,15 @@ final class TypeParamItemNode extends NamedItemNode, TypeItemNode instanceof Typ
ItemNode resolveABound() { result = resolvePath(this.getABoundPath()) }
pragma[nomagic]
ItemNode resolveAdditionalBound(ItemNode constrainingItem) {
result =
resolvePath(this.getAdditionalTypeBoundAt(constrainingItem, _, _)
.getTypeRepr()
.(PathTypeRepr)
.getPath())
}
override string getName() { result = TypeParam.super.getName().getText() }
override Namespace getNamespace() { result.isType() }

View File

@@ -41,16 +41,19 @@ private predicate hasFirstNonTrivialTraitBound(TypeParamItemNode tp, Trait trait
*/
pragma[nomagic]
predicate isBlanketLike(ImplItemNode i, TypePath blanketSelfPath, TypeParam blanketTypeParam) {
blanketTypeParam = i.getBlanketImplementationTypeParam() and
blanketSelfPath.isEmpty()
or
exists(TypeMention tm, Type root, TypeParameter tp |
tm = i.(Impl).getSelfTy() and
complexSelfRoot(root, tp) and
tm.getType() = root and
tm.getTypeAt(blanketSelfPath) = TTypeParamTypeParameter(blanketTypeParam) and
blanketSelfPath = TypePath::singleton(tp) and
hasFirstNonTrivialTraitBound(blanketTypeParam, _)
i.(Impl).hasTrait() and
(
blanketTypeParam = i.getBlanketImplementationTypeParam() and
blanketSelfPath.isEmpty()
or
exists(TypeMention tm, Type root, TypeParameter tp |
tm = i.(Impl).getSelfTy() and
complexSelfRoot(root, tp) and
tm.getType() = root and
tm.getTypeAt(blanketSelfPath) = TTypeParamTypeParameter(blanketTypeParam) and
blanketSelfPath = TypePath::singleton(tp) and
hasFirstNonTrivialTraitBound(blanketTypeParam, _)
)
)
}
@@ -100,7 +103,7 @@ module SatisfiesBlanketConstraint<
}
private module SatisfiesBlanketConstraintInput implements
SatisfiesConstraintInputSig<ArgumentTypeAndBlanketOffset>
SatisfiesTypeInputSig<ArgumentTypeAndBlanketOffset>
{
pragma[nomagic]
additional predicate relevantConstraint(
@@ -120,7 +123,7 @@ module SatisfiesBlanketConstraint<
}
private module SatisfiesBlanketConstraint =
SatisfiesConstraint<ArgumentTypeAndBlanketOffset, SatisfiesBlanketConstraintInput>;
SatisfiesType<ArgumentTypeAndBlanketOffset, SatisfiesBlanketConstraintInput>;
/**
* Holds if the argument type `at` satisfies the first non-trivial blanket

View File

@@ -13,68 +13,105 @@ private import TypeMention
private import TypeInference
private import FunctionType
pragma[nomagic]
private Type resolveNonTypeParameterTypeAt(TypeMention tm, TypePath path) {
result = tm.getTypeAt(path) and
not result instanceof TypeParameter
}
bindingset[t1, t2]
private predicate typeMentionEqual(TypeMention t1, TypeMention t2) {
forex(TypePath path, Type type | resolveNonTypeParameterTypeAt(t1, path) = type |
resolveNonTypeParameterTypeAt(t2, path) = type
)
}
pragma[nomagic]
private predicate implSiblingCandidate(
Impl impl, TraitItemNode trait, Type rootType, TypeMention selfTy
) {
trait = impl.(ImplItemNode).resolveTraitTy() and
selfTy = impl.getSelfTy() and
rootType = selfTy.getType()
}
pragma[nomagic]
private predicate blanketImplSiblingCandidate(ImplItemNode impl, Trait trait) {
impl.isBlanketImplementation() and
trait = impl.resolveTraitTy()
}
private signature Type resolveTypeMentionAtSig(AstNode tm, TypePath path);
/**
* Holds if `impl1` and `impl2` are a sibling implementations of `trait`. We
* consider implementations to be siblings if they implement the same trait for
* the same type. In that case `Self` is the same type in both implementations,
* and method calls to the implementations cannot be resolved unambiguously
* based only on the receiver type.
* Provides logic for identifying sibling implementations, parameterized over
* how to resolve type mentions (`PreTypeMention` vs. `TypeMention`).
*/
pragma[inline]
private predicate implSiblings(TraitItemNode trait, Impl impl1, Impl impl2) {
impl1 != impl2 and
(
exists(Type rootType, TypeMention selfTy1, TypeMention selfTy2 |
implSiblingCandidate(impl1, trait, rootType, selfTy1) and
implSiblingCandidate(impl2, trait, rootType, selfTy2) and
// In principle the second conjunct below should be superflous, but we still
// have ill-formed type mentions for types that we don't understand. For
// those checking both directions restricts further. Note also that we check
// syntactic equality, whereas equality up to renaming would be more
// correct.
typeMentionEqual(selfTy1, selfTy2) and
typeMentionEqual(selfTy2, selfTy1)
private module MkSiblingImpls<resolveTypeMentionAtSig/2 resolveTypeMentionAt> {
pragma[nomagic]
private Type resolveNonTypeParameterTypeAt(AstNode tm, TypePath path) {
result = resolveTypeMentionAt(tm, path) and
not result instanceof TypeParameter
}
bindingset[t1, t2]
private predicate typeMentionEqual(AstNode t1, AstNode t2) {
forex(TypePath path, Type type | resolveNonTypeParameterTypeAt(t1, path) = type |
resolveNonTypeParameterTypeAt(t2, path) = type
)
or
blanketImplSiblingCandidate(impl1, trait) and
blanketImplSiblingCandidate(impl2, trait)
)
}
pragma[nomagic]
private predicate implSiblingCandidate(
Impl impl, TraitItemNode trait, Type rootType, AstNode selfTy
) {
trait = impl.(ImplItemNode).resolveTraitTy() and
selfTy = impl.getSelfTy() and
rootType = resolveTypeMentionAt(selfTy, TypePath::nil())
}
pragma[nomagic]
private predicate blanketImplSiblingCandidate(ImplItemNode impl, Trait trait) {
impl.isBlanketImplementation() and
trait = impl.resolveTraitTy()
}
/**
* Holds if `impl1` and `impl2` are sibling implementations of `trait`. We
* consider implementations to be siblings if they implement the same trait for
* the same type. In that case `Self` is the same type in both implementations,
* and method calls to the implementations cannot be resolved unambiguously
* based only on the receiver type.
*/
pragma[inline]
predicate implSiblings(TraitItemNode trait, Impl impl1, Impl impl2) {
impl1 != impl2 and
(
exists(Type rootType, AstNode selfTy1, AstNode selfTy2 |
implSiblingCandidate(impl1, trait, rootType, selfTy1) and
implSiblingCandidate(impl2, trait, rootType, selfTy2) and
// In principle the second conjunct below should be superfluous, but we still
// have ill-formed type mentions for types that we don't understand. For
// those checking both directions restricts further. Note also that we check
// syntactic equality, whereas equality up to renaming would be more
// correct.
typeMentionEqual(selfTy1, selfTy2) and
typeMentionEqual(selfTy2, selfTy1)
)
or
blanketImplSiblingCandidate(impl1, trait) and
blanketImplSiblingCandidate(impl2, trait)
)
}
/**
* Holds if `impl` is an implementation of `trait` and if another implementation
* exists for the same type.
*/
pragma[nomagic]
predicate implHasSibling(ImplItemNode impl, Trait trait) { implSiblings(trait, impl, _) }
pragma[nomagic]
predicate implHasAmbiguousSiblingAt(ImplItemNode impl, Trait trait, TypePath path) {
exists(ImplItemNode impl2, Type t1, Type t2 |
implSiblings(trait, impl, impl2) and
t1 = resolveTypeMentionAt(impl.getTraitPath(), path) and
t2 = resolveTypeMentionAt(impl2.getTraitPath(), path) and
t1 != t2
|
not t1 instanceof TypeParameter or
not t2 instanceof TypeParameter
)
}
}
/**
* Holds if `impl` is an implementation of `trait` and if another implementation
* exists for the same type.
*/
pragma[nomagic]
private predicate implHasSibling(ImplItemNode impl, Trait trait) { implSiblings(trait, impl, _) }
private Type resolvePreTypeMention(AstNode tm, TypePath path) {
result = tm.(PreTypeMention).getTypeAt(path)
}
private module PreSiblingImpls = MkSiblingImpls<resolvePreTypeMention/2>;
predicate preImplHasAmbiguousSiblingAt = PreSiblingImpls::implHasAmbiguousSiblingAt/3;
private Type resolveTypeMention(AstNode tm, TypePath path) {
result = tm.(TypeMention).getTypeAt(path)
}
private module SiblingImpls = MkSiblingImpls<resolveTypeMention/2>;
import SiblingImpls
/**
* Holds if `f` is a function declared inside `trait`, and the type of `f` at
@@ -124,7 +161,8 @@ private predicate functionResolutionDependsOnArgumentCand(
implHasSibling(impl, trait) and
traitTypeParameterOccurrence(trait, _, functionName, pos, path, traitTp) and
f = impl.getASuccessor(functionName) and
not pos.isSelfOrTypeQualifier()
not pos.isTypeQualifier() and
not (f instanceof Method and pos.asPosition() = 0)
)
}

View File

@@ -6,17 +6,23 @@ private import TypeMention
private import TypeInference
private newtype TFunctionPosition =
TArgumentFunctionPosition(ArgumentPosition pos) or
TArgumentFunctionPosition(ArgumentPosition pos) { not pos.isSelf() } or
TReturnFunctionPosition()
/**
* A position of a type related to a function.
* A function-call adjusted position of a type related to a function.
*
* Either `self`, `return`, or a positional parameter index.
* Either `return` or a positional parameter index, where `self` is translated
* to position `0` and subsequent positional parameters at index `i` are
* translated to position `i + 1`.
*
* Function-call adjusted positions are needed when resolving calls of the
* form `Foo::f(x_1, ..., x_n)`, where we do not know up front whether `f` is a
* method or a non-method, and hence we need to be able to match `x_1` against
* both a potential `self` parameter and a potential first positional parameter
* (and `x_2, ... x_n` against all subsequent positional parameters).
*/
class FunctionPosition extends TFunctionPosition {
predicate isSelf() { this.asArgumentPosition().isSelf() }
int asPosition() { result = this.asArgumentPosition().asPosition() }
predicate isPosition() { exists(this.asPosition()) }
@@ -25,29 +31,18 @@ class FunctionPosition extends TFunctionPosition {
predicate isTypeQualifier() { this.asArgumentPosition().isTypeQualifier() }
predicate isSelfOrTypeQualifier() { this.isSelf() or this.isTypeQualifier() }
predicate isReturn() { this = TReturnFunctionPosition() }
/** Gets the corresponding position when `f` is invoked via a function call. */
bindingset[f]
FunctionPosition getFunctionCallAdjusted(Function f) {
this.isReturn() and
result = this
or
if f.hasSelfParam()
then
this.isSelf() and result.asPosition() = 0
or
result.asPosition() = this.asPosition() + 1
else result = this
}
TypeMention getTypeMention(Function f) {
this.isSelf() and
result = getSelfParamTypeMention(f.getSelfParam())
or
result = f.getParam(this.asPosition()).getTypeRepr()
(
if f instanceof Method
then
result = f.getParam(this.asPosition() - 1).getTypeRepr()
or
result = getSelfParamTypeMention(f.getSelfParam()) and
this.asPosition() = 0
else result = f.getParam(this.asPosition()).getTypeRepr()
)
or
this.isReturn() and
result = getReturnTypeMention(f)
@@ -92,6 +87,7 @@ private newtype TAssocFunctionType =
}
bindingset[abs, constraint, tp]
pragma[inline_late]
private Type getTraitConstraintTypeAt(
TypeAbstraction abs, TypeMention constraint, TypeParameter tp, TypePath path
) {
@@ -197,8 +193,7 @@ class AssocFunctionType extends MkAssocFunctionType {
exists(Function f, ImplOrTraitItemNode i, FunctionPosition pos | this.appliesTo(f, i, pos) |
result = pos.getTypeMention(f)
or
pos.isSelf() and
not f.hasSelfParam() and
pos.isTypeQualifier() and
result = [i.(Impl).getSelfTy().(AstNode), i.(Trait).getName()]
)
}
@@ -219,23 +214,47 @@ private Trait getALookupTrait(Type t) {
result = t.(DynTraitType).getTrait()
}
/**
* Gets the type obtained by substituting in relevant traits in which to do function
* lookup, or `t` itself when no such trait exist.
*/
pragma[nomagic]
Type substituteLookupTraits(Type t) {
private Trait getAdditionalLookupTrait(ItemNode i, Type t) {
result =
t.(TypeParamTypeParameter)
.getTypeParam()
.(TypeParamItemNode)
.resolveAdditionalBound(i.getImmediateParent*())
}
bindingset[n, t]
pragma[inline_late]
Trait getALookupTrait(AstNode n, Type t) {
result = getALookupTrait(t)
or
result = getAdditionalLookupTrait(any(ItemNode i | n = i.getADescendant()), t)
}
bindingset[i, t]
pragma[inline_late]
private Type substituteLookupTraits0(ItemNode i, Type t) {
not exists(getALookupTrait(t)) and
not exists(getAdditionalLookupTrait(i, t)) and
result = t
or
result = TTrait(getALookupTrait(t))
or
result = TTrait(getAdditionalLookupTrait(i, t))
}
/**
* Gets the `n`th `substituteLookupTraits` type for `t`, per some arbitrary order.
* Gets the type obtained by substituting in relevant traits in which to do function
* lookup, or `t` itself when no such trait exists, in the context of AST node `n`.
*/
bindingset[n, t]
pragma[inline_late]
Type substituteLookupTraits(AstNode n, Type t) {
result = substituteLookupTraits0(any(ItemNode i | n = i.getADescendant()), t)
}
pragma[nomagic]
Type getNthLookupType(Type t, int n) {
private Type getNthLookupType(Type t, int n) {
not exists(getALookupTrait(t)) and
result = t and
n = 0
@@ -250,24 +269,66 @@ Type getNthLookupType(Type t, int n) {
}
/**
* Gets the index of the last `substituteLookupTraits` type for `t`.
* Gets the `n`th `substituteLookupTraits` type for `t`, per some arbitrary order,
* in the context of AST node `node`.
*/
bindingset[node, t]
pragma[inline_late]
Type getNthLookupType(AstNode node, Type t, int n) {
exists(ItemNode i | node = i.getADescendant() |
if exists(getAdditionalLookupTrait(i, t))
then
result =
TTrait(rank[n + 1](Trait trait, int j |
trait = [getALookupTrait(t), getAdditionalLookupTrait(i, t)] and
j = idOfTypeParameterAstNode(trait)
|
trait order by j
))
else result = getNthLookupType(t, n)
)
}
pragma[nomagic]
int getLastLookupTypeIndex(Type t) { result = max(int n | exists(getNthLookupType(t, n))) }
private int getLastLookupTypeIndex(Type t) { result = max(int n | exists(getNthLookupType(t, n))) }
/**
* Gets the index of the last `substituteLookupTraits` type for `t`,
* in the context of AST node `node`.
*/
bindingset[node, t]
pragma[inline_late]
int getLastLookupTypeIndex(AstNode node, Type t) {
if exists(getAdditionalLookupTrait(node, t))
then result = max(int n | exists(getNthLookupType(node, t, n)))
else result = getLastLookupTypeIndex(t)
}
signature class ArgSig {
/** Gets the type of this argument at `path`. */
Type getTypeAt(TypePath path);
/** Gets the enclosing item node of this argument. */
ItemNode getEnclosingItemNode();
/** Gets a textual representation of this argument. */
string toString();
/** Gets the location of this argument. */
Location getLocation();
}
/**
* A wrapper around `IsInstantiationOf` which ensures to substitute in lookup
* traits when checking whether argument types are instantiations of function
* types.
*/
module ArgIsInstantiationOf<
HasTypeTreeSig Arg, IsInstantiationOfInputSig<Arg, AssocFunctionType> Input>
{
module ArgIsInstantiationOf<ArgSig Arg, IsInstantiationOfInputSig<Arg, AssocFunctionType> Input> {
final private class ArgFinal = Arg;
private class ArgSubst extends ArgFinal {
Type getTypeAt(TypePath path) {
result = substituteLookupTraits(super.getTypeAt(path)) and
result = substituteLookupTraits0(this.getEnclosingItemNode(), super.getTypeAt(path)) and
not result = TNeverType() and
not result = TUnknownType()
}
@@ -310,10 +371,11 @@ signature module ArgsAreInstantiationsOfInputSig {
* Holds if `f` inside `i` needs to have the type corresponding to type parameter
* `tp` checked.
*
* If `i` is an inherent implementation, `tp` is a type parameter of the type being
* implemented, otherwise `tp` is a type parameter of the trait (being implemented).
* `tp` is a type parameter of the trait being implemented by `f` or the trait to which
* `f` belongs.
*
* `pos` is one of the positions in `f` in which the relevant type occours.
* `pos` is one of the function-call adjusted positions in `f` in which the relevant
* type occurs.
*/
predicate toCheck(ImplOrTraitItemNode i, Function f, TypeParameter tp, FunctionPosition pos);
@@ -323,6 +385,8 @@ signature module ArgsAreInstantiationsOfInputSig {
Location getLocation();
ItemNode getEnclosingItemNode();
Type getArgType(FunctionPosition pos, TypePath path);
predicate hasTargetCand(ImplOrTraitItemNode i, Function f);
@@ -360,7 +424,7 @@ module ArgsAreInstantiationsOf<ArgsAreInstantiationsOfInputSig Input> {
private newtype TCallAndPos =
MkCallAndPos(Input::Call call, FunctionPosition pos) { exists(call.getArgType(pos, _)) }
/** A call tagged with a position. */
/** A call tagged with a function-call adjusted position. */
private class CallAndPos extends MkCallAndPos {
Input::Call call;
FunctionPosition pos;
@@ -371,6 +435,8 @@ module ArgsAreInstantiationsOf<ArgsAreInstantiationsOfInputSig Input> {
FunctionPosition getPos() { result = pos }
ItemNode getEnclosingItemNode() { result = call.getEnclosingItemNode() }
Location getLocation() { result = call.getLocation() }
Type getTypeAt(TypePath path) { result = call.getArgType(pos, path) }
@@ -413,20 +479,21 @@ module ArgsAreInstantiationsOf<ArgsAreInstantiationsOfInputSig Input> {
pragma[nomagic]
private predicate argIsInstantiationOf(
Input::Call call, FunctionPosition pos, ImplOrTraitItemNode i, Function f, int rnk
Input::Call call, ImplOrTraitItemNode i, Function f, int rnk
) {
ArgIsInstantiationOfToIndex::argIsInstantiationOf(MkCallAndPos(call, pos), i, _) and
toCheckRanked(i, f, _, pos, rnk)
exists(FunctionPosition pos |
ArgIsInstantiationOfToIndex::argIsInstantiationOf(MkCallAndPos(call, pos), i, _) and
toCheckRanked(i, f, _, pos, rnk)
)
}
pragma[nomagic]
private predicate argsAreInstantiationsOfToIndex(
Input::Call call, ImplOrTraitItemNode i, Function f, int rnk
) {
exists(FunctionPosition pos |
argIsInstantiationOf(call, pos, i, f, rnk) and
call.hasTargetCand(i, f)
|
argIsInstantiationOf(call, i, f, rnk) and
call.hasTargetCand(i, f) and
(
rnk = 0
or
argsAreInstantiationsOfToIndex(call, i, f, rnk - 1)

View File

@@ -439,11 +439,11 @@ class TypeParamTypeParameter extends TypeParameter, TTypeParamTypeParameter {
*/
class AssociatedTypeTypeParameter extends TypeParameter, TAssociatedTypeTypeParameter {
private Trait trait;
private TypeAlias typeAlias;
private AssocType typeAlias;
AssociatedTypeTypeParameter() { this = TAssociatedTypeTypeParameter(trait, typeAlias) }
TypeAlias getTypeAlias() { result = typeAlias }
AssocType getTypeAlias() { result = typeAlias }
/** Gets the trait that contains this associated type declaration. */
TraitItemNode getTrait() { result = trait }
@@ -457,7 +457,13 @@ class AssociatedTypeTypeParameter extends TypeParameter, TAssociatedTypeTypePara
override ItemNode getDeclaringItem() { result = trait }
override string toString() {
result = typeAlias.getName().getText() + "[" + trait.getName().toString() + "]"
exists(string fromString, TraitItemNode trait2 |
result = typeAlias.getName().getText() + "[" + trait.getName() + fromString + "]" and
trait2 = typeAlias.getTrait() and
if trait = trait2
then fromString = ""
else fromString = " (inherited from " + trait2.getName() + ")"
)
}
override Location getLocation() { result = typeAlias.getLocation() }

View File

@@ -205,6 +205,13 @@ private module MkTypeMention<getAdditionalPathTypeAtSig/2 getAdditionalPathTypeA
)
or
exists(TypeParamItemNode tp | this = tp.getABoundPath() and result = tp)
or
// `<result as this>::...`
exists(PathTypeRepr typeRepr, PathTypeRepr traitRepr |
pathTypeAsTraitAssoc(_, typeRepr, traitRepr, _, _) and
this = traitRepr.getPath() and
result = typeRepr.getPath()
)
}
pragma[nomagic]
@@ -696,16 +703,26 @@ private module PreTypeMention = MkTypeMention<preGetAdditionalPathTypeAt/2>;
class PreTypeMention = PreTypeMention::TypeMention;
private class TraitOrTmTrait extends AstNode {
Type getTypeAt(TypePath path) {
pathTypeAsTraitAssoc(_, _, this, _, _) and
result = this.(PreTypeMention).getTypeAt(path)
or
result = TTrait(this) and
path.isEmpty()
}
}
/**
* Holds if `path` accesses an associated type `alias` from `trait` on a
* concrete type given by `tm`.
*
* `implOrTmTrait` is either the mention that resolves to `trait` when `path`
* is of the form `<Type as Trait>::AssocType`, or the enclosing `impl` block
* when `path` is of the form `Self::AssocType`.
* `traitOrTmTrait` is either the mention that resolves to `trait` when `path`
* is of the form `<Type as Trait>::AssocType`, or the trait being implemented
* when `path` is of the form `Self::AssocType` within an `impl` block.
*/
private predicate pathConcreteTypeAssocType(
Path path, PreTypeMention tm, TraitItemNode trait, AstNode implOrTmTrait, TypeAlias alias
Path path, PreTypeMention tm, TraitItemNode trait, TraitOrTmTrait traitOrTmTrait, TypeAlias alias
) {
exists(Path qualifier |
qualifier = path.getQualifier() and
@@ -713,31 +730,34 @@ private predicate pathConcreteTypeAssocType(
|
// path of the form `<Type as Trait>::AssocType`
// ^^^ tm ^^^^^^^^^ name
// ^^^^^ traitOrTmTrait
exists(string name |
pathTypeAsTraitAssoc(path, tm, implOrTmTrait, trait, name) and
pathTypeAsTraitAssoc(path, tm, traitOrTmTrait, trait, name) and
getTraitAssocType(trait, name) = alias
)
or
// path of the form `Self::AssocType` within an `impl` block
// tm ^^^^ ^^^^^^^^^ name
implOrTmTrait =
any(ImplItemNode impl |
alias = resolvePath(path) and
qualifier = impl.getASelfPath() and
tm = impl.(Impl).getSelfTy() and
trait.getAnAssocItem() = alias
)
exists(ImplItemNode impl |
alias = resolvePath(path) and
qualifier = impl.getASelfPath() and
tm = impl.(Impl).getSelfTy() and
trait.getAnAssocItem() = alias and
traitOrTmTrait = trait
)
)
}
private module PathSatisfiesConstraintInput implements SatisfiesConstraintInputSig<PreTypeMention> {
predicate relevantConstraint(PreTypeMention tm, Type constraint) {
pathConcreteTypeAssocType(_, tm, constraint.(TraitType).getTrait(), _, _)
private module PathSatisfiesConstraintInput implements
PreM2::SatisfiesConstraintInputSig<PreTypeMention, TraitOrTmTrait>
{
predicate relevantConstraint(PreTypeMention tm, TraitOrTmTrait constraint) {
pathConcreteTypeAssocType(_, tm, _, constraint, _)
}
}
private module PathSatisfiesConstraint =
SatisfiesConstraint<PreTypeMention, PathSatisfiesConstraintInput>;
PreM2::SatisfiesConstraint<PreTypeMention, TraitOrTmTrait, PathSatisfiesConstraintInput>;
/**
* Gets the type of `path` at `typePath` when `path` accesses an associated type
@@ -745,26 +765,12 @@ private module PathSatisfiesConstraint =
*/
private Type getPathConcreteAssocTypeAt(Path path, TypePath typePath) {
exists(
PreTypeMention tm, ImplItemNode impl, TraitItemNode trait, TraitType t, AstNode implOrTmTrait,
PreTypeMention tm, ImplItemNode impl, TraitItemNode trait, TraitOrTmTrait traitOrTmTrait,
TypeAlias alias, TypePath path0
|
pathConcreteTypeAssocType(path, tm, trait, implOrTmTrait, alias) and
t = TTrait(trait) and
PathSatisfiesConstraint::satisfiesConstraintTypeThrough(tm, impl, t, path0, result) and
pathConcreteTypeAssocType(path, tm, trait, traitOrTmTrait, alias) and
PathSatisfiesConstraint::satisfiesConstraintTypeThrough(tm, impl, traitOrTmTrait, path0, result) and
path0.isCons(TAssociatedTypeTypeParameter(trait, alias), typePath)
|
implOrTmTrait instanceof Impl
or
// When `path` is of the form `<Type as Trait>::AssocType` we need to check
// that `impl` is not more specific than the mentioned trait
implOrTmTrait =
any(PreTypeMention tmTrait |
not exists(TypePath path1, Type t1 |
t1 = impl.getTraitPath().(PreTypeMention).getTypeAt(path1) and
not t1 instanceof TypeParameter and
t1 != tmTrait.getTypeAt(path1)
)
)
)
}

View File

@@ -5,6 +5,7 @@
import rust
private import codeql.rust.dataflow.DataFlow
private import codeql.rust.dataflow.FlowBarrier
private import codeql.rust.dataflow.FlowSource
private import codeql.rust.dataflow.FlowSink
private import codeql.rust.Concepts
@@ -69,6 +70,13 @@ module AccessInvalidPointer {
ModelsAsDataSink() { sinkNode(this, "pointer-access") }
}
/**
* A barrier for invalid pointer access from model data.
*/
private class ModelsAsDataBarrier extends Barrier {
ModelsAsDataBarrier() { barrierNode(this, "pointer-access") }
}
/**
* A barrier for invalid pointer access vulnerabilities for values checked to
* be non-`null`.

View File

@@ -5,6 +5,7 @@
import rust
private import codeql.rust.dataflow.DataFlow
private import codeql.rust.dataflow.FlowBarrier
private import codeql.rust.dataflow.FlowSink
private import codeql.rust.security.SensitiveData
private import codeql.rust.Concepts
@@ -44,6 +45,13 @@ module CleartextLogging {
ModelsAsDataSink() { sinkNode(this, "log-injection") }
}
/**
* A barrier for logging from model data.
*/
private class ModelsAsDataBarrier extends Barrier {
ModelsAsDataBarrier() { barrierNode(this, "log-injection") }
}
private class BooleanTypeBarrier extends Barrier instanceof Barriers::BooleanTypeBarrier { }
private class FieldlessEnumTypeBarrier extends Barrier instanceof Barriers::FieldlessEnumTypeBarrier

View File

@@ -45,4 +45,11 @@ module CleartextStorageDatabase {
private class ModelsAsDataSink extends Sink {
ModelsAsDataSink() { sinkNode(this, ["sql-injection", "database-store"]) }
}
/**
* A barrier for cleartext storage vulnerabilities from model data.
*/
private class ModelsAsDataBarrier extends Barrier {
ModelsAsDataBarrier() { barrierNode(this, ["sql-injection", "database-store"]) }
}
}

View File

@@ -6,6 +6,7 @@
private import codeql.util.Unit
private import rust
private import codeql.rust.dataflow.DataFlow
private import codeql.rust.dataflow.FlowBarrier
private import codeql.rust.dataflow.FlowSink
private import codeql.rust.security.SensitiveData
private import codeql.rust.Concepts
@@ -55,4 +56,11 @@ module CleartextTransmission {
private class ModelsAsDataSink extends Sink {
ModelsAsDataSink() { sinkNode(this, ["transmission", "request-url"]) }
}
/**
* A barrier defined through MaD.
*/
private class ModelsAsDataBarrier extends Barrier {
ModelsAsDataBarrier() { barrierNode(this, ["transmission", "request-url"]) }
}
}

View File

@@ -5,6 +5,7 @@
import rust
private import codeql.rust.dataflow.DataFlow
private import codeql.rust.dataflow.FlowBarrier
private import codeql.rust.dataflow.FlowSink
private import codeql.rust.Concepts
private import codeql.rust.dataflow.internal.Node as Node
@@ -21,6 +22,11 @@ module DisabledCertificateCheckExtensions {
override string getSinkType() { result = "DisabledCertificateCheck" }
}
/**
* A data flow barrier for disabled certificate check vulnerabilities.
*/
abstract class Barrier extends DataFlow::Node { }
/**
* A sink for disabled certificate check vulnerabilities from model data.
*/
@@ -42,4 +48,11 @@ module DisabledCertificateCheckExtensions {
)
}
}
/**
* A barrier for disabled certificate check vulnerabilities from model data.
*/
private class ModelsAsDataBarrier extends Barrier {
ModelsAsDataBarrier() { barrierNode(this, "disable-certificate") }
}
}

View File

@@ -5,6 +5,7 @@
import rust
private import codeql.rust.dataflow.DataFlow
private import codeql.rust.dataflow.FlowBarrier
private import codeql.rust.dataflow.FlowSource
private import codeql.rust.dataflow.FlowSink
private import codeql.rust.Concepts
@@ -130,6 +131,19 @@ module HardcodedCryptographicValue {
override CryptographicValueKind getKind() { result = kind }
}
/**
* An externally modeled barrier for hard-coded cryptographic value vulnerabilities.
*
* Note that a barrier will block flow to all hard-coded cryptographic value
* sinks, regardless of the `kind` that is specified. For example a barrier of
* kind `credentials-key` will block flow to a sink of kind `credentials-iv`.
*/
private class ModelsAsDataBarrier extends Barrier {
ModelsAsDataBarrier() {
exists(CryptographicValueKind kind | barrierNode(this, "credentials-" + kind))
}
}
/**
* A call to `getrandom` that is a barrier.
*/

View File

@@ -5,6 +5,7 @@
import rust
private import codeql.rust.dataflow.DataFlow
private import codeql.rust.dataflow.FlowBarrier
private import codeql.rust.dataflow.FlowSource
private import codeql.rust.dataflow.FlowSink
private import codeql.rust.Concepts
@@ -48,6 +49,13 @@ module InsecureCookie {
ModelsAsDataSink() { sinkNode(this, "cookie-use") }
}
/**
* A barrier for insecure cookie vulnerabilities from model data.
*/
private class ModelsAsDataBarrier extends Barrier {
ModelsAsDataBarrier() { barrierNode(this, "cookie-use") }
}
/**
* Holds if a models-as-data optional barrier for cookies is specified for `summaryNode`,
* with arguments `attrib` (`secure` or `partitioned`) and `arg` (argument index). For example,

View File

@@ -5,6 +5,7 @@
import rust
private import codeql.rust.dataflow.DataFlow
private import codeql.rust.dataflow.FlowBarrier
private import codeql.rust.dataflow.FlowSink
private import codeql.rust.Concepts
private import codeql.util.Unit
@@ -44,6 +45,13 @@ module LogInjection {
ModelsAsDataSink() { sinkNode(this, "log-injection") }
}
/**
* A barrier for log-injection from model data.
*/
private class ModelsAsDataBarrier extends Barrier {
ModelsAsDataBarrier() { barrierNode(this, "log-injection") }
}
/**
* A barrier for log injection vulnerabilities for nodes whose type is a
* numeric type, which is unlikely to expose any vulnerability.

View File

@@ -5,6 +5,7 @@
import rust
private import codeql.rust.dataflow.DataFlow
private import codeql.rust.dataflow.FlowBarrier
private import codeql.rust.dataflow.FlowSink
private import codeql.rust.dataflow.FlowSource
private import codeql.rust.Concepts
@@ -46,4 +47,11 @@ module RequestForgery {
private class ModelsAsDataSink extends Sink {
ModelsAsDataSink() { sinkNode(this, "request-url") }
}
/**
* A barrier for request forgery from model data.
*/
private class ModelsAsDataBarrier extends Barrier {
ModelsAsDataBarrier() { barrierNode(this, "request-url") }
}
}

View File

@@ -6,6 +6,7 @@
import rust
private import codeql.rust.dataflow.DataFlow
private import codeql.rust.dataflow.FlowBarrier
private import codeql.rust.dataflow.FlowSink
private import codeql.rust.Concepts
private import codeql.util.Unit
@@ -53,12 +54,19 @@ module SqlInjection {
}
/**
* A sink for sql-injection from model data.
* A sink for SQL injection from model data.
*/
private class ModelsAsDataSink extends Sink {
ModelsAsDataSink() { sinkNode(this, "sql-injection") }
}
/**
* A barrier for SQL injection from model data.
*/
private class ModelsAsDataBarrier extends Barrier {
ModelsAsDataBarrier() { barrierNode(this, "sql-injection") }
}
/**
* A barrier for SQL injection vulnerabilities for nodes whose type is a numeric
* type, which is unlikely to expose any vulnerability.

View File

@@ -47,6 +47,11 @@ module TaintedPath {
private class ModelsAsDataSinks extends Sink {
ModelsAsDataSinks() { sinkNode(this, "path-injection") }
}
/** A barrier for path-injection from model data. */
private class ModelsAsDataBarriers extends Barrier {
ModelsAsDataBarriers() { barrierNode(this, "path-injection") }
}
}
private predicate sanitizerGuard(AstNode g, Expr e, boolean branch) {

View File

@@ -6,6 +6,7 @@
import rust
private import codeql.rust.Concepts
private import codeql.rust.dataflow.DataFlow
private import codeql.rust.dataflow.FlowBarrier
private import codeql.rust.dataflow.FlowSink
/**
@@ -32,6 +33,13 @@ module UncontrolledAllocationSize {
ModelsAsDataSink() { sinkNode(this, ["alloc-size", "alloc-layout"]) }
}
/**
* A barrier for uncontrolled allocation size from model data.
*/
private class ModelsAsDataBarrier extends Barrier {
ModelsAsDataBarrier() { barrierNode(this, ["alloc-size", "alloc-layout"]) }
}
/**
* A barrier for uncontrolled allocation size that is an upper bound check / guard.
*/

View File

@@ -5,6 +5,7 @@
import rust
private import codeql.rust.dataflow.DataFlow
private import codeql.rust.dataflow.FlowBarrier
private import codeql.rust.dataflow.FlowSink
private import codeql.rust.Concepts
@@ -59,4 +60,11 @@ module UseOfHttp {
private class ModelsAsDataSink extends Sink {
ModelsAsDataSink() { sinkNode(this, "request-url") }
}
/**
* A barrier for use of HTTP URLs from model data.
*/
private class ModelsAsDataBarrier extends Barrier {
ModelsAsDataBarrier() { barrierNode(this, "request-url") }
}
}

View File

@@ -5,6 +5,7 @@
import rust
private import codeql.rust.dataflow.DataFlow
private import codeql.rust.dataflow.FlowBarrier
private import codeql.rust.dataflow.FlowSink
private import codeql.rust.Concepts
private import codeql.util.Unit
@@ -44,6 +45,13 @@ module Xss {
ModelsAsDataSink() { sinkNode(this, "html-injection") }
}
/**
* A barrier for XSS from model data.
*/
private class ModelsAsDataBarrier extends Barrier {
ModelsAsDataBarrier() { barrierNode(this, "html-injection") }
}
/**
* A barrier for XSS vulnerabilities for nodes whose type is a
* numeric or boolean type, which is unlikely to expose any vulnerability.

View File

@@ -6,6 +6,7 @@
private import codeql.util.Unit
private import rust
private import codeql.rust.dataflow.DataFlow
private import codeql.rust.dataflow.FlowBarrier
private import codeql.rust.dataflow.FlowSink
private import codeql.rust.Concepts
private import codeql.rust.security.Barriers as Barriers
@@ -69,6 +70,13 @@ module RegexInjection {
ModelsAsDataSink() { sinkNode(this, "regex-use") }
}
/**
* A barrier for regular expression injection from model data.
*/
private class ModelsAsDataBarrier extends Barrier {
ModelsAsDataBarrier() { barrierNode(this, "regex-use") }
}
/**
* An escape barrier for regular expression injection vulnerabilities.
*/

View File

@@ -0,0 +1,5 @@
---
category: queryMetadata
---
* The `@security-severity` metadata of `rust/log-injection` has been increased from 2.6 (low) to 6.1 (medium).
* The `@security-severity` metadata of `rust/xss` has been increased from 6.1 (medium) to 7.8 (high).

View File

@@ -4,7 +4,7 @@
* allows for a cross-site scripting vulnerability.
* @kind path-problem
* @problem.severity error
* @security-severity 6.1
* @security-severity 7.8
* @precision high
* @id rust/xss
* @tags security

View File

@@ -4,7 +4,7 @@
* insertion of forged log entries by a malicious user.
* @kind path-problem
* @problem.severity error
* @security-severity 2.6
* @security-severity 6.1
* @precision medium
* @id rust/log-injection
* @tags security

View File

@@ -33,6 +33,8 @@ module DisabledCertificateCheckConfig implements DataFlow::ConfigSig {
predicate isSink(DataFlow::Node node) { node instanceof Sink }
predicate isBarrier(DataFlow::Node node) { node instanceof Barrier }
predicate observeDiffInformedIncrementalMode() { any() }
}

View File

@@ -138,7 +138,10 @@ private module SummaryModelGeneratorInput implements SummaryModelGeneratorInputS
Parameter asParameter(NodeExtended node) { result = node.asParameter() }
predicate isAdditionalContentFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { none() }
predicate isAdditionalContentFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
RustTaintTracking::defaultAdditionalTaintStep(nodeFrom, nodeTo, _) and
not RustDataFlow::readStep(nodeFrom, _, nodeTo)
}
predicate isField(DataFlow::ContentSet c) {
c.(SingletonContentSet).getContent() instanceof FieldContent

View File

@@ -1,41 +1,20 @@
models
edges
| main.rs:9:13:9:19 | ...: ... | main.rs:10:11:10:11 | s | provenance | |
| main.rs:10:11:10:11 | s | main.rs:12:9:12:9 | s | provenance | |
| main.rs:12:9:12:9 | s | main.rs:9:30:14:1 | { ... } | provenance | |
| main.rs:21:9:21:9 | s | main.rs:22:10:22:10 | s | provenance | |
| main.rs:21:13:21:21 | source(...) | main.rs:21:9:21:9 | s | provenance | |
| main.rs:26:9:26:9 | s | main.rs:27:22:27:22 | s | provenance | |
| main.rs:26:13:26:21 | source(...) | main.rs:26:9:26:9 | s | provenance | |
| main.rs:27:9:27:9 | s | main.rs:28:10:28:10 | s | provenance | |
| main.rs:27:13:27:23 | sanitize(...) | main.rs:27:9:27:9 | s | provenance | |
| main.rs:27:22:27:22 | s | main.rs:9:13:9:19 | ...: ... | provenance | |
| main.rs:27:22:27:22 | s | main.rs:27:13:27:23 | sanitize(...) | provenance | |
| main.rs:32:9:32:9 | s | main.rs:33:10:33:10 | s | provenance | |
| main.rs:32:13:32:21 | source(...) | main.rs:32:9:32:9 | s | provenance | |
nodes
| main.rs:9:13:9:19 | ...: ... | semmle.label | ...: ... |
| main.rs:9:30:14:1 | { ... } | semmle.label | { ... } |
| main.rs:10:11:10:11 | s | semmle.label | s |
| main.rs:12:9:12:9 | s | semmle.label | s |
| main.rs:17:10:17:18 | source(...) | semmle.label | source(...) |
| main.rs:21:9:21:9 | s | semmle.label | s |
| main.rs:21:13:21:21 | source(...) | semmle.label | source(...) |
| main.rs:22:10:22:10 | s | semmle.label | s |
| main.rs:26:9:26:9 | s | semmle.label | s |
| main.rs:26:13:26:21 | source(...) | semmle.label | source(...) |
| main.rs:27:9:27:9 | s | semmle.label | s |
| main.rs:27:13:27:23 | sanitize(...) | semmle.label | sanitize(...) |
| main.rs:27:22:27:22 | s | semmle.label | s |
| main.rs:28:10:28:10 | s | semmle.label | s |
| main.rs:32:9:32:9 | s | semmle.label | s |
| main.rs:32:13:32:21 | source(...) | semmle.label | source(...) |
| main.rs:33:10:33:10 | s | semmle.label | s |
subpaths
| main.rs:27:22:27:22 | s | main.rs:9:13:9:19 | ...: ... | main.rs:9:30:14:1 | { ... } | main.rs:27:13:27:23 | sanitize(...) |
testFailures
#select
| main.rs:17:10:17:18 | source(...) | main.rs:17:10:17:18 | source(...) | main.rs:17:10:17:18 | source(...) | $@ | main.rs:17:10:17:18 | source(...) | source(...) |
| main.rs:22:10:22:10 | s | main.rs:21:13:21:21 | source(...) | main.rs:22:10:22:10 | s | $@ | main.rs:21:13:21:21 | source(...) | source(...) |
| main.rs:28:10:28:10 | s | main.rs:26:13:26:21 | source(...) | main.rs:28:10:28:10 | s | $@ | main.rs:26:13:26:21 | source(...) | source(...) |
| main.rs:33:10:33:10 | s | main.rs:32:13:32:21 | source(...) | main.rs:33:10:33:10 | s | $@ | main.rs:32:13:32:21 | source(...) | source(...) |

View File

@@ -0,0 +1,11 @@
extensions:
- addsTo:
pack: codeql/rust-all
extensible: barrierModel
data:
- ["main::sanitize", "ReturnValue", "test-barrier", "manual"]
- addsTo:
pack: codeql/rust-all
extensible: barrierGuardModel
data:
- ["main::verify_safe", "Argument[0]", "true", "test-barrier", "manual"]

View File

@@ -3,8 +3,19 @@
*/
import rust
import codeql.rust.dataflow.DataFlow
import codeql.rust.dataflow.FlowBarrier
import utils.test.InlineFlowTest
import DefaultFlowTest
module CustomConfig implements DataFlow::ConfigSig {
predicate isSource = DefaultFlowConfig::isSource/1;
predicate isSink = DefaultFlowConfig::isSink/1;
predicate isBarrier(DataFlow::Node n) { barrierNode(n, "test-barrier") }
}
import FlowTest<CustomConfig, CustomConfig>
import TaintFlow::PathGraph
from TaintFlow::PathNode source, TaintFlow::PathNode sink

View File

@@ -25,10 +25,24 @@ fn through_variable() {
fn with_barrier() {
let s = source(1);
let s = sanitize(s);
sink(s); // $ SPURIOUS: hasValueFlow=1
sink(s);
}
fn main() {
let s = source(1);
sink(s); // $ hasValueFlow=1
}
fn verify_safe(s: &str) -> bool {
match s {
"dangerous" => false,
_ => true,
}
}
fn with_barrier_guard() {
let s = source(1);
if verify_safe(s) {
sink(s);
}
}

View File

@@ -1,6 +0,0 @@
multipleResolvedTargets
| test.rs:389:30:389:67 | pinned.poll_read(...) |
| test.rs:416:26:416:54 | pinned.poll_fill_buf(...) |
| test.rs:423:27:423:71 | ... .poll_fill_buf(...) |
| test.rs:447:30:447:67 | pinned.poll_read(...) |
| test.rs:470:26:470:54 | pinned.poll_fill_buf(...) |

View File

@@ -100,7 +100,9 @@ edges
| main.rs:161:10:161:18 | source(...) | main.rs:161:10:161:25 | ... .shr(...) | provenance | MaD:30 |
| main.rs:162:19:162:27 | source(...) | main.rs:162:10:162:28 | 1i64.shr(...) | provenance | MaD:30 |
| main.rs:164:10:164:18 | source(...) | main.rs:164:10:164:30 | ... .bitor(...) | provenance | MaD:19 |
| main.rs:165:10:165:18 | source(...) | main.rs:165:10:165:27 | ... .bitor(...) | provenance | MaD:19 |
| main.rs:166:21:166:29 | source(...) | main.rs:166:10:166:30 | 1i64.bitor(...) | provenance | MaD:19 |
| main.rs:167:18:167:26 | source(...) | main.rs:167:10:167:27 | 1.bitor(...) | provenance | MaD:19 |
| main.rs:170:5:170:5 | [post] a | main.rs:171:5:171:5 | a | provenance | |
| main.rs:170:5:170:5 | [post] a | main.rs:172:5:172:5 | a | provenance | |
| main.rs:170:5:170:5 | [post] a | main.rs:173:5:173:5 | a | provenance | |
@@ -351,8 +353,12 @@ nodes
| main.rs:162:19:162:27 | source(...) | semmle.label | source(...) |
| main.rs:164:10:164:18 | source(...) | semmle.label | source(...) |
| main.rs:164:10:164:30 | ... .bitor(...) | semmle.label | ... .bitor(...) |
| main.rs:165:10:165:18 | source(...) | semmle.label | source(...) |
| main.rs:165:10:165:27 | ... .bitor(...) | semmle.label | ... .bitor(...) |
| main.rs:166:10:166:30 | 1i64.bitor(...) | semmle.label | 1i64.bitor(...) |
| main.rs:166:21:166:29 | source(...) | semmle.label | source(...) |
| main.rs:167:10:167:27 | 1.bitor(...) | semmle.label | 1.bitor(...) |
| main.rs:167:18:167:26 | source(...) | semmle.label | source(...) |
| main.rs:170:5:170:5 | [post] a | semmle.label | [post] a |
| main.rs:170:18:170:26 | source(...) | semmle.label | source(...) |
| main.rs:171:5:171:5 | [post] a | semmle.label | [post] a |
@@ -516,7 +522,9 @@ testFailures
| main.rs:161:10:161:25 | ... .shr(...) | main.rs:161:10:161:18 | source(...) | main.rs:161:10:161:25 | ... .shr(...) | $@ | main.rs:161:10:161:18 | source(...) | source(...) |
| main.rs:162:10:162:28 | 1i64.shr(...) | main.rs:162:19:162:27 | source(...) | main.rs:162:10:162:28 | 1i64.shr(...) | $@ | main.rs:162:19:162:27 | source(...) | source(...) |
| main.rs:164:10:164:30 | ... .bitor(...) | main.rs:164:10:164:18 | source(...) | main.rs:164:10:164:30 | ... .bitor(...) | $@ | main.rs:164:10:164:18 | source(...) | source(...) |
| main.rs:165:10:165:27 | ... .bitor(...) | main.rs:165:10:165:18 | source(...) | main.rs:165:10:165:27 | ... .bitor(...) | $@ | main.rs:165:10:165:18 | source(...) | source(...) |
| main.rs:166:10:166:30 | 1i64.bitor(...) | main.rs:166:21:166:29 | source(...) | main.rs:166:10:166:30 | 1i64.bitor(...) | $@ | main.rs:166:21:166:29 | source(...) | source(...) |
| main.rs:167:10:167:27 | 1.bitor(...) | main.rs:167:18:167:26 | source(...) | main.rs:167:10:167:27 | 1.bitor(...) | $@ | main.rs:167:18:167:26 | source(...) | source(...) |
| main.rs:176:10:176:10 | a | main.rs:170:18:170:26 | source(...) | main.rs:176:10:176:10 | a | $@ | main.rs:170:18:170:26 | source(...) | source(...) |
| main.rs:176:10:176:10 | a | main.rs:171:18:171:26 | source(...) | main.rs:176:10:176:10 | a | $@ | main.rs:171:18:171:26 | source(...) | source(...) |
| main.rs:176:10:176:10 | a | main.rs:172:18:172:26 | source(...) | main.rs:176:10:176:10 | a | $@ | main.rs:172:18:172:26 | source(...) | source(...) |

View File

@@ -162,9 +162,9 @@ fn std_ops() {
sink(1i64.shr(source(2))); // $ hasTaintFlow=2
sink(source(1).bitor(2i64)); // $ hasTaintFlow=1
sink(source(1).bitor(2)); // $ MISSING: hasTaintFlow=1
sink(source(1).bitor(2)); // $ hasTaintFlow=1
sink(1i64.bitor(source(2))); // $ hasTaintFlow=2
sink(1.bitor(source(2))); // $ MISSING: hasTaintFlow=2
sink(1.bitor(source(2))); // $ hasTaintFlow=2
let mut a: i64 = 1;
a.add_assign(source(2));

View File

@@ -1,4 +1,4 @@
multipleResolvedTargets
| main.rs:2223:9:2223:31 | ... .my_add(...) |
| main.rs:2225:9:2225:29 | ... .my_add(...) |
| main.rs:2733:13:2733:17 | x.f() |
| main.rs:2740:13:2740:17 | x.f() |

View File

@@ -2643,6 +2643,10 @@ mod context_typed {
fn f(self) {}
}
fn free_function<T: Default>() -> T {
Default::default() // $ target=default
}
pub fn f() {
let x = None; // $ type=x:T.i32
let x: Option<i32> = x;
@@ -2693,6 +2697,9 @@ mod context_typed {
let s = Default::default(); // $ target=default type=s:S
S::f(s); // $ target=f
let z = free_function(); // $ target=free_function type=z:i32
x.push(z); // $ target=push
}
}

View File

@@ -400,3 +400,124 @@ mod from_default {
x
}
}
mod inherent_before_trait {
struct S<T>(T);
trait Trait {
fn foo(&self);
fn bar(&self);
}
impl S<i32> {
// S<i32>::foo
fn foo(x: &Self) {}
// S<i32>::bar
fn bar(&self) {}
}
impl Trait for S<i32> {
// <S<i32>_as_Trait>::foo
fn foo(&self) {
S::foo(self); // $ MISSING: target=S<i32>::foo
S::<i32>::foo(self); // $ target=S<i32>::foo
self.foo() // $ target=<S<i32>_as_Trait>::foo
}
// <S<i32>_as_Trait>::bar
fn bar(&self) {
S::bar(self); // $ target=S<i32>::bar
S::<i32>::bar(self); // $ target=S<i32>::bar
self.bar() // $ target=S<i32>::bar
}
}
impl Trait for S<i64> {
// <S<i64>_as_Trait>::foo
fn foo(&self) {
// `S::foo(self);` is not valid
S::<i64>::foo(self); // $ target=<S<i64>_as_Trait>::foo
self.foo() // $ target=<S<i64>_as_Trait>::foo
}
// <S<i64>_as_Trait>::bar
fn bar(&self) {
// `S::bar(self);` is not valid
S::<i64>::bar(self); // $ target=<S<i64>_as_Trait>::bar
self.bar() // $ target=<S<i64>_as_Trait>::bar
}
}
}
mod trait_bound_impl_overlap {
trait MyTrait<T> {
fn f(&self) -> T;
}
trait MyTrait2<T = Self> {
type Output;
fn f(&self, x: T) -> Self::Output;
}
struct S<T>(T);
impl MyTrait<i32> for S<i32> {
fn f(&self) -> i32 {
0
}
}
impl MyTrait<i64> for S<i32> {
fn f(&self) -> i64 {
0
}
}
impl MyTrait2<S<i32>> for S<i32> {
type Output = i32;
fn f(&self, x: S<i32>) -> Self::Output {
0
}
}
impl MyTrait2<S<i64>> for S<i32> {
type Output = <Self as MyTrait2<S<bool>>>::Output;
fn f(&self, x: S<i64>) -> Self::Output {
0
}
}
impl MyTrait2<S<bool>> for S<i32> {
type Output = i64;
fn f(&self, x: S<bool>) -> Self::Output {
0
}
}
fn call_f<T1, T2: MyTrait<T1>>(x: T2) -> T1 {
x.f() // $ target=f
}
fn call_f2<T1, T2: MyTrait2<T1>>(x: T1, y: T2) -> T2::Output {
y.f(x) // $ target=f
}
fn test() {
let x = S(0);
let y = call_f(x); // $ target=call_f type=y:i32
let z: i32 = y;
let x = S(0);
let y = call_f::<i32, _>(x); // $ target=call_f type=y:i32
let x = S(0);
let y = call_f2(S(0i32), x); // $ target=call_f2 type=y:i32
let x = S(0);
let y = call_f2(S(0i64), x); // $ target=call_f2 type=y:i64
}
}

View File

@@ -74,3 +74,59 @@ mod regression2 {
let x = s1 - &s2; // $ target=S1SubRefS2 type=x:S2
}
}
mod regression3 {
trait SomeTrait {}
trait MyFrom<T> {
fn my_from(value: T) -> Self;
}
impl<T> MyFrom<T> for T {
fn my_from(s: T) -> Self {
s
}
}
impl<T> MyFrom<T> for Option<T> {
fn my_from(val: T) -> Option<T> {
Some(val)
}
}
pub struct S<Ts>(Ts);
pub fn f<T1, T2>(x: T2) -> T2
where
T2: SomeTrait + MyFrom<Option<T1>>,
Option<T1>: MyFrom<T2>,
{
let y = MyFrom::my_from(x); // $ target=my_from
let z = MyFrom::my_from(y); // $ target=my_from
z
}
}
mod regression4 {
trait MyTrait {
// MyTrait::m
fn m(self);
}
impl<T> MyTrait for &T {
// RefAsMyTrait::m
fn m(self) {}
}
struct S<T>(T);
impl<T> S<T> {
fn call_m(self)
where
T: MyTrait,
{
let S(s) = self;
s.m(); // $ target=MyTrait::m
}
}
}

View File

@@ -21,3 +21,9 @@
| test_cipher.rs:109:23:109:56 | ...::new_with_eff_key_len(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:109:23:109:56 | ...::new_with_eff_key_len(...) | The cryptographic algorithm RC2 |
| test_cipher.rs:114:23:114:50 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:114:23:114:50 | ...::new(...) | The cryptographic algorithm RC5 |
| test_cipher.rs:118:23:118:55 | ...::new_from_slice(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:118:23:118:55 | ...::new_from_slice(...) | The cryptographic algorithm RC5 |
| test_cipher.rs:136:23:136:76 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:136:23:136:76 | ...::new(...) | The cryptographic algorithm DES |
| test_cipher.rs:139:23:139:64 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:139:23:139:64 | ...::new(...) | The cryptographic algorithm DES |
| test_cipher.rs:142:23:142:76 | ...::new_from_slices(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:142:23:142:76 | ...::new_from_slices(...) | The cryptographic algorithm DES |
| test_cipher.rs:145:23:145:76 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:145:23:145:76 | ...::new(...) | The cryptographic algorithm DES |
| test_cipher.rs:171:23:171:65 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:171:23:171:65 | ...::new(...) | The cryptographic algorithm DES |
| test_cipher.rs:175:23:175:65 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:175:23:175:65 | ...::new(...) | The cryptographic algorithm RC2 |

View File

@@ -1,2 +0,0 @@
multipleResolvedTargets
| test_cipher.rs:114:23:114:50 | ...::new(...) |

View File

@@ -133,16 +133,16 @@ fn test_cbc(
_ = aes_cipher1.encrypt_padded_mut::<aes::cipher::block_padding::Pkcs7>(data, data_len).unwrap();
// des (broken)
let des_cipher1 = cbc::Encryptor::<des::Des>::new(key.into(), iv.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm]
let des_cipher1 = cbc::Encryptor::<des::Des>::new(key.into(), iv.into()); // $ Alert[rust/weak-cryptographic-algorithm]
_ = des_cipher1.encrypt_padded_mut::<des::cipher::block_padding::Pkcs7>(data, data_len).unwrap();
let des_cipher2 = MyDesEncryptor::new(key.into(), iv.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm]
let des_cipher2 = MyDesEncryptor::new(key.into(), iv.into()); // $ Alert[rust/weak-cryptographic-algorithm]
_ = des_cipher2.encrypt_padded_mut::<des::cipher::block_padding::Pkcs7>(data, data_len).unwrap();
let des_cipher3 = cbc::Encryptor::<des::Des>::new_from_slices(&key, &iv).unwrap(); // $ MISSING: Alert[rust/weak-cryptographic-algorithm]
let des_cipher3 = cbc::Encryptor::<des::Des>::new_from_slices(&key, &iv).unwrap(); // $ Alert[rust/weak-cryptographic-algorithm]
_ = des_cipher3.encrypt_padded_mut::<des::cipher::block_padding::Pkcs7>(data, data_len).unwrap();
let des_cipher4 = cbc::Encryptor::<des::Des>::new(key.into(), iv.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm]
let des_cipher4 = cbc::Encryptor::<des::Des>::new(key.into(), iv.into()); // $ Alert[rust/weak-cryptographic-algorithm]
_ = des_cipher4.encrypt_padded_b2b_mut::<des::cipher::block_padding::Pkcs7>(input, data).unwrap();
}
@@ -168,10 +168,10 @@ fn test_ecb(
_ = aes_cipher4.encrypt_padded_b2b_mut::<aes::cipher::block_padding::Pkcs7>(input, data).unwrap();
// des with ECB (broken cipher + weak block mode)
let des_cipher1 = ecb::Encryptor::<des::Des>::new(key.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm]
let des_cipher1 = ecb::Encryptor::<des::Des>::new(key.into()); // $ Alert[rust/weak-cryptographic-algorithm]
_ = des_cipher1.encrypt_padded_mut::<des::cipher::block_padding::Pkcs7>(data, data_len).unwrap();
// rc2 with ECB (broken cipher + weak block mode)
let rc2_cipher1 = ecb::Encryptor::<rc2::Rc2>::new(key.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm]
let rc2_cipher1 = ecb::Encryptor::<rc2::Rc2>::new(key.into()); // $ Alert[rust/weak-cryptographic-algorithm]
_ = rc2_cipher1.encrypt_padded_mut::<rc2::cipher::block_padding::Pkcs7>(data, data_len).unwrap();
}

View File

@@ -416,7 +416,7 @@ impl<T> MyOption<&T> {
}
}
// MISSING: summary=<test::option::MyOption>::cloned;Argument[self].Field[test::option::MyOption::MySome(0)].Reference;ReturnValue.Field[test::option::MyOption::MySome(0)];value;dfc-generated
// summary=<test::option::MyOption>::cloned;Argument[self].Field[test::option::MyOption::MySome(0)].Reference;ReturnValue.Field[test::option::MyOption::MySome(0)];value;dfc-generated
pub fn cloned(self) -> MyOption<T>
where
T: Clone,
@@ -440,7 +440,7 @@ impl<T> MyOption<&mut T> {
}
}
// MISSING: summary=<test::option::MyOption>::cloned;Argument[self].Field[test::option::MyOption::MySome(0)].Reference;ReturnValue.Field[test::option::MyOption::MySome(0)];value;dfc-generated
// summary=<test::option::MyOption>::cloned;Argument[self].Field[test::option::MyOption::MySome(0)].Reference;ReturnValue.Field[test::option::MyOption::MySome(0)];value;dfc-generated
pub fn cloned(self) -> MyOption<T>
where
T: Clone,