mirror of
https://github.com/github/codeql.git
synced 2026-04-25 16:55:19 +02:00
Merge branch 'main' into redsun82/swift-imported-modules-as-set
This commit is contained in:
1
.github/workflows/ruby-qltest.yml
vendored
1
.github/workflows/ruby-qltest.yml
vendored
@@ -4,6 +4,7 @@ on:
|
||||
push:
|
||||
paths:
|
||||
- "ruby/**"
|
||||
- "shared/**"
|
||||
- .github/workflows/ruby-build.yml
|
||||
- .github/actions/fetch-codeql/action.yml
|
||||
- codeql-workspace.yml
|
||||
|
||||
4
cpp/ql/lib/change-notes/2023-03-30-bufferaccess.md
Normal file
4
cpp/ql/lib/change-notes/2023-03-30-bufferaccess.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* Added overridable predicates `getSizeExpr` and `getSizeMult` to the `BufferAccess` class (`semmle.code.cpp.security.BufferAccess.qll`). This makes it possible to model a larger class of buffer reads and writes using the library.
|
||||
@@ -12,12 +12,92 @@ private import semmle.code.cpp.ir.ValueNumbering
|
||||
module SemanticExprConfig {
|
||||
class Location = Cpp::Location;
|
||||
|
||||
class Expr = IR::Instruction;
|
||||
/** A `ConvertInstruction` or a `CopyValueInstruction`. */
|
||||
private class Conversion extends IR::UnaryInstruction {
|
||||
Conversion() {
|
||||
this instanceof IR::CopyValueInstruction
|
||||
or
|
||||
this instanceof IR::ConvertInstruction
|
||||
}
|
||||
|
||||
/** Holds if this instruction converts a value of type `tFrom` to a value of type `tTo`. */
|
||||
predicate converts(SemType tFrom, SemType tTo) {
|
||||
tFrom = getSemanticType(this.getUnary().getResultIRType()) and
|
||||
tTo = getSemanticType(this.getResultIRType())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a conversion-like instruction that consumes `op`, and
|
||||
* which is guaranteed to not overflow.
|
||||
*/
|
||||
private IR::Instruction safeConversion(IR::Operand op) {
|
||||
exists(Conversion conv, SemType tFrom, SemType tTo |
|
||||
conv.converts(tFrom, tTo) and
|
||||
conversionCannotOverflow(tFrom, tTo) and
|
||||
conv.getUnaryOperand() = op and
|
||||
result = conv
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `i1 = i2` or if `i2` is a safe conversion that consumes `i1`. */
|
||||
private predicate idOrSafeConversion(IR::Instruction i1, IR::Instruction i2) {
|
||||
not i1.getResultIRType() instanceof IR::IRVoidType and
|
||||
(
|
||||
i1 = i2
|
||||
or
|
||||
i2 = safeConversion(i1.getAUse()) and
|
||||
i1.getBlock() = i2.getBlock()
|
||||
)
|
||||
}
|
||||
|
||||
module Equiv = QlBuiltins::EquivalenceRelation<IR::Instruction, idOrSafeConversion/2>;
|
||||
|
||||
/**
|
||||
* The expressions on which we perform range analysis.
|
||||
*/
|
||||
class Expr extends Equiv::EquivalenceClass {
|
||||
/** Gets the n'th instruction in this equivalence class. */
|
||||
private IR::Instruction getInstruction(int n) {
|
||||
result =
|
||||
rank[n + 1](IR::Instruction instr, int i, IR::IRBlock block |
|
||||
this = Equiv::getEquivalenceClass(instr) and block.getInstruction(i) = instr
|
||||
|
|
||||
instr order by i
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = this.getUnconverted().toString() }
|
||||
|
||||
/** Gets the basic block of this expression. */
|
||||
IR::IRBlock getBlock() { result = this.getUnconverted().getBlock() }
|
||||
|
||||
/** Gets the unconverted instruction associated with this expression. */
|
||||
IR::Instruction getUnconverted() { result = this.getInstruction(0) }
|
||||
|
||||
/**
|
||||
* Gets the final instruction associated with this expression. This
|
||||
* represents the result after applying all the safe conversions.
|
||||
*/
|
||||
IR::Instruction getConverted() {
|
||||
exists(int n |
|
||||
result = this.getInstruction(n) and
|
||||
not exists(this.getInstruction(n + 1))
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the type of the result produced by this instruction. */
|
||||
IR::IRType getResultIRType() { result = this.getConverted().getResultIRType() }
|
||||
|
||||
/** Gets the location of the source code for this expression. */
|
||||
Location getLocation() { result = this.getUnconverted().getLocation() }
|
||||
}
|
||||
|
||||
SemBasicBlock getExprBasicBlock(Expr e) { result = getSemanticBasicBlock(e.getBlock()) }
|
||||
|
||||
private predicate anyConstantExpr(Expr expr, SemType type, string value) {
|
||||
exists(IR::ConstantInstruction instr | instr = expr |
|
||||
exists(IR::ConstantInstruction instr | getSemanticExpr(instr) = expr |
|
||||
type = getSemanticType(instr.getResultIRType()) and
|
||||
value = instr.getValue()
|
||||
)
|
||||
@@ -58,41 +138,46 @@ module SemanticExprConfig {
|
||||
predicate nullLiteral(Expr expr, SemAddressType type) { anyConstantExpr(expr, type, _) }
|
||||
|
||||
predicate stringLiteral(Expr expr, SemType type, string value) {
|
||||
anyConstantExpr(expr, type, value) and expr instanceof IR::StringConstantInstruction
|
||||
anyConstantExpr(expr, type, value) and
|
||||
expr.getUnconverted() instanceof IR::StringConstantInstruction
|
||||
}
|
||||
|
||||
predicate binaryExpr(Expr expr, Opcode opcode, SemType type, Expr leftOperand, Expr rightOperand) {
|
||||
exists(IR::BinaryInstruction instr | instr = expr |
|
||||
exists(IR::BinaryInstruction instr |
|
||||
instr = expr.getUnconverted() and
|
||||
type = getSemanticType(instr.getResultIRType()) and
|
||||
leftOperand = instr.getLeft() and
|
||||
rightOperand = instr.getRight() and
|
||||
leftOperand = getSemanticExpr(instr.getLeft()) and
|
||||
rightOperand = getSemanticExpr(instr.getRight()) and
|
||||
// REVIEW: Merge the two `Opcode` types.
|
||||
opcode.toString() = instr.getOpcode().toString()
|
||||
)
|
||||
}
|
||||
|
||||
predicate unaryExpr(Expr expr, Opcode opcode, SemType type, Expr operand) {
|
||||
type = getSemanticType(expr.getResultIRType()) and
|
||||
(
|
||||
exists(IR::UnaryInstruction instr | instr = expr |
|
||||
operand = instr.getUnary() and
|
||||
// REVIEW: Merge the two operand types.
|
||||
opcode.toString() = instr.getOpcode().toString()
|
||||
)
|
||||
or
|
||||
exists(IR::StoreInstruction instr | instr = expr |
|
||||
operand = instr.getSourceValue() and
|
||||
opcode instanceof Opcode::Store
|
||||
)
|
||||
exists(IR::UnaryInstruction instr | instr = expr.getUnconverted() |
|
||||
type = getSemanticType(instr.getResultIRType()) and
|
||||
operand = getSemanticExpr(instr.getUnary()) and
|
||||
// REVIEW: Merge the two operand types.
|
||||
opcode.toString() = instr.getOpcode().toString()
|
||||
)
|
||||
or
|
||||
exists(IR::StoreInstruction instr | instr = expr.getUnconverted() |
|
||||
type = getSemanticType(instr.getResultIRType()) and
|
||||
operand = getSemanticExpr(instr.getSourceValue()) and
|
||||
opcode instanceof Opcode::Store
|
||||
)
|
||||
}
|
||||
|
||||
predicate nullaryExpr(Expr expr, Opcode opcode, SemType type) {
|
||||
type = getSemanticType(expr.getResultIRType()) and
|
||||
(
|
||||
expr instanceof IR::LoadInstruction and opcode instanceof Opcode::Load
|
||||
or
|
||||
expr instanceof IR::InitializeParameterInstruction and
|
||||
exists(IR::LoadInstruction load |
|
||||
load = expr.getUnconverted() and
|
||||
type = getSemanticType(load.getResultIRType()) and
|
||||
opcode instanceof Opcode::Load
|
||||
)
|
||||
or
|
||||
exists(IR::InitializeParameterInstruction init |
|
||||
init = expr.getUnconverted() and
|
||||
type = getSemanticType(init.getResultIRType()) and
|
||||
opcode instanceof Opcode::InitializeParameter
|
||||
)
|
||||
}
|
||||
@@ -122,8 +207,10 @@ module SemanticExprConfig {
|
||||
newtype TSsaVariable =
|
||||
TSsaInstruction(IR::Instruction instr) { instr.hasMemoryResult() } or
|
||||
TSsaOperand(IR::Operand op) { op.isDefinitionInexact() } or
|
||||
TSsaPointerArithmeticGuard(IR::PointerArithmeticInstruction instr) {
|
||||
exists(Guard g, IR::Operand use | use = instr.getAUse() |
|
||||
TSsaPointerArithmeticGuard(ValueNumber instr) {
|
||||
exists(Guard g, IR::Operand use |
|
||||
use = instr.getAUse() and use.getIRType() instanceof IR::IRAddressType
|
||||
|
|
||||
g.comparesLt(use, _, _, _, _) or
|
||||
g.comparesLt(_, use, _, _, _) or
|
||||
g.comparesEq(use, _, _, _, _) or
|
||||
@@ -138,7 +225,7 @@ module SemanticExprConfig {
|
||||
|
||||
IR::Instruction asInstruction() { none() }
|
||||
|
||||
IR::PointerArithmeticInstruction asPointerArithGuard() { none() }
|
||||
ValueNumber asPointerArithGuard() { none() }
|
||||
|
||||
IR::Operand asOperand() { none() }
|
||||
}
|
||||
@@ -156,15 +243,15 @@ module SemanticExprConfig {
|
||||
}
|
||||
|
||||
class SsaPointerArithmeticGuard extends SsaVariable, TSsaPointerArithmeticGuard {
|
||||
IR::PointerArithmeticInstruction instr;
|
||||
ValueNumber vn;
|
||||
|
||||
SsaPointerArithmeticGuard() { this = TSsaPointerArithmeticGuard(instr) }
|
||||
SsaPointerArithmeticGuard() { this = TSsaPointerArithmeticGuard(vn) }
|
||||
|
||||
final override string toString() { result = instr.toString() }
|
||||
final override string toString() { result = vn.toString() }
|
||||
|
||||
final override Location getLocation() { result = instr.getLocation() }
|
||||
final override Location getLocation() { result = vn.getLocation() }
|
||||
|
||||
final override IR::PointerArithmeticInstruction asPointerArithGuard() { result = instr }
|
||||
final override ValueNumber asPointerArithGuard() { result = vn }
|
||||
}
|
||||
|
||||
class SsaOperand extends SsaVariable, TSsaOperand {
|
||||
@@ -179,7 +266,9 @@ module SemanticExprConfig {
|
||||
final override IR::Operand asOperand() { result = op }
|
||||
}
|
||||
|
||||
predicate explicitUpdate(SsaVariable v, Expr sourceExpr) { v.asInstruction() = sourceExpr }
|
||||
predicate explicitUpdate(SsaVariable v, Expr sourceExpr) {
|
||||
getSemanticExpr(v.asInstruction()) = sourceExpr
|
||||
}
|
||||
|
||||
predicate phi(SsaVariable v) { v.asInstruction() instanceof IR::PhiInstruction }
|
||||
|
||||
@@ -192,9 +281,9 @@ module SemanticExprConfig {
|
||||
}
|
||||
|
||||
Expr getAUse(SsaVariable v) {
|
||||
result.(IR::LoadInstruction).getSourceValue() = v.asInstruction()
|
||||
result.getUnconverted().(IR::LoadInstruction).getSourceValue() = v.asInstruction()
|
||||
or
|
||||
result = valueNumber(v.asPointerArithGuard()).getAnInstruction()
|
||||
result.getUnconverted() = v.asPointerArithGuard().getAnInstruction()
|
||||
}
|
||||
|
||||
SemType getSsaVariableType(SsaVariable v) {
|
||||
@@ -236,7 +325,7 @@ module SemanticExprConfig {
|
||||
final override predicate hasRead(SsaVariable v) {
|
||||
exists(IR::Operand operand |
|
||||
operand.getDef() = v.asInstruction() or
|
||||
operand.getDef() = valueNumber(v.asPointerArithGuard()).getAnInstruction()
|
||||
operand.getDef() = v.asPointerArithGuard().getAnInstruction()
|
||||
|
|
||||
not operand instanceof IR::PhiInputOperand and
|
||||
operand.getUse().getBlock() = block
|
||||
@@ -257,7 +346,7 @@ module SemanticExprConfig {
|
||||
final override predicate hasRead(SsaVariable v) {
|
||||
exists(IR::PhiInputOperand operand |
|
||||
operand.getDef() = v.asInstruction() or
|
||||
operand.getDef() = valueNumber(v.asPointerArithGuard()).getAnInstruction()
|
||||
operand.getDef() = v.asPointerArithGuard().getAnInstruction()
|
||||
|
|
||||
operand.getPredecessorBlock() = pred and
|
||||
operand.getUse().getBlock() = succ
|
||||
@@ -303,17 +392,21 @@ module SemanticExprConfig {
|
||||
}
|
||||
|
||||
Expr getBoundExpr(Bound bound, int delta) {
|
||||
result = bound.(IRBound::Bound).getInstruction(delta)
|
||||
result = getSemanticExpr(bound.(IRBound::Bound).getInstruction(delta))
|
||||
}
|
||||
|
||||
class Guard = IRGuards::IRGuardCondition;
|
||||
|
||||
predicate guard(Guard guard, BasicBlock block) { block = guard.getBlock() }
|
||||
|
||||
Expr getGuardAsExpr(Guard guard) { result = guard }
|
||||
Expr getGuardAsExpr(Guard guard) { result = getSemanticExpr(guard) }
|
||||
|
||||
predicate equalityGuard(Guard guard, Expr e1, Expr e2, boolean polarity) {
|
||||
guard.comparesEq(e1.getAUse(), e2.getAUse(), 0, true, polarity)
|
||||
exists(IR::Instruction left, IR::Instruction right |
|
||||
getSemanticExpr(left) = e1 and
|
||||
getSemanticExpr(right) = e2 and
|
||||
guard.comparesEq(left.getAUse(), right.getAUse(), 0, true, polarity)
|
||||
)
|
||||
}
|
||||
|
||||
predicate guardDirectlyControlsBlock(Guard guard, BasicBlock controlled, boolean branch) {
|
||||
@@ -324,16 +417,17 @@ module SemanticExprConfig {
|
||||
guard.controlsEdge(bb1, bb2, branch)
|
||||
}
|
||||
|
||||
Guard comparisonGuard(Expr e) { result = e }
|
||||
Guard comparisonGuard(Expr e) { getSemanticExpr(result) = e }
|
||||
|
||||
predicate implies_v2(Guard g1, boolean b1, Guard g2, boolean b2) {
|
||||
none() // TODO
|
||||
}
|
||||
|
||||
/** Gets the expression associated with `instr`. */
|
||||
SemExpr getSemanticExpr(IR::Instruction instr) { result = Equiv::getEquivalenceClass(instr) }
|
||||
}
|
||||
|
||||
SemExpr getSemanticExpr(IR::Instruction instr) { result = instr }
|
||||
|
||||
IR::Instruction getCppInstruction(SemExpr e) { e = result }
|
||||
predicate getSemanticExpr = SemanticExprConfig::getSemanticExpr/1;
|
||||
|
||||
SemBasicBlock getSemanticBasicBlock(IR::IRBlock block) { result = block }
|
||||
|
||||
|
||||
@@ -16,14 +16,5 @@ module FloatDelta implements DeltaSig {
|
||||
Delta fromInt(int n) { result = n }
|
||||
|
||||
bindingset[f]
|
||||
Delta fromFloat(float f) {
|
||||
result =
|
||||
min(float diff, float res |
|
||||
diff = (res - f) and res = f.ceil()
|
||||
or
|
||||
diff = (f - res) and res = f.floor()
|
||||
|
|
||||
res order by diff
|
||||
)
|
||||
}
|
||||
Delta fromFloat(float f) { result = f }
|
||||
}
|
||||
|
||||
@@ -495,7 +495,7 @@ module RangeStage<DeltaSig D, BoundSig<D> Bounds, LangSig<D> LangParam, UtilSig<
|
||||
SemSsaVariable v2, SemGuard guardEq, boolean eqIsTrue, D::Delta d1, D::Delta d2,
|
||||
D::Delta oldDelta
|
||||
|
|
||||
guardEq = semEqFlowCond(v, semSsaRead(v2, d1), d2, true, eqIsTrue) and
|
||||
guardEq = semEqFlowCond(v, semSsaRead(pragma[only_bind_into](v2), d1), d2, true, eqIsTrue) and
|
||||
result = boundFlowCond(v2, e, oldDelta, upper, testIsTrue) and
|
||||
// guardEq needs to control guard
|
||||
guardEq.directlyControls(result.getBasicBlock(), eqIsTrue) and
|
||||
@@ -1041,20 +1041,21 @@ module RangeStage<DeltaSig D, BoundSig<D> Bounds, LangSig<D> LangParam, UtilSig<
|
||||
)
|
||||
or
|
||||
exists(
|
||||
SemRemExpr rem, SemZeroBound b1, SemZeroBound b2, D::Delta d_max, D::Delta d1, D::Delta d2,
|
||||
boolean fbe1, boolean fbe2, D::Delta od1, D::Delta od2, SemReason r1, SemReason r2
|
||||
SemRemExpr rem, D::Delta d_max, D::Delta d1, D::Delta d2, boolean fbe1, boolean fbe2,
|
||||
D::Delta od1, D::Delta od2, SemReason r1, SemReason r2
|
||||
|
|
||||
rem = e and
|
||||
b instanceof SemZeroBound and
|
||||
not (upper = true and semPositive(rem.getRightOperand())) and
|
||||
not (upper = true and semPositive(rem.getLeftOperand())) and
|
||||
boundedRemExpr(rem, b1, true, d1, fbe1, od1, r1) and
|
||||
boundedRemExpr(rem, b2, false, d2, fbe2, od2, r2) and
|
||||
boundedRemExpr(rem, true, d1, fbe1, od1, r1) and
|
||||
boundedRemExpr(rem, false, d2, fbe2, od2, r2) and
|
||||
(
|
||||
if D::toFloat(d1).abs() > D::toFloat(d2).abs()
|
||||
then (
|
||||
b = b1 and d_max = d1 and fromBackEdge = fbe1 and origdelta = od1 and reason = r1
|
||||
d_max = d1 and fromBackEdge = fbe1 and origdelta = od1 and reason = r1
|
||||
) else (
|
||||
b = b2 and d_max = d2 and fromBackEdge = fbe2 and origdelta = od2 and reason = r2
|
||||
d_max = d2 and fromBackEdge = fbe2 and origdelta = od2 and reason = r2
|
||||
)
|
||||
)
|
||||
|
|
||||
@@ -1103,11 +1104,13 @@ module RangeStage<DeltaSig D, BoundSig<D> Bounds, LangSig<D> LangParam, UtilSig<
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate boundedRemExpr(
|
||||
SemRemExpr rem, SemZeroBound b, boolean upper, D::Delta delta, boolean fromBackEdge,
|
||||
D::Delta origdelta, SemReason reason
|
||||
SemRemExpr rem, boolean upper, D::Delta delta, boolean fromBackEdge, D::Delta origdelta,
|
||||
SemReason reason
|
||||
) {
|
||||
bounded(rem.getRightOperand(), b, delta, upper, fromBackEdge, origdelta, reason)
|
||||
bounded(rem.getRightOperand(), any(SemZeroBound zb), delta, upper, fromBackEdge, origdelta,
|
||||
reason)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -198,6 +198,16 @@ module SignAnalysis<DeltaSig D, UtilSig<D> Utils> {
|
||||
}
|
||||
}
|
||||
|
||||
/** An expression of an unsigned type. */
|
||||
private class UnsignedExpr extends FlowSignExpr {
|
||||
UnsignedExpr() { Utils::getTrackedType(this) instanceof SemUnsignedIntegerType }
|
||||
|
||||
override Sign getSignRestriction() {
|
||||
result = TPos() or
|
||||
result = TZero()
|
||||
}
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate binaryExprOperands(SemBinaryExpr binary, SemExpr left, SemExpr right) {
|
||||
binary.getLeftOperand() = left and binary.getRightOperand() = right
|
||||
@@ -328,10 +338,11 @@ module SignAnalysis<DeltaSig D, UtilSig<D> Utils> {
|
||||
* - `isEq = false` : `v != eqbound`
|
||||
*/
|
||||
private predicate eqBound(SemExpr eqbound, SemSsaVariable v, SemSsaReadPosition pos, boolean isEq) {
|
||||
exists(SemGuard guard, boolean testIsTrue, boolean polarity |
|
||||
pos.hasReadOfVar(v) and
|
||||
semGuardControlsSsaRead(guard, pos, testIsTrue) and
|
||||
guard.isEquality(eqbound, Utils::semSsaRead(v, D::fromInt(0)), polarity) and
|
||||
exists(SemGuard guard, boolean testIsTrue, boolean polarity, SemExpr e |
|
||||
pos.hasReadOfVar(pragma[only_bind_into](v)) and
|
||||
semGuardControlsSsaRead(guard, pragma[only_bind_into](pos), testIsTrue) and
|
||||
e = Utils::semSsaRead(pragma[only_bind_into](v), D::fromInt(0)) and
|
||||
guard.isEquality(eqbound, e, polarity) and
|
||||
isEq = polarity.booleanXor(testIsTrue).booleanNot() and
|
||||
not unknownSign(eqbound)
|
||||
)
|
||||
|
||||
@@ -1105,3 +1105,49 @@ class TranslatedAsmStmt extends TranslatedStmt {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TranslatedVlaDimensionStmt extends TranslatedStmt {
|
||||
override VlaDimensionStmt stmt;
|
||||
|
||||
override TranslatedExpr getChild(int id) {
|
||||
id = 0 and
|
||||
result = getTranslatedExpr(stmt.getDimensionExpr().getFullyConverted())
|
||||
}
|
||||
|
||||
override Instruction getFirstInstruction() { result = this.getChild(0).getFirstInstruction() }
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
none()
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
child = this.getChild(0) and
|
||||
result = this.getParent().getChildSuccessor(this)
|
||||
}
|
||||
}
|
||||
|
||||
class TranslatedVlaDeclarationStmt extends TranslatedStmt {
|
||||
override VlaDeclStmt stmt;
|
||||
|
||||
override TranslatedExpr getChild(int id) { none() }
|
||||
|
||||
override Instruction getFirstInstruction() { result = this.getInstruction(OnlyInstructionTag()) }
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
// TODO: This needs a new kind of instruction that represents initialization of a VLA.
|
||||
// For now we just emit a `NoOp` instruction so that the CFG isn't incomplete.
|
||||
tag = OnlyInstructionTag() and
|
||||
opcode instanceof Opcode::NoOp and
|
||||
resultType = getVoidType()
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
tag = OnlyInstructionTag() and
|
||||
result = this.getParent().getChildSuccessor(this) and
|
||||
kind instanceof GotoEdge
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) { none() }
|
||||
}
|
||||
|
||||
@@ -29,7 +29,23 @@ abstract class BufferAccess extends Expr {
|
||||
*/
|
||||
abstract Expr getBuffer(string bufferDesc, int accessType);
|
||||
|
||||
abstract int getSize();
|
||||
/**
|
||||
* Gets the expression that represents the size of the buffer access. The
|
||||
* actual size is typically the value of this expression multiplied by the
|
||||
* result of `getSizeMult()`, in bytes.
|
||||
*/
|
||||
Expr getSizeExpr() { none() }
|
||||
|
||||
/**
|
||||
* Gets a constant multiplier for the buffer access size given by
|
||||
* `getSizeExpr`, in bytes.
|
||||
*/
|
||||
int getSizeMult() { none() }
|
||||
|
||||
/**
|
||||
* Gets the buffer access size in bytes.
|
||||
*/
|
||||
int getSize() { result = this.getSizeExpr().getValue().toInt() * this.getSizeMult() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,10 +79,10 @@ class MemcpyBA extends BufferAccess {
|
||||
accessType = 1
|
||||
}
|
||||
|
||||
override int getSize() {
|
||||
result =
|
||||
this.(FunctionCall).getArgument(2).getValue().toInt() *
|
||||
getPointedSize(this.(FunctionCall).getTarget().getParameter(0).getType())
|
||||
override Expr getSizeExpr() { result = this.(FunctionCall).getArgument(2) }
|
||||
|
||||
override int getSizeMult() {
|
||||
result = getPointedSize(this.(FunctionCall).getTarget().getParameter(0).getType())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,10 +105,10 @@ class BCopyBA extends BufferAccess {
|
||||
accessType = 1
|
||||
}
|
||||
|
||||
override int getSize() {
|
||||
result =
|
||||
this.(FunctionCall).getArgument(2).getValue().toInt() *
|
||||
getPointedSize(this.(FunctionCall).getTarget().getParameter(0).getType())
|
||||
override Expr getSizeExpr() { result = this.(FunctionCall).getArgument(2) }
|
||||
|
||||
override int getSizeMult() {
|
||||
result = getPointedSize(this.(FunctionCall).getTarget().getParameter(0).getType())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,10 +131,10 @@ class StrncpyBA extends BufferAccess {
|
||||
accessType = 2
|
||||
}
|
||||
|
||||
override int getSize() {
|
||||
result =
|
||||
this.(FunctionCall).getArgument(2).getValue().toInt() *
|
||||
getPointedSize(this.(FunctionCall).getTarget().getParameter(0).getType())
|
||||
override Expr getSizeExpr() { result = this.(FunctionCall).getArgument(2) }
|
||||
|
||||
override int getSizeMult() {
|
||||
result = getPointedSize(this.(FunctionCall).getTarget().getParameter(0).getType())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,10 +157,10 @@ class MemccpyBA extends BufferAccess {
|
||||
accessType = 2
|
||||
}
|
||||
|
||||
override int getSize() {
|
||||
result =
|
||||
this.(FunctionCall).getArgument(3).getValue().toInt() *
|
||||
getPointedSize(this.(FunctionCall).getTarget().getParameter(0).getType())
|
||||
override Expr getSizeExpr() { result = this.(FunctionCall).getArgument(3) }
|
||||
|
||||
override int getSizeMult() {
|
||||
result = getPointedSize(this.(FunctionCall).getTarget().getParameter(0).getType())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,10 +188,10 @@ class MemcmpBA extends BufferAccess {
|
||||
accessType = 2
|
||||
}
|
||||
|
||||
override int getSize() {
|
||||
result =
|
||||
this.(FunctionCall).getArgument(2).getValue().toInt() *
|
||||
getPointedSize(this.(FunctionCall).getTarget().getParameter(0).getType())
|
||||
override Expr getSizeExpr() { result = this.(FunctionCall).getArgument(2) }
|
||||
|
||||
override int getSizeMult() {
|
||||
result = getPointedSize(this.(FunctionCall).getTarget().getParameter(0).getType())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,10 +215,10 @@ class SwabBA extends BufferAccess {
|
||||
accessType = 1
|
||||
}
|
||||
|
||||
override int getSize() {
|
||||
result =
|
||||
this.(FunctionCall).getArgument(2).getValue().toInt() *
|
||||
getPointedSize(this.(FunctionCall).getTarget().getParameter(0).getType())
|
||||
override Expr getSizeExpr() { result = this.(FunctionCall).getArgument(2) }
|
||||
|
||||
override int getSizeMult() {
|
||||
result = getPointedSize(this.(FunctionCall).getTarget().getParameter(0).getType())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,10 +238,10 @@ class MemsetBA extends BufferAccess {
|
||||
accessType = 1
|
||||
}
|
||||
|
||||
override int getSize() {
|
||||
result =
|
||||
this.(FunctionCall).getArgument(2).getValue().toInt() *
|
||||
getPointedSize(this.(FunctionCall).getTarget().getParameter(0).getType())
|
||||
override Expr getSizeExpr() { result = this.(FunctionCall).getArgument(2) }
|
||||
|
||||
override int getSizeMult() {
|
||||
result = getPointedSize(this.(FunctionCall).getTarget().getParameter(0).getType())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,7 +260,9 @@ class ZeroMemoryBA extends BufferAccess {
|
||||
accessType = 1
|
||||
}
|
||||
|
||||
override int getSize() { result = this.(FunctionCall).getArgument(1).getValue().toInt() }
|
||||
override Expr getSizeExpr() { result = this.(FunctionCall).getArgument(1) }
|
||||
|
||||
override int getSizeMult() { result = 1 }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -263,10 +281,10 @@ class MemchrBA extends BufferAccess {
|
||||
accessType = 2
|
||||
}
|
||||
|
||||
override int getSize() {
|
||||
result =
|
||||
this.(FunctionCall).getArgument(2).getValue().toInt() *
|
||||
getPointedSize(this.(FunctionCall).getTarget().getParameter(0).getType())
|
||||
override Expr getSizeExpr() { result = this.(FunctionCall).getArgument(2) }
|
||||
|
||||
override int getSizeMult() {
|
||||
result = getPointedSize(this.(FunctionCall).getTarget().getParameter(0).getType())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -285,11 +303,9 @@ class FreadBA extends BufferAccess {
|
||||
accessType = 2
|
||||
}
|
||||
|
||||
override int getSize() {
|
||||
result =
|
||||
this.(FunctionCall).getArgument(1).getValue().toInt() *
|
||||
this.(FunctionCall).getArgument(2).getValue().toInt()
|
||||
}
|
||||
override Expr getSizeExpr() { result = this.(FunctionCall).getArgument(1) }
|
||||
|
||||
override int getSizeMult() { result = this.(FunctionCall).getArgument(2).getValue().toInt() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -318,11 +334,13 @@ class ArrayExprBA extends BufferAccess {
|
||||
accessType = 3
|
||||
}
|
||||
|
||||
override Expr getSizeExpr() { result = this.(ArrayExpr).getArrayOffset() }
|
||||
|
||||
override int getSize() {
|
||||
// byte size of the buffer that would be required to support this
|
||||
// access
|
||||
result =
|
||||
(1 + this.(ArrayExpr).getArrayOffset().getValue().toInt()) *
|
||||
this.(ArrayExpr).getType().getSize()
|
||||
result = (1 + this.getSizeExpr().getValue().toInt()) * this.getSizeMult()
|
||||
}
|
||||
|
||||
override int getSizeMult() { result = this.(ArrayExpr).getType().getSize() }
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ import DataFlow::PathGraph
|
||||
|
||||
pragma[nomagic]
|
||||
Instruction getABoundIn(SemBound b, IRFunction func) {
|
||||
result = b.getExpr(0) and
|
||||
getSemanticExpr(result) = b.getExpr(0) and
|
||||
result.getEnclosingIRFunction() = func
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ class StringSizeConfiguration extends ProductFlow::Configuration {
|
||||
state1 = s1.toString() and
|
||||
state2 = s2.toString() and
|
||||
add.hasOperands(node1.asOperand(), op) and
|
||||
semBounded(op.getDef(), any(SemZeroBound zero), delta, true, _) and
|
||||
semBounded(getSemanticExpr(op.getDef()), any(SemZeroBound zero), delta, true, _) and
|
||||
node2.asInstruction() = add and
|
||||
s1 = s2 + delta
|
||||
)
|
||||
|
||||
@@ -19,7 +19,7 @@ import PointerArithmeticToDerefFlow::PathGraph
|
||||
|
||||
pragma[nomagic]
|
||||
Instruction getABoundIn(SemBound b, IRFunction func) {
|
||||
result = b.getExpr(0) and
|
||||
getSemanticExpr(result) = b.getExpr(0) and
|
||||
result.getEnclosingIRFunction() = func
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ import semmle.code.cpp.ir.IR
|
||||
|
||||
pragma[nomagic]
|
||||
Instruction getABoundIn(SemBound b, IRFunction func) {
|
||||
result = b.getExpr(0) and
|
||||
getSemanticExpr(result) = b.getExpr(0) and
|
||||
result.getEnclosingIRFunction() = func
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import experimental.semmle.code.cpp.semantic.analysis.RangeUtils
|
||||
import experimental.semmle.code.cpp.semantic.analysis.FloatDelta
|
||||
import experimental.semmle.code.cpp.semantic.analysis.RangeAnalysisSpecific
|
||||
import experimental.semmle.code.cpp.semantic.analysis.RangeAnalysisImpl
|
||||
import experimental.semmle.code.cpp.semantic.SemanticExprSpecific
|
||||
import semmle.code.cpp.ir.IR as IR
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
@@ -18,7 +19,7 @@ class ModulusAnalysisTest extends InlineExpectationsTest {
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(SemExpr e, IR::CallInstruction call |
|
||||
call.getArgument(0) = e and
|
||||
getSemanticExpr(call.getArgument(0)) = e and
|
||||
call.getStaticCallTarget().hasName("mod") and
|
||||
tag = "mod" and
|
||||
element = e.toString() and
|
||||
|
||||
@@ -12,7 +12,7 @@ class RangeAnalysisTest extends InlineExpectationsTest {
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(SemExpr e, IR::CallInstruction call |
|
||||
call.getArgument(0) = e and
|
||||
getSemanticExpr(call.getArgument(0)) = e and
|
||||
call.getStaticCallTarget().hasName("range") and
|
||||
tag = "range" and
|
||||
element = e.toString() and
|
||||
@@ -29,7 +29,7 @@ private string getDirectionString(boolean d) {
|
||||
}
|
||||
|
||||
bindingset[value]
|
||||
private string getOffsetString(int value) {
|
||||
private string getOffsetString(float value) {
|
||||
if value >= 0 then result = "+" + value.toString() else result = value.toString()
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ bindingset[s]
|
||||
string quote(string s) { if s.matches("% %") then result = "\"" + s + "\"" else result = s }
|
||||
|
||||
bindingset[delta]
|
||||
private string getBoundString(SemBound b, int delta) {
|
||||
private string getBoundString(SemBound b, float delta) {
|
||||
b instanceof SemZeroBound and result = delta.toString()
|
||||
or
|
||||
result =
|
||||
@@ -51,7 +51,7 @@ private string getBoundString(SemBound b, int delta) {
|
||||
}
|
||||
|
||||
private string getARangeString(SemExpr e) {
|
||||
exists(SemBound b, int delta, boolean upper |
|
||||
exists(SemBound b, float delta, boolean upper |
|
||||
semBounded(e, b, delta, upper, _) and
|
||||
if semBounded(e, b, delta, upper.booleanNot(), _)
|
||||
then delta != 0 and result = "==" + getBoundString(b, delta)
|
||||
|
||||
@@ -18,7 +18,7 @@ int test2(struct List* p) {
|
||||
int count = 0;
|
||||
for (; p; p = p->next) {
|
||||
count = (count+1) % 10;
|
||||
range(count); // $ range=>=-9 range=<=9
|
||||
range(count); // $ range=<=9 range=>=-9 range=<=count:p+1
|
||||
}
|
||||
range(count); // $ range=>=-9 range=<=9
|
||||
return count;
|
||||
@@ -29,7 +29,7 @@ int test3(struct List* p) {
|
||||
for (; p; p = p->next) {
|
||||
range(count++); // $ range=>=-9 range=<=9
|
||||
count = count % 10;
|
||||
range(count); // $ range=>=-9 range=<=9
|
||||
range(count); // $ range=<=9 range=>=-9 range="<=... +++0" range=<=count:p+1
|
||||
}
|
||||
range(count); // $ range=>=-9 range=<=9
|
||||
return count;
|
||||
@@ -149,7 +149,7 @@ int test11(char *p) {
|
||||
range(*p);
|
||||
}
|
||||
if (c == ':') {
|
||||
range(c);
|
||||
range(c); // $ range===58
|
||||
c = *p;
|
||||
range(*p);
|
||||
if (c != '\0') {
|
||||
@@ -318,7 +318,7 @@ int test_mult01(int a, int b) {
|
||||
int r = a*b; // -143 .. 253
|
||||
range(r);
|
||||
total += r;
|
||||
range(total);
|
||||
range(total); // $ MISSING: range=">=... * ...+0"
|
||||
}
|
||||
if (3 <= a && a <= 11 && -13 <= b && b <= 0) {
|
||||
range(a); // $ range=<=11 range=>=3
|
||||
@@ -366,7 +366,7 @@ int test_mult02(int a, int b) {
|
||||
int r = a*b; // -143 .. 253
|
||||
range(r);
|
||||
total += r;
|
||||
range(total);
|
||||
range(total); // $ MISSING: range=">=... * ...+0"
|
||||
}
|
||||
if (0 <= a && a <= 11 && -13 <= b && b <= 0) {
|
||||
range(a); // $ range=<=11 range=>=0
|
||||
@@ -461,7 +461,7 @@ int test_mult04(int a, int b) {
|
||||
int r = a*b; // -391 .. 221
|
||||
range(r);
|
||||
total += r;
|
||||
range(total);
|
||||
range(total); // $ MISSING: range="<=... * ...+0"
|
||||
}
|
||||
if (-17 <= a && a <= 0 && -13 <= b && b <= 0) {
|
||||
range(a); // $ range=<=0 range=>=-17
|
||||
@@ -509,7 +509,7 @@ int test_mult05(int a, int b) {
|
||||
int r = a*b; // -391 .. 221
|
||||
range(r);
|
||||
total += r;
|
||||
range(total);
|
||||
range(total); // $ MISSING: range="<=... * ...+0"
|
||||
}
|
||||
if (-17 <= a && a <= -2 && -13 <= b && b <= 0) {
|
||||
range(a); // $ range=<=-2 range=>=-17
|
||||
@@ -741,7 +741,7 @@ unsigned long mult_rounding() {
|
||||
range(y); // $ range===1000000003
|
||||
range(x); // $ range===1000000003
|
||||
xy = x * y;
|
||||
range(xy); // $ range===2147483647
|
||||
range(xy); // $ range===1000000006000000000
|
||||
return xy; // BUG: upper bound should be >= 1000000006000000009UL
|
||||
}
|
||||
|
||||
@@ -856,18 +856,18 @@ int notequal_type_endpoint(unsigned n) {
|
||||
|
||||
void notequal_refinement(short n) {
|
||||
if (n < 0) {
|
||||
range(n);
|
||||
range(n); // $ range=<=-1
|
||||
return;
|
||||
}
|
||||
|
||||
if (n == 0) {
|
||||
range(n); // 0 .. 0
|
||||
} else {
|
||||
range(n); // 1 ..
|
||||
range(n); // $ range=>=1
|
||||
}
|
||||
|
||||
if (n) {
|
||||
range(n); // 1 ..
|
||||
range(n); // $ range=>=1
|
||||
} else {
|
||||
range(n); // 0 .. 0
|
||||
}
|
||||
@@ -883,16 +883,16 @@ void notequal_refinement(short n) {
|
||||
void notequal_variations(short n, float f) {
|
||||
if (n != 0) {
|
||||
if (n >= 0) {
|
||||
range(n); // 1 .. [BUG: we can't handle `!=` coming first]
|
||||
range(n); // $ range=>=1
|
||||
}
|
||||
}
|
||||
|
||||
if (n >= 5) {
|
||||
if (2 * n - 10 == 0) { // Same as `n == 10/2` (modulo overflow)
|
||||
range(n);
|
||||
range(n); // $ range=>=5 MISSING: range===5
|
||||
return;
|
||||
}
|
||||
range(n); // 6 ..
|
||||
range(n); // $ range=>=5 MISSING: range=>=6
|
||||
}
|
||||
|
||||
if (n != -32768 && n != -32767) {
|
||||
@@ -900,8 +900,12 @@ void notequal_variations(short n, float f) {
|
||||
}
|
||||
|
||||
if (n >= 0) {
|
||||
n ? (range(n), n) : (range(n), n); // ? 1.. : 0..0
|
||||
!n ? (range(n), n) : (range(n), n); // ? 0..0 : 1..
|
||||
n ?
|
||||
(range(n), n) // $ range=>=1
|
||||
: (range(n), n); // $ MISSING: range===0
|
||||
!n ?
|
||||
(range(n), n) // $ MISSING: range===0
|
||||
: (range(n), n); // $ range=>=1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -917,7 +921,7 @@ void two_bounds_from_one_test(short ss, unsigned short us) {
|
||||
}
|
||||
|
||||
if (ss < 0x8001) { // Lower bound removed in `getDefLowerBounds`
|
||||
range(ss); // -32768 .. 32767
|
||||
range(ss); // $ range=<=32768 MISSING: range=>=-32768
|
||||
}
|
||||
|
||||
if ((short)us >= 0) {
|
||||
@@ -970,7 +974,7 @@ void test_mod_neg(int s) {
|
||||
|
||||
void test_mod_ternary(int s, bool b) {
|
||||
int s2 = s % (b ? 5 : 500);
|
||||
range(s2); // $ range=>=-499 range=<=499
|
||||
range(s2); // $ range=>=-499 range=<=499 range="<=... ? ... : ...-1"
|
||||
}
|
||||
|
||||
void test_mod_ternary2(int s, bool b1, bool b2) {
|
||||
|
||||
@@ -4,6 +4,7 @@ import experimental.semmle.code.cpp.semantic.Semantic
|
||||
import experimental.semmle.code.cpp.semantic.analysis.RangeUtils
|
||||
import experimental.semmle.code.cpp.semantic.analysis.FloatDelta
|
||||
import experimental.semmle.code.cpp.semantic.analysis.RangeAnalysisSpecific
|
||||
import experimental.semmle.code.cpp.semantic.SemanticExprSpecific
|
||||
import semmle.code.cpp.ir.IR as IR
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
@@ -16,7 +17,7 @@ class SignAnalysisTest extends InlineExpectationsTest {
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(SemExpr e, IR::CallInstruction call |
|
||||
call.getArgument(0) = e and
|
||||
getSemanticExpr(call.getArgument(0)) = e and
|
||||
call.getStaticCallTarget().hasName("sign") and
|
||||
tag = "sign" and
|
||||
element = e.toString() and
|
||||
|
||||
@@ -1814,3 +1814,81 @@ ssa.cpp:
|
||||
|
||||
# 383| Block 5
|
||||
# 383| v383_17(void) = Unreached :
|
||||
|
||||
# 401| void vla(int, int, int, bool)
|
||||
# 401| Block 0
|
||||
# 401| v401_1(void) = EnterFunction :
|
||||
# 401| m401_2(unknown) = AliasedDefinition :
|
||||
# 401| m401_3(unknown) = InitializeNonLocal :
|
||||
# 401| m401_4(unknown) = Chi : total:m401_2, partial:m401_3
|
||||
# 401| r401_5(glval<int>) = VariableAddress[n1] :
|
||||
# 401| m401_6(int) = InitializeParameter[n1] : &:r401_5
|
||||
# 401| r401_7(glval<int>) = VariableAddress[n2] :
|
||||
# 401| m401_8(int) = InitializeParameter[n2] : &:r401_7
|
||||
# 401| r401_9(glval<int>) = VariableAddress[n3] :
|
||||
# 401| m401_10(int) = InitializeParameter[n3] : &:r401_9
|
||||
# 401| r401_11(glval<bool>) = VariableAddress[b1] :
|
||||
# 401| m401_12(bool) = InitializeParameter[b1] : &:r401_11
|
||||
# 402| r402_1(glval<int[]>) = VariableAddress[b] :
|
||||
# 402| m402_2(int[]) = Uninitialized[b] : &:r402_1
|
||||
# 402| r402_3(glval<int>) = VariableAddress[n1] :
|
||||
# 402| r402_4(int) = Load[n1] : &:r402_3, m401_6
|
||||
# 402| v402_5(void) = NoOp :
|
||||
# 403| r403_1(glval<int[][]>) = VariableAddress[c] :
|
||||
# 403| m403_2(int[][]) = Uninitialized[c] : &:r403_1
|
||||
# 403| m403_3(unknown) = Chi : total:m401_4, partial:m403_2
|
||||
# 403| r403_4(glval<int>) = VariableAddress[n1] :
|
||||
# 403| r403_5(int) = Load[n1] : &:r403_4, m401_6
|
||||
# 403| r403_6(glval<int>) = VariableAddress[n2] :
|
||||
# 403| r403_7(int) = Load[n2] : &:r403_6, m401_8
|
||||
# 403| v403_8(void) = NoOp :
|
||||
# 405| r405_1(int) = Constant[0] :
|
||||
# 405| r405_2(glval<int[]>) = VariableAddress[b] :
|
||||
# 405| r405_3(int *) = Convert : r405_2
|
||||
# 405| r405_4(glval<int>) = CopyValue : r405_3
|
||||
# 405| m405_5(int) = Store[?] : &:r405_4, r405_1
|
||||
# 405| m405_6(int[]) = Chi : total:m402_2, partial:m405_5
|
||||
# 406| r406_1(int) = Constant[1] :
|
||||
# 406| r406_2(glval<int[]>) = VariableAddress[b] :
|
||||
# 406| r406_3(int *) = Convert : r406_2
|
||||
# 406| r406_4(int) = Constant[0] :
|
||||
# 406| r406_5(glval<int>) = PointerAdd[4] : r406_3, r406_4
|
||||
# 406| m406_6(int) = Store[?] : &:r406_5, r406_1
|
||||
# 406| m406_7(int[]) = Chi : total:m405_6, partial:m406_6
|
||||
# 408| r408_1(int) = Constant[0] :
|
||||
# 408| r408_2(glval<int[][]>) = VariableAddress[c] :
|
||||
# 408| r408_3(int(*)[]) = Convert : r408_2
|
||||
# 408| r408_4(int) = Constant[1] :
|
||||
# 408| r408_5(int(*)[]) = PointerAdd : r408_3, r408_4
|
||||
# 408| r408_6(glval<int[]>) = CopyValue : r408_5
|
||||
# 408| r408_7(int *) = Convert : r408_6
|
||||
# 408| r408_8(glval<int>) = CopyValue : r408_7
|
||||
# 408| m408_9(int) = Store[?] : &:r408_8, r408_1
|
||||
# 408| m408_10(unknown) = Chi : total:m403_3, partial:m408_9
|
||||
# 410| r410_1(glval<bool>) = VariableAddress[b1] :
|
||||
# 410| r410_2(bool) = Load[b1] : &:r410_1, m401_12
|
||||
# 410| v410_3(void) = ConditionalBranch : r410_2
|
||||
#-----| False -> Block 2
|
||||
#-----| True -> Block 1
|
||||
|
||||
# 411| Block 1
|
||||
# 411| r411_1(glval<int[]>) = VariableAddress[b] :
|
||||
# 411| m411_2(int[]) = Uninitialized[b] : &:r411_1
|
||||
# 411| r411_3(glval<int>) = VariableAddress[n1] :
|
||||
# 411| r411_4(int) = Load[n1] : &:r411_3, m401_6
|
||||
# 411| v411_5(void) = NoOp :
|
||||
#-----| Goto -> Block 3
|
||||
|
||||
# 413| Block 2
|
||||
# 413| r413_1(glval<int[]>) = VariableAddress[b] :
|
||||
# 413| m413_2(int[]) = Uninitialized[b] : &:r413_1
|
||||
# 413| r413_3(glval<int>) = VariableAddress[n2] :
|
||||
# 413| r413_4(int) = Load[n2] : &:r413_3, m401_8
|
||||
# 413| v413_5(void) = NoOp :
|
||||
#-----| Goto -> Block 3
|
||||
|
||||
# 415| Block 3
|
||||
# 415| v415_1(void) = NoOp :
|
||||
# 401| v401_13(void) = ReturnVoid :
|
||||
# 401| v401_14(void) = AliasedUse : ~m408_10
|
||||
# 401| v401_15(void) = ExitFunction :
|
||||
|
||||
@@ -1804,3 +1804,80 @@ ssa.cpp:
|
||||
|
||||
# 383| Block 5
|
||||
# 383| v383_17(void) = Unreached :
|
||||
|
||||
# 401| void vla(int, int, int, bool)
|
||||
# 401| Block 0
|
||||
# 401| v401_1(void) = EnterFunction :
|
||||
# 401| m401_2(unknown) = AliasedDefinition :
|
||||
# 401| m401_3(unknown) = InitializeNonLocal :
|
||||
# 401| m401_4(unknown) = Chi : total:m401_2, partial:m401_3
|
||||
# 401| r401_5(glval<int>) = VariableAddress[n1] :
|
||||
# 401| m401_6(int) = InitializeParameter[n1] : &:r401_5
|
||||
# 401| r401_7(glval<int>) = VariableAddress[n2] :
|
||||
# 401| m401_8(int) = InitializeParameter[n2] : &:r401_7
|
||||
# 401| r401_9(glval<int>) = VariableAddress[n3] :
|
||||
# 401| m401_10(int) = InitializeParameter[n3] : &:r401_9
|
||||
# 401| r401_11(glval<bool>) = VariableAddress[b1] :
|
||||
# 401| m401_12(bool) = InitializeParameter[b1] : &:r401_11
|
||||
# 402| r402_1(glval<int[]>) = VariableAddress[b] :
|
||||
# 402| m402_2(int[]) = Uninitialized[b] : &:r402_1
|
||||
# 402| r402_3(glval<int>) = VariableAddress[n1] :
|
||||
# 402| r402_4(int) = Load[n1] : &:r402_3, m401_6
|
||||
# 402| v402_5(void) = NoOp :
|
||||
# 403| r403_1(glval<int[][]>) = VariableAddress[c] :
|
||||
# 403| m403_2(int[][]) = Uninitialized[c] : &:r403_1
|
||||
# 403| r403_3(glval<int>) = VariableAddress[n1] :
|
||||
# 403| r403_4(int) = Load[n1] : &:r403_3, m401_6
|
||||
# 403| r403_5(glval<int>) = VariableAddress[n2] :
|
||||
# 403| r403_6(int) = Load[n2] : &:r403_5, m401_8
|
||||
# 403| v403_7(void) = NoOp :
|
||||
# 405| r405_1(int) = Constant[0] :
|
||||
# 405| r405_2(glval<int[]>) = VariableAddress[b] :
|
||||
# 405| r405_3(int *) = Convert : r405_2
|
||||
# 405| r405_4(glval<int>) = CopyValue : r405_3
|
||||
# 405| m405_5(int) = Store[?] : &:r405_4, r405_1
|
||||
# 405| m405_6(int[]) = Chi : total:m402_2, partial:m405_5
|
||||
# 406| r406_1(int) = Constant[1] :
|
||||
# 406| r406_2(glval<int[]>) = VariableAddress[b] :
|
||||
# 406| r406_3(int *) = Convert : r406_2
|
||||
# 406| r406_4(int) = Constant[0] :
|
||||
# 406| r406_5(glval<int>) = PointerAdd[4] : r406_3, r406_4
|
||||
# 406| m406_6(int) = Store[?] : &:r406_5, r406_1
|
||||
# 406| m406_7(int[]) = Chi : total:m405_6, partial:m406_6
|
||||
# 408| r408_1(int) = Constant[0] :
|
||||
# 408| r408_2(glval<int[][]>) = VariableAddress[c] :
|
||||
# 408| r408_3(int(*)[]) = Convert : r408_2
|
||||
# 408| r408_4(int) = Constant[1] :
|
||||
# 408| r408_5(int(*)[]) = PointerAdd : r408_3, r408_4
|
||||
# 408| r408_6(glval<int[]>) = CopyValue : r408_5
|
||||
# 408| r408_7(int *) = Convert : r408_6
|
||||
# 408| r408_8(glval<int>) = CopyValue : r408_7
|
||||
# 408| m408_9(int) = Store[?] : &:r408_8, r408_1
|
||||
# 408| m408_10(unknown) = Chi : total:m401_4, partial:m408_9
|
||||
# 410| r410_1(glval<bool>) = VariableAddress[b1] :
|
||||
# 410| r410_2(bool) = Load[b1] : &:r410_1, m401_12
|
||||
# 410| v410_3(void) = ConditionalBranch : r410_2
|
||||
#-----| False -> Block 2
|
||||
#-----| True -> Block 1
|
||||
|
||||
# 411| Block 1
|
||||
# 411| r411_1(glval<int[]>) = VariableAddress[b] :
|
||||
# 411| m411_2(int[]) = Uninitialized[b] : &:r411_1
|
||||
# 411| r411_3(glval<int>) = VariableAddress[n1] :
|
||||
# 411| r411_4(int) = Load[n1] : &:r411_3, m401_6
|
||||
# 411| v411_5(void) = NoOp :
|
||||
#-----| Goto -> Block 3
|
||||
|
||||
# 413| Block 2
|
||||
# 413| r413_1(glval<int[]>) = VariableAddress[b] :
|
||||
# 413| m413_2(int[]) = Uninitialized[b] : &:r413_1
|
||||
# 413| r413_3(glval<int>) = VariableAddress[n2] :
|
||||
# 413| r413_4(int) = Load[n2] : &:r413_3, m401_8
|
||||
# 413| v413_5(void) = NoOp :
|
||||
#-----| Goto -> Block 3
|
||||
|
||||
# 415| Block 3
|
||||
# 415| v415_1(void) = NoOp :
|
||||
# 401| v401_13(void) = ReturnVoid :
|
||||
# 401| v401_14(void) = AliasedUse : ~m408_10
|
||||
# 401| v401_15(void) = ExitFunction :
|
||||
|
||||
@@ -396,4 +396,20 @@ int FusedBlockPhiOperand(int x, int y, int z, bool b1) {
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void vla(int n1, int n2, int n3, bool b1) {
|
||||
int b[n1];
|
||||
int c[n1][n2];
|
||||
|
||||
*b = 0;
|
||||
b[0] = 1;
|
||||
|
||||
**(c + 1) = 0;
|
||||
|
||||
if(b1) {
|
||||
int b[n1];
|
||||
} else {
|
||||
int b[n2];
|
||||
}
|
||||
}
|
||||
@@ -1695,3 +1695,76 @@ ssa.cpp:
|
||||
# 383| v383_13(void) = ReturnValue : &:r383_12, m398_5
|
||||
# 383| v383_14(void) = AliasedUse : ~m?
|
||||
# 383| v383_15(void) = ExitFunction :
|
||||
|
||||
# 401| void vla(int, int, int, bool)
|
||||
# 401| Block 0
|
||||
# 401| v401_1(void) = EnterFunction :
|
||||
# 401| mu401_2(unknown) = AliasedDefinition :
|
||||
# 401| mu401_3(unknown) = InitializeNonLocal :
|
||||
# 401| r401_4(glval<int>) = VariableAddress[n1] :
|
||||
# 401| m401_5(int) = InitializeParameter[n1] : &:r401_4
|
||||
# 401| r401_6(glval<int>) = VariableAddress[n2] :
|
||||
# 401| m401_7(int) = InitializeParameter[n2] : &:r401_6
|
||||
# 401| r401_8(glval<int>) = VariableAddress[n3] :
|
||||
# 401| m401_9(int) = InitializeParameter[n3] : &:r401_8
|
||||
# 401| r401_10(glval<bool>) = VariableAddress[b1] :
|
||||
# 401| m401_11(bool) = InitializeParameter[b1] : &:r401_10
|
||||
# 402| r402_1(glval<int[]>) = VariableAddress[b] :
|
||||
# 402| mu402_2(int[]) = Uninitialized[b] : &:r402_1
|
||||
# 402| r402_3(glval<int>) = VariableAddress[n1] :
|
||||
# 402| r402_4(int) = Load[n1] : &:r402_3, m401_5
|
||||
# 402| v402_5(void) = NoOp :
|
||||
# 403| r403_1(glval<int[][]>) = VariableAddress[c] :
|
||||
# 403| mu403_2(int[][]) = Uninitialized[c] : &:r403_1
|
||||
# 403| r403_3(glval<int>) = VariableAddress[n1] :
|
||||
# 403| r403_4(int) = Load[n1] : &:r403_3, m401_5
|
||||
# 403| r403_5(glval<int>) = VariableAddress[n2] :
|
||||
# 403| r403_6(int) = Load[n2] : &:r403_5, m401_7
|
||||
# 403| v403_7(void) = NoOp :
|
||||
# 405| r405_1(int) = Constant[0] :
|
||||
# 405| r405_2(glval<int[]>) = VariableAddress[b] :
|
||||
# 405| r405_3(int *) = Convert : r405_2
|
||||
# 405| r405_4(glval<int>) = CopyValue : r405_3
|
||||
# 405| mu405_5(int) = Store[?] : &:r405_4, r405_1
|
||||
# 406| r406_1(int) = Constant[1] :
|
||||
# 406| r406_2(glval<int[]>) = VariableAddress[b] :
|
||||
# 406| r406_3(int *) = Convert : r406_2
|
||||
# 406| r406_4(int) = Constant[0] :
|
||||
# 406| r406_5(glval<int>) = PointerAdd[4] : r406_3, r406_4
|
||||
# 406| mu406_6(int) = Store[?] : &:r406_5, r406_1
|
||||
# 408| r408_1(int) = Constant[0] :
|
||||
# 408| r408_2(glval<int[][]>) = VariableAddress[c] :
|
||||
# 408| r408_3(int(*)[]) = Convert : r408_2
|
||||
# 408| r408_4(int) = Constant[1] :
|
||||
# 408| r408_5(int(*)[]) = PointerAdd : r408_3, r408_4
|
||||
# 408| r408_6(glval<int[]>) = CopyValue : r408_5
|
||||
# 408| r408_7(int *) = Convert : r408_6
|
||||
# 408| r408_8(glval<int>) = CopyValue : r408_7
|
||||
# 408| mu408_9(int) = Store[?] : &:r408_8, r408_1
|
||||
# 410| r410_1(glval<bool>) = VariableAddress[b1] :
|
||||
# 410| r410_2(bool) = Load[b1] : &:r410_1, m401_11
|
||||
# 410| v410_3(void) = ConditionalBranch : r410_2
|
||||
#-----| False -> Block 2
|
||||
#-----| True -> Block 1
|
||||
|
||||
# 411| Block 1
|
||||
# 411| r411_1(glval<int[]>) = VariableAddress[b] :
|
||||
# 411| m411_2(int[]) = Uninitialized[b] : &:r411_1
|
||||
# 411| r411_3(glval<int>) = VariableAddress[n1] :
|
||||
# 411| r411_4(int) = Load[n1] : &:r411_3, m401_5
|
||||
# 411| v411_5(void) = NoOp :
|
||||
#-----| Goto -> Block 3
|
||||
|
||||
# 413| Block 2
|
||||
# 413| r413_1(glval<int[]>) = VariableAddress[b] :
|
||||
# 413| m413_2(int[]) = Uninitialized[b] : &:r413_1
|
||||
# 413| r413_3(glval<int>) = VariableAddress[n2] :
|
||||
# 413| r413_4(int) = Load[n2] : &:r413_3, m401_7
|
||||
# 413| v413_5(void) = NoOp :
|
||||
#-----| Goto -> Block 3
|
||||
|
||||
# 415| Block 3
|
||||
# 415| v415_1(void) = NoOp :
|
||||
# 401| v401_12(void) = ReturnVoid :
|
||||
# 401| v401_13(void) = AliasedUse : ~m?
|
||||
# 401| v401_14(void) = ExitFunction :
|
||||
|
||||
@@ -1695,3 +1695,76 @@ ssa.cpp:
|
||||
# 383| v383_13(void) = ReturnValue : &:r383_12, m398_5
|
||||
# 383| v383_14(void) = AliasedUse : ~m?
|
||||
# 383| v383_15(void) = ExitFunction :
|
||||
|
||||
# 401| void vla(int, int, int, bool)
|
||||
# 401| Block 0
|
||||
# 401| v401_1(void) = EnterFunction :
|
||||
# 401| mu401_2(unknown) = AliasedDefinition :
|
||||
# 401| mu401_3(unknown) = InitializeNonLocal :
|
||||
# 401| r401_4(glval<int>) = VariableAddress[n1] :
|
||||
# 401| m401_5(int) = InitializeParameter[n1] : &:r401_4
|
||||
# 401| r401_6(glval<int>) = VariableAddress[n2] :
|
||||
# 401| m401_7(int) = InitializeParameter[n2] : &:r401_6
|
||||
# 401| r401_8(glval<int>) = VariableAddress[n3] :
|
||||
# 401| m401_9(int) = InitializeParameter[n3] : &:r401_8
|
||||
# 401| r401_10(glval<bool>) = VariableAddress[b1] :
|
||||
# 401| m401_11(bool) = InitializeParameter[b1] : &:r401_10
|
||||
# 402| r402_1(glval<int[]>) = VariableAddress[b] :
|
||||
# 402| mu402_2(int[]) = Uninitialized[b] : &:r402_1
|
||||
# 402| r402_3(glval<int>) = VariableAddress[n1] :
|
||||
# 402| r402_4(int) = Load[n1] : &:r402_3, m401_5
|
||||
# 402| v402_5(void) = NoOp :
|
||||
# 403| r403_1(glval<int[][]>) = VariableAddress[c] :
|
||||
# 403| mu403_2(int[][]) = Uninitialized[c] : &:r403_1
|
||||
# 403| r403_3(glval<int>) = VariableAddress[n1] :
|
||||
# 403| r403_4(int) = Load[n1] : &:r403_3, m401_5
|
||||
# 403| r403_5(glval<int>) = VariableAddress[n2] :
|
||||
# 403| r403_6(int) = Load[n2] : &:r403_5, m401_7
|
||||
# 403| v403_7(void) = NoOp :
|
||||
# 405| r405_1(int) = Constant[0] :
|
||||
# 405| r405_2(glval<int[]>) = VariableAddress[b] :
|
||||
# 405| r405_3(int *) = Convert : r405_2
|
||||
# 405| r405_4(glval<int>) = CopyValue : r405_3
|
||||
# 405| mu405_5(int) = Store[?] : &:r405_4, r405_1
|
||||
# 406| r406_1(int) = Constant[1] :
|
||||
# 406| r406_2(glval<int[]>) = VariableAddress[b] :
|
||||
# 406| r406_3(int *) = Convert : r406_2
|
||||
# 406| r406_4(int) = Constant[0] :
|
||||
# 406| r406_5(glval<int>) = PointerAdd[4] : r406_3, r406_4
|
||||
# 406| mu406_6(int) = Store[?] : &:r406_5, r406_1
|
||||
# 408| r408_1(int) = Constant[0] :
|
||||
# 408| r408_2(glval<int[][]>) = VariableAddress[c] :
|
||||
# 408| r408_3(int(*)[]) = Convert : r408_2
|
||||
# 408| r408_4(int) = Constant[1] :
|
||||
# 408| r408_5(int(*)[]) = PointerAdd : r408_3, r408_4
|
||||
# 408| r408_6(glval<int[]>) = CopyValue : r408_5
|
||||
# 408| r408_7(int *) = Convert : r408_6
|
||||
# 408| r408_8(glval<int>) = CopyValue : r408_7
|
||||
# 408| mu408_9(int) = Store[?] : &:r408_8, r408_1
|
||||
# 410| r410_1(glval<bool>) = VariableAddress[b1] :
|
||||
# 410| r410_2(bool) = Load[b1] : &:r410_1, m401_11
|
||||
# 410| v410_3(void) = ConditionalBranch : r410_2
|
||||
#-----| False -> Block 2
|
||||
#-----| True -> Block 1
|
||||
|
||||
# 411| Block 1
|
||||
# 411| r411_1(glval<int[]>) = VariableAddress[b] :
|
||||
# 411| m411_2(int[]) = Uninitialized[b] : &:r411_1
|
||||
# 411| r411_3(glval<int>) = VariableAddress[n1] :
|
||||
# 411| r411_4(int) = Load[n1] : &:r411_3, m401_5
|
||||
# 411| v411_5(void) = NoOp :
|
||||
#-----| Goto -> Block 3
|
||||
|
||||
# 413| Block 2
|
||||
# 413| r413_1(glval<int[]>) = VariableAddress[b] :
|
||||
# 413| m413_2(int[]) = Uninitialized[b] : &:r413_1
|
||||
# 413| r413_3(glval<int>) = VariableAddress[n2] :
|
||||
# 413| r413_4(int) = Load[n2] : &:r413_3, m401_7
|
||||
# 413| v413_5(void) = NoOp :
|
||||
#-----| Goto -> Block 3
|
||||
|
||||
# 415| Block 3
|
||||
# 415| v415_1(void) = NoOp :
|
||||
# 401| v401_12(void) = ReturnVoid :
|
||||
# 401| v401_13(void) = AliasedUse : ~m?
|
||||
# 401| v401_14(void) = ExitFunction :
|
||||
|
||||
@@ -12,12 +12,9 @@ instructionWithoutSuccessor
|
||||
| condition_decls.cpp:26:23:26:24 | Chi: call to BoxedInt | Instruction 'Chi: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:25:6:25:21 | void switch_decl_bind(int) | void switch_decl_bind(int) |
|
||||
| condition_decls.cpp:41:22:41:23 | Chi: call to BoxedInt | Instruction 'Chi: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:40:6:40:20 | void while_decl_bind(int) | void while_decl_bind(int) |
|
||||
| condition_decls.cpp:48:52:48:53 | Chi: call to BoxedInt | Instruction 'Chi: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:47:6:47:18 | void for_decl_bind(int) | void for_decl_bind(int) |
|
||||
| misc.c:171:10:171:13 | Uninitialized: definition of str2 | Instruction 'Uninitialized: definition of str2' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() |
|
||||
| ms_try_mix.cpp:35:13:35:19 | ThrowValue: throw ... | Instruction 'ThrowValue: throw ...' has no successors in function '$@'. | ms_try_mix.cpp:29:6:29:19 | void ms_finally_mix(int) | void ms_finally_mix(int) |
|
||||
| ms_try_mix.cpp:53:5:53:11 | ThrowValue: throw ... | Instruction 'ThrowValue: throw ...' has no successors in function '$@'. | ms_try_mix.cpp:49:6:49:28 | void ms_empty_finally_at_end() | void ms_empty_finally_at_end() |
|
||||
| stmt_expr.cpp:27:5:27:15 | Store: ... = ... | Instruction 'Store: ... = ...' has no successors in function '$@'. | stmt_expr.cpp:21:13:21:13 | void stmtexpr::g(int) | void stmtexpr::g(int) |
|
||||
| vla.c:5:9:5:14 | Uninitialized: definition of matrix | Instruction 'Uninitialized: definition of matrix' has no successors in function '$@'. | vla.c:3:12:3:12 | int f(int, char**) | int f(int, char**) |
|
||||
| vla.c:11:6:11:16 | Chi: vla_typedef | Instruction 'Chi: vla_typedef' has no successors in function '$@'. | vla.c:11:6:11:16 | void vla_typedef() | void vla_typedef() |
|
||||
ambiguousSuccessors
|
||||
unexplainedLoop
|
||||
unnecessaryPhiInstruction
|
||||
|
||||
@@ -23,29 +23,11 @@ instructionWithoutSuccessor
|
||||
| file://:0:0:0:0 | CompareNE: (bool)... | Instruction 'CompareNE: (bool)...' has no successors in function '$@'. | condition_decls.cpp:15:6:15:17 | void if_decl_bind(int) | void if_decl_bind(int) |
|
||||
| file://:0:0:0:0 | CompareNE: (bool)... | Instruction 'CompareNE: (bool)...' has no successors in function '$@'. | condition_decls.cpp:40:6:40:20 | void while_decl_bind(int) | void while_decl_bind(int) |
|
||||
| file://:0:0:0:0 | CompareNE: (bool)... | Instruction 'CompareNE: (bool)...' has no successors in function '$@'. | condition_decls.cpp:47:6:47:18 | void for_decl_bind(int) | void for_decl_bind(int) |
|
||||
| misc.c:171:10:171:13 | Uninitialized: definition of str2 | Instruction 'Uninitialized: definition of str2' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() |
|
||||
| misc.c:171:15:171:31 | Add: ... + ... | Instruction 'Add: ... + ...' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() |
|
||||
| misc.c:173:14:173:26 | Mul: ... * ... | Instruction 'Mul: ... * ...' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() |
|
||||
| misc.c:173:37:173:39 | Store: array to pointer conversion | Instruction 'Store: array to pointer conversion' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() |
|
||||
| misc.c:174:17:174:22 | CallSideEffect: call to getInt | Instruction 'CallSideEffect: call to getInt' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() |
|
||||
| misc.c:174:30:174:35 | CallSideEffect: call to getInt | Instruction 'CallSideEffect: call to getInt' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() |
|
||||
| misc.c:174:55:174:60 | Store: (char ****)... | Instruction 'Store: (char ****)...' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() |
|
||||
| ms_try_mix.cpp:35:13:35:19 | ThrowValue: throw ... | Instruction 'ThrowValue: throw ...' has no successors in function '$@'. | ms_try_mix.cpp:29:6:29:19 | void ms_finally_mix(int) | void ms_finally_mix(int) |
|
||||
| ms_try_mix.cpp:53:5:53:11 | ThrowValue: throw ... | Instruction 'ThrowValue: throw ...' has no successors in function '$@'. | ms_try_mix.cpp:49:6:49:28 | void ms_empty_finally_at_end() | void ms_empty_finally_at_end() |
|
||||
| stmt_expr.cpp:27:5:27:15 | Store: ... = ... | Instruction 'Store: ... = ...' has no successors in function '$@'. | stmt_expr.cpp:21:13:21:13 | void stmtexpr::g(int) | void stmtexpr::g(int) |
|
||||
| stmt_expr.cpp:29:11:32:11 | CopyValue: (statement expression) | Instruction 'CopyValue: (statement expression)' has no successors in function '$@'. | stmt_expr.cpp:21:13:21:13 | void stmtexpr::g(int) | void stmtexpr::g(int) |
|
||||
| stmt_in_type.cpp:5:53:5:53 | Constant: 1 | Instruction 'Constant: 1' has no successors in function '$@'. | stmt_in_type.cpp:2:6:2:12 | void cpp_fun() | void cpp_fun() |
|
||||
| vla.c:5:9:5:14 | Uninitialized: definition of matrix | Instruction 'Uninitialized: definition of matrix' has no successors in function '$@'. | vla.c:3:12:3:12 | int f(int, char**) | int f(int, char**) |
|
||||
| vla.c:5:16:5:19 | Load: argc | Instruction 'Load: argc' has no successors in function '$@'. | vla.c:3:12:3:12 | int f(int, char**) | int f(int, char**) |
|
||||
| vla.c:5:27:5:33 | BufferReadSideEffect: (const char *)... | Instruction 'BufferReadSideEffect: (const char *)...' has no successors in function '$@'. | vla.c:3:12:3:12 | int f(int, char**) | int f(int, char**) |
|
||||
| vla.c:11:6:11:16 | InitializeNonLocal: vla_typedef | Instruction 'InitializeNonLocal: vla_typedef' has no successors in function '$@'. | vla.c:11:6:11:16 | void vla_typedef() | void vla_typedef() |
|
||||
| vla.c:12:33:12:44 | Add: ... + ... | Instruction 'Add: ... + ...' has no successors in function '$@'. | vla.c:11:6:11:16 | void vla_typedef() | void vla_typedef() |
|
||||
| vla.c:12:50:12:62 | Mul: ... * ... | Instruction 'Mul: ... * ...' has no successors in function '$@'. | vla.c:11:6:11:16 | void vla_typedef() | void vla_typedef() |
|
||||
| vla.c:13:12:13:14 | Uninitialized: definition of var | Instruction 'Uninitialized: definition of var' has no successors in function '$@'. | vla.c:11:6:11:16 | void vla_typedef() | void vla_typedef() |
|
||||
| vla.c:14:36:14:47 | Add: ... + ... | Instruction 'Add: ... + ...' has no successors in function '$@'. | vla.c:11:6:11:16 | void vla_typedef() | void vla_typedef() |
|
||||
| vla.c:14:53:14:65 | Mul: ... * ... | Instruction 'Mul: ... * ...' has no successors in function '$@'. | vla.c:11:6:11:16 | void vla_typedef() | void vla_typedef() |
|
||||
| vla.c:14:74:14:79 | CallSideEffect: call to getInt | Instruction 'CallSideEffect: call to getInt' has no successors in function '$@'. | vla.c:11:6:11:16 | void vla_typedef() | void vla_typedef() |
|
||||
| vla.c:14:92:14:94 | Store: (char *)... | Instruction 'Store: (char *)...' has no successors in function '$@'. | vla.c:11:6:11:16 | void vla_typedef() | void vla_typedef() |
|
||||
ambiguousSuccessors
|
||||
unexplainedLoop
|
||||
unnecessaryPhiInstruction
|
||||
@@ -65,7 +47,6 @@ useNotDominatedByDefinition
|
||||
| ms_try_except.cpp:19:17:19:21 | Left | Operand 'Left' is not dominated by its definition in function '$@'. | ms_try_except.cpp:2:6:2:18 | void ms_try_except(int) | void ms_try_except(int) |
|
||||
| static_init_templates.cpp:15:1:15:18 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | static_init_templates.cpp:15:1:15:18 | void MyClass::MyClass() | void MyClass::MyClass() |
|
||||
| try_catch.cpp:21:9:21:9 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | try_catch.cpp:19:6:19:23 | void throw_from_nonstmt(int) | void throw_from_nonstmt(int) |
|
||||
| vla.c:3:31:3:34 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | vla.c:3:12:3:12 | int f(int, char**) | int f(int, char**) |
|
||||
switchInstructionWithoutDefaultEdge
|
||||
notMarkedAsConflated
|
||||
wronglyMarkedAsConflated
|
||||
|
||||
@@ -12,12 +12,9 @@ instructionWithoutSuccessor
|
||||
| condition_decls.cpp:26:23:26:24 | IndirectMayWriteSideEffect: call to BoxedInt | Instruction 'IndirectMayWriteSideEffect: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:25:6:25:21 | void switch_decl_bind(int) | void switch_decl_bind(int) |
|
||||
| condition_decls.cpp:41:22:41:23 | IndirectMayWriteSideEffect: call to BoxedInt | Instruction 'IndirectMayWriteSideEffect: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:40:6:40:20 | void while_decl_bind(int) | void while_decl_bind(int) |
|
||||
| condition_decls.cpp:48:52:48:53 | IndirectMayWriteSideEffect: call to BoxedInt | Instruction 'IndirectMayWriteSideEffect: call to BoxedInt' has no successors in function '$@'. | condition_decls.cpp:47:6:47:18 | void for_decl_bind(int) | void for_decl_bind(int) |
|
||||
| misc.c:171:10:171:13 | Uninitialized: definition of str2 | Instruction 'Uninitialized: definition of str2' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() |
|
||||
| ms_try_mix.cpp:35:13:35:19 | ThrowValue: throw ... | Instruction 'ThrowValue: throw ...' has no successors in function '$@'. | ms_try_mix.cpp:29:6:29:19 | void ms_finally_mix(int) | void ms_finally_mix(int) |
|
||||
| ms_try_mix.cpp:53:5:53:11 | ThrowValue: throw ... | Instruction 'ThrowValue: throw ...' has no successors in function '$@'. | ms_try_mix.cpp:49:6:49:28 | void ms_empty_finally_at_end() | void ms_empty_finally_at_end() |
|
||||
| stmt_expr.cpp:27:5:27:15 | Store: ... = ... | Instruction 'Store: ... = ...' has no successors in function '$@'. | stmt_expr.cpp:21:13:21:13 | void stmtexpr::g(int) | void stmtexpr::g(int) |
|
||||
| vla.c:5:9:5:14 | Uninitialized: definition of matrix | Instruction 'Uninitialized: definition of matrix' has no successors in function '$@'. | vla.c:3:12:3:12 | int f(int, char**) | int f(int, char**) |
|
||||
| vla.c:11:6:11:16 | InitializeNonLocal: vla_typedef | Instruction 'InitializeNonLocal: vla_typedef' has no successors in function '$@'. | vla.c:11:6:11:16 | void vla_typedef() | void vla_typedef() |
|
||||
ambiguousSuccessors
|
||||
unexplainedLoop
|
||||
unnecessaryPhiInstruction
|
||||
|
||||
@@ -64,9 +64,11 @@ class SymmetricEncryptionCreateDecryptorSink extends SymmetricEncryptionKeySink
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `SymmetricKey` instead.
|
||||
*
|
||||
* Symmetric Key Data Flow configuration.
|
||||
*/
|
||||
class SymmetricKeyTaintTrackingConfiguration extends TaintTracking::Configuration {
|
||||
deprecated class SymmetricKeyTaintTrackingConfiguration extends TaintTracking::Configuration {
|
||||
SymmetricKeyTaintTrackingConfiguration() { this = "SymmetricKeyTaintTracking" }
|
||||
|
||||
/** Holds if the node is a key source. */
|
||||
@@ -78,3 +80,22 @@ class SymmetricKeyTaintTrackingConfiguration extends TaintTracking::Configuratio
|
||||
/** Holds if the node is a key sanitizer. */
|
||||
override predicate isSanitizer(DataFlow::Node sanitizer) { sanitizer instanceof KeySanitizer }
|
||||
}
|
||||
|
||||
/**
|
||||
* Symmetric Key Data Flow configuration.
|
||||
*/
|
||||
private module SymmetricKeyConfig implements DataFlow::ConfigSig {
|
||||
/** Holds if the node is a key source. */
|
||||
predicate isSource(DataFlow::Node src) { src instanceof KeySource }
|
||||
|
||||
/** Holds if the node is a symmetric encryption key sink. */
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof SymmetricEncryptionKeySink }
|
||||
|
||||
/** Holds if the node is a key sanitizer. */
|
||||
predicate isBarrier(DataFlow::Node sanitizer) { sanitizer instanceof KeySanitizer }
|
||||
}
|
||||
|
||||
/**
|
||||
* Symmetric Key Data Flow configuration.
|
||||
*/
|
||||
module SymmetricKey = TaintTracking::Global<SymmetricKeyConfig>;
|
||||
|
||||
@@ -62,9 +62,11 @@ module HardcodedSymmetricEncryptionKey {
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `HardCodedSymmetricEncryption` instead.
|
||||
*
|
||||
* A taint-tracking configuration for uncontrolled data in path expression vulnerabilities.
|
||||
*/
|
||||
class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
||||
deprecated class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
||||
TaintTrackingConfiguration() { this = "HardcodedSymmetricEncryptionKey" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
@@ -85,4 +87,32 @@ module HardcodedSymmetricEncryptionKey {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for uncontrolled data in path expression vulnerabilities.
|
||||
*/
|
||||
private module HardCodedSymmetricEncryptionConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
|
||||
|
||||
/**
|
||||
* Since `CryptographicBuffer` uses native code inside, taint tracking doesn't pass through it.
|
||||
* Need to create an additional custom step.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(MethodCall mc, CryptographicBuffer c |
|
||||
pred.asExpr() = mc.getAnArgument() and
|
||||
mc.getTarget() = c.getAMethod() and
|
||||
succ.asExpr() = mc
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking module for uncontrolled data in path expression vulnerabilities.
|
||||
*/
|
||||
module HardCodedSymmetricEncryption = TaintTracking::Global<HardCodedSymmetricEncryptionConfig>;
|
||||
}
|
||||
|
||||
@@ -25,9 +25,11 @@ abstract class Sink extends DataFlow::ExprNode { }
|
||||
abstract class Sanitizer extends DataFlow::ExprNode { }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `CodeInjection` instead.
|
||||
*
|
||||
* A taint-tracking configuration for user input treated as code vulnerabilities.
|
||||
*/
|
||||
class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
||||
deprecated class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
||||
TaintTrackingConfiguration() { this = "CodeInjection" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
@@ -37,6 +39,22 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
||||
override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for user input treated as code vulnerabilities.
|
||||
*/
|
||||
private module CodeInjectionConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking module for user input treated as code vulnerabilities.
|
||||
*/
|
||||
module CodeInjection = TaintTracking::Global<CodeInjectionConfig>;
|
||||
|
||||
/** A source of remote user input. */
|
||||
class RemoteSource extends Source instanceof RemoteFlowSource { }
|
||||
|
||||
|
||||
@@ -23,9 +23,11 @@ abstract class Sink extends DataFlow::ExprNode { }
|
||||
abstract class Sanitizer extends DataFlow::ExprNode { }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `CommandInjection` instead.
|
||||
*
|
||||
* A taint-tracking configuration for command injection vulnerabilities.
|
||||
*/
|
||||
class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
||||
deprecated class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
||||
TaintTrackingConfiguration() { this = "CommandInjection" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
@@ -35,6 +37,32 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
||||
override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for command injection vulnerabilities.
|
||||
*/
|
||||
module CommandInjectionConfig implements DataFlow::ConfigSig {
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source.
|
||||
*/
|
||||
predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink.
|
||||
*/
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited. This completely removes
|
||||
* `node` from the data flow graph.
|
||||
*/
|
||||
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking module for command injection vulnerabilities.
|
||||
*/
|
||||
module CommandInjection = TaintTracking::Global<CommandInjectionConfig>;
|
||||
|
||||
/** A source of remote user input. */
|
||||
class RemoteSource extends Source instanceof RemoteFlowSource { }
|
||||
|
||||
|
||||
@@ -30,9 +30,11 @@ abstract class Sink extends DataFlow::ExprNode {
|
||||
abstract class Sanitizer extends DataFlow::ExprNode { }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `ConditionalBypass` instead.
|
||||
*
|
||||
* A taint-tracking configuration for user-controlled bypass of sensitive method.
|
||||
*/
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
deprecated class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "UserControlledBypassOfSensitiveMethodConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
@@ -42,6 +44,22 @@ class Configuration extends TaintTracking::Configuration {
|
||||
override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for user-controlled bypass of sensitive method.
|
||||
*/
|
||||
private module ConditionalBypassConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking module for user-controlled bypass of sensitive method.
|
||||
*/
|
||||
module ConditionalBypass = TaintTracking::Global<ConditionalBypassConfig>;
|
||||
|
||||
/** A source of remote user input. */
|
||||
class RemoteSource extends Source instanceof RemoteFlowSource { }
|
||||
|
||||
|
||||
@@ -23,9 +23,11 @@ abstract class Sink extends DataFlow::ExprNode { }
|
||||
abstract class Sanitizer extends DataFlow::ExprNode { }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `ExposureOfPrivateInformation` instead.
|
||||
*
|
||||
* A taint-tracking configuration for private information flowing unencrypted to an external location.
|
||||
*/
|
||||
class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
||||
deprecated class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
||||
TaintTrackingConfiguration() { this = "ExposureOfPrivateInformation" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
@@ -35,6 +37,22 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
||||
override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for private information flowing unencrypted to an external location.
|
||||
*/
|
||||
private module ExposureOfPrivateInformationConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking module for private information flowing unencrypted to an external location.
|
||||
*/
|
||||
module ExposureOfPrivateInformation = TaintTracking::Global<ExposureOfPrivateInformationConfig>;
|
||||
|
||||
private class PrivateDataSource extends Source {
|
||||
PrivateDataSource() { this.getExpr() instanceof PrivateDataExpr }
|
||||
}
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
|
||||
import csharp
|
||||
import semmle.code.csharp.security.dataflow.CommandInjectionQuery
|
||||
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
|
||||
import CommandInjection::PathGraph
|
||||
|
||||
from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where c.hasFlowPath(source, sink)
|
||||
from CommandInjection::PathNode source, CommandInjection::PathNode sink
|
||||
where CommandInjection::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "This command line depends on a $@.", source.getNode(),
|
||||
"user-provided value"
|
||||
|
||||
@@ -16,13 +16,19 @@
|
||||
import csharp
|
||||
import semmle.code.csharp.security.dataflow.flowsources.Stored
|
||||
import semmle.code.csharp.security.dataflow.CommandInjectionQuery
|
||||
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
|
||||
import StoredCommandInjection::PathGraph
|
||||
|
||||
class StoredTaintTrackingConfiguration extends TaintTrackingConfiguration {
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof StoredFlowSource }
|
||||
module StoredCommandInjectionConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof StoredFlowSource }
|
||||
|
||||
predicate isSink = CommandInjectionConfig::isSink/1;
|
||||
|
||||
predicate isBarrier = CommandInjectionConfig::isBarrier/1;
|
||||
}
|
||||
|
||||
from StoredTaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where c.hasFlowPath(source, sink)
|
||||
module StoredCommandInjection = TaintTracking::Global<StoredCommandInjectionConfig>;
|
||||
|
||||
from StoredCommandInjection::PathNode source, StoredCommandInjection::PathNode sink
|
||||
where StoredCommandInjection::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "This command line depends on a $@.", source.getNode(),
|
||||
"stored (potentially user-provided) value"
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
|
||||
import csharp
|
||||
import semmle.code.csharp.security.dataflow.CodeInjectionQuery
|
||||
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
|
||||
import CodeInjection::PathGraph
|
||||
|
||||
from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where c.hasFlowPath(source, sink)
|
||||
from CodeInjection::PathNode source, CodeInjection::PathNode sink
|
||||
where CodeInjection::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "This code compilation depends on a $@.", source.getNode(),
|
||||
"user-provided value"
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
import csharp
|
||||
import semmle.code.csharp.security.cryptography.EncryptionKeyDataFlowQuery
|
||||
import DataFlow::PathGraph
|
||||
import SymmetricKey::PathGraph
|
||||
|
||||
/**
|
||||
* The creation of a literal byte array.
|
||||
@@ -38,10 +38,10 @@ class StringLiteralSource extends KeySource {
|
||||
}
|
||||
|
||||
from
|
||||
SymmetricKeyTaintTrackingConfiguration keyFlow, DataFlow::PathNode source,
|
||||
DataFlow::PathNode sink, KeySource srcNode, SymmetricEncryptionKeySink sinkNode
|
||||
SymmetricKey::PathNode source, SymmetricKey::PathNode sink, KeySource srcNode,
|
||||
SymmetricEncryptionKeySink sinkNode
|
||||
where
|
||||
keyFlow.hasFlowPath(source, sink) and
|
||||
SymmetricKey::flowPath(source, sink) and
|
||||
source.getNode() = srcNode and
|
||||
sink.getNode() = sinkNode
|
||||
select sink.getNode(), source, sink,
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
|
||||
import csharp
|
||||
import semmle.code.csharp.security.cryptography.HardcodedSymmetricEncryptionKey::HardcodedSymmetricEncryptionKey
|
||||
import DataFlow::PathGraph
|
||||
import HardCodedSymmetricEncryption::PathGraph
|
||||
|
||||
from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where c.hasFlowPath(source, sink)
|
||||
from HardCodedSymmetricEncryption::PathNode source, HardCodedSymmetricEncryption::PathNode sink
|
||||
where HardCodedSymmetricEncryption::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink,
|
||||
"Hard-coded symmetric $@ is used in symmetric algorithm in " +
|
||||
sink.getNode().(Sink).getDescription() + ".", source.getNode(), "key"
|
||||
|
||||
@@ -13,10 +13,10 @@
|
||||
|
||||
import csharp
|
||||
import semmle.code.csharp.security.dataflow.ExposureOfPrivateInformationQuery
|
||||
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
|
||||
import ExposureOfPrivateInformation::PathGraph
|
||||
|
||||
from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where c.hasFlowPath(source, sink)
|
||||
from ExposureOfPrivateInformation::PathNode source, ExposureOfPrivateInformation::PathNode sink
|
||||
where ExposureOfPrivateInformation::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink,
|
||||
"Private data returned by $@ is written to an external location.", source.getNode(),
|
||||
source.getNode().toString()
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
|
||||
import csharp
|
||||
import semmle.code.csharp.security.dataflow.ConditionalBypassQuery
|
||||
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
|
||||
import ConditionalBypass::PathGraph
|
||||
|
||||
from Configuration config, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where config.hasFlowPath(source, sink)
|
||||
from ConditionalBypass::PathNode source, ConditionalBypass::PathNode sink
|
||||
where ConditionalBypass::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "This condition guards a sensitive $@, but a $@ controls it.",
|
||||
sink.getNode().(Sink).getSensitiveMethodCall(), "action", source.getNode(), "user-provided value"
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
category: deprecated
|
||||
---
|
||||
* The `execTainted` predicate in `CommandLineQuery.qll` has been deprecated and replaced with the predicate `execIsTainted`.
|
||||
|
||||
@@ -12,9 +12,11 @@ import semmle.code.java.security.ExternalProcess
|
||||
import semmle.code.java.security.CommandArguments
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `RemoteUserInputToArgumentToExecFlow` instead.
|
||||
*
|
||||
* A taint-tracking configuration for unvalidated user input that is used to run an external process.
|
||||
*/
|
||||
class RemoteUserInputToArgumentToExecFlowConfig extends TaintTracking::Configuration {
|
||||
deprecated class RemoteUserInputToArgumentToExecFlowConfig extends TaintTracking::Configuration {
|
||||
RemoteUserInputToArgumentToExecFlowConfig() {
|
||||
this = "ExecCommon::RemoteUserInputToArgumentToExecFlowConfig"
|
||||
}
|
||||
@@ -33,12 +35,52 @@ class RemoteUserInputToArgumentToExecFlowConfig extends TaintTracking::Configura
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for unvalidated user input that is used to run an external process.
|
||||
*/
|
||||
module RemoteUserInputToArgumentToExecFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof ArgumentToExec }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
node.getType() instanceof PrimitiveType
|
||||
or
|
||||
node.getType() instanceof BoxedType
|
||||
or
|
||||
isSafeCommandArgument(node.asExpr())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Taint-tracking flow for unvalidated user input that is used to run an external process.
|
||||
*/
|
||||
module RemoteUserInputToArgumentToExecFlow =
|
||||
TaintTracking::Global<RemoteUserInputToArgumentToExecFlowConfig>;
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `execIsTainted` instead.
|
||||
*
|
||||
* Implementation of `ExecTainted.ql`. It is extracted to a QLL
|
||||
* so that it can be excluded from `ExecUnescaped.ql` to avoid
|
||||
* reporting overlapping results.
|
||||
*/
|
||||
predicate execTainted(DataFlow::PathNode source, DataFlow::PathNode sink, ArgumentToExec execArg) {
|
||||
deprecated predicate execTainted(
|
||||
DataFlow::PathNode source, DataFlow::PathNode sink, ArgumentToExec execArg
|
||||
) {
|
||||
exists(RemoteUserInputToArgumentToExecFlowConfig conf |
|
||||
conf.hasFlowPath(source, sink) and sink.getNode() = DataFlow::exprNode(execArg)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of `ExecTainted.ql`. It is extracted to a QLL
|
||||
* so that it can be excluded from `ExecUnescaped.ql` to avoid
|
||||
* reporting overlapping results.
|
||||
*/
|
||||
predicate execIsTainted(
|
||||
RemoteUserInputToArgumentToExecFlow::PathNode source,
|
||||
RemoteUserInputToArgumentToExecFlow::PathNode sink, ArgumentToExec execArg
|
||||
) {
|
||||
RemoteUserInputToArgumentToExecFlow::flowPath(source, sink) and
|
||||
sink.getNode() = DataFlow::exprNode(execArg)
|
||||
}
|
||||
|
||||
@@ -6,10 +6,12 @@ import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.security.GroovyInjection
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `GroovyInjectionFlow` instead.
|
||||
*
|
||||
* A taint-tracking configuration for unsafe user input
|
||||
* that is used to evaluate a Groovy expression.
|
||||
*/
|
||||
class GroovyInjectionConfig extends TaintTracking::Configuration {
|
||||
deprecated class GroovyInjectionConfig extends TaintTracking::Configuration {
|
||||
GroovyInjectionConfig() { this = "GroovyInjectionConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
@@ -20,3 +22,23 @@ class GroovyInjectionConfig extends TaintTracking::Configuration {
|
||||
any(GroovyInjectionAdditionalTaintStep c).step(fromNode, toNode)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for unsafe user input
|
||||
* that is used to evaluate a Groovy expression.
|
||||
*/
|
||||
module GroovyInjectionConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof GroovyInjectionSink }
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
any(GroovyInjectionAdditionalTaintStep c).step(fromNode, toNode)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect taint flow of unsafe user input
|
||||
* that is used to evaluate a Groovy expression.
|
||||
*/
|
||||
module GroovyInjectionFlow = TaintTracking::Global<GroovyInjectionConfig>;
|
||||
|
||||
@@ -39,11 +39,13 @@ private class DefaultJexlInjectionAdditionalTaintStep extends JexlInjectionAddit
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `JexlInjectionFlow` instead.
|
||||
*
|
||||
* A taint-tracking configuration for unsafe user input
|
||||
* that is used to construct and evaluate a JEXL expression.
|
||||
* It supports both JEXL 2 and 3.
|
||||
*/
|
||||
class JexlInjectionConfig extends TaintTracking::Configuration {
|
||||
deprecated class JexlInjectionConfig extends TaintTracking::Configuration {
|
||||
JexlInjectionConfig() { this = "JexlInjectionConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
@@ -55,6 +57,27 @@ class JexlInjectionConfig extends TaintTracking::Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for unsafe user input
|
||||
* that is used to construct and evaluate a JEXL expression.
|
||||
* It supports both JEXL 2 and 3.
|
||||
*/
|
||||
module JexlInjectionConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof JexlEvaluationSink }
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
any(JexlInjectionAdditionalTaintStep c).step(node1, node2)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks unsafe user input that is used to construct and evaluate a JEXL expression.
|
||||
* It supports both JEXL 2 and 3.
|
||||
*/
|
||||
module JexlInjectionFlow = TaintTracking::Global<JexlInjectionConfig>;
|
||||
|
||||
/**
|
||||
* Holds if `n1` to `n2` is a dataflow step that creates a JEXL script using an unsafe engine
|
||||
* by calling `tainted.createScript(jexlExpr)`.
|
||||
@@ -99,19 +122,15 @@ private predicate createJexlTemplateStep(DataFlow::Node n1, DataFlow::Node n2) {
|
||||
/**
|
||||
* Holds if `expr` is a JEXL engine that is configured with a sandbox.
|
||||
*/
|
||||
private predicate isSafeEngine(Expr expr) {
|
||||
exists(SandboxedJexlFlowConfig config | config.hasFlowTo(DataFlow::exprNode(expr)))
|
||||
}
|
||||
private predicate isSafeEngine(Expr expr) { SandboxedJexlFlow::flowToExpr(expr) }
|
||||
|
||||
/**
|
||||
* A configuration for tracking sandboxed JEXL engines.
|
||||
*/
|
||||
private class SandboxedJexlFlowConfig extends DataFlow2::Configuration {
|
||||
SandboxedJexlFlowConfig() { this = "JexlInjection::SandboxedJexlFlowConfig" }
|
||||
private module SandboxedJexlFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node node) { node instanceof SandboxedJexlSource }
|
||||
|
||||
override predicate isSource(DataFlow::Node node) { node instanceof SandboxedJexlSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node node) {
|
||||
predicate isSink(DataFlow::Node node) {
|
||||
exists(MethodAccess ma, Method m |
|
||||
m instanceof CreateJexlScriptMethod or
|
||||
m instanceof CreateJexlExpressionMethod or
|
||||
@@ -121,11 +140,13 @@ private class SandboxedJexlFlowConfig extends DataFlow2::Configuration {
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
createJexlEngineStep(fromNode, toNode)
|
||||
}
|
||||
}
|
||||
|
||||
private module SandboxedJexlFlow = DataFlow::Global<SandboxedJexlFlowConfig>;
|
||||
|
||||
/**
|
||||
* Defines a data flow source for JEXL engines configured with a sandbox.
|
||||
*/
|
||||
|
||||
@@ -7,9 +7,11 @@ import semmle.code.java.frameworks.SpringLdap
|
||||
import semmle.code.java.security.JndiInjection
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `JndiInjectionFlow` instead.
|
||||
*
|
||||
* A taint-tracking configuration for unvalidated user input that is used in JNDI lookup.
|
||||
*/
|
||||
class JndiInjectionFlowConfig extends TaintTracking::Configuration {
|
||||
deprecated class JndiInjectionFlowConfig extends TaintTracking::Configuration {
|
||||
JndiInjectionFlowConfig() { this = "JndiInjectionFlowConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
@@ -27,14 +29,34 @@ class JndiInjectionFlowConfig extends TaintTracking::Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for unvalidated user input that is used in JNDI lookup.
|
||||
*/
|
||||
module JndiInjectionFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof JndiInjectionSink }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
node.getType() instanceof PrimitiveType or
|
||||
node.getType() instanceof BoxedType or
|
||||
node instanceof JndiInjectionSanitizer
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
any(JndiInjectionAdditionalTaintStep c).step(node1, node2)
|
||||
}
|
||||
}
|
||||
|
||||
/** Tracks flow of unvalidated user input that is used in JNDI lookup */
|
||||
module JndiInjectionFlow = TaintTracking::Global<JndiInjectionFlowConfig>;
|
||||
|
||||
/**
|
||||
* A method that does a JNDI lookup when it receives a `SearchControls` argument with `setReturningObjFlag` = `true`
|
||||
*/
|
||||
private class UnsafeSearchControlsSink extends JndiInjectionSink {
|
||||
UnsafeSearchControlsSink() {
|
||||
exists(UnsafeSearchControlsConf conf, MethodAccess ma |
|
||||
conf.hasFlowTo(DataFlow::exprNode(ma.getAnArgument()))
|
||||
|
|
||||
exists(MethodAccess ma | UnsafeSearchControlsFlow::flowToExpr(ma.getAnArgument()) |
|
||||
this.asExpr() = ma.getArgument(0)
|
||||
)
|
||||
}
|
||||
@@ -44,14 +66,14 @@ private class UnsafeSearchControlsSink extends JndiInjectionSink {
|
||||
* Find flows between a `SearchControls` object with `setReturningObjFlag` = `true`
|
||||
* and an argument of an `LdapOperations.search` or `DirContext.search` call.
|
||||
*/
|
||||
private class UnsafeSearchControlsConf extends DataFlow2::Configuration {
|
||||
UnsafeSearchControlsConf() { this = "UnsafeSearchControlsConf" }
|
||||
private module UnsafeSearchControlsConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof UnsafeSearchControls }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof UnsafeSearchControls }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof UnsafeSearchControlsArgument }
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof UnsafeSearchControlsArgument }
|
||||
}
|
||||
|
||||
private module UnsafeSearchControlsFlow = DataFlow::Global<UnsafeSearchControlsConfig>;
|
||||
|
||||
/**
|
||||
* An argument of type `SearchControls` of an `LdapOperations.search` or `DirContext.search` call.
|
||||
*/
|
||||
|
||||
@@ -6,10 +6,12 @@ import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.security.MvelInjection
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `MvelInjectionFlow` instead.
|
||||
*
|
||||
* A taint-tracking configuration for unsafe user input
|
||||
* that is used to construct and evaluate a MVEL expression.
|
||||
*/
|
||||
class MvelInjectionFlowConfig extends TaintTracking::Configuration {
|
||||
deprecated class MvelInjectionFlowConfig extends TaintTracking::Configuration {
|
||||
MvelInjectionFlowConfig() { this = "MvelInjectionFlowConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
@@ -24,3 +26,22 @@ class MvelInjectionFlowConfig extends TaintTracking::Configuration {
|
||||
any(MvelInjectionAdditionalTaintStep c).step(node1, node2)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for unsafe user input
|
||||
* that is used to construct and evaluate a MVEL expression.
|
||||
*/
|
||||
module MvelInjectionFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof MvelEvaluationSink }
|
||||
|
||||
predicate isBarrier(DataFlow::Node sanitizer) { sanitizer instanceof MvelInjectionSanitizer }
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
any(MvelInjectionAdditionalTaintStep c).step(node1, node2)
|
||||
}
|
||||
}
|
||||
|
||||
/** Tracks flow of unsafe user input that is used to construct and evaluate a MVEL expression. */
|
||||
module MvelInjectionFlow = TaintTracking::Global<MvelInjectionFlowConfig>;
|
||||
|
||||
@@ -5,9 +5,11 @@ import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.security.OgnlInjection
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `OgnlInjectionFlow` instead.
|
||||
*
|
||||
* A taint-tracking configuration for unvalidated user input that is used in OGNL EL evaluation.
|
||||
*/
|
||||
class OgnlInjectionFlowConfig extends TaintTracking::Configuration {
|
||||
deprecated class OgnlInjectionFlowConfig extends TaintTracking::Configuration {
|
||||
OgnlInjectionFlowConfig() { this = "OgnlInjectionFlowConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
@@ -22,3 +24,23 @@ class OgnlInjectionFlowConfig extends TaintTracking::Configuration {
|
||||
any(OgnlInjectionAdditionalTaintStep c).step(node1, node2)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for unvalidated user input that is used in OGNL EL evaluation.
|
||||
*/
|
||||
module OgnlInjectionFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof OgnlInjectionSink }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
any(OgnlInjectionAdditionalTaintStep c).step(node1, node2)
|
||||
}
|
||||
}
|
||||
|
||||
/** Tracks flow of unvalidated user input that is used in OGNL EL evaluation. */
|
||||
module OgnlInjectionFlow = TaintTracking::Global<OgnlInjectionFlowConfig>;
|
||||
|
||||
@@ -35,7 +35,7 @@ deprecated class RequestForgeryConfiguration extends TaintTracking::Configuratio
|
||||
/**
|
||||
* A taint-tracking configuration characterising request-forgery risks.
|
||||
*/
|
||||
private module RequestForgeryConfig implements DataFlow::ConfigSig {
|
||||
module RequestForgeryConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source instanceof RemoteFlowSource and
|
||||
// Exclude results of remote HTTP requests: fetching something else based on that result
|
||||
|
||||
@@ -7,10 +7,12 @@ private import semmle.code.java.frameworks.spring.SpringExpression
|
||||
private import semmle.code.java.security.SpelInjection
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `SpelInjectionFlow` instead.
|
||||
*
|
||||
* A taint-tracking configuration for unsafe user input
|
||||
* that is used to construct and evaluate a SpEL expression.
|
||||
*/
|
||||
class SpelInjectionConfig extends TaintTracking::Configuration {
|
||||
deprecated class SpelInjectionConfig extends TaintTracking::Configuration {
|
||||
SpelInjectionConfig() { this = "SpelInjectionConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
@@ -22,15 +24,30 @@ class SpelInjectionConfig extends TaintTracking::Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for unsafe user input
|
||||
* that is used to construct and evaluate a SpEL expression.
|
||||
*/
|
||||
module SpelInjectionConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof SpelExpressionEvaluationSink }
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
any(SpelExpressionInjectionAdditionalTaintStep c).step(node1, node2)
|
||||
}
|
||||
}
|
||||
|
||||
/** Tracks flow of unsafe user input that is used to construct and evaluate a SpEL expression. */
|
||||
module SpelInjectionFlow = TaintTracking::Global<SpelInjectionConfig>;
|
||||
|
||||
/** Default sink for SpEL injection vulnerabilities. */
|
||||
private class DefaultSpelExpressionEvaluationSink extends SpelExpressionEvaluationSink {
|
||||
DefaultSpelExpressionEvaluationSink() {
|
||||
exists(MethodAccess ma |
|
||||
ma.getMethod() instanceof ExpressionEvaluationMethod and
|
||||
ma.getQualifier() = this.asExpr() and
|
||||
not exists(SafeEvaluationContextFlowConfig config |
|
||||
config.hasFlowTo(DataFlow::exprNode(ma.getArgument(0)))
|
||||
)
|
||||
not SafeEvaluationContextFlow::flowToExpr(ma.getArgument(0))
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -38,21 +55,21 @@ private class DefaultSpelExpressionEvaluationSink extends SpelExpressionEvaluati
|
||||
/**
|
||||
* A configuration for safe evaluation context that may be used in expression evaluation.
|
||||
*/
|
||||
private class SafeEvaluationContextFlowConfig extends DataFlow2::Configuration {
|
||||
SafeEvaluationContextFlowConfig() { this = "SpelInjection::SafeEvaluationContextFlowConfig" }
|
||||
private module SafeEvaluationContextFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof SafeContextSource }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof SafeContextSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodAccess ma |
|
||||
ma.getMethod() instanceof ExpressionEvaluationMethod and
|
||||
ma.getArgument(0) = sink.asExpr()
|
||||
)
|
||||
}
|
||||
|
||||
override int fieldFlowBranchLimit() { result = 0 }
|
||||
int fieldFlowBranchLimit() { result = 0 }
|
||||
}
|
||||
|
||||
private module SafeEvaluationContextFlow = DataFlow::Global<SafeEvaluationContextFlowConfig>;
|
||||
|
||||
/**
|
||||
* A `ContextSource` that is safe from SpEL injection.
|
||||
*/
|
||||
|
||||
@@ -11,9 +11,11 @@ import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.security.QueryInjection
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `QueryInjectionFlow` instead.
|
||||
*
|
||||
* A taint-tracking configuration for unvalidated user input that is used in SQL queries.
|
||||
*/
|
||||
class QueryInjectionFlowConfig extends TaintTracking::Configuration {
|
||||
deprecated class QueryInjectionFlowConfig extends TaintTracking::Configuration {
|
||||
QueryInjectionFlowConfig() { this = "SqlInjectionLib::QueryInjectionFlowConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
|
||||
@@ -31,12 +33,44 @@ class QueryInjectionFlowConfig extends TaintTracking::Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for unvalidated user input that is used in SQL queries.
|
||||
*/
|
||||
module QueryInjectionFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof QueryInjectionSink }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
node.getType() instanceof PrimitiveType or
|
||||
node.getType() instanceof BoxedType or
|
||||
node.getType() instanceof NumberType
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
any(AdditionalQueryInjectionTaintStep s).step(node1, node2)
|
||||
}
|
||||
}
|
||||
|
||||
/** Tracks flow of unvalidated user input that is used in SQL queries. */
|
||||
module QueryInjectionFlow = TaintTracking::Global<QueryInjectionFlowConfig>;
|
||||
|
||||
/**
|
||||
* Implementation of `SqlTainted.ql`. This is extracted to a QLL so that it
|
||||
* can be excluded from `SqlConcatenated.ql` to avoid overlapping results.
|
||||
*/
|
||||
predicate queryTaintedBy(
|
||||
deprecated predicate queryTaintedBy(
|
||||
QueryInjectionSink query, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
) {
|
||||
exists(QueryInjectionFlowConfig conf | conf.hasFlowPath(source, sink) and sink.getNode() = query)
|
||||
any(QueryInjectionFlowConfig c).hasFlowPath(source, sink) and sink.getNode() = query
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of `SqlTainted.ql`. This is extracted to a QLL so that it
|
||||
* can be excluded from `SqlConcatenated.ql` to avoid overlapping results.
|
||||
*/
|
||||
predicate queryIsTaintedBy(
|
||||
QueryInjectionSink query, QueryInjectionFlow::PathNode source, QueryInjectionFlow::PathNode sink
|
||||
) {
|
||||
QueryInjectionFlow::flowPath(source, sink) and sink.getNode() = query
|
||||
}
|
||||
|
||||
@@ -5,8 +5,12 @@ import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.security.TemplateInjection
|
||||
|
||||
/** A taint tracking configuration to reason about server-side template injection (SST) vulnerabilities */
|
||||
class TemplateInjectionFlowConfig extends TaintTracking::Configuration {
|
||||
/**
|
||||
* DEPRECATED: Use `TemplateInjectionFlow` instead.
|
||||
*
|
||||
* A taint tracking configuration to reason about server-side template injection (SST) vulnerabilities
|
||||
*/
|
||||
deprecated class TemplateInjectionFlowConfig extends TaintTracking::Configuration {
|
||||
TemplateInjectionFlowConfig() { this = "TemplateInjectionFlowConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) {
|
||||
@@ -36,3 +40,35 @@ class TemplateInjectionFlowConfig extends TaintTracking::Configuration {
|
||||
any(TemplateInjectionAdditionalTaintStep a).isAdditionalTaintStep(node1, state1, node2, state2)
|
||||
}
|
||||
}
|
||||
|
||||
/** A taint tracking configuration to reason about server-side template injection (SST) vulnerabilities */
|
||||
module TemplateInjectionFlowConfig implements DataFlow::StateConfigSig {
|
||||
class FlowState = DataFlow::FlowState;
|
||||
|
||||
predicate isSource(DataFlow::Node source, FlowState state) {
|
||||
source.(TemplateInjectionSource).hasState(state)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink, FlowState state) {
|
||||
sink.(TemplateInjectionSink).hasState(state)
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node sanitizer) { sanitizer instanceof TemplateInjectionSanitizer }
|
||||
|
||||
predicate isBarrier(DataFlow::Node sanitizer, FlowState state) {
|
||||
sanitizer.(TemplateInjectionSanitizerWithState).hasState(state)
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
any(TemplateInjectionAdditionalTaintStep a).isAdditionalTaintStep(node1, node2)
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(
|
||||
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
|
||||
) {
|
||||
any(TemplateInjectionAdditionalTaintStep a).isAdditionalTaintStep(node1, state1, node2, state2)
|
||||
}
|
||||
}
|
||||
|
||||
/** Tracks server-side template injection (SST) vulnerabilities */
|
||||
module TemplateInjectionFlow = TaintTracking::GlobalWithState<TemplateInjectionFlowConfig>;
|
||||
|
||||
@@ -7,9 +7,11 @@ import semmle.code.java.security.XmlParsers
|
||||
import semmle.code.java.security.XsltInjection
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `XsltInjectionFlow` instead.
|
||||
*
|
||||
* A taint-tracking configuration for unvalidated user input that is used in XSLT transformation.
|
||||
*/
|
||||
class XsltInjectionFlowConfig extends TaintTracking::Configuration {
|
||||
deprecated class XsltInjectionFlowConfig extends TaintTracking::Configuration {
|
||||
XsltInjectionFlowConfig() { this = "XsltInjectionFlowConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
@@ -25,6 +27,28 @@ class XsltInjectionFlowConfig extends TaintTracking::Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for unvalidated user input that is used in XSLT transformation.
|
||||
*/
|
||||
module XsltInjectionFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof XsltInjectionSink }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
any(XsltInjectionAdditionalTaintStep c).step(node1, node2)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks flow from unvalidated user input to XSLT transformation.
|
||||
*/
|
||||
module XsltInjectionFlow = TaintTracking::Global<XsltInjectionFlowConfig>;
|
||||
|
||||
/**
|
||||
* A set of additional taint steps to consider when taint tracking XSLT related data flows.
|
||||
* These steps use data flow logic themselves.
|
||||
@@ -46,22 +70,17 @@ private predicate newTransformerOrTemplatesStep(DataFlow::Node n1, DataFlow::Nod
|
||||
n2.asExpr() = ma and
|
||||
m.getDeclaringType() instanceof TransformerFactory and
|
||||
m.hasName(["newTransformer", "newTemplates"]) and
|
||||
not exists(TransformerFactoryWithSecureProcessingFeatureFlowConfig conf |
|
||||
conf.hasFlowToExpr(ma.getQualifier())
|
||||
)
|
||||
not TransformerFactoryWithSecureProcessingFeatureFlow::flowToExpr(ma.getQualifier())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow configuration for secure processing feature that is enabled on `TransformerFactory`.
|
||||
*/
|
||||
private class TransformerFactoryWithSecureProcessingFeatureFlowConfig extends DataFlow2::Configuration
|
||||
private module TransformerFactoryWithSecureProcessingFeatureFlowConfig implements
|
||||
DataFlow::ConfigSig
|
||||
{
|
||||
TransformerFactoryWithSecureProcessingFeatureFlowConfig() {
|
||||
this = "TransformerFactoryWithSecureProcessingFeatureFlowConfig"
|
||||
}
|
||||
|
||||
override predicate isSource(DataFlow::Node src) {
|
||||
predicate isSource(DataFlow::Node src) {
|
||||
exists(Variable v | v = src.asExpr().(VarAccess).getVariable() |
|
||||
exists(TransformerFactoryFeatureConfig config | config.getQualifier() = v.getAnAccess() |
|
||||
config.enables(configSecureProcessing())
|
||||
@@ -69,16 +88,19 @@ private class TransformerFactoryWithSecureProcessingFeatureFlowConfig extends Da
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodAccess ma |
|
||||
sink.asExpr() = ma.getQualifier() and
|
||||
ma.getMethod().getDeclaringType() instanceof TransformerFactory
|
||||
)
|
||||
}
|
||||
|
||||
override int fieldFlowBranchLimit() { result = 0 }
|
||||
int fieldFlowBranchLimit() { result = 0 }
|
||||
}
|
||||
|
||||
private module TransformerFactoryWithSecureProcessingFeatureFlow =
|
||||
DataFlow::Global<TransformerFactoryWithSecureProcessingFeatureFlowConfig>;
|
||||
|
||||
/** A `ParserConfig` specific to `TransformerFactory`. */
|
||||
private class TransformerFactoryFeatureConfig extends ParserConfig {
|
||||
TransformerFactoryFeatureConfig() {
|
||||
|
||||
@@ -5,8 +5,12 @@ import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.security.regexp.RegexInjection
|
||||
|
||||
/** A taint-tracking configuration for untrusted user input used to construct regular expressions. */
|
||||
class RegexInjectionConfiguration extends TaintTracking::Configuration {
|
||||
/**
|
||||
* DEPRECATED: Use `RegexInjectionFlow` instead.
|
||||
*
|
||||
* A taint-tracking configuration for untrusted user input used to construct regular expressions.
|
||||
*/
|
||||
deprecated class RegexInjectionConfiguration extends TaintTracking::Configuration {
|
||||
RegexInjectionConfiguration() { this = "RegexInjection" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
@@ -15,3 +19,19 @@ class RegexInjectionConfiguration extends TaintTracking::Configuration {
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) { node instanceof RegexInjectionSanitizer }
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for untrusted user input used to construct regular expressions.
|
||||
*/
|
||||
module RegexInjectionConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof RegexInjectionSink }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) { node instanceof RegexInjectionSanitizer }
|
||||
}
|
||||
|
||||
/**
|
||||
* Taint-tracking flow for untrusted user input used to construct regular expressions.
|
||||
*/
|
||||
module RegexInjectionFlow = TaintTracking::Global<RegexInjectionConfig>;
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
|
||||
import java
|
||||
import semmle.code.java.security.JndiInjectionQuery
|
||||
import DataFlow::PathGraph
|
||||
import JndiInjectionFlow::PathGraph
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, JndiInjectionFlowConfig conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
from JndiInjectionFlow::PathNode source, JndiInjectionFlow::PathNode sink
|
||||
where JndiInjectionFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "JNDI lookup might include name from $@.", source.getNode(),
|
||||
"this user input"
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
|
||||
import java
|
||||
import semmle.code.java.security.XsltInjectionQuery
|
||||
import DataFlow::PathGraph
|
||||
import XsltInjectionFlow::PathGraph
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, XsltInjectionFlowConfig conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
from XsltInjectionFlow::PathNode source, XsltInjectionFlow::PathNode sink
|
||||
where XsltInjectionFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "XSLT transformation might include stylesheet from $@.",
|
||||
source.getNode(), "this user input"
|
||||
|
||||
@@ -16,9 +16,11 @@ import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.security.ExternalProcess
|
||||
import semmle.code.java.security.CommandLineQuery
|
||||
import DataFlow::PathGraph
|
||||
import RemoteUserInputToArgumentToExecFlow::PathGraph
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, ArgumentToExec execArg
|
||||
where execTainted(source, sink, execArg)
|
||||
from
|
||||
RemoteUserInputToArgumentToExecFlow::PathNode source,
|
||||
RemoteUserInputToArgumentToExecFlow::PathNode sink, ArgumentToExec execArg
|
||||
where execIsTainted(source, sink, execArg)
|
||||
select execArg, source, sink, "This command line depends on a $@.", source.getNode(),
|
||||
"user-provided value"
|
||||
|
||||
@@ -48,5 +48,5 @@ predicate builtFromUncontrolledConcat(Expr expr) {
|
||||
from StringArgumentToExec argument
|
||||
where
|
||||
builtFromUncontrolledConcat(argument) and
|
||||
not execTainted(_, _, argument)
|
||||
not execIsTainted(_, _, argument)
|
||||
select argument, "Command line is built with string concatenation."
|
||||
|
||||
@@ -48,6 +48,6 @@ where
|
||||
UncontrolledStringBuilderSourceFlow::flow(DataFlow::exprNode(sbv.getToStringCall()), query)
|
||||
)
|
||||
) and
|
||||
not queryTaintedBy(query, _, _)
|
||||
not queryIsTaintedBy(query, _, _)
|
||||
select query, "Query built by concatenation with $@, which may be untrusted.", uncontrolled,
|
||||
"this expression"
|
||||
|
||||
@@ -15,8 +15,9 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.security.SqlInjectionQuery
|
||||
import DataFlow::PathGraph
|
||||
import QueryInjectionFlow::PathGraph
|
||||
|
||||
from QueryInjectionSink query, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where queryTaintedBy(query, source, sink)
|
||||
from
|
||||
QueryInjectionSink query, QueryInjectionFlow::PathNode source, QueryInjectionFlow::PathNode sink
|
||||
where queryIsTaintedBy(query, source, sink)
|
||||
select query, source, sink, "This query depends on a $@.", source.getNode(), "user-provided value"
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
|
||||
import java
|
||||
import semmle.code.java.security.GroovyInjectionQuery
|
||||
import DataFlow::PathGraph
|
||||
import GroovyInjectionFlow::PathGraph
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, GroovyInjectionConfig conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
from GroovyInjectionFlow::PathNode source, GroovyInjectionFlow::PathNode sink
|
||||
where GroovyInjectionFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "Groovy script depends on a $@.", source.getNode(),
|
||||
"user-provided value"
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
|
||||
import java
|
||||
import semmle.code.java.security.JexlInjectionQuery
|
||||
import DataFlow::PathGraph
|
||||
import JexlInjectionFlow::PathGraph
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, JexlInjectionConfig conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
from JexlInjectionFlow::PathNode source, JexlInjectionFlow::PathNode sink
|
||||
where JexlInjectionFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "JEXL expression depends on a $@.", source.getNode(),
|
||||
"user-provided value"
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
|
||||
import java
|
||||
import semmle.code.java.security.MvelInjectionQuery
|
||||
import DataFlow::PathGraph
|
||||
import MvelInjectionFlow::PathGraph
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, MvelInjectionFlowConfig conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
from MvelInjectionFlow::PathNode source, MvelInjectionFlow::PathNode sink
|
||||
where MvelInjectionFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "MVEL expression depends on a $@.", source.getNode(),
|
||||
"user-provided value"
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
import java
|
||||
import semmle.code.java.security.SpelInjectionQuery
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import DataFlow::PathGraph
|
||||
import SpelInjectionFlow::PathGraph
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, SpelInjectionConfig conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
from SpelInjectionFlow::PathNode source, SpelInjectionFlow::PathNode sink
|
||||
where SpelInjectionFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "SpEL expression depends on a $@.", source.getNode(),
|
||||
"user-provided value"
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
|
||||
import java
|
||||
import semmle.code.java.security.TemplateInjectionQuery
|
||||
import DataFlow::PathGraph
|
||||
import TemplateInjectionFlow::PathGraph
|
||||
|
||||
from TemplateInjectionFlowConfig config, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where config.hasFlowPath(source, sink)
|
||||
from TemplateInjectionFlow::PathNode source, TemplateInjectionFlow::PathNode sink
|
||||
where TemplateInjectionFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "Template, which may contain code, depends on a $@.",
|
||||
source.getNode(), "user-provided value"
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
|
||||
import java
|
||||
import semmle.code.java.security.regexp.RegexInjectionQuery
|
||||
import DataFlow::PathGraph
|
||||
import RegexInjectionFlow::PathGraph
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, RegexInjectionConfiguration c
|
||||
where c.hasFlowPath(source, sink)
|
||||
from RegexInjectionFlow::PathNode source, RegexInjectionFlow::PathNode sink
|
||||
where RegexInjectionFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "This regular expression is constructed from a $@.",
|
||||
source.getNode(), "user-provided value"
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
|
||||
import java
|
||||
import semmle.code.java.security.OgnlInjectionQuery
|
||||
import DataFlow::PathGraph
|
||||
import OgnlInjectionFlow::PathGraph
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, OgnlInjectionFlowConfig conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
from OgnlInjectionFlow::PathNode source, OgnlInjectionFlow::PathNode sink
|
||||
where OgnlInjectionFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "OGNL Expression Language statement depends on a $@.",
|
||||
source.getNode(), "user-provided value"
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
import java
|
||||
import semmle.code.java.Diagnostics
|
||||
|
||||
extensible predicate extractorInformationSkipKey(string key);
|
||||
|
||||
predicate compilationInfo(string key, int value) {
|
||||
exists(Compilation c, string infoKey |
|
||||
key = infoKey + ": " + c.getInfo(infoKey) and
|
||||
@@ -85,13 +87,16 @@ predicate extractorTotalDiagnostics(string key, int value) {
|
||||
|
||||
from string key, int value
|
||||
where
|
||||
compilationInfo(key, value) or
|
||||
fileCount(key, value) or
|
||||
fileCountByExtension(key, value) or
|
||||
totalNumberOfLines(key, value) or
|
||||
numberOfLinesOfCode(key, value) or
|
||||
totalNumberOfLinesByExtension(key, value) or
|
||||
numberOfLinesOfCodeByExtension(key, value) or
|
||||
extractorDiagnostics(key, value) or
|
||||
extractorTotalDiagnostics(key, value)
|
||||
not extractorInformationSkipKey(key) and
|
||||
(
|
||||
compilationInfo(key, value) or
|
||||
fileCount(key, value) or
|
||||
fileCountByExtension(key, value) or
|
||||
totalNumberOfLines(key, value) or
|
||||
numberOfLinesOfCode(key, value) or
|
||||
totalNumberOfLinesByExtension(key, value) or
|
||||
numberOfLinesOfCodeByExtension(key, value) or
|
||||
extractorDiagnostics(key, value) or
|
||||
extractorTotalDiagnostics(key, value)
|
||||
)
|
||||
select key, value
|
||||
|
||||
5
java/ql/src/Telemetry/ExtractorInformation.yml
Normal file
5
java/ql/src/Telemetry/ExtractorInformation.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/java-queries
|
||||
extensible: extractorInformationSkipKey
|
||||
data: []
|
||||
@@ -17,10 +17,12 @@ import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.security.ExternalProcess
|
||||
import semmle.code.java.security.CommandLineQuery
|
||||
import JSchOSInjection
|
||||
import DataFlow::PathGraph
|
||||
import RemoteUserInputToArgumentToExecFlow::PathGraph
|
||||
|
||||
// This is a clone of query `java/command-line-injection` that also includes experimental sinks.
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, ArgumentToExec execArg
|
||||
where execTainted(source, sink, execArg)
|
||||
from
|
||||
RemoteUserInputToArgumentToExecFlow::PathNode source,
|
||||
RemoteUserInputToArgumentToExecFlow::PathNode sink, ArgumentToExec execArg
|
||||
where execIsTainted(source, sink, execArg)
|
||||
select execArg, source, sink, "This command line depends on a $@.", source.getNode(),
|
||||
"user-provided value"
|
||||
|
||||
@@ -10,3 +10,5 @@ dependencies:
|
||||
codeql/java-all: ${workspace}
|
||||
codeql/suite-helpers: ${workspace}
|
||||
codeql/util: ${workspace}
|
||||
dataExtensions:
|
||||
- Telemetry/ExtractorInformation.yml
|
||||
|
||||
@@ -9,7 +9,7 @@ class HasJndiInjectionTest extends InlineExpectationsTest {
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
tag = "hasJndiInjection" and
|
||||
exists(DataFlow::Node sink, JndiInjectionFlowConfig conf | conf.hasFlowTo(sink) |
|
||||
exists(DataFlow::Node sink | JndiInjectionFlow::flowTo(sink) |
|
||||
sink.getLocation() = location and
|
||||
element = sink.toString() and
|
||||
value = ""
|
||||
|
||||
@@ -11,7 +11,7 @@ class HasXsltInjectionTest extends InlineExpectationsTest {
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
tag = "hasXsltInjection" and
|
||||
exists(DataFlow::Node sink, XsltInjectionFlowConfig conf | conf.hasFlowTo(sink) |
|
||||
exists(DataFlow::Node sink | XsltInjectionFlow::flowTo(sink) |
|
||||
sink.getLocation() = location and
|
||||
element = sink.toString() and
|
||||
value = ""
|
||||
|
||||
@@ -11,7 +11,7 @@ class HasGroovyInjectionTest extends InlineExpectationsTest {
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
tag = "hasGroovyInjection" and
|
||||
exists(DataFlow::Node sink, GroovyInjectionConfig conf | conf.hasFlowTo(sink) |
|
||||
exists(DataFlow::Node sink | GroovyInjectionFlow::flowTo(sink) |
|
||||
sink.getLocation() = location and
|
||||
element = sink.toString() and
|
||||
value = ""
|
||||
|
||||
@@ -9,7 +9,7 @@ class JexlInjectionTest extends InlineExpectationsTest {
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
tag = "hasJexlInjection" and
|
||||
exists(DataFlow::Node sink, JexlInjectionConfig conf | conf.hasFlowTo(sink) |
|
||||
exists(DataFlow::Node sink | JexlInjectionFlow::flowTo(sink) |
|
||||
sink.getLocation() = location and
|
||||
element = sink.toString() and
|
||||
value = ""
|
||||
|
||||
@@ -11,7 +11,7 @@ class HasMvelInjectionTest extends InlineExpectationsTest {
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
tag = "hasMvelInjection" and
|
||||
exists(DataFlow::Node sink, MvelInjectionFlowConfig conf | conf.hasFlowTo(sink) |
|
||||
exists(DataFlow::Node sink | MvelInjectionFlow::flowTo(sink) |
|
||||
sink.getLocation() = location and
|
||||
element = sink.toString() and
|
||||
value = ""
|
||||
|
||||
@@ -11,7 +11,7 @@ class HasSpelInjectionTest extends InlineExpectationsTest {
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
tag = "hasSpelInjection" and
|
||||
exists(DataFlow::Node sink, SpelInjectionConfig conf | conf.hasFlowTo(sink) |
|
||||
exists(DataFlow::Node sink | SpelInjectionFlow::flowTo(sink) |
|
||||
sink.getLocation() = location and
|
||||
element = sink.toString() and
|
||||
value = ""
|
||||
|
||||
@@ -9,7 +9,7 @@ class TemplateInjectionTest extends InlineExpectationsTest {
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
tag = "hasTemplateInjection" and
|
||||
exists(DataFlow::Node sink, TemplateInjectionFlowConfig conf | conf.hasFlowTo(sink) |
|
||||
exists(DataFlow::Node sink | TemplateInjectionFlow::flowTo(sink) |
|
||||
sink.getLocation() = location and
|
||||
element = sink.toString() and
|
||||
value = ""
|
||||
|
||||
@@ -9,7 +9,7 @@ class RegexInjectionTest extends InlineExpectationsTest {
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
tag = "hasRegexInjection" and
|
||||
exists(DataFlow::PathNode sink, RegexInjectionConfiguration c | c.hasFlowPath(_, sink) |
|
||||
exists(RegexInjectionFlow::PathNode sink | RegexInjectionFlow::flowPath(_, sink) |
|
||||
location = sink.getNode().getLocation() and
|
||||
element = sink.getNode().toString() and
|
||||
value = ""
|
||||
|
||||
@@ -9,7 +9,7 @@ class OgnlInjectionTest extends InlineExpectationsTest {
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
tag = "hasOgnlInjection" and
|
||||
exists(DataFlow::Node sink, OgnlInjectionFlowConfig conf | conf.hasFlowTo(sink) |
|
||||
exists(DataFlow::Node sink | OgnlInjectionFlow::flowTo(sink) |
|
||||
sink.getLocation() = location and
|
||||
element = sink.toString() and
|
||||
value = ""
|
||||
|
||||
@@ -122,6 +122,14 @@ class Configuration extends TaintTracking::Configuration {
|
||||
TaintedUrlSuffix::step(src, trg, TaintedUrlSuffix::label(), DataFlow::FlowLabel::taint()) and
|
||||
inlbl = TaintedUrlSuffix::label() and
|
||||
outlbl = prefixLabel()
|
||||
or
|
||||
exists(DataFlow::FunctionNode callback, DataFlow::Node arg |
|
||||
any(JQuery::MethodCall c).interpretsArgumentAsHtml(arg) and
|
||||
callback = arg.getABoundFunctionValue(_) and
|
||||
src = callback.getReturnNode() and
|
||||
trg = callback and
|
||||
inlbl = outlbl
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@ DataFlow::InvokeNode tlsInvocation() {
|
||||
or
|
||||
result = DataFlow::moduleMember("https", "Agent").getAnInstantiation()
|
||||
or
|
||||
result = DataFlow::moduleMember("https", "createServer").getACall()
|
||||
or
|
||||
exists(DataFlow::NewNode new |
|
||||
new = DataFlow::moduleMember("tls", "TLSSocket").getAnInstantiation()
|
||||
|
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The `DisablingCertificateValidation.ql` query has been updated to check `createServer` from `https` for disabled certificate validation.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Improved the model of jQuery to account for XSS sinks where the HTML string
|
||||
is provided via a callback. This may lead to more results for the `js/xss` query.
|
||||
@@ -431,6 +431,11 @@ nodes
|
||||
| jquery.js:34:5:34:25 | '<b>' + ... '</b>' |
|
||||
| jquery.js:34:5:34:25 | '<b>' + ... '</b>' |
|
||||
| jquery.js:34:13:34:16 | hash |
|
||||
| jquery.js:36:25:36:31 | tainted |
|
||||
| jquery.js:36:25:36:31 | tainted |
|
||||
| jquery.js:37:25:37:37 | () => tainted |
|
||||
| jquery.js:37:25:37:37 | () => tainted |
|
||||
| jquery.js:37:31:37:37 | tainted |
|
||||
| json-stringify.jsx:5:9:5:36 | locale |
|
||||
| json-stringify.jsx:5:9:5:36 | locale |
|
||||
| json-stringify.jsx:5:18:5:36 | req.param("locale") |
|
||||
@@ -1512,6 +1517,9 @@ edges
|
||||
| express.js:7:15:7:33 | req.param("wobble") | express.js:7:15:7:33 | req.param("wobble") |
|
||||
| jquery.js:2:7:2:40 | tainted | jquery.js:7:20:7:26 | tainted |
|
||||
| jquery.js:2:7:2:40 | tainted | jquery.js:8:28:8:34 | tainted |
|
||||
| jquery.js:2:7:2:40 | tainted | jquery.js:36:25:36:31 | tainted |
|
||||
| jquery.js:2:7:2:40 | tainted | jquery.js:36:25:36:31 | tainted |
|
||||
| jquery.js:2:7:2:40 | tainted | jquery.js:37:31:37:37 | tainted |
|
||||
| jquery.js:2:17:2:40 | documen ... .search | jquery.js:2:7:2:40 | tainted |
|
||||
| jquery.js:2:17:2:40 | documen ... .search | jquery.js:2:7:2:40 | tainted |
|
||||
| jquery.js:7:20:7:26 | tainted | jquery.js:7:5:7:34 | "<div i ... + "\\">" |
|
||||
@@ -1565,6 +1573,8 @@ edges
|
||||
| jquery.js:28:5:28:26 | window. ... .search | jquery.js:28:5:28:43 | window. ... ?', '') |
|
||||
| jquery.js:34:13:34:16 | hash | jquery.js:34:5:34:25 | '<b>' + ... '</b>' |
|
||||
| jquery.js:34:13:34:16 | hash | jquery.js:34:5:34:25 | '<b>' + ... '</b>' |
|
||||
| jquery.js:37:31:37:37 | tainted | jquery.js:37:25:37:37 | () => tainted |
|
||||
| jquery.js:37:31:37:37 | tainted | jquery.js:37:25:37:37 | () => tainted |
|
||||
| json-stringify.jsx:5:9:5:36 | locale | json-stringify.jsx:11:51:11:56 | locale |
|
||||
| json-stringify.jsx:5:9:5:36 | locale | json-stringify.jsx:19:56:19:61 | locale |
|
||||
| json-stringify.jsx:5:9:5:36 | locale | json-stringify.jsx:31:55:31:60 | locale |
|
||||
@@ -2355,6 +2365,8 @@ edges
|
||||
| jquery.js:27:5:27:25 | hash.re ... #', '') | jquery.js:18:14:18:33 | window.location.hash | jquery.js:27:5:27:25 | hash.re ... #', '') | Cross-site scripting vulnerability due to $@. | jquery.js:18:14:18:33 | window.location.hash | user-provided value |
|
||||
| jquery.js:28:5:28:43 | window. ... ?', '') | jquery.js:28:5:28:26 | window. ... .search | jquery.js:28:5:28:43 | window. ... ?', '') | Cross-site scripting vulnerability due to $@. | jquery.js:28:5:28:26 | window. ... .search | user-provided value |
|
||||
| jquery.js:34:5:34:25 | '<b>' + ... '</b>' | jquery.js:18:14:18:33 | window.location.hash | jquery.js:34:5:34:25 | '<b>' + ... '</b>' | Cross-site scripting vulnerability due to $@. | jquery.js:18:14:18:33 | window.location.hash | user-provided value |
|
||||
| jquery.js:36:25:36:31 | tainted | jquery.js:2:17:2:40 | documen ... .search | jquery.js:36:25:36:31 | tainted | Cross-site scripting vulnerability due to $@. | jquery.js:2:17:2:40 | documen ... .search | user-provided value |
|
||||
| jquery.js:37:25:37:37 | () => tainted | jquery.js:2:17:2:40 | documen ... .search | jquery.js:37:25:37:37 | () => tainted | Cross-site scripting vulnerability due to $@. | jquery.js:2:17:2:40 | documen ... .search | user-provided value |
|
||||
| json-stringify.jsx:31:40:31:61 | JSON.st ... locale) | json-stringify.jsx:5:18:5:36 | req.param("locale") | json-stringify.jsx:31:40:31:61 | JSON.st ... locale) | Cross-site scripting vulnerability due to $@. | json-stringify.jsx:5:18:5:36 | req.param("locale") | user-provided value |
|
||||
| json-stringify.jsx:35:40:35:61 | JSON.st ... jsonLD) | json-stringify.jsx:5:18:5:36 | req.param("locale") | json-stringify.jsx:35:40:35:61 | JSON.st ... jsonLD) | Cross-site scripting vulnerability due to $@. | json-stringify.jsx:5:18:5:36 | req.param("locale") | user-provided value |
|
||||
| jwt-server.js:11:19:11:29 | decoded.foo | jwt-server.js:7:17:7:35 | req.param("wobble") | jwt-server.js:11:19:11:29 | decoded.foo | Cross-site scripting vulnerability due to $@. | jwt-server.js:7:17:7:35 | req.param("wobble") | user-provided value |
|
||||
|
||||
@@ -431,6 +431,11 @@ nodes
|
||||
| jquery.js:34:5:34:25 | '<b>' + ... '</b>' |
|
||||
| jquery.js:34:5:34:25 | '<b>' + ... '</b>' |
|
||||
| jquery.js:34:13:34:16 | hash |
|
||||
| jquery.js:36:25:36:31 | tainted |
|
||||
| jquery.js:36:25:36:31 | tainted |
|
||||
| jquery.js:37:25:37:37 | () => tainted |
|
||||
| jquery.js:37:25:37:37 | () => tainted |
|
||||
| jquery.js:37:31:37:37 | tainted |
|
||||
| json-stringify.jsx:5:9:5:36 | locale |
|
||||
| json-stringify.jsx:5:9:5:36 | locale |
|
||||
| json-stringify.jsx:5:18:5:36 | req.param("locale") |
|
||||
@@ -1562,6 +1567,9 @@ edges
|
||||
| express.js:7:15:7:33 | req.param("wobble") | express.js:7:15:7:33 | req.param("wobble") |
|
||||
| jquery.js:2:7:2:40 | tainted | jquery.js:7:20:7:26 | tainted |
|
||||
| jquery.js:2:7:2:40 | tainted | jquery.js:8:28:8:34 | tainted |
|
||||
| jquery.js:2:7:2:40 | tainted | jquery.js:36:25:36:31 | tainted |
|
||||
| jquery.js:2:7:2:40 | tainted | jquery.js:36:25:36:31 | tainted |
|
||||
| jquery.js:2:7:2:40 | tainted | jquery.js:37:31:37:37 | tainted |
|
||||
| jquery.js:2:17:2:40 | documen ... .search | jquery.js:2:7:2:40 | tainted |
|
||||
| jquery.js:2:17:2:40 | documen ... .search | jquery.js:2:7:2:40 | tainted |
|
||||
| jquery.js:7:20:7:26 | tainted | jquery.js:7:5:7:34 | "<div i ... + "\\">" |
|
||||
@@ -1615,6 +1623,8 @@ edges
|
||||
| jquery.js:28:5:28:26 | window. ... .search | jquery.js:28:5:28:43 | window. ... ?', '') |
|
||||
| jquery.js:34:13:34:16 | hash | jquery.js:34:5:34:25 | '<b>' + ... '</b>' |
|
||||
| jquery.js:34:13:34:16 | hash | jquery.js:34:5:34:25 | '<b>' + ... '</b>' |
|
||||
| jquery.js:37:31:37:37 | tainted | jquery.js:37:25:37:37 | () => tainted |
|
||||
| jquery.js:37:31:37:37 | tainted | jquery.js:37:25:37:37 | () => tainted |
|
||||
| json-stringify.jsx:5:9:5:36 | locale | json-stringify.jsx:11:51:11:56 | locale |
|
||||
| json-stringify.jsx:5:9:5:36 | locale | json-stringify.jsx:19:56:19:61 | locale |
|
||||
| json-stringify.jsx:5:9:5:36 | locale | json-stringify.jsx:31:55:31:60 | locale |
|
||||
|
||||
@@ -32,4 +32,7 @@ function test() {
|
||||
$(hash + 'blah'); // OK
|
||||
$('blah' + hash); // OK - does not start with '<'
|
||||
$('<b>' + hash + '</b>'); // NOT OK
|
||||
|
||||
$('#foo').replaceWith(tainted); // NOT OK
|
||||
$('#foo').replaceWith(() => tainted); // NOT OK
|
||||
}
|
||||
|
||||
@@ -9,3 +9,4 @@
|
||||
| tst.js:45:2:45:28 | rejectU ... !!false | Disabling certificate validation is strongly discouraged. |
|
||||
| tst.js:48:2:48:26 | rejectU ... : !true | Disabling certificate validation is strongly discouraged. |
|
||||
| tst.js:74:9:74:33 | rejectU ... : false | Disabling certificate validation is strongly discouraged. |
|
||||
| tst.js:80:5:80:29 | rejectU ... : false | Disabling certificate validation is strongly discouraged. |
|
||||
|
||||
@@ -74,4 +74,8 @@ function getSomeunsafeOptions() {
|
||||
rejectUnauthorized: false // NOT OK
|
||||
}
|
||||
}
|
||||
new https.Agent(getSomeunsafeOptions());
|
||||
new https.Agent(getSomeunsafeOptions());
|
||||
|
||||
https.createServer({
|
||||
rejectUnauthorized: false // NOT OK
|
||||
});
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @name Unsafe usage of v1 version of Azure Storage client-side encryption.
|
||||
* @description Using version v1 of Azure Storage client-side encryption is insecure, and may enable an attacker to decrypt encrypted data
|
||||
* @kind problem
|
||||
* @kind path-problem
|
||||
* @tags security
|
||||
* experimental
|
||||
* cryptography
|
||||
@@ -12,80 +12,145 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.dataflow.new.DataFlow
|
||||
import semmle.python.ApiGraphs
|
||||
|
||||
predicate isUnsafeClientSideAzureStorageEncryptionViaAttributes(Call call, AttrNode node) {
|
||||
exists(
|
||||
API::Node n, API::Node n2, Attribute a, AssignStmt astmt, API::Node uploadBlob,
|
||||
ControlFlowNode ctrlFlowNode, string s
|
||||
|
|
||||
s in ["key_encryption_key", "key_resolver_function"] and
|
||||
n =
|
||||
API::moduleImport("azure")
|
||||
.getMember("storage")
|
||||
.getMember("blob")
|
||||
.getMember("BlobClient")
|
||||
.getReturn()
|
||||
.getMember(s) and
|
||||
n2 =
|
||||
API::moduleImport("azure")
|
||||
.getMember("storage")
|
||||
.getMember("blob")
|
||||
.getMember("BlobClient")
|
||||
.getReturn()
|
||||
.getMember("upload_blob") and
|
||||
n.getAValueReachableFromSource().asExpr() = a and
|
||||
astmt.getATarget() = a and
|
||||
a.getAFlowNode() = node and
|
||||
uploadBlob =
|
||||
API::moduleImport("azure")
|
||||
.getMember("storage")
|
||||
.getMember("blob")
|
||||
.getMember("BlobClient")
|
||||
.getReturn()
|
||||
.getMember("upload_blob") and
|
||||
uploadBlob.getACall().asExpr() = call and
|
||||
ctrlFlowNode = call.getAFlowNode() and
|
||||
node.strictlyReaches(ctrlFlowNode) and
|
||||
node != ctrlFlowNode and
|
||||
not exists(
|
||||
AssignStmt astmt2, Attribute a2, AttrNode encryptionVersionSet, StrConst uc,
|
||||
API::Node encryptionVersion
|
||||
|
|
||||
uc = astmt2.getValue() and
|
||||
uc.getText() in ["'2.0'", "2.0"] and
|
||||
encryptionVersion =
|
||||
API::moduleImport("azure")
|
||||
.getMember("storage")
|
||||
.getMember("blob")
|
||||
.getMember("BlobClient")
|
||||
.getReturn()
|
||||
.getMember("encryption_version") and
|
||||
encryptionVersion.getAValueReachableFromSource().asExpr() = a2 and
|
||||
astmt2.getATarget() = a2 and
|
||||
a2.getAFlowNode() = encryptionVersionSet and
|
||||
encryptionVersionSet.strictlyReaches(ctrlFlowNode)
|
||||
)
|
||||
)
|
||||
API::Node getBlobServiceClient(boolean isSource) {
|
||||
isSource = true and
|
||||
result =
|
||||
API::moduleImport("azure")
|
||||
.getMember("storage")
|
||||
.getMember("blob")
|
||||
.getMember("BlobServiceClient")
|
||||
.getReturn()
|
||||
or
|
||||
isSource = true and
|
||||
result =
|
||||
API::moduleImport("azure")
|
||||
.getMember("storage")
|
||||
.getMember("blob")
|
||||
.getMember("BlobServiceClient")
|
||||
.getMember("from_connection_string")
|
||||
.getReturn()
|
||||
}
|
||||
|
||||
predicate isUnsafeClientSideAzureStorageEncryptionViaObjectCreation(Call call, ControlFlowNode node) {
|
||||
exists(API::Node c, string s, Keyword k | k.getAFlowNode() = node |
|
||||
c.getACall().asExpr() = call and
|
||||
c = API::moduleImport("azure").getMember("storage").getMember("blob").getMember(s) and
|
||||
s in ["ContainerClient", "BlobClient", "BlobServiceClient"] and
|
||||
k.getArg() = "key_encryption_key" and
|
||||
k = call.getANamedArg() and
|
||||
not k.getValue() instanceof None and
|
||||
not exists(Keyword k2 | k2 = call.getANamedArg() |
|
||||
k2.getArg() = "encryption_version" and
|
||||
k2.getValue().(StrConst).getText() in ["'2.0'", "2.0"]
|
||||
)
|
||||
)
|
||||
API::CallNode getTransitionToContainerClient() {
|
||||
result = getBlobServiceClient(_).getMember("get_container_client").getACall()
|
||||
or
|
||||
result = getBlobClient(_).getMember("_get_container_client").getACall()
|
||||
}
|
||||
|
||||
from Call call, ControlFlowNode node
|
||||
where
|
||||
isUnsafeClientSideAzureStorageEncryptionViaAttributes(call, node) or
|
||||
isUnsafeClientSideAzureStorageEncryptionViaObjectCreation(call, node)
|
||||
select node, "Unsafe usage of v1 version of Azure Storage client-side encryption."
|
||||
API::Node getContainerClient(boolean isSource) {
|
||||
isSource = false and
|
||||
result = getTransitionToContainerClient().getReturn()
|
||||
or
|
||||
isSource = true and
|
||||
result =
|
||||
API::moduleImport("azure")
|
||||
.getMember("storage")
|
||||
.getMember("blob")
|
||||
.getMember("ContainerClient")
|
||||
.getReturn()
|
||||
or
|
||||
isSource = true and
|
||||
result =
|
||||
API::moduleImport("azure")
|
||||
.getMember("storage")
|
||||
.getMember("blob")
|
||||
.getMember("ContainerClient")
|
||||
.getMember(["from_connection_string", "from_container_url"])
|
||||
.getReturn()
|
||||
}
|
||||
|
||||
API::CallNode getTransitionToBlobClient() {
|
||||
result = [getBlobServiceClient(_), getContainerClient(_)].getMember("get_blob_client").getACall()
|
||||
}
|
||||
|
||||
API::Node getBlobClient(boolean isSource) {
|
||||
isSource = false and
|
||||
result = getTransitionToBlobClient().getReturn()
|
||||
or
|
||||
isSource = true and
|
||||
result =
|
||||
API::moduleImport("azure")
|
||||
.getMember("storage")
|
||||
.getMember("blob")
|
||||
.getMember("BlobClient")
|
||||
.getReturn()
|
||||
or
|
||||
isSource = true and
|
||||
result =
|
||||
API::moduleImport("azure")
|
||||
.getMember("storage")
|
||||
.getMember("blob")
|
||||
.getMember("BlobClient")
|
||||
.getMember(["from_connection_string", "from_blob_url"])
|
||||
.getReturn()
|
||||
}
|
||||
|
||||
API::Node anyClient(boolean isSource) {
|
||||
result in [getBlobServiceClient(isSource), getContainerClient(isSource), getBlobClient(isSource)]
|
||||
}
|
||||
|
||||
newtype TAzureFlowState =
|
||||
MkUsesV1Encryption() or
|
||||
MkUsesNoEncryption()
|
||||
|
||||
module AzureBlobClientConfig implements DataFlow::StateConfigSig {
|
||||
class FlowState = TAzureFlowState;
|
||||
|
||||
predicate isSource(DataFlow::Node node, FlowState state) {
|
||||
state = MkUsesNoEncryption() and
|
||||
node = anyClient(true).asSource()
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node node, FlowState state) {
|
||||
exists(state) and
|
||||
exists(DataFlow::AttrWrite attr |
|
||||
node = anyClient(_).getAValueReachableFromSource() and
|
||||
attr.accesses(node, "encryption_version") and
|
||||
attr.getValue().asExpr().(StrConst).getText() in ["'2.0'", "2.0"]
|
||||
)
|
||||
or
|
||||
// small optimization to block flow with no encryption out of the post-update node
|
||||
// for the attribute assignment.
|
||||
isAdditionalFlowStep(_, MkUsesNoEncryption(), node, MkUsesV1Encryption()) and
|
||||
state = MkUsesNoEncryption()
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
exists(DataFlow::MethodCallNode call |
|
||||
call in [getTransitionToContainerClient(), getTransitionToBlobClient()] and
|
||||
node1 = call.getObject() and
|
||||
node2 = call
|
||||
)
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(
|
||||
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
|
||||
) {
|
||||
node1 = node2.(DataFlow::PostUpdateNode).getPreUpdateNode() and
|
||||
state1 = MkUsesNoEncryption() and
|
||||
state2 = MkUsesV1Encryption() and
|
||||
exists(DataFlow::AttrWrite attr |
|
||||
node1 = anyClient(_).getAValueReachableFromSource() and
|
||||
attr.accesses(node1, ["key_encryption_key", "key_resolver_function"])
|
||||
)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node node, FlowState state) {
|
||||
state = MkUsesV1Encryption() and
|
||||
exists(DataFlow::MethodCallNode call |
|
||||
call = getBlobClient(_).getMember("upload_blob").getACall() and
|
||||
node = call.getObject()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module AzureBlobClient = DataFlow::GlobalWithState<AzureBlobClientConfig>;
|
||||
|
||||
import AzureBlobClient::PathGraph
|
||||
|
||||
from AzureBlobClient::PathNode source, AzureBlobClient::PathNode sink
|
||||
where AzureBlobClient::flowPath(source, sink)
|
||||
select sink, source, sink, "Unsafe usage of v1 version of Azure Storage client-side encryption"
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
edges
|
||||
| test.py:0:0:0:0 | ModuleVariableNode for test.BSC | test.py:7:19:7:21 | ControlFlowNode for BSC |
|
||||
| test.py:0:0:0:0 | ModuleVariableNode for test.BSC | test.py:35:19:35:21 | ControlFlowNode for BSC |
|
||||
| test.py:0:0:0:0 | ModuleVariableNode for test.BSC | test.py:66:19:66:21 | ControlFlowNode for BSC |
|
||||
| test.py:3:1:3:3 | GSSA Variable BSC | test.py:0:0:0:0 | ModuleVariableNode for test.BSC |
|
||||
| test.py:3:7:3:51 | ControlFlowNode for Attribute() | test.py:3:1:3:3 | GSSA Variable BSC |
|
||||
| test.py:7:19:7:21 | ControlFlowNode for BSC | test.py:8:5:8:15 | ControlFlowNode for blob_client |
|
||||
| test.py:8:5:8:15 | ControlFlowNode for blob_client | test.py:9:5:9:15 | ControlFlowNode for blob_client |
|
||||
| test.py:9:5:9:15 | ControlFlowNode for blob_client | test.py:9:5:9:15 | [post] ControlFlowNode for blob_client |
|
||||
| test.py:9:5:9:15 | [post] ControlFlowNode for blob_client | test.py:11:9:11:19 | ControlFlowNode for blob_client |
|
||||
| test.py:15:27:15:71 | ControlFlowNode for Attribute() | test.py:16:5:16:23 | ControlFlowNode for blob_service_client |
|
||||
| test.py:16:5:16:23 | ControlFlowNode for blob_service_client | test.py:17:5:17:23 | ControlFlowNode for blob_service_client |
|
||||
| test.py:17:5:17:23 | ControlFlowNode for blob_service_client | test.py:17:5:17:23 | [post] ControlFlowNode for blob_service_client |
|
||||
| test.py:17:5:17:23 | [post] ControlFlowNode for blob_service_client | test.py:21:9:21:19 | ControlFlowNode for blob_client |
|
||||
| test.py:25:24:25:66 | ControlFlowNode for Attribute() | test.py:26:5:26:20 | ControlFlowNode for container_client |
|
||||
| test.py:26:5:26:20 | ControlFlowNode for container_client | test.py:27:5:27:20 | ControlFlowNode for container_client |
|
||||
| test.py:27:5:27:20 | ControlFlowNode for container_client | test.py:27:5:27:20 | [post] ControlFlowNode for container_client |
|
||||
| test.py:27:5:27:20 | [post] ControlFlowNode for container_client | test.py:31:9:31:19 | ControlFlowNode for blob_client |
|
||||
| test.py:35:19:35:21 | ControlFlowNode for BSC | test.py:36:5:36:15 | ControlFlowNode for blob_client |
|
||||
| test.py:36:5:36:15 | ControlFlowNode for blob_client | test.py:37:5:37:15 | ControlFlowNode for blob_client |
|
||||
| test.py:37:5:37:15 | ControlFlowNode for blob_client | test.py:37:5:37:15 | [post] ControlFlowNode for blob_client |
|
||||
| test.py:37:5:37:15 | [post] ControlFlowNode for blob_client | test.py:43:9:43:19 | ControlFlowNode for blob_client |
|
||||
| test.py:66:19:66:21 | ControlFlowNode for BSC | test.py:67:5:67:15 | ControlFlowNode for blob_client |
|
||||
| test.py:67:5:67:15 | ControlFlowNode for blob_client | test.py:68:5:68:15 | ControlFlowNode for blob_client |
|
||||
| test.py:68:5:68:15 | ControlFlowNode for blob_client | test.py:68:5:68:15 | [post] ControlFlowNode for blob_client |
|
||||
| test.py:68:5:68:15 | [post] ControlFlowNode for blob_client | test.py:69:12:69:22 | ControlFlowNode for blob_client |
|
||||
| test.py:69:12:69:22 | ControlFlowNode for blob_client | test.py:73:10:73:33 | ControlFlowNode for get_unsafe_blob_client() |
|
||||
| test.py:73:10:73:33 | ControlFlowNode for get_unsafe_blob_client() | test.py:75:9:75:10 | ControlFlowNode for bc |
|
||||
nodes
|
||||
| test.py:0:0:0:0 | ModuleVariableNode for test.BSC | semmle.label | ModuleVariableNode for test.BSC |
|
||||
| test.py:3:1:3:3 | GSSA Variable BSC | semmle.label | GSSA Variable BSC |
|
||||
| test.py:3:7:3:51 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| test.py:7:19:7:21 | ControlFlowNode for BSC | semmle.label | ControlFlowNode for BSC |
|
||||
| test.py:8:5:8:15 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client |
|
||||
| test.py:9:5:9:15 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client |
|
||||
| test.py:9:5:9:15 | [post] ControlFlowNode for blob_client | semmle.label | [post] ControlFlowNode for blob_client |
|
||||
| test.py:11:9:11:19 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client |
|
||||
| test.py:15:27:15:71 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| test.py:16:5:16:23 | ControlFlowNode for blob_service_client | semmle.label | ControlFlowNode for blob_service_client |
|
||||
| test.py:17:5:17:23 | ControlFlowNode for blob_service_client | semmle.label | ControlFlowNode for blob_service_client |
|
||||
| test.py:17:5:17:23 | [post] ControlFlowNode for blob_service_client | semmle.label | [post] ControlFlowNode for blob_service_client |
|
||||
| test.py:21:9:21:19 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client |
|
||||
| test.py:25:24:25:66 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| test.py:26:5:26:20 | ControlFlowNode for container_client | semmle.label | ControlFlowNode for container_client |
|
||||
| test.py:27:5:27:20 | ControlFlowNode for container_client | semmle.label | ControlFlowNode for container_client |
|
||||
| test.py:27:5:27:20 | [post] ControlFlowNode for container_client | semmle.label | [post] ControlFlowNode for container_client |
|
||||
| test.py:31:9:31:19 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client |
|
||||
| test.py:35:19:35:21 | ControlFlowNode for BSC | semmle.label | ControlFlowNode for BSC |
|
||||
| test.py:36:5:36:15 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client |
|
||||
| test.py:37:5:37:15 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client |
|
||||
| test.py:37:5:37:15 | [post] ControlFlowNode for blob_client | semmle.label | [post] ControlFlowNode for blob_client |
|
||||
| test.py:43:9:43:19 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client |
|
||||
| test.py:66:19:66:21 | ControlFlowNode for BSC | semmle.label | ControlFlowNode for BSC |
|
||||
| test.py:67:5:67:15 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client |
|
||||
| test.py:68:5:68:15 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client |
|
||||
| test.py:68:5:68:15 | [post] ControlFlowNode for blob_client | semmle.label | [post] ControlFlowNode for blob_client |
|
||||
| test.py:69:12:69:22 | ControlFlowNode for blob_client | semmle.label | ControlFlowNode for blob_client |
|
||||
| test.py:73:10:73:33 | ControlFlowNode for get_unsafe_blob_client() | semmle.label | ControlFlowNode for get_unsafe_blob_client() |
|
||||
| test.py:75:9:75:10 | ControlFlowNode for bc | semmle.label | ControlFlowNode for bc |
|
||||
subpaths
|
||||
#select
|
||||
| test.py:11:9:11:19 | ControlFlowNode for blob_client | test.py:3:7:3:51 | ControlFlowNode for Attribute() | test.py:11:9:11:19 | ControlFlowNode for blob_client | Unsafe usage of v1 version of Azure Storage client-side encryption |
|
||||
| test.py:21:9:21:19 | ControlFlowNode for blob_client | test.py:15:27:15:71 | ControlFlowNode for Attribute() | test.py:21:9:21:19 | ControlFlowNode for blob_client | Unsafe usage of v1 version of Azure Storage client-side encryption |
|
||||
| test.py:31:9:31:19 | ControlFlowNode for blob_client | test.py:25:24:25:66 | ControlFlowNode for Attribute() | test.py:31:9:31:19 | ControlFlowNode for blob_client | Unsafe usage of v1 version of Azure Storage client-side encryption |
|
||||
| test.py:43:9:43:19 | ControlFlowNode for blob_client | test.py:3:7:3:51 | ControlFlowNode for Attribute() | test.py:43:9:43:19 | ControlFlowNode for blob_client | Unsafe usage of v1 version of Azure Storage client-side encryption |
|
||||
| test.py:75:9:75:10 | ControlFlowNode for bc | test.py:3:7:3:51 | ControlFlowNode for Attribute() | test.py:75:9:75:10 | ControlFlowNode for bc | Unsafe usage of v1 version of Azure Storage client-side encryption |
|
||||
@@ -0,0 +1 @@
|
||||
experimental/Security/CWE-327/Azure/UnsafeUsageOfClientSideEncryptionVersion.ql
|
||||
@@ -0,0 +1,89 @@
|
||||
from azure.storage.blob import BlobServiceClient, ContainerClient, BlobClient
|
||||
|
||||
BSC = BlobServiceClient.from_connection_string(...)
|
||||
|
||||
def unsafe():
|
||||
# does not set encryption_version to 2.0, default is unsafe
|
||||
blob_client = BSC.get_blob_client(...)
|
||||
blob_client.require_encryption = True
|
||||
blob_client.key_encryption_key = ...
|
||||
with open("decryptedcontentfile.txt", "rb") as stream:
|
||||
blob_client.upload_blob(stream) # BAD
|
||||
|
||||
|
||||
def unsafe_setting_on_blob_service_client():
|
||||
blob_service_client = BlobServiceClient.from_connection_string(...)
|
||||
blob_service_client.require_encryption = True
|
||||
blob_service_client.key_encryption_key = ...
|
||||
|
||||
blob_client = blob_service_client.get_blob_client(...)
|
||||
with open("decryptedcontentfile.txt", "rb") as stream:
|
||||
blob_client.upload_blob(stream)
|
||||
|
||||
|
||||
def unsafe_setting_on_container_client():
|
||||
container_client = ContainerClient.from_connection_string(...)
|
||||
container_client.require_encryption = True
|
||||
container_client.key_encryption_key = ...
|
||||
|
||||
blob_client = container_client.get_blob_client(...)
|
||||
with open("decryptedcontentfile.txt", "rb") as stream:
|
||||
blob_client.upload_blob(stream)
|
||||
|
||||
|
||||
def potentially_unsafe(use_new_version=False):
|
||||
blob_client = BSC.get_blob_client(...)
|
||||
blob_client.require_encryption = True
|
||||
blob_client.key_encryption_key = ...
|
||||
|
||||
if use_new_version:
|
||||
blob_client.encryption_version = '2.0'
|
||||
|
||||
with open("decryptedcontentfile.txt", "rb") as stream:
|
||||
blob_client.upload_blob(stream) # BAD
|
||||
|
||||
|
||||
def safe():
|
||||
blob_client = BSC.get_blob_client(...)
|
||||
blob_client.require_encryption = True
|
||||
blob_client.key_encryption_key = ...
|
||||
# GOOD: Must use `encryption_version` set to `2.0`
|
||||
blob_client.encryption_version = '2.0'
|
||||
with open("decryptedcontentfile.txt", "rb") as stream:
|
||||
blob_client.upload_blob(stream) # OK
|
||||
|
||||
|
||||
def safe_different_order():
|
||||
blob_client: BlobClient = BSC.get_blob_client(...)
|
||||
blob_client.encryption_version = '2.0'
|
||||
blob_client.require_encryption = True
|
||||
blob_client.key_encryption_key = ...
|
||||
with open("decryptedcontentfile.txt", "rb") as stream:
|
||||
blob_client.upload_blob(stream) # OK
|
||||
|
||||
|
||||
def get_unsafe_blob_client():
|
||||
blob_client = BSC.get_blob_client(...)
|
||||
blob_client.require_encryption = True
|
||||
blob_client.key_encryption_key = ...
|
||||
return blob_client
|
||||
|
||||
|
||||
def unsafe_with_calls():
|
||||
bc = get_unsafe_blob_client()
|
||||
with open("decryptedcontentfile.txt", "rb") as stream:
|
||||
bc.upload_blob(stream) # BAD
|
||||
|
||||
|
||||
def get_safe_blob_client():
|
||||
blob_client = BSC.get_blob_client(...)
|
||||
blob_client.require_encryption = True
|
||||
blob_client.key_encryption_key = ...
|
||||
blob_client.encryption_version = '2.0'
|
||||
return blob_client
|
||||
|
||||
|
||||
def safe_with_calls():
|
||||
bc = get_safe_blob_client()
|
||||
with open("decryptedcontentfile.txt", "rb") as stream:
|
||||
bc.upload_blob(stream) # OK
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,6 @@
|
||||
class TypeAliasDecl extends @type_alias_decl {
|
||||
string toString() { result = "TypeAliasDecl" }
|
||||
}
|
||||
|
||||
from TypeAliasDecl id
|
||||
select id
|
||||
@@ -0,0 +1,3 @@
|
||||
description: Revert adding TypeAliasDecl.getAliasedType()
|
||||
compatibility: full
|
||||
type_alias_decls.rel: run type_alias_decls.qlo
|
||||
@@ -265,7 +265,8 @@ class SwiftDispatcher {
|
||||
private:
|
||||
bool isLazyDeclaration(const swift::Decl& decl) {
|
||||
swift::ModuleDecl* module = decl.getModuleContext();
|
||||
return module->isBuiltinModule() || module->getName().str() == "__ObjC";
|
||||
return module->isBuiltinModule() || module->getName().str() == "__ObjC" ||
|
||||
module->isNonSwiftModule();
|
||||
}
|
||||
|
||||
template <typename T, typename = void>
|
||||
|
||||
@@ -206,6 +206,7 @@ std::optional<codeql::AssociatedTypeDecl> DeclTranslator::translateAssociatedTyp
|
||||
std::optional<codeql::TypeAliasDecl> DeclTranslator::translateTypeAliasDecl(
|
||||
const swift::TypeAliasDecl& decl) {
|
||||
if (auto entry = createNamedEntry(decl)) {
|
||||
entry->aliased_type = dispatcher.fetchLabel(decl.getUnderlyingType());
|
||||
fillTypeDecl(decl, *entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
| Builtin.NativeObject | BuiltinNativeObjectType |
|
||||
| Builtin.RawPointer | BuiltinRawPointerType |
|
||||
| Builtin.RawUnsafeContinuation | BuiltinRawUnsafeContinuationType |
|
||||
| Builtin.UnsafeValueBuffer | BuiltinUnsafeValueBufferType |
|
||||
| Builtin.Vec2xFPIEEE32 | BuiltinVectorType |
|
||||
| Builtin.Vec2xFPIEEE64 | BuiltinVectorType |
|
||||
| Builtin.Vec2xInt8 | BuiltinVectorType |
|
||||
|
||||
@@ -381,10 +381,10 @@ ql/lib/codeql/swift/generated/File.qll f88c485883dd9b2b4a366080e098372912e03fb31
|
||||
ql/lib/codeql/swift/generated/Locatable.qll bdc98b9fb7788f44a4bf7e487ee5bd329473409950a8e9f116d61995615ad849 0b36b4fe45e2aa195e4bb70c50ea95f32f141b8e01e5f23466c6427dd9ab88fb
|
||||
ql/lib/codeql/swift/generated/Location.qll 851766e474cdfdfa67da42e0031fc42dd60196ff5edd39d82f08d3e32deb84c1 b29b2c37672f5acff15f1d3c5727d902f193e51122327b31bd27ec5f877bca3b
|
||||
ql/lib/codeql/swift/generated/OtherAvailabilitySpec.qll 0e26a203b26ff0581b7396b0c6d1606feec5cc32477f676585cdec4911af91c5 0e26a203b26ff0581b7396b0c6d1606feec5cc32477f676585cdec4911af91c5
|
||||
ql/lib/codeql/swift/generated/ParentChild.qll 0ac2139b8b2e172858262d80950a0212b21fe46bf6af7259d9058fb7193f8242 6f7464ecd8ca04b6aa261139b36a162e5b0636237d514b8431ef4f97a1c603dc
|
||||
ql/lib/codeql/swift/generated/ParentChild.qll 7d45d4e872e769f37a5b157ba422c48afe482552e44d94ff5f6a5a6449d672e7 6f7464ecd8ca04b6aa261139b36a162e5b0636237d514b8431ef4f97a1c603dc
|
||||
ql/lib/codeql/swift/generated/PlatformVersionAvailabilitySpec.qll f82d9ca416fe8bd59b5531b65b1c74c9f317b3297a6101544a11339a1cffce38 7f5c6d3309e66c134107afe55bae76dfc9a72cb7cdd6d4c3706b6b34cee09fa0
|
||||
ql/lib/codeql/swift/generated/PureSynthConstructors.qll 173c0dd59396a1de26fe870e3bc2766c46de689da2a4d8807cb62023bbce1a98 173c0dd59396a1de26fe870e3bc2766c46de689da2a4d8807cb62023bbce1a98
|
||||
ql/lib/codeql/swift/generated/Raw.qll 02e54c90cb3ee38fe39b2c17fd4720b5a78fa617edb530a1627a2853798a272f 91f4d685e0e3ebec70566bbab89754b12af0be434445856c39a9b19e5d5e7041
|
||||
ql/lib/codeql/swift/generated/Raw.qll 60bce9edc4af395d7c64959e1fb8abd6d0a79ea4920417e978783c3d357ef087 69d97b1a3a7e32834057fb95e9015fadbae4358af4f76b7e0c646f254c62f0ad
|
||||
ql/lib/codeql/swift/generated/Synth.qll af02e0b49fe7b488592687996cc74d9525d4e3fbc9d324820b310b356f4d2612 5c740a660721173e9e4e45eb701d373ca19ff14d61cdaea309b65871e0deea90
|
||||
ql/lib/codeql/swift/generated/SynthConstructors.qll a1b3ca33017f82124286ccad317a05484fee144fb9c3cdd2e500ce38e5efcec4 a1b3ca33017f82124286ccad317a05484fee144fb9c3cdd2e500ce38e5efcec4
|
||||
ql/lib/codeql/swift/generated/UnknownFile.qll 0fcf9beb8de79440bcdfff4bb6ab3dd139bd273e6c32754e05e6a632651e85f6 0fcf9beb8de79440bcdfff4bb6ab3dd139bd273e6c32754e05e6a632651e85f6
|
||||
@@ -428,7 +428,7 @@ ql/lib/codeql/swift/generated/decl/ProtocolDecl.qll 4b03e3c2a7af66e66e8abc40bd2e
|
||||
ql/lib/codeql/swift/generated/decl/StructDecl.qll 9343b001dfeec83a6b41e88dc1ec75744d39c397e8e48441aa4d01493f10026a 9343b001dfeec83a6b41e88dc1ec75744d39c397e8e48441aa4d01493f10026a
|
||||
ql/lib/codeql/swift/generated/decl/SubscriptDecl.qll 31cb1f90d4c60060f64c432850821969953f1a46e36ce772456c67dfff375ff5 1d0098518c56aed96039b0b660b2cce5ea0db7ac4c9a550af07d758e282d4f61
|
||||
ql/lib/codeql/swift/generated/decl/TopLevelCodeDecl.qll aececf62fda517bd90b1c56bb112bb3ee2eecac3bb2358a889dc8c4de898346e d8c69935ac88f0343a03f17ea155653b97e9b9feff40586cfa8452ac5232700d
|
||||
ql/lib/codeql/swift/generated/decl/TypeAliasDecl.qll 15cb5bdbe9d722c403874f744bfb3da85f532e33638a64a593acbbdee2f6095e 15cb5bdbe9d722c403874f744bfb3da85f532e33638a64a593acbbdee2f6095e
|
||||
ql/lib/codeql/swift/generated/decl/TypeAliasDecl.qll 640912badc9d2278b6d14a746d85ed71b17c52cd1f2006aef46d5a4aeaa544f2 a6cbe000ea9d5d1ccd37eb50c23072e19ee0234d53dcb943fef20e3f553fcf4e
|
||||
ql/lib/codeql/swift/generated/decl/TypeDecl.qll 74bb5f0fe2648d95c84fdce804740f2bba5c7671e15cbea671d8509456bf5c2b 32bc7154c8585c25f27a3587bb4ba039c8d69f09d945725e45d730de44f7a5ae
|
||||
ql/lib/codeql/swift/generated/decl/ValueDecl.qll 7b4e4c9334be676f242857c77099306d8a0a4357b253f8bc68f71328cedf1f58 f18938c47f670f2e0c27ffd7e31e55f291f88fb50d8e576fcea116d5f9e5c66d
|
||||
ql/lib/codeql/swift/generated/decl/VarDecl.qll bdea76fe6c8f721bae52bbc26a2fc1cbd665a19a6920b36097822839158d9d3b 9c91d8159fd7a53cba479d8c8f31f49ad2b1e2617b8cd9e7d1a2cb4796dfa2da
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
* 1. The `namespace` column selects a package.
|
||||
* 2. The `type` column selects a type within that package.
|
||||
* 3. The `subtypes` is a boolean that indicates whether to jump to an
|
||||
* arbitrary subtype of that type.
|
||||
* arbitrary subtype of that type. Set this to `false` if leaving the `type`
|
||||
* blank (for example, a free function).
|
||||
* 4. The `name` column optionally selects a specific named member of the type.
|
||||
* 5. The `signature` column optionally restricts the named member. If
|
||||
* `signature` is blank then no such filtering is done. The format of the
|
||||
|
||||
@@ -10,7 +10,7 @@ class TypeAliasType extends Generated::TypeAliasType {
|
||||
* typealias MyInt = Int
|
||||
* ```
|
||||
*/
|
||||
Type getAliasedType() { none() } // TODO: not yet implemented.
|
||||
Type getAliasedType() { result = this.getDecl().getAliasedType() }
|
||||
|
||||
override Type getUnderlyingType() { result = this } // TODO: not yet implemented.
|
||||
override Type getUnderlyingType() { result = this.getAliasedType().getUnderlyingType() }
|
||||
}
|
||||
|
||||
@@ -662,6 +662,16 @@ module Raw {
|
||||
|
||||
class TypeAliasDecl extends @type_alias_decl, GenericTypeDecl {
|
||||
override string toString() { result = "TypeAliasDecl" }
|
||||
|
||||
/**
|
||||
* Gets the aliased type on the right-hand side of this type alias declaration.
|
||||
*
|
||||
* For example the aliased type of `MyInt` in the following code is `Int`:
|
||||
* ```
|
||||
* typealias MyInt = Int
|
||||
* ```
|
||||
*/
|
||||
Type getAliasedType() { type_alias_decls(this, result) }
|
||||
}
|
||||
|
||||
class ClassDecl extends @class_decl, NominalTypeDecl {
|
||||
|
||||
@@ -2,9 +2,39 @@
|
||||
private import codeql.swift.generated.Synth
|
||||
private import codeql.swift.generated.Raw
|
||||
import codeql.swift.elements.decl.GenericTypeDecl
|
||||
import codeql.swift.elements.type.Type
|
||||
|
||||
module Generated {
|
||||
/**
|
||||
* A declaration of a type alias to another type. For example:
|
||||
* ```
|
||||
* typealias MyInt = Int
|
||||
* ```
|
||||
*/
|
||||
class TypeAliasDecl extends Synth::TTypeAliasDecl, GenericTypeDecl {
|
||||
override string getAPrimaryQlClass() { result = "TypeAliasDecl" }
|
||||
|
||||
/**
|
||||
* Gets the aliased type on the right-hand side of this type alias declaration.
|
||||
*
|
||||
* This includes nodes from the "hidden" AST. It can be overridden in subclasses to change the
|
||||
* behavior of both the `Immediate` and non-`Immediate` versions.
|
||||
*/
|
||||
Type getImmediateAliasedType() {
|
||||
result =
|
||||
Synth::convertTypeFromRaw(Synth::convertTypeAliasDeclToRaw(this)
|
||||
.(Raw::TypeAliasDecl)
|
||||
.getAliasedType())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the aliased type on the right-hand side of this type alias declaration.
|
||||
*
|
||||
* For example the aliased type of `MyInt` in the following code is `Int`:
|
||||
* ```
|
||||
* typealias MyInt = Int
|
||||
* ```
|
||||
*/
|
||||
final Type getAliasedType() { result = getImmediateAliasedType().resolve() }
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user