Merge branch 'main' into rust-core-std-models

This commit is contained in:
Simon Friis Vindum
2025-02-25 15:07:29 +01:00
35 changed files with 1171 additions and 954 deletions

View File

@@ -869,12 +869,11 @@ private predicate elementSpecMatchesSignature(
bindingset[nameWithoutArgs]
pragma[inline_late]
private Class getClassAndNameImpl(Function method, string nameWithoutArgs) {
exists(string memberName | result = method.getClassAndName(memberName) |
nameWithoutArgs = "operator " + method.(ConversionOperator).getDestType()
or
not method instanceof ConversionOperator and
memberName = nameWithoutArgs
)
result = method.getDeclaringType() and
nameWithoutArgs = "operator " + method.(ConversionOperator).getDestType()
or
result = method.getClassAndName(nameWithoutArgs) and
not method instanceof ConversionOperator
}
/**

View File

@@ -46,6 +46,7 @@ private predicate alwaysInvokesToString(ParameterRead pr) {
* method from `System.Object` or `System.ValueType`.
*/
predicate alwaysDefaultToString(ValueOrRefType t) {
not t instanceof TupleType and
exists(ToStringMethod m | t.hasMethod(m) |
m.getDeclaringType() instanceof SystemObjectClass or
m.getDeclaringType() instanceof SystemValueTypeClass
@@ -55,6 +56,11 @@ predicate alwaysDefaultToString(ValueOrRefType t) {
overriding.getABaseType+() = t
) and
((t.isAbstract() or t instanceof Interface) implies not t.isEffectivelyPublic())
or
exists(ValueOrRefType elem |
elem = t.(TupleType).getElementType(_) and
alwaysDefaultToString(elem)
)
}
class DefaultToStringType extends ValueOrRefType {

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* C#: Improve precision of the query `cs/call-to-object-tostring` for value tuples.

View File

@@ -35,6 +35,16 @@ public class DefaultToString
IPublic g = null;
Console.WriteLine(g); // GOOD
Console.WriteLine(new ValueTuple<int, int>(1, 2)); // GOOD
Console.WriteLine((1, 2)); // GOOD
var t1 = new ValueTuple<int, DefaultToString>(1, new DefaultToString());
Console.WriteLine(t1); // BAD
var t2 = new ValueTuple<A, D>(new A(), new D());
Console.WriteLine(t2); // GOOD
}
class A

View File

@@ -2,7 +2,8 @@
| DefaultToString.cs:10:28:10:28 | access to local variable d | Default 'ToString()': $@ inherits 'ToString()' from 'Object', and so is not suitable for printing. | DefaultToString.cs:4:14:4:28 | DefaultToString | DefaultToString |
| DefaultToString.cs:16:27:16:30 | access to local variable ints | Default 'ToString()': $@ inherits 'ToString()' from 'Object', and so is not suitable for printing. | file://:0:0:0:0 | Int32[] | Int32[] |
| DefaultToString.cs:19:24:19:27 | access to local variable ints | Default 'ToString()': $@ inherits 'ToString()' from 'Object', and so is not suitable for printing. | file://:0:0:0:0 | Int32[] | Int32[] |
| DefaultToString.cs:34:27:34:27 | access to local variable f | Default 'ToString()': $@ inherits 'ToString()' from 'Object', and so is not suitable for printing. | DefaultToString.cs:62:23:62:30 | IPrivate | IPrivate |
| DefaultToString.cs:34:27:34:27 | access to local variable f | Default 'ToString()': $@ inherits 'ToString()' from 'Object', and so is not suitable for printing. | DefaultToString.cs:72:23:72:30 | IPrivate | IPrivate |
| DefaultToString.cs:44:27:44:28 | (...) ... | Default 'ToString()': $@ inherits 'ToString()' from 'Object', and so is not suitable for printing. | file://:0:0:0:0 | (Int32,DefaultToString) | (Int32,DefaultToString) |
| DefaultToStringBad.cs:8:35:8:35 | access to local variable p | Default 'ToString()': $@ inherits 'ToString()' from 'Object', and so is not suitable for printing. | DefaultToStringBad.cs:14:11:14:16 | Person | Person |
| DefaultToStringBad.cs:11:38:11:41 | access to local variable ints | Default 'ToString()': $@ inherits 'ToString()' from 'Object', and so is not suitable for printing. | file://:0:0:0:0 | Int32[] | Int32[] |
| WriteLineArray.cs:7:23:7:26 | access to parameter args | Default 'ToString()': $@ inherits 'ToString()' from 'Object', and so is not suitable for printing. | file://:0:0:0:0 | String[] | String[] |

View File

@@ -379,6 +379,14 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
)
}
bindingset[inp, c]
pragma[inline_late]
private Node getInputNode(FunctionInput inp, CallNode c) { result = inp.getNode(c) }
bindingset[outp, c]
pragma[inline_late]
private Node getOutputNode(FunctionOutput outp, CallNode c) { result = outp.getNode(c) }
pragma[noinline]
private predicate guardingCall(
Node g, Function f, FunctionInput inp, FunctionOutput outp, DataFlow::Property p, CallNode c,
@@ -386,8 +394,8 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
) {
guardingFunction(g, f, inp, outp, p) and
c = f.getACall() and
nd = inp.getNode(c) and
localFlow(pragma[only_bind_out](outp.getNode(c)), resNode)
nd = getInputNode(inp, c) and
localFlow(getOutputNode(outp, c), resNode)
}
private predicate onlyPossibleReturnSatisfyingProperty(

View File

@@ -12,6 +12,7 @@
*/
import java
private import codeql.ssa.Ssa as SsaImplCommon
private newtype TBaseSsaSourceVariable =
TLocalVar(Callable c, LocalScopeVariable v) {
@@ -56,10 +57,8 @@ class BaseSsaSourceVariable extends TBaseSsaSourceVariable {
Type getType() { result = this.getVariable().getType() }
}
cached
private module BaseSsaImpl {
/** Gets the destination variable of an update of a tracked variable. */
cached
BaseSsaSourceVariable getDestVar(VariableUpdate upd) {
result.getAnAccess() = upd.(Assignment).getDest()
or
@@ -71,7 +70,6 @@ private module BaseSsaImpl {
}
/** Holds if `n` updates the local variable `v`. */
cached
predicate variableUpdate(BaseSsaSourceVariable v, ControlFlowNode n, BasicBlock b, int i) {
exists(VariableUpdate a | a.getControlFlowNode() = n | getDestVar(a) = v) and
b.getNode(i) = n and
@@ -119,50 +117,14 @@ private module BaseSsaImpl {
)
}
/** Holds if `VarAccess` `use` of `v` occurs in `b` at index `i`. */
private predicate variableUse(BaseSsaSourceVariable v, VarRead use, BasicBlock b, int i) {
v.getAnAccess() = use and b.getNode(i) = use.getControlFlowNode()
}
/** Holds if the value of `v` is captured in `b` at index `i`. */
private predicate variableCapture(
predicate variableCapture(
BaseSsaSourceVariable capturedvar, BaseSsaSourceVariable closurevar, BasicBlock b, int i
) {
b.getNode(i) = captureNode(capturedvar, closurevar)
}
/** Holds if the value of `v` is read in `b` at index `i`. */
private predicate variableUseOrCapture(BaseSsaSourceVariable v, BasicBlock b, int i) {
variableUse(v, _, b, i) or variableCapture(v, _, b, i)
}
/*
* Liveness analysis to restrict the size of the SSA representation.
*/
private predicate liveAtEntry(BaseSsaSourceVariable v, BasicBlock b) {
exists(int i | variableUseOrCapture(v, b, i) |
not exists(int j | variableUpdate(v, _, b, j) | j < i)
)
or
liveAtExit(v, b) and not variableUpdate(v, _, b, _)
}
private predicate liveAtExit(BaseSsaSourceVariable v, BasicBlock b) {
liveAtEntry(v, b.getABBSuccessor())
}
/** Holds if a phi node for `v` is needed at the beginning of basic block `b`. */
cached
predicate phiNode(BaseSsaSourceVariable v, BasicBlock b) {
liveAtEntry(v, b) and
exists(BasicBlock def | dominanceFrontier(def, b) |
variableUpdate(v, _, def, _) or phiNode(v, def)
)
}
/** Holds if `v` has an implicit definition at the entry, `b`, of the callable. */
cached
predicate hasEntryDef(BaseSsaSourceVariable v, BasicBlock b) {
exists(LocalScopeVariable l, Callable c |
v = TLocalVar(c, l) and c.getBody().getControlFlowNode() = b
@@ -171,236 +133,110 @@ private module BaseSsaImpl {
l.getCallable() != c
)
}
}
private import BaseSsaImpl
private module SsaInput implements SsaImplCommon::InputSig<Location> {
private import java as J
private import semmle.code.java.controlflow.Dominance as Dom
class BasicBlock = J::BasicBlock;
class ControlFlowNode = J::ControlFlowNode;
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { Dom::bbIDominates(result, bb) }
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getABBSuccessor() }
class SourceVariable = BaseSsaSourceVariable;
/**
* The construction of SSA form ensures that each use of a variable is
* dominated by its definition. A definition of an SSA variable therefore
* reaches a `ControlFlowNode` if it is the _closest_ SSA variable definition
* that dominates the node. If two definitions dominate a node then one must
* dominate the other, so therefore the definition of _closest_ is given by the
* dominator tree. Thus, reaching definitions can be calculated in terms of
* dominance.
* Holds if the `i`th node of basic block `bb` is a write to source variable
* `v`.
*/
cached
module SsaDefReaches {
/**
* Holds if `rankix` is the rank the index `i` at which there is an SSA definition or use of
* `v` in the basic block `b`.
*
* Basic block indices are translated to rank indices in order to skip
* irrelevant indices at which there is no definition or use when traversing
* basic blocks.
*/
private predicate defUseRank(BaseSsaSourceVariable v, BasicBlock b, int rankix, int i) {
i =
rank[rankix](int j |
any(TrackedSsaDef def).definesAt(v, b, j) or variableUseOrCapture(v, b, j)
)
}
/** Gets the maximum rank index for the given variable and basic block. */
private int lastRank(BaseSsaSourceVariable v, BasicBlock b) {
result = max(int rankix | defUseRank(v, b, rankix, _))
}
/** Holds if a definition of an SSA variable occurs at the specified rank index in basic block `b`. */
private predicate ssaDefRank(
BaseSsaSourceVariable v, TrackedSsaDef def, BasicBlock b, int rankix
) {
exists(int i |
def.definesAt(v, b, i) and
defUseRank(v, b, rankix, i)
)
}
/** Holds if the SSA definition reaches the rank index `rankix` in its own basic block `b`. */
private predicate ssaDefReachesRank(
BaseSsaSourceVariable v, TrackedSsaDef def, BasicBlock b, int rankix
) {
ssaDefRank(v, def, b, rankix)
or
ssaDefReachesRank(v, def, b, rankix - 1) and
rankix <= lastRank(v, b) and
not ssaDefRank(v, _, b, rankix)
}
/**
* Holds if the SSA definition of `v` at `def` reaches the end of a basic block `b`, at
* which point it is still live, without crossing another SSA definition of `v`.
*/
cached
predicate ssaDefReachesEndOfBlock(BaseSsaSourceVariable v, TrackedSsaDef def, BasicBlock b) {
liveAtExit(v, b) and
(
ssaDefReachesRank(v, def, b, lastRank(v, b))
or
exists(BasicBlock idom |
bbIDominates(pragma[only_bind_into](idom), b) and // It is sufficient to traverse the dominator graph, cf. discussion above.
ssaDefReachesEndOfBlock(v, def, idom) and
not any(TrackedSsaDef other).definesAt(v, b, _)
)
)
}
/**
* Holds if the SSA definition of `v` at `def` reaches `use` in the same basic block
* without crossing another SSA definition of `v`.
*/
private predicate ssaDefReachesUseWithinBlock(
BaseSsaSourceVariable v, TrackedSsaDef def, VarRead use
) {
exists(BasicBlock b, int rankix, int i |
ssaDefReachesRank(v, def, b, rankix) and
defUseRank(v, b, rankix, i) and
variableUse(v, use, b, i)
)
}
/**
* Holds if the SSA definition of `v` at `def` reaches `use` without crossing another
* SSA definition of `v`.
*/
cached
predicate ssaDefReachesUse(BaseSsaSourceVariable v, TrackedSsaDef def, VarRead use) {
ssaDefReachesUseWithinBlock(v, def, use)
or
exists(BasicBlock b |
variableUse(v, use, b, _) and
ssaDefReachesEndOfBlock(v, def, b.getABBPredecessor()) and
not ssaDefReachesUseWithinBlock(v, _, use)
)
}
/**
* Holds if the SSA definition of `v` at `def` reaches the capture point of
* `closurevar` in the same basic block without crossing another SSA
* definition of `v`.
*/
private predicate ssaDefReachesCaptureWithinBlock(
BaseSsaSourceVariable v, TrackedSsaDef def, BaseSsaSourceVariable closurevar
) {
exists(BasicBlock b, int rankix, int i |
ssaDefReachesRank(v, def, b, rankix) and
defUseRank(v, b, rankix, i) and
variableCapture(v, closurevar, b, i)
)
}
/**
* Holds if the SSA definition of `v` at `def` reaches capture point of
* `closurevar` without crossing another SSA definition of `v`.
*/
cached
predicate ssaDefReachesCapture(
BaseSsaSourceVariable v, TrackedSsaDef def, BaseSsaSourceVariable closurevar
) {
ssaDefReachesCaptureWithinBlock(v, def, closurevar)
or
exists(BasicBlock b |
variableCapture(v, closurevar, b, _) and
ssaDefReachesEndOfBlock(v, def, b.getABBPredecessor()) and
not ssaDefReachesCaptureWithinBlock(v, _, closurevar)
)
}
predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) {
variableUpdate(v, _, bb, i) and
certain = true
or
hasEntryDef(v, bb) and
i = 0 and
certain = true
}
private module AdjacentUsesImpl {
/**
* Holds if `rankix` is the rank the index `i` at which there is an SSA definition or explicit use of
* `v` in the basic block `b`.
*/
private predicate defUseRank(BaseSsaSourceVariable v, BasicBlock b, int rankix, int i) {
i = rank[rankix](int j | any(TrackedSsaDef def).definesAt(v, b, j) or variableUse(v, _, b, j))
}
/** Gets the maximum rank index for the given variable and basic block. */
private int lastRank(BaseSsaSourceVariable v, BasicBlock b) {
result = max(int rankix | defUseRank(v, b, rankix, _))
}
/** Holds if `v` is defined or used in `b`. */
private predicate varOccursInBlock(BaseSsaSourceVariable v, BasicBlock b) {
defUseRank(v, b, _, _)
}
/** Holds if `v` occurs in `b` or one of `b`'s transitive successors. */
private predicate blockPrecedesVar(BaseSsaSourceVariable v, BasicBlock b) {
varOccursInBlock(v, b)
or
ssaDefReachesEndOfBlock(v, _, b)
}
/**
* Holds if `b2` is a transitive successor of `b1` and `v` occurs in `b1` and
* in `b2` or one of its transitive successors but not in any block on the path
* between `b1` and `b2`.
*/
private predicate varBlockReaches(BaseSsaSourceVariable v, BasicBlock b1, BasicBlock b2) {
varOccursInBlock(v, b1) and
pragma[only_bind_into](b2) = b1.getABBSuccessor() and
blockPrecedesVar(v, b2)
or
exists(BasicBlock mid |
varBlockReaches(v, b1, mid) and
pragma[only_bind_into](b2) = mid.getABBSuccessor() and
not varOccursInBlock(v, mid) and
blockPrecedesVar(v, b2)
)
}
/**
* Holds if `b2` is a transitive successor of `b1` and `v` occurs in `b1` and
* `b2` but not in any block on the path between `b1` and `b2`.
*/
private predicate varBlockStep(BaseSsaSourceVariable v, BasicBlock b1, BasicBlock b2) {
varBlockReaches(v, b1, b2) and
varOccursInBlock(v, b2)
}
/**
* Holds if `v` occurs at index `i1` in `b1` and at index `i2` in `b2` and
* there is a path between them without any occurrence of `v`.
*/
pragma[nomagic]
predicate adjacentVarRefs(BaseSsaSourceVariable v, BasicBlock b1, int i1, BasicBlock b2, int i2) {
exists(int rankix |
b1 = b2 and
defUseRank(v, b1, rankix, i1) and
defUseRank(v, b2, rankix + 1, i2)
)
or
defUseRank(v, b1, lastRank(v, b1), i1) and
varBlockStep(v, b1, b2) and
defUseRank(v, b2, 1, i2)
}
}
private import AdjacentUsesImpl
/**
* Holds if the value defined at `def` can reach `use` without passing through
* any other uses, but possibly through phi nodes.
* Holds if the `i`th of basic block `bb` reads source variable `v`.
*/
cached
predicate firstUse(TrackedSsaDef def, VarRead use) {
exists(BaseSsaSourceVariable v, BasicBlock b1, int i1, BasicBlock b2, int i2 |
adjacentVarRefs(v, b1, i1, b2, i2) and
def.definesAt(v, b1, i1) and
variableUse(v, use, b2, i2)
predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) {
exists(VarRead use |
v.getAnAccess() = use and bb.getNode(i) = use.getControlFlowNode() and certain = true
)
or
exists(
BaseSsaSourceVariable v, TrackedSsaDef redef, BasicBlock b1, int i1, BasicBlock b2, int i2
|
redef instanceof BaseSsaPhiNode
|
adjacentVarRefs(v, b1, i1, b2, i2) and
def.definesAt(v, b1, i1) and
redef.definesAt(v, b2, i2) and
firstUse(redef, use)
variableCapture(v, _, bb, i) and
certain = false
}
}
private module Impl = SsaImplCommon::Make<Location, SsaInput>;
private import Cached
cached
private module Cached {
cached
VarRead getAUse(Impl::Definition def) {
exists(BaseSsaSourceVariable v, BasicBlock bb, int i |
Impl::ssaDefReachesRead(v, def, bb, i) and
result.getControlFlowNode() = bb.getNode(i) and
result = v.getAnAccess()
)
}
cached
predicate ssaDefReachesEndOfBlock(BasicBlock bb, Impl::Definition def) {
Impl::ssaDefReachesEndOfBlock(bb, def, _)
}
cached
predicate firstUse(Impl::Definition def, VarRead use) {
exists(BasicBlock bb, int i |
Impl::firstUse(def, bb, i, _) and
use.getControlFlowNode() = bb.getNode(i)
)
}
cached
predicate ssaUpdate(Impl::Definition def, VariableUpdate upd) {
exists(BaseSsaSourceVariable v, BasicBlock bb, int i |
def.definesAt(v, bb, i) and
variableUpdate(v, upd.getControlFlowNode(), bb, i) and
getDestVar(upd) = v
)
}
cached
predicate ssaImplicitInit(Impl::WriteDefinition def) {
exists(BaseSsaSourceVariable v, BasicBlock bb, int i |
def.definesAt(v, bb, i) and
hasEntryDef(v, bb) and
i = 0
)
}
/** Holds if `init` is a closure variable that captures the value of `capturedvar`. */
cached
predicate captures(BaseSsaImplicitInit init, BaseSsaVariable capturedvar) {
exists(BasicBlock bb, int i |
Impl::ssaDefReachesRead(_, capturedvar, bb, i) and
variableCapture(capturedvar.getSourceVariable(), init.getSourceVariable(), bb, i)
)
}
cached
predicate phiHasInputFromBlock(Impl::PhiNode phi, Impl::Definition inp, BasicBlock bb) {
Impl::phiHasInputFromBlock(phi, inp, bb)
}
cached
module SsaPublic {
/**
@@ -410,10 +246,10 @@ private module BaseSsaImpl {
*/
cached
predicate baseSsaAdjacentUseUseSameVar(VarRead use1, VarRead use2) {
exists(BaseSsaSourceVariable v, BasicBlock b1, int i1, BasicBlock b2, int i2 |
adjacentVarRefs(v, b1, i1, b2, i2) and
variableUse(v, use1, b1, i1) and
variableUse(v, use2, b2, i2)
exists(BasicBlock bb1, int i1, BasicBlock bb2, int i2 |
use1.getControlFlowNode() = bb1.getNode(i1) and
use2.getControlFlowNode() = bb2.getNode(i2) and
Impl::adjacentUseUse(bb1, i1, bb2, i2, _, true)
)
}
@@ -425,78 +261,28 @@ private module BaseSsaImpl {
*/
cached
predicate baseSsaAdjacentUseUse(VarRead use1, VarRead use2) {
baseSsaAdjacentUseUseSameVar(use1, use2)
or
exists(
BaseSsaSourceVariable v, TrackedSsaDef def, BasicBlock b1, int i1, BasicBlock b2, int i2
|
adjacentVarRefs(v, b1, i1, b2, i2) and
variableUse(v, use1, b1, i1) and
def.definesAt(v, b2, i2) and
firstUse(def, use2) and
def instanceof BaseSsaPhiNode
exists(BasicBlock bb1, int i1, BasicBlock bb2, int i2 |
use1.getControlFlowNode() = bb1.getNode(i1) and
use2.getControlFlowNode() = bb2.getNode(i2) and
Impl::adjacentUseUse(bb1, i1, bb2, i2, _, _)
)
}
}
}
private import BaseSsaImpl
private import SsaDefReaches
import SsaPublic
private newtype TBaseSsaVariable =
TSsaPhiNode(BaseSsaSourceVariable v, BasicBlock b) { phiNode(v, b) } or
TSsaUpdate(BaseSsaSourceVariable v, ControlFlowNode n, BasicBlock b, int i) {
variableUpdate(v, n, b, i)
} or
TSsaEntryDef(BaseSsaSourceVariable v, BasicBlock b) { hasEntryDef(v, b) }
/**
* An SSA definition excluding those variables that use a trivial SSA construction.
*/
private class TrackedSsaDef extends BaseSsaVariable {
/**
* Holds if this SSA definition occurs at the specified position.
* Phi nodes are placed at index -1.
*/
predicate definesAt(BaseSsaSourceVariable v, BasicBlock b, int i) {
this = TSsaPhiNode(v, b) and i = -1
or
this = TSsaUpdate(v, _, b, i)
or
this = TSsaEntryDef(v, b) and i = 0
}
}
/**
* An SSA variable.
*/
class BaseSsaVariable extends TBaseSsaVariable {
/** Gets the SSA source variable underlying this SSA variable. */
BaseSsaSourceVariable getSourceVariable() {
this = TSsaPhiNode(result, _) or
this = TSsaUpdate(result, _, _, _) or
this = TSsaEntryDef(result, _)
}
class BaseSsaVariable extends Impl::Definition {
/** Gets the `ControlFlowNode` at which this SSA variable is defined. */
ControlFlowNode getCfgNode() {
this = TSsaPhiNode(_, result) or
this = TSsaUpdate(_, result, _, _) or
this = TSsaEntryDef(_, result)
exists(BasicBlock bb, int i | this.definesAt(_, bb, i) and result = bb.getNode(0.maximum(i)))
}
/** Gets a textual representation of this element. */
string toString() { none() }
/** Gets the source location for this element. */
Location getLocation() { result = this.getCfgNode().getLocation() }
/** Gets the `BasicBlock` in which this SSA variable is defined. */
BasicBlock getBasicBlock() { result = this.getCfgNode().getBasicBlock() }
/** Gets an access of this SSA variable. */
VarRead getAUse() { ssaDefReachesUse(_, this, result) }
VarRead getAUse() { result = getAUse(this) }
/**
* Gets an access of the SSA source variable underlying this SSA variable
@@ -509,7 +295,7 @@ class BaseSsaVariable extends TBaseSsaVariable {
VarRead getAFirstUse() { firstUse(this, result) }
/** Holds if this SSA variable is live at the end of `b`. */
predicate isLiveAtEndOfBlock(BasicBlock b) { ssaDefReachesEndOfBlock(_, this, b) }
predicate isLiveAtEndOfBlock(BasicBlock b) { ssaDefReachesEndOfBlock(b, this) }
/** Gets an input to the phi node defining the SSA variable. */
private BaseSsaVariable getAPhiInput() { result = this.(BaseSsaPhiNode).getAPhiInput() }
@@ -536,33 +322,22 @@ class BaseSsaVariable extends TBaseSsaVariable {
}
/** An SSA variable that is defined by a `VariableUpdate`. */
class BaseSsaUpdate extends BaseSsaVariable, TSsaUpdate {
BaseSsaUpdate() {
exists(VariableUpdate upd |
upd.getControlFlowNode() = this.getCfgNode() and getDestVar(upd) = this.getSourceVariable()
)
}
override string toString() { result = "SSA def(" + this.getSourceVariable() + ")" }
class BaseSsaUpdate extends BaseSsaVariable instanceof Impl::WriteDefinition {
BaseSsaUpdate() { ssaUpdate(this, _) }
/** Gets the `VariableUpdate` defining the SSA variable. */
VariableUpdate getDefiningExpr() {
result.getControlFlowNode() = this.getCfgNode() and
getDestVar(result) = this.getSourceVariable()
}
VariableUpdate getDefiningExpr() { ssaUpdate(this, result) }
}
/**
* An SSA variable that is defined by its initial value in the callable. This
* includes initial values of parameters, fields, and closure variables.
*/
class BaseSsaImplicitInit extends BaseSsaVariable, TSsaEntryDef {
override string toString() { result = "SSA init(" + this.getSourceVariable() + ")" }
class BaseSsaImplicitInit extends BaseSsaVariable instanceof Impl::WriteDefinition {
BaseSsaImplicitInit() { ssaImplicitInit(this) }
/** Holds if this is a closure variable that captures the value of `capturedvar`. */
predicate captures(BaseSsaVariable capturedvar) {
ssaDefReachesCapture(_, capturedvar, this.getSourceVariable())
}
predicate captures(BaseSsaVariable capturedvar) { captures(this, capturedvar) }
/**
* Holds if the SSA variable is a parameter defined by its initial value in the callable.
@@ -574,15 +349,7 @@ class BaseSsaImplicitInit extends BaseSsaVariable, TSsaEntryDef {
}
/** An SSA phi node. */
class BaseSsaPhiNode extends BaseSsaVariable, TSsaPhiNode {
override string toString() { result = "SSA phi(" + this.getSourceVariable() + ")" }
class BaseSsaPhiNode extends BaseSsaVariable instanceof Impl::PhiNode {
/** Gets an input to the phi node defining the SSA variable. */
BaseSsaVariable getAPhiInput() {
exists(BasicBlock phiPred, BaseSsaSourceVariable v |
v = this.getSourceVariable() and
this.getCfgNode().(BasicBlock).getABBPredecessor() = phiPred and
ssaDefReachesEndOfBlock(v, result, phiPred)
)
}
BaseSsaVariable getAPhiInput() { phiHasInputFromBlock(this, result, _) }
}

View File

@@ -315,6 +315,16 @@ class ResponseSetHeaderMethod extends Method {
}
}
/**
* The method `setContentType` declared in `javax.servlet.http.HttpServletResponse`.
*/
class ResponseSetContentTypeMethod extends Method {
ResponseSetContentTypeMethod() {
this.getDeclaringType() instanceof ServletResponse and
this.hasName("setContentType")
}
}
/**
* A class that has `javax.servlet.Servlet` as an ancestor.
*/

View File

@@ -92,9 +92,25 @@ private class WritingMethod extends Method {
/** An output stream or writer that writes to a servlet, JSP or JSF response. */
class XssVulnerableWriterSource extends MethodCall {
XssVulnerableWriterSource() {
this.getMethod() instanceof ServletResponseGetWriterMethod
or
this.getMethod() instanceof ServletResponseGetOutputStreamMethod
(
this.getMethod() instanceof ServletResponseGetWriterMethod
or
this.getMethod() instanceof ServletResponseGetOutputStreamMethod
) and
not exists(MethodCall mc, Expr contentType |
mc.getMethod() instanceof ResponseSetContentTypeMethod and
contentType = mc.getArgument(0)
or
(
mc.getMethod() instanceof ResponseAddHeaderMethod or
mc.getMethod() instanceof ResponseSetHeaderMethod
) and
mc.getArgument(0).(CompileTimeConstantExpr).getStringValue().toLowerCase() = "content-type" and
contentType = mc.getArgument(1)
|
isXssSafeContentTypeString(contentType.(CompileTimeConstantExpr).getStringValue()) and
DataFlow::localExprFlow(mc.getQualifier(), this.getQualifier())
)
or
exists(Method m | m = this.getMethod() |
m.hasQualifiedName("javax.servlet.jsp", "JspContext", "getOut")
@@ -106,6 +122,11 @@ class XssVulnerableWriterSource extends MethodCall {
}
}
pragma[nomagic]
private predicate isXssSafeContentTypeString(string s) {
s = any(CompileTimeConstantExpr cte).getStringValue() and isXssSafeContentType(s)
}
/**
* A xss vulnerable writer source node.
*/

View File

@@ -0,0 +1,4 @@
---
category: majorAnalysis
---
* Fixed false positive alerts in the java query "Cross-site scripting" (`java/xss`) when `javax.servlet.http.HttpServletResponse` is used with a content type which is not exploitable.

View File

@@ -19,18 +19,18 @@ public class JaxXSS {
if(!safeContentType) {
if(chainDirectly) {
if(contentTypeFirst)
return builder.type(MediaType.TEXT_HTML).entity(userControlled).build(); // $xss
return builder.type(MediaType.TEXT_HTML).entity(userControlled).build(); // $ xss
else
return builder.entity(userControlled).type(MediaType.TEXT_HTML).build(); // $xss
return builder.entity(userControlled).type(MediaType.TEXT_HTML).build(); // $ xss
}
else {
if(contentTypeFirst) {
Response.ResponseBuilder builder2 = builder.type(MediaType.TEXT_HTML);
return builder2.entity(userControlled).build(); // $xss
return builder2.entity(userControlled).build(); // $ xss
}
else {
Response.ResponseBuilder builder2 = builder.entity(userControlled);
return builder2.type(MediaType.TEXT_HTML).build(); // $xss
return builder2.type(MediaType.TEXT_HTML).build(); // $ xss
}
}
}
@@ -105,39 +105,39 @@ public class JaxXSS {
else {
if(route == 0) {
// via ok, as a string literal:
return Response.ok("text/html").entity(userControlled).build(); // $xss
return Response.ok("text/html").entity(userControlled).build(); // $ xss
}
else if(route == 1) {
// via ok, as a string constant:
return Response.ok(MediaType.TEXT_HTML).entity(userControlled).build(); // $xss
return Response.ok(MediaType.TEXT_HTML).entity(userControlled).build(); // $ xss
}
else if(route == 2) {
// via ok, as a MediaType constant:
return Response.ok(MediaType.TEXT_HTML_TYPE).entity(userControlled).build(); // $xss
return Response.ok(MediaType.TEXT_HTML_TYPE).entity(userControlled).build(); // $ xss
}
else if(route == 3) {
// via ok, as a Variant, via constructor:
return Response.ok(new Variant(MediaType.TEXT_HTML_TYPE, "language", "encoding")).entity(userControlled).build(); // $xss
return Response.ok(new Variant(MediaType.TEXT_HTML_TYPE, "language", "encoding")).entity(userControlled).build(); // $ xss
}
else if(route == 4) {
// via ok, as a Variant, via static method:
return Response.ok(Variant.mediaTypes(MediaType.TEXT_HTML_TYPE).build()).entity(userControlled).build(); // $xss
return Response.ok(Variant.mediaTypes(MediaType.TEXT_HTML_TYPE).build()).entity(userControlled).build(); // $ xss
}
else if(route == 5) {
// via ok, as a Variant, via instance method:
return Response.ok(Variant.languages(Locale.UK).mediaTypes(MediaType.TEXT_HTML_TYPE).build()).entity(userControlled).build(); // $xss
return Response.ok(Variant.languages(Locale.UK).mediaTypes(MediaType.TEXT_HTML_TYPE).build()).entity(userControlled).build(); // $ xss
}
else if(route == 6) {
// via builder variant, before entity:
return Response.ok().variant(new Variant(MediaType.TEXT_HTML_TYPE, "language", "encoding")).entity(userControlled).build(); // $xss
return Response.ok().variant(new Variant(MediaType.TEXT_HTML_TYPE, "language", "encoding")).entity(userControlled).build(); // $ xss
}
else if(route == 7) {
// via builder variant, after entity:
return Response.ok().entity(userControlled).variant(new Variant(MediaType.TEXT_HTML_TYPE, "language", "encoding")).build(); // $xss
return Response.ok().entity(userControlled).variant(new Variant(MediaType.TEXT_HTML_TYPE, "language", "encoding")).build(); // $ xss
}
else if(route == 8) {
// provide entity via ok, then content-type via builder:
return Response.ok(userControlled).type(MediaType.TEXT_HTML_TYPE).build(); // $xss
return Response.ok(userControlled).type(MediaType.TEXT_HTML_TYPE).build(); // $ xss
}
}
@@ -162,27 +162,27 @@ public class JaxXSS {
@GET @Produces(MediaType.TEXT_HTML)
public static Response methodContentTypeUnsafe(String userControlled) {
return Response.ok(userControlled).build(); // $xss
return Response.ok(userControlled).build(); // $ xss
}
@POST @Produces(MediaType.TEXT_HTML)
public static Response methodContentTypeUnsafePost(String userControlled) {
return Response.ok(userControlled).build(); // $xss
return Response.ok(userControlled).build(); // $ xss
}
@GET @Produces("text/html")
public static Response methodContentTypeUnsafeStringLiteral(String userControlled) {
return Response.ok(userControlled).build(); // $xss
return Response.ok(userControlled).build(); // $ xss
}
@GET @Produces({MediaType.TEXT_HTML, MediaType.APPLICATION_JSON})
public static Response methodContentTypeMaybeSafe(String userControlled) {
return Response.ok(userControlled).build(); // $xss
return Response.ok(userControlled).build(); // $ xss
}
@GET @Produces(MediaType.APPLICATION_JSON)
public static Response methodContentTypeSafeOverriddenWithUnsafe(String userControlled) {
return Response.ok().type(MediaType.TEXT_HTML).entity(userControlled).build(); // $xss
return Response.ok().type(MediaType.TEXT_HTML).entity(userControlled).build(); // $ xss
}
@GET @Produces(MediaType.TEXT_HTML)
@@ -205,12 +205,12 @@ public class JaxXSS {
@GET @Produces({"text/html"})
public Response overridesWithUnsafe(String userControlled) {
return Response.ok(userControlled).build(); // $xss
return Response.ok(userControlled).build(); // $ xss
}
@GET
public Response overridesWithUnsafe2(String userControlled) {
return Response.ok().type(MediaType.TEXT_HTML).entity(userControlled).build(); // $xss
return Response.ok().type(MediaType.TEXT_HTML).entity(userControlled).build(); // $ xss
}
}
@@ -219,12 +219,12 @@ public class JaxXSS {
public static class ClassContentTypeUnsafe {
@GET
public Response test(String userControlled) {
return Response.ok(userControlled).build(); // $xss
return Response.ok(userControlled).build(); // $ xss
}
@GET
public String testDirectReturn(String userControlled) {
return userControlled; // $xss
return userControlled; // $ xss
}
@GET @Produces({"application/json"})
@@ -240,12 +240,12 @@ public class JaxXSS {
@GET
public static Response entityWithNoMediaType(String userControlled) {
return Response.ok(userControlled).build(); // $xss
return Response.ok(userControlled).build(); // $ xss
}
@GET
public static String stringWithNoMediaType(String userControlled) {
return userControlled; // $xss
return userControlled; // $ xss
}
}
}

View File

@@ -26,7 +26,7 @@ public class JsfXSS extends Renderer
writer.write("(function(){");
writer.write("dswh.init('" + windowId + "','"
+ "......" + "',"
+ -1 + ",{"); // $xss
+ -1 + ",{"); // $ xss
writer.write("});");
writer.write("})();");
writer.write("</script>");
@@ -57,13 +57,13 @@ public class JsfXSS extends Renderer
{
ExternalContext ec = facesContext.getExternalContext();
ResponseWriter writer = facesContext.getResponseWriter();
writer.write(ec.getRequestParameterMap().keySet().iterator().next()); // $xss
writer.write(ec.getRequestParameterNames().next()); // $xss
writer.write(ec.getRequestParameterValuesMap().get("someKey")[0]); // $xss
writer.write(ec.getRequestParameterValuesMap().keySet().iterator().next()); // $xss
writer.write(ec.getRequestPathInfo()); // $xss
writer.write(((Cookie)ec.getRequestCookieMap().get("someKey")).getName()); // $xss
writer.write(ec.getRequestHeaderMap().get("someKey")); // $xss
writer.write(ec.getRequestHeaderValuesMap().get("someKey")[0]); // $xss
writer.write(ec.getRequestParameterMap().keySet().iterator().next()); // $ xss
writer.write(ec.getRequestParameterNames().next()); // $ xss
writer.write(ec.getRequestParameterValuesMap().get("someKey")[0]); // $ xss
writer.write(ec.getRequestParameterValuesMap().keySet().iterator().next()); // $ xss
writer.write(ec.getRequestPathInfo()); // $ xss
writer.write(((Cookie)ec.getRequestCookieMap().get("someKey")).getName()); // $ xss
writer.write(ec.getRequestHeaderMap().get("someKey")); // $ xss
writer.write(ec.getRequestHeaderValuesMap().get("someKey")[0]); // $ xss
}
}

View File

@@ -6,7 +6,7 @@ import android.webkit.WebSettings;
public class SetJavascriptEnabled {
public static void configureWebViewUnsafe(WebView view) {
WebSettings settings = view.getSettings();
settings.setJavaScriptEnabled(true); // $javascriptEnabled
settings.setJavaScriptEnabled(true); // $ javascriptEnabled
}
public static void configureWebViewSafe(WebView view) {

View File

@@ -17,13 +17,13 @@ public class SpringXSS {
ResponseEntity.BodyBuilder builder = ResponseEntity.ok();
if(safeContentType) {
if(!safeContentType) {
if(chainDirectly) {
return builder.contentType(MediaType.TEXT_HTML).body(userControlled); // $xss
return builder.contentType(MediaType.TEXT_HTML).body(userControlled); // $ xss
}
else {
ResponseEntity.BodyBuilder builder2 = builder.contentType(MediaType.TEXT_HTML);
return builder2.body(userControlled); // $xss
return builder2.body(userControlled); // $ xss
}
}
else {
@@ -60,22 +60,22 @@ public class SpringXSS {
@GetMapping(value = "/xyz", produces = MediaType.TEXT_HTML_VALUE)
public static ResponseEntity<String> methodContentTypeUnsafe(String userControlled) {
return ResponseEntity.ok(userControlled); // $xss
return ResponseEntity.ok(userControlled); // $ xss
}
@GetMapping(value = "/xyz", produces = "text/html")
public static ResponseEntity<String> methodContentTypeUnsafeStringLiteral(String userControlled) {
return ResponseEntity.ok(userControlled); // $xss
return ResponseEntity.ok(userControlled); // $ xss
}
@GetMapping(value = "/xyz", produces = {MediaType.TEXT_HTML_VALUE, MediaType.APPLICATION_JSON_VALUE})
public static ResponseEntity<String> methodContentTypeMaybeSafe(String userControlled) {
return ResponseEntity.ok(userControlled); // $xss
return ResponseEntity.ok(userControlled); // $ xss
}
@GetMapping(value = "/xyz", produces = MediaType.APPLICATION_JSON_VALUE)
public static ResponseEntity<String> methodContentTypeSafeOverriddenWithUnsafe(String userControlled) {
return ResponseEntity.ok().contentType(MediaType.TEXT_HTML).body(userControlled); // $xss
return ResponseEntity.ok().contentType(MediaType.TEXT_HTML).body(userControlled); // $ xss
}
@GetMapping(value = "/xyz", produces = MediaType.TEXT_HTML_VALUE)
@@ -88,13 +88,13 @@ public class SpringXSS {
// Also try out some alternative constructors for the ResponseEntity:
switch(constructionMethod) {
case 0:
return ResponseEntity.ok(userControlled); // $xss
return ResponseEntity.ok(userControlled); // $ xss
case 1:
return ResponseEntity.of(Optional.of(userControlled)); // $xss
return ResponseEntity.of(Optional.of(userControlled)); // $ xss
case 2:
return ResponseEntity.ok().body(userControlled); // $xss
return ResponseEntity.ok().body(userControlled); // $ xss
case 3:
return new ResponseEntity<String>(userControlled, HttpStatus.OK); // $xss
return new ResponseEntity<String>(userControlled, HttpStatus.OK); // $ xss
default:
return null;
}
@@ -115,12 +115,12 @@ public class SpringXSS {
@GetMapping(value = "/xyz", produces = {"text/html"})
public ResponseEntity<String> overridesWithUnsafe(String userControlled) {
return ResponseEntity.ok(userControlled); // $xss
return ResponseEntity.ok(userControlled); // $ xss
}
@GetMapping(value = "/abc")
public ResponseEntity<String> overridesWithUnsafe2(String userControlled) {
return ResponseEntity.ok().contentType(MediaType.TEXT_HTML).body(userControlled); // $xss
return ResponseEntity.ok().contentType(MediaType.TEXT_HTML).body(userControlled); // $ xss
}
}
@@ -129,12 +129,12 @@ public class SpringXSS {
private static class ClassContentTypeUnsafe {
@GetMapping(value = "/abc")
public ResponseEntity<String> test(String userControlled) {
return ResponseEntity.ok(userControlled); // $xss
return ResponseEntity.ok(userControlled); // $ xss
}
@GetMapping(value = "/abc")
public String testDirectReturn(String userControlled) {
return userControlled; // $xss
return userControlled; // $ xss
}
@GetMapping(value = "/xyz", produces = {"application/json"})
@@ -150,12 +150,12 @@ public class SpringXSS {
@GetMapping(value = "/abc")
public static ResponseEntity<String> entityWithNoMediaType(String userControlled) {
return ResponseEntity.ok(userControlled); // $xss
return ResponseEntity.ok(userControlled); // $ xss
}
@GetMapping(value = "/abc")
public static String stringWithNoMediaType(String userControlled) {
return userControlled; // $xss
return userControlled; // $ xss
}
@GetMapping(value = "/abc")

View File

@@ -12,11 +12,11 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class XSS extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
protected void doGet(HttpServletRequest request, HttpServletResponse response, boolean safeContentType, boolean getWriter, int setContentMethod)
throws ServletException, IOException {
// BAD: a request parameter is written directly to the Servlet response stream
response.getWriter()
.print("The page \"" + request.getParameter("page") + "\" was not found."); // $xss
.print("The page \"" + request.getParameter("page") + "\" was not found."); // $ xss
// GOOD: servlet API encodes the error message HTML for the HTML context
response.sendError(HttpServletResponse.SC_NOT_FOUND,
@@ -31,13 +31,86 @@ public class XSS extends HttpServlet {
"The page \"" + capitalizeName(request.getParameter("page")) + "\" was not found.");
// BAD: outputting the path of the resource
response.getWriter().print("The path section of the URL was " + request.getPathInfo()); // $xss
response.getWriter().print("The path section of the URL was " + request.getPathInfo()); // $ xss
// BAD: typical XSS, this time written to an OutputStream instead of a Writer
response.getOutputStream().write(request.getPathInfo().getBytes()); // $xss
response.getOutputStream().write(request.getPathInfo().getBytes()); // $ xss
// GOOD: sanitizer
response.getOutputStream().write(hudson.Util.escape(request.getPathInfo()).getBytes()); // safe
if(safeContentType) {
if(getWriter) {
if(setContentMethod == 0) {
// GOOD: set content-type to something safe
response.setContentType("text/plain");
response.getWriter().print(request.getPathInfo());
}
else if(setContentMethod == 1) {
// GOOD: set content-type to something safe
response.setHeader("Content-Type", "text/plain");
response.getWriter().print(request.getPathInfo());
}
else {
// GOOD: set content-type to something safe
response.addHeader("Content-Type", "text/plain");
response.getWriter().print(request.getPathInfo());
}
}
else {
if(setContentMethod == 0) {
// GOOD: set content-type to something safe
response.setContentType("text/plain");
response.getOutputStream().write(request.getPathInfo().getBytes());
}
else if(setContentMethod == 1) {
// GOOD: set content-type to something safe
response.setHeader("Content-Type", "text/plain");
response.getOutputStream().write(request.getPathInfo().getBytes());
}
else {
// GOOD: set content-type to something safe
response.addHeader("Content-Type", "text/plain");
response.getOutputStream().write(request.getPathInfo().getBytes());
}
}
}
else {
if(getWriter) {
if(setContentMethod == 0) {
// BAD: set content-type to something that is not safe
response.setContentType("text/html");
response.getWriter().print(request.getPathInfo()); // $ xss
}
else if(setContentMethod == 1) {
// BAD: set content-type to something that is not safe
response.setHeader("Content-Type", "text/html");
response.getWriter().print(request.getPathInfo()); // $ xss
}
else {
// BAD: set content-type to something that is not safe
response.addHeader("Content-Type", "text/html");
response.getWriter().print(request.getPathInfo()); // $ xss
}
}
else {
if(setContentMethod == 0) {
// BAD: set content-type to something that is not safe
response.setContentType("text/html");
response.getOutputStream().write(request.getPathInfo().getBytes()); // $ xss
}
else if(setContentMethod == 1) {
// BAD: set content-type to something that is not safe
response.setHeader("Content-Type", "text/html");
response.getOutputStream().write(request.getPathInfo().getBytes()); // $ xss
}
else {
// BAD: set content-type to something that is not safe
response.addHeader("Content-Type", "text/html");
response.getOutputStream().write(request.getPathInfo().getBytes()); // $ xss
}
}
}
}
/**

View File

@@ -0,0 +1,63 @@
#select
| StaticInitializationVector.java:19:51:19:56 | ivSpec | StaticInitializationVector.java:13:21:13:81 | new byte[] : byte[] | StaticInitializationVector.java:19:51:19:56 | ivSpec | A $@ should not be used for encryption. | StaticInitializationVector.java:13:21:13:81 | new byte[] | static initialization vector |
| StaticInitializationVector.java:32:51:32:56 | ivSpec | StaticInitializationVector.java:26:21:26:32 | new byte[] : byte[] | StaticInitializationVector.java:32:51:32:56 | ivSpec | A $@ should not be used for encryption. | StaticInitializationVector.java:26:21:26:32 | new byte[] | static initialization vector |
| StaticInitializationVector.java:48:51:48:56 | ivSpec | StaticInitializationVector.java:39:21:39:32 | new byte[] : byte[] | StaticInitializationVector.java:48:51:48:56 | ivSpec | A $@ should not be used for encryption. | StaticInitializationVector.java:39:21:39:32 | new byte[] | static initialization vector |
| StaticInitializationVector.java:64:51:64:56 | ivSpec | StaticInitializationVector.java:55:30:58:9 | new byte[][] : byte[][] | StaticInitializationVector.java:64:51:64:56 | ivSpec | A $@ should not be used for encryption. | StaticInitializationVector.java:55:30:58:9 | new byte[][] | static initialization vector |
| StaticInitializationVector.java:80:51:80:56 | ivSpec | StaticInitializationVector.java:71:30:74:9 | new byte[][] : byte[][] | StaticInitializationVector.java:80:51:80:56 | ivSpec | A $@ should not be used for encryption. | StaticInitializationVector.java:71:30:74:9 | new byte[][] | static initialization vector |
| StaticInitializationVector.java:96:51:96:56 | ivSpec | StaticInitializationVector.java:88:13:88:23 | new byte[] : byte[] | StaticInitializationVector.java:96:51:96:56 | ivSpec | A $@ should not be used for encryption. | StaticInitializationVector.java:88:13:88:23 | new byte[] | static initialization vector |
| StaticInitializationVector.java:96:51:96:56 | ivSpec | StaticInitializationVector.java:89:13:89:24 | new byte[] : byte[] | StaticInitializationVector.java:96:51:96:56 | ivSpec | A $@ should not be used for encryption. | StaticInitializationVector.java:89:13:89:24 | new byte[] | static initialization vector |
edges
| StaticInitializationVector.java:13:21:13:81 | new byte[] : byte[] | StaticInitializationVector.java:15:61:15:62 | iv : byte[] | provenance | |
| StaticInitializationVector.java:15:35:15:63 | new GCMParameterSpec(...) : GCMParameterSpec | StaticInitializationVector.java:19:51:19:56 | ivSpec | provenance | Sink:MaD:1 |
| StaticInitializationVector.java:15:61:15:62 | iv : byte[] | StaticInitializationVector.java:15:35:15:63 | new GCMParameterSpec(...) : GCMParameterSpec | provenance | MaD:2 |
| StaticInitializationVector.java:26:21:26:32 | new byte[] : byte[] | StaticInitializationVector.java:28:61:28:62 | iv : byte[] | provenance | |
| StaticInitializationVector.java:28:35:28:63 | new GCMParameterSpec(...) : GCMParameterSpec | StaticInitializationVector.java:32:51:32:56 | ivSpec | provenance | Sink:MaD:1 |
| StaticInitializationVector.java:28:61:28:62 | iv : byte[] | StaticInitializationVector.java:28:35:28:63 | new GCMParameterSpec(...) : GCMParameterSpec | provenance | MaD:2 |
| StaticInitializationVector.java:39:21:39:32 | new byte[] : byte[] | StaticInitializationVector.java:44:54:44:55 | iv : byte[] | provenance | |
| StaticInitializationVector.java:44:34:44:56 | new IvParameterSpec(...) : IvParameterSpec | StaticInitializationVector.java:48:51:48:56 | ivSpec | provenance | Sink:MaD:1 |
| StaticInitializationVector.java:44:54:44:55 | iv : byte[] | StaticInitializationVector.java:44:34:44:56 | new IvParameterSpec(...) : IvParameterSpec | provenance | MaD:3 |
| StaticInitializationVector.java:55:30:58:9 | new byte[][] : byte[][] | StaticInitializationVector.java:60:61:60:72 | ...[...] : byte[] | provenance | |
| StaticInitializationVector.java:60:35:60:73 | new GCMParameterSpec(...) : GCMParameterSpec | StaticInitializationVector.java:64:51:64:56 | ivSpec | provenance | Sink:MaD:1 |
| StaticInitializationVector.java:60:61:60:72 | ...[...] : byte[] | StaticInitializationVector.java:60:35:60:73 | new GCMParameterSpec(...) : GCMParameterSpec | provenance | MaD:2 |
| StaticInitializationVector.java:71:30:74:9 | new byte[][] : byte[][] | StaticInitializationVector.java:76:61:76:72 | ...[...] : byte[] | provenance | |
| StaticInitializationVector.java:76:35:76:73 | new GCMParameterSpec(...) : GCMParameterSpec | StaticInitializationVector.java:80:51:80:56 | ivSpec | provenance | Sink:MaD:1 |
| StaticInitializationVector.java:76:61:76:72 | ...[...] : byte[] | StaticInitializationVector.java:76:35:76:73 | new GCMParameterSpec(...) : GCMParameterSpec | provenance | MaD:2 |
| StaticInitializationVector.java:87:24:90:9 | {...} : byte[][] [[]] : byte[] | StaticInitializationVector.java:92:61:92:63 | ivs : byte[][] [[]] : byte[] | provenance | |
| StaticInitializationVector.java:88:13:88:23 | new byte[] : byte[] | StaticInitializationVector.java:87:24:90:9 | {...} : byte[][] [[]] : byte[] | provenance | |
| StaticInitializationVector.java:89:13:89:24 | new byte[] : byte[] | StaticInitializationVector.java:87:24:90:9 | {...} : byte[][] [[]] : byte[] | provenance | |
| StaticInitializationVector.java:92:35:92:67 | new GCMParameterSpec(...) : GCMParameterSpec | StaticInitializationVector.java:96:51:96:56 | ivSpec | provenance | Sink:MaD:1 |
| StaticInitializationVector.java:92:61:92:63 | ivs : byte[][] [[]] : byte[] | StaticInitializationVector.java:92:61:92:66 | ...[...] : byte[] | provenance | |
| StaticInitializationVector.java:92:61:92:66 | ...[...] : byte[] | StaticInitializationVector.java:92:35:92:67 | new GCMParameterSpec(...) : GCMParameterSpec | provenance | MaD:2 |
models
| 1 | Sink: javax.crypto; Cipher; true; init; (int,Key,AlgorithmParameterSpec); ; Argument[2]; encryption-iv; manual |
| 2 | Summary: javax.crypto.spec; GCMParameterSpec; true; GCMParameterSpec; ; ; Argument[1]; Argument[this]; taint; manual |
| 3 | Summary: javax.crypto.spec; IvParameterSpec; true; IvParameterSpec; ; ; Argument[0]; Argument[this]; taint; manual |
nodes
| StaticInitializationVector.java:13:21:13:81 | new byte[] : byte[] | semmle.label | new byte[] : byte[] |
| StaticInitializationVector.java:15:35:15:63 | new GCMParameterSpec(...) : GCMParameterSpec | semmle.label | new GCMParameterSpec(...) : GCMParameterSpec |
| StaticInitializationVector.java:15:61:15:62 | iv : byte[] | semmle.label | iv : byte[] |
| StaticInitializationVector.java:19:51:19:56 | ivSpec | semmle.label | ivSpec |
| StaticInitializationVector.java:26:21:26:32 | new byte[] : byte[] | semmle.label | new byte[] : byte[] |
| StaticInitializationVector.java:28:35:28:63 | new GCMParameterSpec(...) : GCMParameterSpec | semmle.label | new GCMParameterSpec(...) : GCMParameterSpec |
| StaticInitializationVector.java:28:61:28:62 | iv : byte[] | semmle.label | iv : byte[] |
| StaticInitializationVector.java:32:51:32:56 | ivSpec | semmle.label | ivSpec |
| StaticInitializationVector.java:39:21:39:32 | new byte[] : byte[] | semmle.label | new byte[] : byte[] |
| StaticInitializationVector.java:44:34:44:56 | new IvParameterSpec(...) : IvParameterSpec | semmle.label | new IvParameterSpec(...) : IvParameterSpec |
| StaticInitializationVector.java:44:54:44:55 | iv : byte[] | semmle.label | iv : byte[] |
| StaticInitializationVector.java:48:51:48:56 | ivSpec | semmle.label | ivSpec |
| StaticInitializationVector.java:55:30:58:9 | new byte[][] : byte[][] | semmle.label | new byte[][] : byte[][] |
| StaticInitializationVector.java:60:35:60:73 | new GCMParameterSpec(...) : GCMParameterSpec | semmle.label | new GCMParameterSpec(...) : GCMParameterSpec |
| StaticInitializationVector.java:60:61:60:72 | ...[...] : byte[] | semmle.label | ...[...] : byte[] |
| StaticInitializationVector.java:64:51:64:56 | ivSpec | semmle.label | ivSpec |
| StaticInitializationVector.java:71:30:74:9 | new byte[][] : byte[][] | semmle.label | new byte[][] : byte[][] |
| StaticInitializationVector.java:76:35:76:73 | new GCMParameterSpec(...) : GCMParameterSpec | semmle.label | new GCMParameterSpec(...) : GCMParameterSpec |
| StaticInitializationVector.java:76:61:76:72 | ...[...] : byte[] | semmle.label | ...[...] : byte[] |
| StaticInitializationVector.java:80:51:80:56 | ivSpec | semmle.label | ivSpec |
| StaticInitializationVector.java:87:24:90:9 | {...} : byte[][] [[]] : byte[] | semmle.label | {...} : byte[][] [[]] : byte[] |
| StaticInitializationVector.java:88:13:88:23 | new byte[] : byte[] | semmle.label | new byte[] : byte[] |
| StaticInitializationVector.java:89:13:89:24 | new byte[] : byte[] | semmle.label | new byte[] : byte[] |
| StaticInitializationVector.java:92:35:92:67 | new GCMParameterSpec(...) : GCMParameterSpec | semmle.label | new GCMParameterSpec(...) : GCMParameterSpec |
| StaticInitializationVector.java:92:61:92:63 | ivs : byte[][] [[]] : byte[] | semmle.label | ivs : byte[][] [[]] : byte[] |
| StaticInitializationVector.java:92:61:92:66 | ...[...] : byte[] | semmle.label | ...[...] : byte[] |
| StaticInitializationVector.java:96:51:96:56 | ivSpec | semmle.label | ivSpec |
subpaths

View File

@@ -10,33 +10,33 @@ public class StaticInitializationVector {
// BAD: AES-GCM with static IV from a byte array
public byte[] encryptWithStaticIvByteArrayWithInitializer(byte[] key, byte[] plaintext) throws Exception {
byte[] iv = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5 };
byte[] iv = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5 }; // $Source
GCMParameterSpec ivSpec = new GCMParameterSpec(128, iv);
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/GCM/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec); // $staticInitializationVector
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec); // $Alert
cipher.update(plaintext);
return cipher.doFinal();
}
// BAD: AES-GCM with static IV from zero-initialized byte array
public byte[] encryptWithZeroStaticIvByteArray(byte[] key, byte[] plaintext) throws Exception {
byte[] iv = new byte[16];
byte[] iv = new byte[16]; // $Source
GCMParameterSpec ivSpec = new GCMParameterSpec(128, iv);
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/GCM/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec); // $staticInitializationVector
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec); // $Alert
cipher.update(plaintext);
return cipher.doFinal();
}
// BAD: AES-CBC with static IV from zero-initialized byte array
public byte[] encryptWithStaticIvByteArray(byte[] key, byte[] plaintext) throws Exception {
byte[] iv = new byte[16];
byte[] iv = new byte[16]; // $Source
for (byte i = 0; i < iv.length; i++) {
iv[i] = 1;
}
@@ -45,7 +45,7 @@ public class StaticInitializationVector {
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec); // $staticInitializationVector
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec); // $Alert
cipher.update(plaintext);
return cipher.doFinal();
}
@@ -55,13 +55,13 @@ public class StaticInitializationVector {
byte[][] staticIvs = new byte[][] {
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5 },
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 42 }
};
}; // $Source
GCMParameterSpec ivSpec = new GCMParameterSpec(128, staticIvs[1]);
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/GCM/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec); // $staticInitializationVector
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec); // $Alert
cipher.update(plaintext);
return cipher.doFinal();
}
@@ -71,13 +71,13 @@ public class StaticInitializationVector {
byte[][] staticIvs = new byte[][] {
new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5 },
new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 42 }
};
}; // $Source
GCMParameterSpec ivSpec = new GCMParameterSpec(128, staticIvs[1]);
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/GCM/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec); // $staticInitializationVector
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec); // $Alert
cipher.update(plaintext);
return cipher.doFinal();
}
@@ -85,15 +85,15 @@ public class StaticInitializationVector {
// BAD: AES-GCM with static IV from a multidimensional byte array
public byte[] encryptWithOneOfStaticZeroIvs(byte[] key, byte[] plaintext) throws Exception {
byte[][] ivs = new byte[][] {
new byte[8],
new byte[16]
new byte[8], // $Source
new byte[16] // $Source
};
GCMParameterSpec ivSpec = new GCMParameterSpec(128, ivs[1]);
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/GCM/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec); // $staticInitializationVector
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec); // $Alert
cipher.update(plaintext);
return cipher.doFinal();
}

View File

@@ -0,0 +1,4 @@
query: Security/CWE/CWE-1204/StaticInitializationVector.ql
postprocess:
- utils/test/PrettyPrintModels.ql
- utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,18 +0,0 @@
import java
import semmle.code.java.security.StaticInitializationVectorQuery
import utils.test.InlineExpectationsTest
module StaticInitializationVectorTest implements TestSig {
string getARelevantTag() { result = "staticInitializationVector" }
predicate hasActualResult(Location location, string element, string tag, string value) {
tag = "staticInitializationVector" and
exists(DataFlow::Node sink | StaticInitializationVectorFlow::flowTo(sink) |
sink.getLocation() = location and
element = sink.toString() and
value = ""
)
}
}
import MakeTest<StaticInitializationVectorTest>

View File

@@ -14,7 +14,7 @@
| Macro calls - resolved | 2 |
| Macro calls - total | 2 |
| Macro calls - unresolved | 0 |
| Taint edges - number of edges | 1465 |
| Taint edges - number of edges | 1471 |
| Taint reach - nodes tainted | 0 |
| Taint reach - per million nodes | 0 |
| Taint sinks - cryptographic operations | 0 |

View File

@@ -14,7 +14,7 @@
| Macro calls - resolved | 2 |
| Macro calls - total | 2 |
| Macro calls - unresolved | 0 |
| Taint edges - number of edges | 1465 |
| Taint edges - number of edges | 1471 |
| Taint reach - nodes tainted | 0 |
| Taint reach - per million nodes | 0 |
| Taint sinks - cryptographic operations | 0 |

View File

@@ -14,7 +14,7 @@
| Macro calls - resolved | 2 |
| Macro calls - total | 2 |
| Macro calls - unresolved | 0 |
| Taint edges - number of edges | 1465 |
| Taint edges - number of edges | 1471 |
| Taint reach - nodes tainted | 0 |
| Taint reach - per million nodes | 0 |
| Taint sinks - cryptographic operations | 0 |

View File

@@ -6,8 +6,22 @@ extensions:
# Fmt
- ["lang:alloc", "crate::fmt::format", "Argument[0]", "ReturnValue", "taint", "manual"]
# Iterator
- ["lang:core", "<[_]>::iter", "Argument[Self].Element", "ReturnValue.Element", "value", "manual"]
- ["lang:core", "<[_]>::iter_mut", "Argument[Self].Element", "ReturnValue.Element", "value", "manual"]
- ["lang:core", "<[_]>::into_iter", "Argument[Self].Element", "ReturnValue.Element", "value", "manual"]
- ["lang:core", "crate::iter::traits::iterator::Iterator::nth", "Argument[self].Element", "ReturnValue.Field[crate::option::Option::Some(0)]", "value", "manual"]
- ["lang:core", "crate::iter::traits::iterator::Iterator::next", "Argument[self].Element", "ReturnValue.Field[crate::option::Option::Some(0)]", "value", "manual"]
- ["lang:core", "crate::iter::traits::iterator::Iterator::collect", "Argument[self].Element", "ReturnValue.Element", "value", "manual"]
- ["lang:core", "crate::iter::traits::iterator::Iterator::map", "Argument[self].Element", "Argument[0].Parameter[0]", "value", "manual"]
- ["lang:core", "crate::iter::traits::iterator::Iterator::for_each", "Argument[self].Element", "Argument[0].Parameter[0]", "value", "manual"]
- ["lang:core", "<crate::slice::iter::Iter as crate::iter::traits::iterator::Iterator>::nth", "Argument[self].Element", "ReturnValue.Field[crate::option::Option::Some(0)]", "value", "manual"]
- ["lang:core", "<crate::slice::iter::Iter as crate::iter::traits::iterator::Iterator>::next", "Argument[self].Element", "ReturnValue.Field[crate::option::Option::Some(0)]", "value", "manual"]
- ["lang:core", "<crate::slice::iter::Iter as crate::iter::traits::iterator::Iterator>::collect", "Argument[self].Element", "ReturnValue.Element", "value", "manual"]
- ["lang:core", "<crate::slice::iter::Iter as crate::iter::traits::iterator::Iterator>::map", "Argument[self].Element", "Argument[0].Parameter[0]", "value", "manual"]
- ["lang:core", "<crate::slice::iter::Iter as crate::iter::traits::iterator::Iterator>::for_each", "Argument[self].Element", "Argument[0].Parameter[0]", "value", "manual"]
# Str
- ["lang:core", "<str>::parse", "Argument[self]", "ReturnValue.Field[crate::result::Result::Ok(0)]", "taint", "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"]
- ["lang:alloc", "<_ as crate::string::ToString>::to_string", "Argument[self]", "ReturnValue", "taint", "manual"]

File diff suppressed because it is too large Load Diff

View File

@@ -187,14 +187,23 @@ edges
| main.rs:421:10:421:16 | mut_arr [element] | main.rs:421:10:421:19 | mut_arr[0] | provenance | |
| main.rs:444:9:444:9 | s | main.rs:445:10:445:10 | s | provenance | |
| main.rs:444:25:444:26 | source(...) | main.rs:444:9:444:9 | s | provenance | |
| main.rs:449:9:449:9 | a | main.rs:454:10:454:10 | a | provenance | |
| main.rs:449:13:449:22 | source(...) | main.rs:449:9:449:9 | a | provenance | |
| main.rs:451:9:451:9 | c | main.rs:452:18:452:18 | c | provenance | |
| main.rs:451:13:451:22 | source(...) | main.rs:451:9:451:9 | c | provenance | |
| main.rs:452:9:452:13 | c_ref [&ref] | main.rs:457:11:457:15 | c_ref [&ref] | provenance | |
| main.rs:452:17:452:18 | &c [&ref] | main.rs:452:9:452:13 | c_ref [&ref] | provenance | |
| main.rs:452:18:452:18 | c | main.rs:452:17:452:18 | &c [&ref] | provenance | |
| main.rs:457:11:457:15 | c_ref [&ref] | main.rs:457:10:457:15 | * ... | provenance | |
| main.rs:453:9:453:9 | a | main.rs:458:10:458:10 | a | provenance | |
| main.rs:453:13:453:22 | source(...) | main.rs:453:9:453:9 | a | provenance | |
| main.rs:465:9:465:10 | vs [element] | main.rs:467:10:467:11 | vs [element] | provenance | |
| main.rs:465:9:465:10 | vs [element] | main.rs:471:14:471:15 | vs [element] | provenance | |
| main.rs:465:14:465:34 | [...] [element] | main.rs:465:9:465:10 | vs [element] | provenance | |
| main.rs:465:15:465:24 | source(...) | main.rs:465:14:465:34 | [...] [element] | provenance | |
| main.rs:467:10:467:11 | vs [element] | main.rs:467:10:467:14 | vs[0] | provenance | |
| main.rs:471:9:471:9 | v | main.rs:472:14:472:14 | v | provenance | |
| main.rs:471:14:471:15 | vs [element] | main.rs:471:9:471:9 | v | provenance | |
| main.rs:502:9:502:9 | a | main.rs:507:10:507:10 | a | provenance | |
| main.rs:502:13:502:22 | source(...) | main.rs:502:9:502:9 | a | provenance | |
| main.rs:504:9:504:9 | c | main.rs:505:18:505:18 | c | provenance | |
| main.rs:504:13:504:22 | source(...) | main.rs:504:9:504:9 | c | provenance | |
| main.rs:505:9:505:13 | c_ref [&ref] | main.rs:510:11:510:15 | c_ref [&ref] | provenance | |
| main.rs:505:17:505:18 | &c [&ref] | main.rs:505:9:505:13 | c_ref [&ref] | provenance | |
| main.rs:505:18:505:18 | c | main.rs:505:17:505:18 | &c [&ref] | provenance | |
| main.rs:510:11:510:15 | c_ref [&ref] | main.rs:510:10:510:15 | * ... | provenance | |
nodes
| main.rs:18:10:18:18 | source(...) | semmle.label | source(...) |
| main.rs:22:9:22:9 | s | semmle.label | s |
@@ -411,16 +420,27 @@ nodes
| main.rs:444:9:444:9 | s | semmle.label | s |
| main.rs:444:25:444:26 | source(...) | semmle.label | source(...) |
| main.rs:445:10:445:10 | s | semmle.label | s |
| main.rs:449:9:449:9 | a | semmle.label | a |
| main.rs:449:13:449:22 | source(...) | semmle.label | source(...) |
| main.rs:451:9:451:9 | c | semmle.label | c |
| main.rs:451:13:451:22 | source(...) | semmle.label | source(...) |
| main.rs:452:9:452:13 | c_ref [&ref] | semmle.label | c_ref [&ref] |
| main.rs:452:17:452:18 | &c [&ref] | semmle.label | &c [&ref] |
| main.rs:452:18:452:18 | c | semmle.label | c |
| main.rs:454:10:454:10 | a | semmle.label | a |
| main.rs:457:10:457:15 | * ... | semmle.label | * ... |
| main.rs:457:11:457:15 | c_ref [&ref] | semmle.label | c_ref [&ref] |
| main.rs:453:9:453:9 | a | semmle.label | a |
| main.rs:453:13:453:22 | source(...) | semmle.label | source(...) |
| main.rs:458:10:458:10 | a | semmle.label | a |
| main.rs:465:9:465:10 | vs [element] | semmle.label | vs [element] |
| main.rs:465:14:465:34 | [...] [element] | semmle.label | [...] [element] |
| main.rs:465:15:465:24 | source(...) | semmle.label | source(...) |
| main.rs:467:10:467:11 | vs [element] | semmle.label | vs [element] |
| main.rs:467:10:467:14 | vs[0] | semmle.label | vs[0] |
| main.rs:471:9:471:9 | v | semmle.label | v |
| main.rs:471:14:471:15 | vs [element] | semmle.label | vs [element] |
| main.rs:472:14:472:14 | v | semmle.label | v |
| main.rs:502:9:502:9 | a | semmle.label | a |
| main.rs:502:13:502:22 | source(...) | semmle.label | source(...) |
| main.rs:504:9:504:9 | c | semmle.label | c |
| main.rs:504:13:504:22 | source(...) | semmle.label | source(...) |
| main.rs:505:9:505:13 | c_ref [&ref] | semmle.label | c_ref [&ref] |
| main.rs:505:17:505:18 | &c [&ref] | semmle.label | &c [&ref] |
| main.rs:505:18:505:18 | c | semmle.label | c |
| main.rs:507:10:507:10 | a | semmle.label | a |
| main.rs:510:10:510:15 | * ... | semmle.label | * ... |
| main.rs:510:11:510:15 | c_ref [&ref] | semmle.label | c_ref [&ref] |
subpaths
testFailures
#select
@@ -466,5 +486,8 @@ testFailures
| main.rs:420:10:420:10 | d | main.rs:418:18:418:27 | source(...) | main.rs:420:10:420:10 | d | $@ | main.rs:418:18:418:27 | source(...) | source(...) |
| main.rs:421:10:421:19 | mut_arr[0] | main.rs:418:18:418:27 | source(...) | main.rs:421:10:421:19 | mut_arr[0] | $@ | main.rs:418:18:418:27 | source(...) | source(...) |
| main.rs:445:10:445:10 | s | main.rs:444:25:444:26 | source(...) | main.rs:445:10:445:10 | s | $@ | main.rs:444:25:444:26 | source(...) | source(...) |
| main.rs:454:10:454:10 | a | main.rs:449:13:449:22 | source(...) | main.rs:454:10:454:10 | a | $@ | main.rs:449:13:449:22 | source(...) | source(...) |
| main.rs:457:10:457:15 | * ... | main.rs:451:13:451:22 | source(...) | main.rs:457:10:457:15 | * ... | $@ | main.rs:451:13:451:22 | source(...) | source(...) |
| main.rs:458:10:458:10 | a | main.rs:453:13:453:22 | source(...) | main.rs:458:10:458:10 | a | $@ | main.rs:453:13:453:22 | source(...) | source(...) |
| main.rs:467:10:467:14 | vs[0] | main.rs:465:15:465:24 | source(...) | main.rs:467:10:467:14 | vs[0] | $@ | main.rs:465:15:465:24 | source(...) | source(...) |
| main.rs:472:14:472:14 | v | main.rs:465:15:465:24 | source(...) | main.rs:472:14:472:14 | v | $@ | main.rs:465:15:465:24 | source(...) | source(...) |
| main.rs:507:10:507:10 | a | main.rs:502:13:502:22 | source(...) | main.rs:507:10:507:10 | a | $@ | main.rs:502:13:502:22 | source(...) | source(...) |
| main.rs:510:10:510:15 | * ... | main.rs:504:13:504:22 | source(...) | main.rs:510:10:510:15 | * ... | $@ | main.rs:504:13:504:22 | source(...) | source(...) |

View File

@@ -445,6 +445,59 @@ fn macro_invocation() {
sink(s); // $ hasValueFlow=37
}
fn sink_string(s: String) {
println!("{}", s);
}
fn parse() {
let a = source(90);
let b = a.to_string();
let c = b.parse::<i64>().unwrap();
let d : i64 = b.parse().unwrap();
sink(a); // $ hasValueFlow=90
sink_string(b); // $ hasTaintFlow=90
sink(c); // $ hasTaintFlow=90
sink(d); // $ hasTaintFlow=90
}
fn iterators() {
let vs = [source(91), 2, 3, 4];
sink(vs[0]); // $ hasValueFlow=91
sink(*vs.iter().next().unwrap()); // $ MISSING: hasValueFlow=91
sink(*vs.iter().nth(0).unwrap()); // $ MISSING: hasValueFlow=91
for v in vs {
sink(v); // $ hasValueFlow=91
}
for &v in vs.iter() {
sink(v); // $ MISSING: hasValueFlow=91
}
let vs2 : Vec<&i64> = vs.iter().collect();
for &v in vs2 {
sink(v); // $ MISSING: hasValueFlow=91
}
vs.iter().map(|x| sink(*x)); // $ MISSING: hasValueFlow=91
vs.iter().for_each(|x| sink(*x)); // $ MISSING: hasValueFlow=91
for v in vs.into_iter() {
sink(v); // $ MISSING: hasValueFlow=91
}
let mut vs_mut = [source(92), 2, 3, 4];
sink(vs_mut[0]); // $ MISSING: hasValueFlow=92
sink(*vs_mut.iter().next().unwrap()); // $ MISSING: hasValueFlow=92
sink(*vs_mut.iter().nth(0).unwrap()); // $ MISSING: hasValueFlow=92
for &mut v in vs_mut.iter_mut() {
sink(v); // $ MISSING: hasValueFlow=92
}
}
fn references() {
let a = source(40);
let b = source(41);
@@ -494,5 +547,7 @@ fn main() {
array_assignment();
captured_variable_and_continue(vec![]);
macro_invocation();
parse();
iterators();
references();
}

View File

@@ -7,18 +7,19 @@
| test.rs:29:29:29:42 | ...::args | Flow source 'CommandLineArgs' of type commandargs. |
| test.rs:32:16:32:29 | ...::args | Flow source 'CommandLineArgs' of type commandargs. |
| test.rs:33:16:33:32 | ...::args_os | Flow source 'CommandLineArgs' of type commandargs. |
| test.rs:40:16:40:29 | ...::args | Flow source 'CommandLineArgs' of type commandargs. |
| test.rs:44:16:44:32 | ...::args_os | Flow source 'CommandLineArgs' of type commandargs. |
| test.rs:50:15:50:35 | ...::current_dir | Flow source 'CommandLineArgs' of type commandargs. |
| test.rs:51:15:51:35 | ...::current_exe | Flow source 'CommandLineArgs' of type commandargs. |
| test.rs:52:16:52:33 | ...::home_dir | Flow source 'CommandLineArgs' of type commandargs. |
| test.rs:60:26:60:47 | ...::get | Flow source 'RemoteSource' of type remote (DEFAULT). |
| test.rs:63:26:63:47 | ...::get | Flow source 'RemoteSource' of type remote (DEFAULT). |
| test.rs:66:26:66:47 | ...::get | Flow source 'RemoteSource' of type remote (DEFAULT). |
| test.rs:69:26:69:47 | ...::get | Flow source 'RemoteSource' of type remote (DEFAULT). |
| test.rs:72:26:72:37 | ...::get | Flow source 'RemoteSource' of type remote (DEFAULT). |
| test.rs:75:26:75:37 | ...::get | Flow source 'RemoteSource' of type remote (DEFAULT). |
| test.rs:78:24:78:35 | ...::get | Flow source 'RemoteSource' of type remote (DEFAULT). |
| test.rs:110:35:110:46 | send_request | Flow source 'RemoteSource' of type remote (DEFAULT). |
| test.rs:117:31:117:42 | send_request | Flow source 'RemoteSource' of type remote (DEFAULT). |
| test.rs:201:16:201:29 | ...::args | Flow source 'CommandLineArgs' of type commandargs. |
| test.rs:34:16:34:29 | ...::args | Flow source 'CommandLineArgs' of type commandargs. |
| test.rs:42:16:42:29 | ...::args | Flow source 'CommandLineArgs' of type commandargs. |
| test.rs:46:16:46:32 | ...::args_os | Flow source 'CommandLineArgs' of type commandargs. |
| test.rs:52:15:52:35 | ...::current_dir | Flow source 'CommandLineArgs' of type commandargs. |
| test.rs:53:15:53:35 | ...::current_exe | Flow source 'CommandLineArgs' of type commandargs. |
| test.rs:54:16:54:33 | ...::home_dir | Flow source 'CommandLineArgs' of type commandargs. |
| test.rs:62:26:62:47 | ...::get | Flow source 'RemoteSource' of type remote (DEFAULT). |
| test.rs:65:26:65:47 | ...::get | Flow source 'RemoteSource' of type remote (DEFAULT). |
| test.rs:68:26:68:47 | ...::get | Flow source 'RemoteSource' of type remote (DEFAULT). |
| test.rs:71:26:71:47 | ...::get | Flow source 'RemoteSource' of type remote (DEFAULT). |
| test.rs:74:26:74:37 | ...::get | Flow source 'RemoteSource' of type remote (DEFAULT). |
| test.rs:77:26:77:37 | ...::get | Flow source 'RemoteSource' of type remote (DEFAULT). |
| test.rs:80:24:80:35 | ...::get | Flow source 'RemoteSource' of type remote (DEFAULT). |
| test.rs:112:35:112:46 | send_request | Flow source 'RemoteSource' of type remote (DEFAULT). |
| test.rs:119:31:119:42 | send_request | Flow source 'RemoteSource' of type remote (DEFAULT). |
| test.rs:203:16:203:29 | ...::args | Flow source 'CommandLineArgs' of type commandargs. |

View File

@@ -31,11 +31,13 @@ fn test_env_args() {
let arg1 = &args[1];
let arg2 = std::env::args().nth(2).unwrap(); // $ Alert[rust/summary/taint-sources]
let arg3 = std::env::args_os().nth(3).unwrap(); // $ Alert[rust/summary/taint-sources]
let arg4 = std::env::args().nth(4).unwrap().parse::<usize>().unwrap(); // $ Alert[rust/summary/taint-sources]
sink(my_path); // $ hasTaintFlow
sink(arg1); // $ hasTaintFlow
sink(arg2); // $ hasTaintFlow
sink(arg3); // $ hasTaintFlow
sink(arg4); // $ hasTaintFlow
for arg in std::env::args() { // $ Alert[rust/summary/taint-sources]
sink(arg); // $ hasTaintFlow

View File

@@ -1,8 +1,9 @@
models
| 1 | Summary: lang:alloc; <crate::string::String as crate::convert::From>::from; Argument[0]; ReturnValue; value |
| 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: lang:core; crate::hint::must_use; Argument[0]; ReturnValue; value |
| 1 | Summary: lang:alloc; <_ as crate::string::ToString>::to_string; Argument[self]; ReturnValue; taint |
| 2 | Summary: lang:alloc; <crate::string::String as crate::convert::From>::from; Argument[0]; ReturnValue; value |
| 3 | Summary: lang:alloc; <crate::string::String>::as_str; Argument[self]; ReturnValue; taint |
| 4 | Summary: lang:alloc; crate::fmt::format; Argument[0]; ReturnValue; taint |
| 5 | Summary: lang:core; crate::hint::must_use; Argument[0]; ReturnValue; value |
edges
| main.rs:26:9:26:9 | s | main.rs:27:19:27:25 | s[...] | provenance | |
| main.rs:26:13:26:22 | source(...) | main.rs:26:9:26:9 | s | provenance | |
@@ -16,37 +17,42 @@ edges
| main.rs:51:14:51:29 | source_slice(...) | main.rs:51:9:51:10 | s1 | provenance | |
| main.rs:52:9:52:10 | s2 | main.rs:53:10:53:11 | s2 | provenance | |
| main.rs:52:14:52:29 | ...::from(...) | main.rs:52:9:52:10 | s2 | provenance | |
| main.rs:52:27:52:28 | s1 | main.rs:52:14:52:29 | ...::from(...) | provenance | MaD:1 |
| main.rs:52:27:52:28 | s1 | main.rs:52:14:52:29 | ...::from(...) | provenance | MaD:2 |
| main.rs:57:9:57:10 | s1 | main.rs:58:14:58:15 | s1 | provenance | |
| main.rs:57:14:57:29 | source_slice(...) | main.rs:57:9:57:10 | s1 | provenance | |
| main.rs:58:9:58:10 | s2 | main.rs:59:10:59:11 | s2 | provenance | |
| main.rs:58:14:58:15 | s1 | main.rs:58:14:58:27 | s1.to_string(...) | provenance | MaD:1 |
| main.rs:58:14:58:27 | s1.to_string(...) | main.rs:58:9:58:10 | s2 | provenance | |
| main.rs:63:9:63:9 | s | main.rs:64:16:64:16 | s | provenance | |
| main.rs:63:13:63:22 | source(...) | main.rs:63:9:63:9 | s | provenance | |
| main.rs:64:16:64:16 | s | main.rs:64:16:64:25 | s.as_str(...) | provenance | MaD:2 |
| main.rs:64:16:64:16 | s | main.rs:64:16:64:25 | s.as_str(...) | provenance | MaD:3 |
| main.rs:68:9:68:9 | s | main.rs:70:34:70:61 | MacroExpr | provenance | |
| main.rs:68:9:68:9 | s | main.rs:73:34:73:59 | MacroExpr | provenance | |
| main.rs:68:13:68:22 | source(...) | main.rs:68:9:68:9 | s | provenance | |
| main.rs:70:9:70:18 | formatted1 | main.rs:71:10:71:19 | formatted1 | provenance | |
| main.rs:70:22:70:62 | ...::format(...) | main.rs:70:9:70:18 | formatted1 | provenance | |
| main.rs:70:34:70:61 | MacroExpr | main.rs:70:22:70:62 | ...::format(...) | provenance | MaD:3 |
| main.rs:70:34:70:61 | MacroExpr | main.rs:70:22:70:62 | ...::format(...) | provenance | MaD:4 |
| main.rs:73:9:73:18 | formatted2 | main.rs:74:10:74:19 | formatted2 | provenance | |
| main.rs:73:22:73:60 | ...::format(...) | main.rs:73:9:73:18 | formatted2 | provenance | |
| main.rs:73:34:73:59 | MacroExpr | main.rs:73:22:73:60 | ...::format(...) | provenance | MaD:3 |
| main.rs:73:34:73:59 | MacroExpr | main.rs:73:22:73:60 | ...::format(...) | provenance | MaD:4 |
| main.rs:76:9:76:13 | width | main.rs:77:34:77:74 | MacroExpr | provenance | |
| main.rs:76:17:76:32 | source_usize(...) | main.rs:76:9:76:13 | width | provenance | |
| main.rs:77:9:77:18 | formatted3 | main.rs:78:10:78:19 | formatted3 | provenance | |
| main.rs:77:22:77:75 | ...::format(...) | main.rs:77:9:77:18 | formatted3 | provenance | |
| main.rs:77:34:77:74 | MacroExpr | main.rs:77:22:77:75 | ...::format(...) | provenance | MaD:3 |
| main.rs:77:34:77:74 | MacroExpr | main.rs:77:22:77:75 | ...::format(...) | provenance | MaD:4 |
| main.rs:82:9:82:10 | s1 | main.rs:86:18:86:25 | MacroExpr | provenance | |
| main.rs:82:9:82:10 | s1 | main.rs:87:18:87:32 | MacroExpr | provenance | |
| main.rs:82:14:82:23 | source(...) | main.rs:82:9:82:10 | s1 | provenance | |
| main.rs:86:10:86:26 | res | main.rs:86:18:86:25 | { ... } | provenance | |
| main.rs:86:18:86:25 | ...::format(...) | main.rs:86:10:86:26 | res | provenance | |
| main.rs:86:18:86:25 | ...::must_use(...) | main.rs:86:10:86:26 | MacroExpr | provenance | |
| main.rs:86:18:86:25 | MacroExpr | main.rs:86:18:86:25 | ...::format(...) | provenance | MaD:3 |
| main.rs:86:18:86:25 | { ... } | main.rs:86:18:86:25 | ...::must_use(...) | provenance | MaD:4 |
| main.rs:86:18:86:25 | MacroExpr | main.rs:86:18:86:25 | ...::format(...) | provenance | MaD:4 |
| main.rs:86:18:86:25 | { ... } | main.rs:86:18:86:25 | ...::must_use(...) | provenance | MaD:5 |
| main.rs:87:10:87:33 | res | main.rs:87:18:87:32 | { ... } | provenance | |
| main.rs:87:18:87:32 | ...::format(...) | main.rs:87:10:87:33 | res | provenance | |
| main.rs:87:18:87:32 | ...::must_use(...) | main.rs:87:10:87:33 | MacroExpr | provenance | |
| main.rs:87:18:87:32 | MacroExpr | main.rs:87:18:87:32 | ...::format(...) | provenance | MaD:3 |
| main.rs:87:18:87:32 | { ... } | main.rs:87:18:87:32 | ...::must_use(...) | provenance | MaD:4 |
| main.rs:87:18:87:32 | MacroExpr | main.rs:87:18:87:32 | ...::format(...) | provenance | MaD:4 |
| main.rs:87:18:87:32 | { ... } | main.rs:87:18:87:32 | ...::must_use(...) | provenance | MaD:5 |
nodes
| main.rs:26:9:26:9 | s | semmle.label | s |
| main.rs:26:13:26:22 | source(...) | semmle.label | source(...) |
@@ -64,6 +70,12 @@ nodes
| main.rs:52:14:52:29 | ...::from(...) | semmle.label | ...::from(...) |
| main.rs:52:27:52:28 | s1 | semmle.label | s1 |
| main.rs:53:10:53:11 | s2 | semmle.label | s2 |
| main.rs:57:9:57:10 | s1 | semmle.label | s1 |
| main.rs:57:14:57:29 | source_slice(...) | semmle.label | source_slice(...) |
| main.rs:58:9:58:10 | s2 | semmle.label | s2 |
| main.rs:58:14:58:15 | s1 | semmle.label | s1 |
| main.rs:58:14:58:27 | s1.to_string(...) | semmle.label | s1.to_string(...) |
| main.rs:59:10:59:11 | s2 | semmle.label | s2 |
| main.rs:63:9:63:9 | s | semmle.label | s |
| main.rs:63:13:63:22 | source(...) | semmle.label | source(...) |
| main.rs:64:16:64:16 | s | semmle.label | s |
@@ -100,10 +112,12 @@ nodes
| main.rs:87:18:87:32 | { ... } | semmle.label | { ... } |
subpaths
testFailures
| main.rs:59:10:59:11 | s2 | Fixed missing result: hasTaintFlow=22 |
#select
| main.rs:28:16:28:21 | sliced | main.rs:26:13:26:22 | source(...) | main.rs:28:16:28:21 | sliced | $@ | main.rs:26:13:26:22 | source(...) | source(...) |
| main.rs:38:10:38:11 | s4 | main.rs:32:14:32:23 | source(...) | main.rs:38:10:38:11 | s4 | $@ | main.rs:32:14:32:23 | source(...) | source(...) |
| main.rs:53:10:53:11 | s2 | main.rs:51:14:51:29 | source_slice(...) | main.rs:53:10:53:11 | s2 | $@ | main.rs:51:14:51:29 | source_slice(...) | source_slice(...) |
| main.rs:59:10:59:11 | s2 | main.rs:57:14:57:29 | source_slice(...) | main.rs:59:10:59:11 | s2 | $@ | main.rs:57:14:57:29 | source_slice(...) | source_slice(...) |
| main.rs:64:16:64:25 | s.as_str(...) | main.rs:63:13:63:22 | source(...) | main.rs:64:16:64:25 | s.as_str(...) | $@ | main.rs:63:13:63:22 | source(...) | source(...) |
| main.rs:71:10:71:19 | formatted1 | main.rs:68:13:68:22 | source(...) | main.rs:71:10:71:19 | formatted1 | $@ | main.rs:68:13:68:22 | source(...) | source(...) |
| main.rs:74:10:74:19 | formatted2 | main.rs:68:13:68:22 | source(...) | main.rs:74:10:74:19 | formatted2 | $@ | main.rs:68:13:68:22 | source(...) | source(...) |

View File

@@ -24,6 +24,6 @@
| PostUpdateNode should not be the target of local flow | 0 |
| PostUpdateNode should not equal its pre-update node | 0 |
| Read step does not preserve enclosing callable | 0 |
| Speculative step already hasM Model | 0 |
| Speculative step already has Model | 0 |
| Store step does not preserve enclosing callable | 0 |
| Type compatibility predicate is not reflexive | 0 |

View File

@@ -14,7 +14,7 @@
| Macro calls - resolved | 8 |
| Macro calls - total | 9 |
| Macro calls - unresolved | 1 |
| Taint edges - number of edges | 1465 |
| Taint edges - number of edges | 1471 |
| Taint reach - nodes tainted | 0 |
| Taint reach - per million nodes | 0 |
| Taint sinks - cryptographic operations | 0 |

View File

@@ -1,21 +1,37 @@
#select
| sqlx.rs:62:26:62:46 | safe_query_3.as_str(...) | sqlx.rs:48:25:48:46 | ...::get | sqlx.rs:62:26:62:46 | safe_query_3.as_str(...) | This query depends on a $@. | sqlx.rs:48:25:48:46 | ...::get | user-provided value |
| sqlx.rs:67:30:67:52 | unsafe_query_4.as_str(...) | sqlx.rs:48:25:48:46 | ...::get | sqlx.rs:67:30:67:52 | unsafe_query_4.as_str(...) | This query depends on a $@. | sqlx.rs:48:25:48:46 | ...::get | user-provided value |
| sqlx.rs:73:25:73:45 | safe_query_3.as_str(...) | sqlx.rs:48:25:48:46 | ...::get | sqlx.rs:73:25:73:45 | safe_query_3.as_str(...) | This query depends on a $@. | sqlx.rs:48:25:48:46 | ...::get | user-provided value |
| sqlx.rs:78:29:78:51 | unsafe_query_4.as_str(...) | sqlx.rs:48:25:48:46 | ...::get | sqlx.rs:78:29:78:51 | unsafe_query_4.as_str(...) | This query depends on a $@. | sqlx.rs:48:25:48:46 | ...::get | user-provided value |
edges
| sqlx.rs:48:9:48:21 | remote_string | sqlx.rs:49:25:49:37 | remote_string | provenance | |
| sqlx.rs:48:9:48:21 | remote_string | sqlx.rs:56:34:56:89 | MacroExpr | provenance | |
| sqlx.rs:48:25:48:46 | ...::get | sqlx.rs:48:25:48:69 | ...::get(...) [Ok] | provenance | Src:MaD:1 |
| sqlx.rs:48:25:48:69 | ...::get(...) [Ok] | sqlx.rs:48:25:48:78 | ... .unwrap(...) | provenance | MaD:4 |
| sqlx.rs:48:25:48:78 | ... .unwrap(...) | sqlx.rs:48:25:48:85 | ... .text(...) [Ok] | provenance | MaD:7 |
| sqlx.rs:48:25:48:78 | ... .unwrap(...) | sqlx.rs:48:25:48:85 | ... .text(...) [Ok] | provenance | MaD:8 |
| sqlx.rs:48:25:48:85 | ... .text(...) [Ok] | sqlx.rs:48:25:48:118 | ... .unwrap_or(...) | provenance | MaD:5 |
| sqlx.rs:48:25:48:118 | ... .unwrap_or(...) | sqlx.rs:48:9:48:21 | remote_string | provenance | |
| sqlx.rs:49:9:49:21 | remote_number | sqlx.rs:52:32:52:87 | MacroExpr | provenance | |
| sqlx.rs:49:25:49:37 | remote_string | sqlx.rs:49:25:49:52 | remote_string.parse(...) [Ok] | provenance | MaD:6 |
| sqlx.rs:49:25:49:52 | remote_string.parse(...) [Ok] | sqlx.rs:49:25:49:65 | ... .unwrap_or(...) | provenance | MaD:5 |
| sqlx.rs:49:25:49:65 | ... .unwrap_or(...) | sqlx.rs:49:9:49:21 | remote_number | provenance | |
| sqlx.rs:52:9:52:20 | safe_query_3 | sqlx.rs:62:26:62:37 | safe_query_3 | provenance | |
| sqlx.rs:52:9:52:20 | safe_query_3 | sqlx.rs:73:25:73:36 | safe_query_3 | provenance | |
| sqlx.rs:52:24:52:88 | res | sqlx.rs:52:32:52:87 | { ... } | provenance | |
| sqlx.rs:52:32:52:87 | ...::format(...) | sqlx.rs:52:24:52:88 | res | provenance | |
| sqlx.rs:52:32:52:87 | ...::must_use(...) | sqlx.rs:52:9:52:20 | safe_query_3 | provenance | |
| sqlx.rs:52:32:52:87 | MacroExpr | sqlx.rs:52:32:52:87 | ...::format(...) | provenance | MaD:3 |
| sqlx.rs:52:32:52:87 | { ... } | sqlx.rs:52:32:52:87 | ...::must_use(...) | provenance | MaD:7 |
| sqlx.rs:56:9:56:22 | unsafe_query_4 | sqlx.rs:67:30:67:43 | unsafe_query_4 | provenance | |
| sqlx.rs:56:9:56:22 | unsafe_query_4 | sqlx.rs:78:29:78:42 | unsafe_query_4 | provenance | |
| sqlx.rs:56:26:56:90 | res | sqlx.rs:56:34:56:89 | { ... } | provenance | |
| sqlx.rs:56:34:56:89 | ...::format(...) | sqlx.rs:56:26:56:90 | res | provenance | |
| sqlx.rs:56:34:56:89 | ...::must_use(...) | sqlx.rs:56:9:56:22 | unsafe_query_4 | provenance | |
| sqlx.rs:56:34:56:89 | MacroExpr | sqlx.rs:56:34:56:89 | ...::format(...) | provenance | MaD:3 |
| sqlx.rs:56:34:56:89 | { ... } | sqlx.rs:56:34:56:89 | ...::must_use(...) | provenance | MaD:6 |
| sqlx.rs:56:34:56:89 | { ... } | sqlx.rs:56:34:56:89 | ...::must_use(...) | provenance | MaD:7 |
| sqlx.rs:62:26:62:37 | safe_query_3 | sqlx.rs:62:26:62:46 | safe_query_3.as_str(...) | provenance | MaD:2 |
| sqlx.rs:67:30:67:43 | unsafe_query_4 | sqlx.rs:67:30:67:52 | unsafe_query_4.as_str(...) | provenance | MaD:2 |
| sqlx.rs:73:25:73:36 | safe_query_3 | sqlx.rs:73:25:73:45 | safe_query_3.as_str(...) | provenance | MaD:2 |
| sqlx.rs:78:29:78:42 | unsafe_query_4 | sqlx.rs:78:29:78:51 | unsafe_query_4.as_str(...) | provenance | MaD:2 |
models
| 1 | Source: repo:https://github.com/seanmonstar/reqwest:reqwest; crate::blocking::get; remote; ReturnValue.Field[crate::result::Result::Ok(0)] |
@@ -23,8 +39,9 @@ models
| 3 | Summary: lang:alloc; crate::fmt::format; Argument[0]; ReturnValue; taint |
| 4 | Summary: lang:core; <crate::result::Result>::unwrap; Argument[self].Field[crate::result::Result::Ok(0)]; ReturnValue; value |
| 5 | Summary: lang:core; <crate::result::Result>::unwrap_or; Argument[self].Field[crate::result::Result::Ok(0)]; ReturnValue; value |
| 6 | Summary: lang:core; crate::hint::must_use; Argument[0]; ReturnValue; value |
| 7 | Summary: repo:https://github.com/seanmonstar/reqwest:reqwest; <crate::blocking::response::Response>::text; Argument[self]; ReturnValue.Field[crate::result::Result::Ok(0)]; taint |
| 6 | Summary: lang:core; <str>::parse; Argument[self]; ReturnValue.Field[crate::result::Result::Ok(0)]; taint |
| 7 | Summary: lang:core; crate::hint::must_use; Argument[0]; ReturnValue; value |
| 8 | Summary: repo:https://github.com/seanmonstar/reqwest:reqwest; <crate::blocking::response::Response>::text; Argument[self]; ReturnValue.Field[crate::result::Result::Ok(0)]; taint |
nodes
| sqlx.rs:48:9:48:21 | remote_string | semmle.label | remote_string |
| sqlx.rs:48:25:48:46 | ...::get | semmle.label | ...::get |
@@ -32,14 +49,28 @@ nodes
| sqlx.rs:48:25:48:78 | ... .unwrap(...) | semmle.label | ... .unwrap(...) |
| sqlx.rs:48:25:48:85 | ... .text(...) [Ok] | semmle.label | ... .text(...) [Ok] |
| sqlx.rs:48:25:48:118 | ... .unwrap_or(...) | semmle.label | ... .unwrap_or(...) |
| sqlx.rs:49:9:49:21 | remote_number | semmle.label | remote_number |
| sqlx.rs:49:25:49:37 | remote_string | semmle.label | remote_string |
| sqlx.rs:49:25:49:52 | remote_string.parse(...) [Ok] | semmle.label | remote_string.parse(...) [Ok] |
| sqlx.rs:49:25:49:65 | ... .unwrap_or(...) | semmle.label | ... .unwrap_or(...) |
| sqlx.rs:52:9:52:20 | safe_query_3 | semmle.label | safe_query_3 |
| sqlx.rs:52:24:52:88 | res | semmle.label | res |
| sqlx.rs:52:32:52:87 | ...::format(...) | semmle.label | ...::format(...) |
| sqlx.rs:52:32:52:87 | ...::must_use(...) | semmle.label | ...::must_use(...) |
| sqlx.rs:52:32:52:87 | MacroExpr | semmle.label | MacroExpr |
| sqlx.rs:52:32:52:87 | { ... } | semmle.label | { ... } |
| sqlx.rs:56:9:56:22 | unsafe_query_4 | semmle.label | unsafe_query_4 |
| sqlx.rs:56:26:56:90 | res | semmle.label | res |
| sqlx.rs:56:34:56:89 | ...::format(...) | semmle.label | ...::format(...) |
| sqlx.rs:56:34:56:89 | ...::must_use(...) | semmle.label | ...::must_use(...) |
| sqlx.rs:56:34:56:89 | MacroExpr | semmle.label | MacroExpr |
| sqlx.rs:56:34:56:89 | { ... } | semmle.label | { ... } |
| sqlx.rs:62:26:62:37 | safe_query_3 | semmle.label | safe_query_3 |
| sqlx.rs:62:26:62:46 | safe_query_3.as_str(...) | semmle.label | safe_query_3.as_str(...) |
| sqlx.rs:67:30:67:43 | unsafe_query_4 | semmle.label | unsafe_query_4 |
| sqlx.rs:67:30:67:52 | unsafe_query_4.as_str(...) | semmle.label | unsafe_query_4.as_str(...) |
| sqlx.rs:73:25:73:36 | safe_query_3 | semmle.label | safe_query_3 |
| sqlx.rs:73:25:73:45 | safe_query_3.as_str(...) | semmle.label | safe_query_3.as_str(...) |
| sqlx.rs:78:29:78:42 | unsafe_query_4 | semmle.label | unsafe_query_4 |
| sqlx.rs:78:29:78:51 | unsafe_query_4.as_str(...) | semmle.label | unsafe_query_4.as_str(...) |
subpaths

View File

@@ -59,7 +59,7 @@ async fn test_sqlx_mysql(url: &str, enable_remote: bool) -> Result<(), sqlx::Err
// direct execution
let _ = conn.execute(safe_query_1.as_str()).await?; // $ sql-sink
let _ = conn.execute(safe_query_2.as_str()).await?; // $ sql-sink
let _ = conn.execute(safe_query_3.as_str()).await?; // $ sql-sink
let _ = conn.execute(safe_query_3.as_str()).await?; // $ sql-sink SPURIOUS: Alert[rust/sql-injection]=remote1
let _ = conn.execute(unsafe_query_1.as_str()).await?; // $ sql-sink MISSING: Alert[rust/sql-injection]=args1
if enable_remote {
let _ = conn.execute(unsafe_query_2.as_str()).await?; // $ sql-sink MISSING: Alert[rust/sql-injection]=remote1
@@ -70,7 +70,7 @@ async fn test_sqlx_mysql(url: &str, enable_remote: bool) -> Result<(), sqlx::Err
// prepared queries
let _ = sqlx::query(safe_query_1.as_str()).execute(&pool).await?; // $ sql-sink
let _ = sqlx::query(safe_query_2.as_str()).execute(&pool).await?; // $ sql-sink
let _ = sqlx::query(safe_query_3.as_str()).execute(&pool).await?; // $ sql-sink
let _ = sqlx::query(safe_query_3.as_str()).execute(&pool).await?; // $ sql-sink SPURIOUS: Alert[rust/sql-injection]=remote1
let _ = sqlx::query(unsafe_query_1.as_str()).execute(&pool).await?; // $ sql-sink MISSING: Alert[rust/sql-injection][rust/sql-injection]=args1
if enable_remote {
let _ = sqlx::query(unsafe_query_2.as_str()).execute(&pool).await?; // $ sql-sink MISSING: Alert[rust/sql-injection]=remote1

View File

@@ -441,7 +441,7 @@ module MakeConsistency<
result =
count(DataFlowCall call, Node receiver | lambdaCallEnclosingCallableMismatch(call, receiver))
or
type = "Speculative step already hasM Model" and
type = "Speculative step already has Model" and
result = count(Node n1, Node n2 | speculativeStepAlreadyHasModel(n1, n2, _))
}
}