Merge branch 'main' into redsun82/swift-imported-modules-as-set

This commit is contained in:
Paolo Tranquilli
2023-03-30 16:42:35 +02:00
125 changed files with 12397 additions and 654 deletions

View File

@@ -4,6 +4,7 @@ on:
push:
paths:
- "ruby/**"
- "shared/**"
- .github/workflows/ruby-build.yml
- .github/actions/fetch-codeql/action.yml
- codeql-workspace.yml

View 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.

View File

@@ -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 }

View File

@@ -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 }
}

View File

@@ -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)
}
/**

View File

@@ -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)
)

View File

@@ -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() }
}

View File

@@ -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() }
}

View File

@@ -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
)

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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

View File

@@ -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)

View File

@@ -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) {

View File

@@ -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

View File

@@ -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 :

View File

@@ -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 :

View File

@@ -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];
}
}

View File

@@ -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 :

View File

@@ -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 :

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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>;

View File

@@ -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>;
}

View File

@@ -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 { }

View File

@@ -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 { }

View File

@@ -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 { }

View File

@@ -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 }
}

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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,

View File

@@ -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"

View File

@@ -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()

View File

@@ -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"

View File

@@ -0,0 +1,5 @@
---
category: deprecated
---
* The `execTainted` predicate in `CommandLineQuery.qll` has been deprecated and replaced with the predicate `execIsTainted`.

View File

@@ -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)
}

View File

@@ -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>;

View File

@@ -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.
*/

View File

@@ -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.
*/

View File

@@ -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>;

View File

@@ -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>;

View File

@@ -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

View File

@@ -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.
*/

View File

@@ -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
}

View File

@@ -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>;

View File

@@ -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() {

View File

@@ -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>;

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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."

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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

View File

@@ -0,0 +1,5 @@
extensions:
- addsTo:
pack: codeql/java-queries
extensible: extractorInformationSkipKey
data: []

View File

@@ -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"

View File

@@ -10,3 +10,5 @@ dependencies:
codeql/java-all: ${workspace}
codeql/suite-helpers: ${workspace}
codeql/util: ${workspace}
dataExtensions:
- Telemetry/ExtractorInformation.yml

View File

@@ -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 = ""

View File

@@ -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 = ""

View File

@@ -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 = ""

View File

@@ -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 = ""

View File

@@ -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 = ""

View File

@@ -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 = ""

View File

@@ -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 = ""

View File

@@ -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 = ""

View File

@@ -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 = ""

View File

@@ -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
)
}
}

View File

@@ -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()
|

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* The `DisablingCertificateValidation.ql` query has been updated to check `createServer` from `https` for disabled certificate validation.

View File

@@ -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.

View File

@@ -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 |

View File

@@ -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 |

View File

@@ -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
}

View File

@@ -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. |

View File

@@ -74,4 +74,8 @@ function getSomeunsafeOptions() {
rejectUnauthorized: false // NOT OK
}
}
new https.Agent(getSomeunsafeOptions());
new https.Agent(getSomeunsafeOptions());
https.createServer({
rejectUnauthorized: false // NOT OK
});

View File

@@ -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"

View File

@@ -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 |

View File

@@ -0,0 +1 @@
experimental/Security/CWE-327/Azure/UnsafeUsageOfClientSideEncryptionVersion.ql

View File

@@ -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

View File

@@ -0,0 +1,6 @@
class TypeAliasDecl extends @type_alias_decl {
string toString() { result = "TypeAliasDecl" }
}
from TypeAliasDecl id
select id

View File

@@ -0,0 +1,3 @@
description: Revert adding TypeAliasDecl.getAliasedType()
compatibility: full
type_alias_decls.rel: run type_alias_decls.qlo

View File

@@ -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>

View File

@@ -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;
}

View File

@@ -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 |

View File

@@ -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

View File

@@ -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

View File

@@ -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() }
}

View File

@@ -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 {

View File

@@ -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