mirror of
https://github.com/github/codeql.git
synced 2026-04-25 08:45:14 +02:00
Merge branch 'main' into rust-core-std-models
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 {
|
||||
|
||||
4
csharp/ql/src/change-notes/2025-02-24-object-tostring.md
Normal file
4
csharp/ql/src/change-notes/2025-02-24-object-tostring.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* C#: Improve precision of the query `cs/call-to-object-tostring` for value tuples.
|
||||
@@ -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
|
||||
|
||||
@@ -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[] |
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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, _) }
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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.
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
query: Security/CWE/CWE-1204/StaticInitializationVector.ql
|
||||
postprocess:
|
||||
- utils/test/PrettyPrintModels.ql
|
||||
- utils/test/InlineExpectationsTestQuery.ql
|
||||
@@ -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>
|
||||
@@ -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 |
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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
@@ -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(...) |
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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. |
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(...) |
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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, _))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user