mirror of
https://github.com/github/codeql.git
synced 2026-05-02 12:15:17 +02:00
Merge branch 'main' into rdmarsh2/range-analysis-overflow
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
---
|
||||
category: deprecated
|
||||
---
|
||||
* The `SslContextCallAbstractConfig`, `SslContextCallConfig`, `SslContextCallBannedProtocolConfig`, `SslContextCallTls12ProtocolConfig`, `SslContextCallTls13ProtocolConfig`, `SslContextCallTlsProtocolConfig`, `SslContextFlowsToSetOptionConfig`, `SslOptionConfig` dataflow configurations from `BoostorgAsio` have been deprecated. Please use `SslContextCallConfigSig`, `SslContextCallMake`, `SslContextCallFlow`, `SslContextCallBannedProtocolFlow`, `SslContextCallTls12ProtocolFlow`, `SslContextCallTls13ProtocolFlow`, `SslContextCallTlsProtocolFlow`, `SslContextFlowsToSetOptionFlow`.
|
||||
* The `SslContextCallAbstractConfig`, `SslContextCallConfig`, `SslContextCallBannedProtocolConfig`, `SslContextCallTls12ProtocolConfig`, `SslContextCallTls13ProtocolConfig`, `SslContextCallTlsProtocolConfig`, `SslContextFlowsToSetOptionConfig`, `SslOptionConfig` dataflow configurations from `BoostorgAsio` have been deprecated. Please use `SslContextCallConfigSig`, `SslContextCallGlobal`, `SslContextCallFlow`, `SslContextCallBannedProtocolFlow`, `SslContextCallTls12ProtocolFlow`, `SslContextCallTls13ProtocolFlow`, `SslContextCallTlsProtocolFlow`, `SslContextFlowsToSetOptionFlow`.
|
||||
|
||||
6
cpp/ql/lib/change-notes/2023-03-23-dataflow-renaming.md
Normal file
6
cpp/ql/lib/change-notes/2023-03-23-dataflow-renaming.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: deprecated
|
||||
---
|
||||
* The recently introduced new data flow and taint tracking APIs have had a
|
||||
number of module and predicate renamings. The old APIs remain in place for
|
||||
now.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: fix
|
||||
---
|
||||
* Fixed some accidental predicate visibility in the backwards-compatible wrapper for data flow configurations. In particular `DataFlow::hasFlowPath`, `DataFlow::hasFlow`, `DataFlow::hasFlowTo`, and `DataFlow::hasFlowToExpr` were accidentally exposed in a single version.
|
||||
4
cpp/ql/lib/change-notes/2023-03-30-bufferaccess.md
Normal file
4
cpp/ql/lib/change-notes/2023-03-30-bufferaccess.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* Added overridable predicates `getSizeExpr` and `getSizeMult` to the `BufferAccess` class (`semmle.code.cpp.security.BufferAccess.qll`). This makes it possible to model a larger class of buffer reads and writes using the library.
|
||||
@@ -3,3 +3,4 @@ import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
|
||||
// Import each extension we want to enable
|
||||
import extensions.SubtractSelf
|
||||
import extensions.ConstantBitwiseAndExprRange
|
||||
import extensions.StrlenLiteralRangeExpr
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
private import cpp
|
||||
private import experimental.semmle.code.cpp.models.interfaces.SimpleRangeAnalysisExpr
|
||||
|
||||
/**
|
||||
* Provides range analysis information for calls to `strlen` on literal strings.
|
||||
* For example, the range of `strlen("literal")` will be 7.
|
||||
*/
|
||||
class StrlenLiteralRangeExpr extends SimpleRangeAnalysisExpr, FunctionCall {
|
||||
StrlenLiteralRangeExpr() {
|
||||
getTarget().hasGlobalOrStdName("strlen") and getArgument(0).isConstant()
|
||||
}
|
||||
|
||||
override int getLowerBounds() { result = getArgument(0).getValue().length() }
|
||||
|
||||
override int getUpperBounds() { result = getArgument(0).getValue().length() }
|
||||
|
||||
override predicate dependsOnChild(Expr e) { none() }
|
||||
}
|
||||
@@ -54,7 +54,7 @@ module PrivateCleartextWrite {
|
||||
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
|
||||
}
|
||||
|
||||
module WriteFlow = TaintTracking::Make<WriteConfig>;
|
||||
module WriteFlow = TaintTracking::Global<WriteConfig>;
|
||||
|
||||
class PrivateDataSource extends Source {
|
||||
PrivateDataSource() { this.getExpr() instanceof PrivateDataExpr }
|
||||
|
||||
@@ -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 }
|
||||
|
||||
|
||||
@@ -250,16 +250,26 @@ SemType getSemanticType(Specific::Type type) {
|
||||
Specific::unknownType(type) and result = TSemUnknownType()
|
||||
}
|
||||
|
||||
private class SemNumericOrBooleanType extends SemSizedType {
|
||||
SemNumericOrBooleanType() {
|
||||
this instanceof SemNumericType
|
||||
or
|
||||
this instanceof SemBooleanType
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the conversion from `fromType` to `toType` can never overflow or underflow.
|
||||
*/
|
||||
predicate conversionCannotOverflow(SemNumericType fromType, SemNumericType toType) {
|
||||
predicate conversionCannotOverflow(SemNumericOrBooleanType fromType, SemNumericOrBooleanType toType) {
|
||||
// Identity cast
|
||||
fromType = toType
|
||||
or
|
||||
// Treat any cast to an FP type as safe. It can lose precision, but not overflow.
|
||||
toType instanceof SemFloatingPointType and fromType = any(SemNumericType n)
|
||||
or
|
||||
fromType instanceof SemBooleanType and toType instanceof SemIntegerType
|
||||
or
|
||||
exists(SemIntegerType fromInteger, SemIntegerType toInteger, int fromSize, int toSize |
|
||||
fromInteger = fromType and
|
||||
toInteger = toType and
|
||||
|
||||
@@ -17,16 +17,7 @@ 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 }
|
||||
}
|
||||
|
||||
module FloatOverflow implements OverflowSig<FloatDelta> {
|
||||
|
||||
@@ -502,7 +502,7 @@ UtilSig<D> UtilParam> {
|
||||
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
|
||||
@@ -598,24 +598,6 @@ UtilSig<D> UtilParam> {
|
||||
delta = D::fromInt(0) and
|
||||
(upper = true or upper = false)
|
||||
or
|
||||
exists(SemExpr x | e2.(SemAddExpr).hasOperands(e1, x) |
|
||||
// `x instanceof ConstantIntegerExpr` is covered by valueFlowStep
|
||||
not x instanceof SemConstantIntegerExpr and
|
||||
not e1 instanceof SemConstantIntegerExpr and
|
||||
if strictlyPositiveIntegralExpr(x)
|
||||
then upper = false and delta = D::fromInt(1)
|
||||
else
|
||||
if semPositive(x)
|
||||
then upper = false and delta = D::fromInt(0)
|
||||
else
|
||||
if strictlyNegativeIntegralExpr(x)
|
||||
then upper = true and delta = D::fromInt(-1)
|
||||
else
|
||||
if semNegative(x)
|
||||
then upper = true and delta = D::fromInt(0)
|
||||
else none()
|
||||
)
|
||||
or
|
||||
exists(SemExpr x, SemSubExpr sub |
|
||||
e2 = sub and
|
||||
sub.getLeftOperand() = e1 and
|
||||
@@ -1085,13 +1067,196 @@ UtilSig<D> UtilParam> {
|
||||
delta = D::fromFloat(f) and
|
||||
if semPositive(e) then f >= 0 else any()
|
||||
)
|
||||
or
|
||||
exists(
|
||||
SemBound bLeft, SemBound bRight, D::Delta dLeft, D::Delta dRight, boolean fbeLeft,
|
||||
boolean fbeRight, D::Delta odLeft, D::Delta odRight, SemReason rLeft, SemReason rRight
|
||||
|
|
||||
boundedAddOperand(e, upper, bLeft, false, dLeft, fbeLeft, odLeft, rLeft) and
|
||||
boundedAddOperand(e, upper, bRight, true, dRight, fbeRight, odRight, rRight) and
|
||||
delta = D::fromFloat(D::toFloat(dLeft) + D::toFloat(dRight)) and
|
||||
fromBackEdge = fbeLeft.booleanOr(fbeRight)
|
||||
|
|
||||
b = bLeft and origdelta = odLeft and reason = rLeft and bRight instanceof SemZeroBound
|
||||
or
|
||||
b = bRight and origdelta = odRight and reason = rRight and bLeft instanceof SemZeroBound
|
||||
)
|
||||
or
|
||||
exists(
|
||||
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, true, d1, fbe1, od1, r1) and
|
||||
boundedRemExpr(rem, false, d2, fbe2, od2, r2) and
|
||||
(
|
||||
if D::toFloat(d1).abs() > D::toFloat(d2).abs()
|
||||
then (
|
||||
d_max = d1 and fromBackEdge = fbe1 and origdelta = od1 and reason = r1
|
||||
) else (
|
||||
d_max = d2 and fromBackEdge = fbe2 and origdelta = od2 and reason = r2
|
||||
)
|
||||
)
|
||||
|
|
||||
upper = true and delta = D::fromFloat(D::toFloat(d_max).abs() - 1)
|
||||
or
|
||||
upper = false and delta = D::fromFloat(-D::toFloat(d_max).abs() + 1)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
D::Delta dLeft, D::Delta dRight, boolean fbeLeft, boolean fbeRight, D::Delta odLeft,
|
||||
D::Delta odRight, SemReason rLeft, SemReason rRight
|
||||
|
|
||||
boundedMulOperand(e, upper, true, dLeft, fbeLeft, odLeft, rLeft) and
|
||||
boundedMulOperand(e, upper, false, dRight, fbeRight, odRight, rRight) and
|
||||
delta = D::fromFloat(D::toFloat(dLeft) * D::toFloat(dRight)) and
|
||||
fromBackEdge = fbeLeft.booleanOr(fbeRight)
|
||||
|
|
||||
b instanceof SemZeroBound and origdelta = odLeft and reason = rLeft
|
||||
or
|
||||
b instanceof SemZeroBound and origdelta = odRight and reason = rRight
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate boundedConditionalExpr(
|
||||
SemConditionalExpr cond, SemBound b, boolean upper, boolean branch, D::Delta delta,
|
||||
boolean fromBackEdge, D::Delta origdelta, SemReason reason
|
||||
) {
|
||||
bounded(cond.getBranchExpr(branch), b, delta, upper, fromBackEdge, origdelta, reason)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate boundedAddOperand(
|
||||
SemAddExpr add, boolean upper, SemBound b, boolean isLeft, D::Delta delta, boolean fromBackEdge,
|
||||
D::Delta origdelta, SemReason reason
|
||||
) {
|
||||
// `semValueFlowStep` already handles the case where one of the operands is a constant.
|
||||
not semValueFlowStep(add, _, _) and
|
||||
(
|
||||
isLeft = true and
|
||||
bounded(add.getLeftOperand(), b, delta, upper, fromBackEdge, origdelta, reason)
|
||||
or
|
||||
isLeft = false and
|
||||
bounded(add.getRightOperand(), b, delta, upper, fromBackEdge, origdelta, reason)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate boundedRemExpr(
|
||||
SemRemExpr rem, boolean upper, D::Delta delta, boolean fromBackEdge, D::Delta origdelta,
|
||||
SemReason reason
|
||||
) {
|
||||
bounded(rem.getRightOperand(), any(SemZeroBound zb), delta, upper, fromBackEdge, origdelta,
|
||||
reason)
|
||||
}
|
||||
|
||||
/**
|
||||
* Define `cmp(true) = <=` and `cmp(false) = >=`.
|
||||
*
|
||||
* Holds if `mul = left * right`, and in order to know if `mul cmp(upper) 0 + k` (for
|
||||
* some `k`) we need to know that `left cmp(upperLeft) 0 + k1` and
|
||||
* `right cmp(upperRight) 0 + k2` (for some `k1` and `k2`).
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate boundedMulOperandCand(
|
||||
SemMulExpr mul, SemExpr left, SemExpr right, boolean upper, boolean upperLeft,
|
||||
boolean upperRight
|
||||
) {
|
||||
not boundFlowStepMul(mul, _, _) and
|
||||
mul.getLeftOperand() = left and
|
||||
mul.getRightOperand() = right and
|
||||
(
|
||||
semPositive(left) and
|
||||
(
|
||||
// left, right >= 0
|
||||
semPositive(right) and
|
||||
(
|
||||
// max(left * right) = max(left) * max(right)
|
||||
upper = true and
|
||||
upperLeft = true and
|
||||
upperRight = true
|
||||
or
|
||||
// min(left * right) = min(left) * min(right)
|
||||
upper = false and
|
||||
upperLeft = false and
|
||||
upperRight = false
|
||||
)
|
||||
or
|
||||
// left >= 0, right <= 0
|
||||
semNegative(right) and
|
||||
(
|
||||
// max(left * right) = min(left) * max(right)
|
||||
upper = true and
|
||||
upperLeft = false and
|
||||
upperRight = true
|
||||
or
|
||||
// min(left * right) = max(left) * min(right)
|
||||
upper = false and
|
||||
upperLeft = true and
|
||||
upperRight = false
|
||||
)
|
||||
)
|
||||
or
|
||||
semNegative(left) and
|
||||
(
|
||||
// left <= 0, right >= 0
|
||||
semPositive(right) and
|
||||
(
|
||||
// max(left * right) = max(left) * min(right)
|
||||
upper = true and
|
||||
upperLeft = true and
|
||||
upperRight = false
|
||||
or
|
||||
// min(left * right) = min(left) * max(right)
|
||||
upper = false and
|
||||
upperLeft = false and
|
||||
upperRight = true
|
||||
)
|
||||
or
|
||||
// left, right <= 0
|
||||
semNegative(right) and
|
||||
(
|
||||
// max(left * right) = min(left) * min(right)
|
||||
upper = true and
|
||||
upperLeft = false and
|
||||
upperRight = false
|
||||
or
|
||||
// min(left * right) = max(left) * max(right)
|
||||
upper = false and
|
||||
upperLeft = true and
|
||||
upperRight = true
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `isLeft = true` and `mul`'s left operand is bounded by `delta`,
|
||||
* or if `isLeft = false` and `mul`'s right operand is bounded by `delta`.
|
||||
*
|
||||
* If `upper = true` the computed bound contributes to an upper bound of `mul`,
|
||||
* and if `upper = false` it contributes to a lower bound.
|
||||
* The `fromBackEdge`, `origdelta`, `reason` triple are defined by the recursive
|
||||
* call to `bounded`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate boundedMulOperand(
|
||||
SemMulExpr mul, boolean upper, boolean isLeft, D::Delta delta, boolean fromBackEdge,
|
||||
D::Delta origdelta, SemReason reason
|
||||
) {
|
||||
exists(boolean upperLeft, boolean upperRight, SemExpr left, SemExpr right |
|
||||
boundedMulOperandCand(mul, left, right, upper, upperLeft, upperRight)
|
||||
|
|
||||
isLeft = true and
|
||||
bounded(left, any(SemZeroBound zb), delta, upperLeft, fromBackEdge, origdelta, reason)
|
||||
or
|
||||
isLeft = false and
|
||||
bounded(right, any(SemZeroBound zb), delta, upperRight, fromBackEdge, origdelta, reason)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,6 +198,16 @@ module SignAnalysis<DeltaSig D, UtilSig<D> Utils> {
|
||||
}
|
||||
}
|
||||
|
||||
/** An expression of an unsigned type. */
|
||||
private class UnsignedExpr extends FlowSignExpr {
|
||||
UnsignedExpr() { Utils::getTrackedType(this) instanceof SemUnsignedIntegerType }
|
||||
|
||||
override Sign getSignRestriction() {
|
||||
result = TPos() or
|
||||
result = TZero()
|
||||
}
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate binaryExprOperands(SemBinaryExpr binary, SemExpr left, SemExpr right) {
|
||||
binary.getLeftOperand() = left and binary.getRightOperand() = right
|
||||
@@ -328,10 +338,11 @@ module SignAnalysis<DeltaSig D, UtilSig<D> Utils> {
|
||||
* - `isEq = false` : `v != eqbound`
|
||||
*/
|
||||
private predicate eqBound(SemExpr eqbound, SemSsaVariable v, SemSsaReadPosition pos, boolean isEq) {
|
||||
exists(SemGuard guard, boolean testIsTrue, boolean polarity |
|
||||
pos.hasReadOfVar(v) and
|
||||
semGuardControlsSsaRead(guard, pos, testIsTrue) and
|
||||
guard.isEquality(eqbound, Utils::semSsaRead(v, D::fromInt(0)), polarity) and
|
||||
exists(SemGuard guard, boolean testIsTrue, boolean polarity, SemExpr e |
|
||||
pos.hasReadOfVar(pragma[only_bind_into](v)) and
|
||||
semGuardControlsSsaRead(guard, pragma[only_bind_into](pos), testIsTrue) and
|
||||
e = Utils::semSsaRead(pragma[only_bind_into](v), D::fromInt(0)) and
|
||||
guard.isEquality(eqbound, e, polarity) and
|
||||
isEq = polarity.booleanXor(testIsTrue).booleanNot() and
|
||||
not unknownSign(eqbound)
|
||||
)
|
||||
|
||||
@@ -8,3 +8,4 @@ upgrades: upgrades
|
||||
dependencies:
|
||||
codeql/ssa: ${workspace}
|
||||
codeql/tutorial: ${workspace}
|
||||
codeql/util: ${workspace}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Provides an implementation of global (interprocedural) data flow. This file
|
||||
* re-exports the local (intraprocedural) data flow analysis from
|
||||
* `DataFlowImplSpecific::Public` and adds a global analysis, mainly exposed
|
||||
* through the `Make` and `MakeWithState` modules.
|
||||
* through the `Global` and `GlobalWithState` modules.
|
||||
*/
|
||||
|
||||
private import DataFlowImplCommon
|
||||
@@ -73,10 +73,10 @@ signature module ConfigSig {
|
||||
*/
|
||||
default FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
/** Holds if sources should be grouped in the result of `flowPath`. */
|
||||
default predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
/** Holds if sinks should be grouped in the result of `flowPath`. */
|
||||
default predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
@@ -166,10 +166,10 @@ signature module StateConfigSig {
|
||||
*/
|
||||
default FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
/** Holds if sources should be grouped in the result of `flowPath`. */
|
||||
default predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
/** Holds if sinks should be grouped in the result of `flowPath`. */
|
||||
default predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
@@ -182,15 +182,15 @@ signature module StateConfigSig {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
|
||||
* Gets the exploration limit for `partialFlow` and `partialFlowRev`
|
||||
* measured in approximate number of interprocedural steps.
|
||||
*/
|
||||
signature int explorationLimitSig();
|
||||
|
||||
/**
|
||||
* The output of a data flow computation.
|
||||
* The output of a global data flow computation.
|
||||
*/
|
||||
signature module DataFlowSig {
|
||||
signature module GlobalFlowSig {
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks) and an access path.
|
||||
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
|
||||
@@ -203,28 +203,28 @@ signature module DataFlowSig {
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink);
|
||||
predicate flowPath(PathNode source, PathNode sink);
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `source` to `sink`.
|
||||
*/
|
||||
predicate hasFlow(Node source, Node sink);
|
||||
predicate flow(Node source, Node sink);
|
||||
|
||||
/**
|
||||
* Holds if data can flow from some source to `sink`.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink);
|
||||
predicate flowTo(Node sink);
|
||||
|
||||
/**
|
||||
* Holds if data can flow from some source to `sink`.
|
||||
*/
|
||||
predicate hasFlowToExpr(DataFlowExpr sink);
|
||||
predicate flowToExpr(DataFlowExpr sink);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a standard data flow computation.
|
||||
* Constructs a global data flow computation.
|
||||
*/
|
||||
module Make<ConfigSig Config> implements DataFlowSig {
|
||||
module Global<ConfigSig Config> implements GlobalFlowSig {
|
||||
private module C implements FullStateConfigSig {
|
||||
import DefaultState<Config>
|
||||
import Config
|
||||
@@ -233,10 +233,15 @@ module Make<ConfigSig Config> implements DataFlowSig {
|
||||
import Impl<C>
|
||||
}
|
||||
|
||||
/** DEPRECATED: Use `Global` instead. */
|
||||
deprecated module Make<ConfigSig Config> implements GlobalFlowSig {
|
||||
import Global<Config>
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a data flow computation using flow state.
|
||||
* Constructs a global data flow computation using flow state.
|
||||
*/
|
||||
module MakeWithState<StateConfigSig Config> implements DataFlowSig {
|
||||
module GlobalWithState<StateConfigSig Config> implements GlobalFlowSig {
|
||||
private module C implements FullStateConfigSig {
|
||||
import Config
|
||||
}
|
||||
@@ -244,6 +249,11 @@ module MakeWithState<StateConfigSig Config> implements DataFlowSig {
|
||||
import Impl<C>
|
||||
}
|
||||
|
||||
/** DEPRECATED: Use `GlobalWithState` instead. */
|
||||
deprecated module MakeWithState<StateConfigSig Config> implements GlobalFlowSig {
|
||||
import GlobalWithState<Config>
|
||||
}
|
||||
|
||||
signature class PathNodeSig {
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString();
|
||||
|
||||
@@ -8,6 +8,7 @@ private import DataFlowImplCommon
|
||||
private import DataFlowImplSpecific::Private
|
||||
private import DataFlowImplSpecific::Public
|
||||
private import DataFlowImplCommonPublic
|
||||
private import codeql.util.Unit
|
||||
import DataFlow
|
||||
|
||||
/**
|
||||
@@ -91,10 +92,10 @@ signature module FullStateConfigSig {
|
||||
*/
|
||||
FlowFeature getAFeature();
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
/** Holds if sources should be grouped in the result of `flowPath`. */
|
||||
predicate sourceGrouping(Node source, string sourceGroup);
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
/** Holds if sinks should be grouped in the result of `flowPath`. */
|
||||
predicate sinkGrouping(Node sink, string sinkGroup);
|
||||
|
||||
/**
|
||||
@@ -445,11 +446,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
}
|
||||
|
||||
private module Stage1 implements StageSig {
|
||||
class Ap extends int {
|
||||
// workaround for bad functionality-induced joins (happens when using `Unit`)
|
||||
pragma[nomagic]
|
||||
Ap() { this in [0 .. 1] and this < 1 }
|
||||
}
|
||||
class Ap = Unit;
|
||||
|
||||
private class Cc = boolean;
|
||||
|
||||
@@ -3633,7 +3630,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) {
|
||||
predicate flowPath(PathNode source, PathNode sink) {
|
||||
exists(PathNodeImpl flowsource, PathNodeImpl flowsink |
|
||||
source = flowsource and sink = flowsink
|
||||
|
|
||||
@@ -3643,6 +3640,9 @@ module Impl<FullStateConfigSig Config> {
|
||||
)
|
||||
}
|
||||
|
||||
/** DEPRECATED: Use `flowPath` instead. */
|
||||
deprecated predicate hasFlowPath = flowPath/2;
|
||||
|
||||
private predicate flowsTo(PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink) {
|
||||
flowsource.isSource() and
|
||||
flowsource.getNodeEx().asNode() = source and
|
||||
@@ -3653,17 +3653,26 @@ module Impl<FullStateConfigSig Config> {
|
||||
/**
|
||||
* Holds if data can flow from `source` to `sink`.
|
||||
*/
|
||||
predicate hasFlow(Node source, Node sink) { flowsTo(_, _, source, sink) }
|
||||
predicate flow(Node source, Node sink) { flowsTo(_, _, source, sink) }
|
||||
|
||||
/** DEPRECATED: Use `flow` instead. */
|
||||
deprecated predicate hasFlow = flow/2;
|
||||
|
||||
/**
|
||||
* Holds if data can flow from some source to `sink`.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) { sink = any(PathNodeSink n).getNodeEx().asNode() }
|
||||
predicate flowTo(Node sink) { sink = any(PathNodeSink n).getNodeEx().asNode() }
|
||||
|
||||
/** DEPRECATED: Use `flowTo` instead. */
|
||||
deprecated predicate hasFlowTo = flowTo/1;
|
||||
|
||||
/**
|
||||
* Holds if data can flow from some source to `sink`.
|
||||
*/
|
||||
predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) }
|
||||
predicate flowToExpr(DataFlowExpr sink) { flowTo(exprNode(sink)) }
|
||||
|
||||
/** DEPRECATED: Use `flowToExpr` instead. */
|
||||
deprecated predicate hasFlowToExpr = flowToExpr/1;
|
||||
|
||||
private predicate finalStats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples
|
||||
@@ -4574,7 +4583,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
*
|
||||
* To use this in a `path-problem` query, import the module `PartialPathGraph`.
|
||||
*/
|
||||
predicate hasPartialFlow(PartialPathNode source, PartialPathNode node, int dist) {
|
||||
predicate partialFlow(PartialPathNode source, PartialPathNode node, int dist) {
|
||||
partialFlow(source, node) and
|
||||
dist = node.getSourceDistance()
|
||||
}
|
||||
@@ -4594,7 +4603,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
* Note that reverse flow has slightly lower precision than the corresponding
|
||||
* forward flow, as reverse flow disregards type pruning among other features.
|
||||
*/
|
||||
predicate hasPartialFlowRev(PartialPathNode node, PartialPathNode sink, int dist) {
|
||||
predicate partialFlowRev(PartialPathNode node, PartialPathNode sink, int dist) {
|
||||
revPartialFlow(node, sink) and
|
||||
dist = node.getSinkDistance()
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* DEPRECATED: Use `Make` and `MakeWithState` instead.
|
||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
||||
*
|
||||
* Provides a `Configuration` class backwards-compatible interface to the data
|
||||
* flow library.
|
||||
@@ -11,6 +11,7 @@ import DataFlowImplSpecific::Public
|
||||
private import DataFlowImpl
|
||||
import DataFlowImplCommonPublic
|
||||
import FlowStateString
|
||||
private import codeql.util.Unit
|
||||
|
||||
/**
|
||||
* A configuration of interprocedural data flow analysis. This defines
|
||||
@@ -328,7 +329,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +379,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +390,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
hasFlowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* DEPRECATED: Use `Make` and `MakeWithState` instead.
|
||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
||||
*
|
||||
* Provides a `Configuration` class backwards-compatible interface to the data
|
||||
* flow library.
|
||||
@@ -11,6 +11,7 @@ import DataFlowImplSpecific::Public
|
||||
private import DataFlowImpl
|
||||
import DataFlowImplCommonPublic
|
||||
import FlowStateString
|
||||
private import codeql.util.Unit
|
||||
|
||||
/**
|
||||
* A configuration of interprocedural data flow analysis. This defines
|
||||
@@ -328,7 +329,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +379,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +390,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
hasFlowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* DEPRECATED: Use `Make` and `MakeWithState` instead.
|
||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
||||
*
|
||||
* Provides a `Configuration` class backwards-compatible interface to the data
|
||||
* flow library.
|
||||
@@ -11,6 +11,7 @@ import DataFlowImplSpecific::Public
|
||||
private import DataFlowImpl
|
||||
import DataFlowImplCommonPublic
|
||||
import FlowStateString
|
||||
private import codeql.util.Unit
|
||||
|
||||
/**
|
||||
* A configuration of interprocedural data flow analysis. This defines
|
||||
@@ -328,7 +329,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +379,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +390,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
hasFlowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* DEPRECATED: Use `Make` and `MakeWithState` instead.
|
||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
||||
*
|
||||
* Provides a `Configuration` class backwards-compatible interface to the data
|
||||
* flow library.
|
||||
@@ -11,6 +11,7 @@ import DataFlowImplSpecific::Public
|
||||
private import DataFlowImpl
|
||||
import DataFlowImplCommonPublic
|
||||
import FlowStateString
|
||||
private import codeql.util.Unit
|
||||
|
||||
/**
|
||||
* A configuration of interprocedural data flow analysis. This defines
|
||||
@@ -328,7 +329,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +379,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +390,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
hasFlowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
@@ -140,10 +140,8 @@ private module LambdaFlow {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private TReturnPositionSimple viableReturnPosLambda(
|
||||
DataFlowCall call, DataFlowCallOption lastCall, ReturnKind kind
|
||||
) {
|
||||
result = TReturnPositionSimple0(viableCallableLambda(call, lastCall), kind)
|
||||
private TReturnPositionSimple viableReturnPosLambda(DataFlowCall call, ReturnKind kind) {
|
||||
result = TReturnPositionSimple0(viableCallableLambda(call, _), kind)
|
||||
}
|
||||
|
||||
private predicate viableReturnPosOutNonLambda(
|
||||
@@ -155,11 +153,12 @@ private module LambdaFlow {
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate viableReturnPosOutLambda(
|
||||
DataFlowCall call, DataFlowCallOption lastCall, TReturnPositionSimple pos, OutNode out
|
||||
DataFlowCall call, TReturnPositionSimple pos, OutNode out
|
||||
) {
|
||||
exists(ReturnKind kind |
|
||||
pos = viableReturnPosLambda(call, lastCall, kind) and
|
||||
pos = viableReturnPosLambda(call, kind) and
|
||||
out = getAnOutNode(call, kind)
|
||||
)
|
||||
}
|
||||
@@ -188,6 +187,7 @@ private module LambdaFlow {
|
||||
else any()
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
pragma[nomagic]
|
||||
predicate revLambdaFlow0(
|
||||
DataFlowCall lambdaCall, LambdaCallKind kind, Node node, DataFlowType t, boolean toReturn,
|
||||
@@ -274,6 +274,7 @@ private module LambdaFlow {
|
||||
)
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
pragma[nomagic]
|
||||
predicate revLambdaFlowOut(
|
||||
DataFlowCall lambdaCall, LambdaCallKind kind, TReturnPositionSimple pos, DataFlowType t,
|
||||
@@ -285,7 +286,7 @@ private module LambdaFlow {
|
||||
or
|
||||
// non-linear recursion
|
||||
revLambdaFlowOutLambdaCall(lambdaCall, kind, out, t, toJump, call, lastCall) and
|
||||
viableReturnPosOutLambda(call, _, pos, out)
|
||||
viableReturnPosOutLambda(call, pos, out)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* DEPRECATED: Use `Make` and `MakeWithState` instead.
|
||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
||||
*
|
||||
* Provides a `Configuration` class backwards-compatible interface to the data
|
||||
* flow library.
|
||||
@@ -11,6 +11,7 @@ import DataFlowImplSpecific::Public
|
||||
private import DataFlowImpl
|
||||
import DataFlowImplCommonPublic
|
||||
import FlowStateString
|
||||
private import codeql.util.Unit
|
||||
|
||||
/**
|
||||
* A configuration of interprocedural data flow analysis. This defines
|
||||
@@ -328,7 +329,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +379,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +390,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
hasFlowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
@@ -3,6 +3,7 @@ private import DataFlowUtil
|
||||
private import DataFlowDispatch
|
||||
private import FlowVar
|
||||
private import DataFlowImplConsistency
|
||||
private import codeql.util.Unit
|
||||
|
||||
/** Gets the callable in which this node occurs. */
|
||||
DataFlowCallable nodeGetEnclosingCallable(Node n) { result = n.getEnclosingCallable() }
|
||||
@@ -264,15 +265,6 @@ int accessPathLimit() { result = 5 }
|
||||
*/
|
||||
predicate forceHighPrecision(Content c) { none() }
|
||||
|
||||
/** The unit type. */
|
||||
private newtype TUnit = TMkUnit()
|
||||
|
||||
/** The trivial type with a single element. */
|
||||
class Unit extends TUnit {
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = "unit" }
|
||||
}
|
||||
|
||||
/** Holds if `n` should be hidden from path explanations. */
|
||||
predicate nodeIsHidden(Node n) { none() }
|
||||
|
||||
|
||||
@@ -33,9 +33,9 @@ private module AddTaintDefaults<DataFlowInternal::FullStateConfigSig Config> imp
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a standard taint tracking computation.
|
||||
* Constructs a global taint tracking computation.
|
||||
*/
|
||||
module Make<DataFlow::ConfigSig Config> implements DataFlow::DataFlowSig {
|
||||
module Global<DataFlow::ConfigSig Config> implements DataFlow::GlobalFlowSig {
|
||||
private module Config0 implements DataFlowInternal::FullStateConfigSig {
|
||||
import DataFlowInternal::DefaultState<Config>
|
||||
import Config
|
||||
@@ -48,10 +48,15 @@ module Make<DataFlow::ConfigSig Config> implements DataFlow::DataFlowSig {
|
||||
import DataFlowInternal::Impl<C>
|
||||
}
|
||||
|
||||
/** DEPRECATED: Use `Global` instead. */
|
||||
deprecated module Make<DataFlow::ConfigSig Config> implements DataFlow::GlobalFlowSig {
|
||||
import Global<Config>
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a taint tracking computation using flow state.
|
||||
* Constructs a global taint tracking computation using flow state.
|
||||
*/
|
||||
module MakeWithState<DataFlow::StateConfigSig Config> implements DataFlow::DataFlowSig {
|
||||
module GlobalWithState<DataFlow::StateConfigSig Config> implements DataFlow::GlobalFlowSig {
|
||||
private module Config0 implements DataFlowInternal::FullStateConfigSig {
|
||||
import Config
|
||||
}
|
||||
@@ -62,3 +67,8 @@ module MakeWithState<DataFlow::StateConfigSig Config> implements DataFlow::DataF
|
||||
|
||||
import DataFlowInternal::Impl<C>
|
||||
}
|
||||
|
||||
/** DEPRECATED: Use `GlobalWithState` instead. */
|
||||
deprecated module MakeWithState<DataFlow::StateConfigSig Config> implements DataFlow::GlobalFlowSig {
|
||||
import GlobalWithState<Config>
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Provides an implementation of global (interprocedural) data flow. This file
|
||||
* re-exports the local (intraprocedural) data flow analysis from
|
||||
* `DataFlowImplSpecific::Public` and adds a global analysis, mainly exposed
|
||||
* through the `Make` and `MakeWithState` modules.
|
||||
* through the `Global` and `GlobalWithState` modules.
|
||||
*/
|
||||
|
||||
private import DataFlowImplCommon
|
||||
@@ -73,10 +73,10 @@ signature module ConfigSig {
|
||||
*/
|
||||
default FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
/** Holds if sources should be grouped in the result of `flowPath`. */
|
||||
default predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
/** Holds if sinks should be grouped in the result of `flowPath`. */
|
||||
default predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
@@ -166,10 +166,10 @@ signature module StateConfigSig {
|
||||
*/
|
||||
default FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
/** Holds if sources should be grouped in the result of `flowPath`. */
|
||||
default predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
/** Holds if sinks should be grouped in the result of `flowPath`. */
|
||||
default predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
@@ -182,15 +182,15 @@ signature module StateConfigSig {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
|
||||
* Gets the exploration limit for `partialFlow` and `partialFlowRev`
|
||||
* measured in approximate number of interprocedural steps.
|
||||
*/
|
||||
signature int explorationLimitSig();
|
||||
|
||||
/**
|
||||
* The output of a data flow computation.
|
||||
* The output of a global data flow computation.
|
||||
*/
|
||||
signature module DataFlowSig {
|
||||
signature module GlobalFlowSig {
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks) and an access path.
|
||||
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
|
||||
@@ -203,28 +203,28 @@ signature module DataFlowSig {
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink);
|
||||
predicate flowPath(PathNode source, PathNode sink);
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `source` to `sink`.
|
||||
*/
|
||||
predicate hasFlow(Node source, Node sink);
|
||||
predicate flow(Node source, Node sink);
|
||||
|
||||
/**
|
||||
* Holds if data can flow from some source to `sink`.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink);
|
||||
predicate flowTo(Node sink);
|
||||
|
||||
/**
|
||||
* Holds if data can flow from some source to `sink`.
|
||||
*/
|
||||
predicate hasFlowToExpr(DataFlowExpr sink);
|
||||
predicate flowToExpr(DataFlowExpr sink);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a standard data flow computation.
|
||||
* Constructs a global data flow computation.
|
||||
*/
|
||||
module Make<ConfigSig Config> implements DataFlowSig {
|
||||
module Global<ConfigSig Config> implements GlobalFlowSig {
|
||||
private module C implements FullStateConfigSig {
|
||||
import DefaultState<Config>
|
||||
import Config
|
||||
@@ -233,10 +233,15 @@ module Make<ConfigSig Config> implements DataFlowSig {
|
||||
import Impl<C>
|
||||
}
|
||||
|
||||
/** DEPRECATED: Use `Global` instead. */
|
||||
deprecated module Make<ConfigSig Config> implements GlobalFlowSig {
|
||||
import Global<Config>
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a data flow computation using flow state.
|
||||
* Constructs a global data flow computation using flow state.
|
||||
*/
|
||||
module MakeWithState<StateConfigSig Config> implements DataFlowSig {
|
||||
module GlobalWithState<StateConfigSig Config> implements GlobalFlowSig {
|
||||
private module C implements FullStateConfigSig {
|
||||
import Config
|
||||
}
|
||||
@@ -244,6 +249,11 @@ module MakeWithState<StateConfigSig Config> implements DataFlowSig {
|
||||
import Impl<C>
|
||||
}
|
||||
|
||||
/** DEPRECATED: Use `GlobalWithState` instead. */
|
||||
deprecated module MakeWithState<StateConfigSig Config> implements GlobalFlowSig {
|
||||
import GlobalWithState<Config>
|
||||
}
|
||||
|
||||
signature class PathNodeSig {
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString();
|
||||
|
||||
@@ -8,6 +8,7 @@ private import DataFlowImplCommon
|
||||
private import DataFlowImplSpecific::Private
|
||||
private import DataFlowImplSpecific::Public
|
||||
private import DataFlowImplCommonPublic
|
||||
private import codeql.util.Unit
|
||||
import DataFlow
|
||||
|
||||
/**
|
||||
@@ -91,10 +92,10 @@ signature module FullStateConfigSig {
|
||||
*/
|
||||
FlowFeature getAFeature();
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
/** Holds if sources should be grouped in the result of `flowPath`. */
|
||||
predicate sourceGrouping(Node source, string sourceGroup);
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
/** Holds if sinks should be grouped in the result of `flowPath`. */
|
||||
predicate sinkGrouping(Node sink, string sinkGroup);
|
||||
|
||||
/**
|
||||
@@ -445,11 +446,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
}
|
||||
|
||||
private module Stage1 implements StageSig {
|
||||
class Ap extends int {
|
||||
// workaround for bad functionality-induced joins (happens when using `Unit`)
|
||||
pragma[nomagic]
|
||||
Ap() { this in [0 .. 1] and this < 1 }
|
||||
}
|
||||
class Ap = Unit;
|
||||
|
||||
private class Cc = boolean;
|
||||
|
||||
@@ -3633,7 +3630,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) {
|
||||
predicate flowPath(PathNode source, PathNode sink) {
|
||||
exists(PathNodeImpl flowsource, PathNodeImpl flowsink |
|
||||
source = flowsource and sink = flowsink
|
||||
|
|
||||
@@ -3643,6 +3640,9 @@ module Impl<FullStateConfigSig Config> {
|
||||
)
|
||||
}
|
||||
|
||||
/** DEPRECATED: Use `flowPath` instead. */
|
||||
deprecated predicate hasFlowPath = flowPath/2;
|
||||
|
||||
private predicate flowsTo(PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink) {
|
||||
flowsource.isSource() and
|
||||
flowsource.getNodeEx().asNode() = source and
|
||||
@@ -3653,17 +3653,26 @@ module Impl<FullStateConfigSig Config> {
|
||||
/**
|
||||
* Holds if data can flow from `source` to `sink`.
|
||||
*/
|
||||
predicate hasFlow(Node source, Node sink) { flowsTo(_, _, source, sink) }
|
||||
predicate flow(Node source, Node sink) { flowsTo(_, _, source, sink) }
|
||||
|
||||
/** DEPRECATED: Use `flow` instead. */
|
||||
deprecated predicate hasFlow = flow/2;
|
||||
|
||||
/**
|
||||
* Holds if data can flow from some source to `sink`.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) { sink = any(PathNodeSink n).getNodeEx().asNode() }
|
||||
predicate flowTo(Node sink) { sink = any(PathNodeSink n).getNodeEx().asNode() }
|
||||
|
||||
/** DEPRECATED: Use `flowTo` instead. */
|
||||
deprecated predicate hasFlowTo = flowTo/1;
|
||||
|
||||
/**
|
||||
* Holds if data can flow from some source to `sink`.
|
||||
*/
|
||||
predicate hasFlowToExpr(DataFlowExpr sink) { hasFlowTo(exprNode(sink)) }
|
||||
predicate flowToExpr(DataFlowExpr sink) { flowTo(exprNode(sink)) }
|
||||
|
||||
/** DEPRECATED: Use `flowToExpr` instead. */
|
||||
deprecated predicate hasFlowToExpr = flowToExpr/1;
|
||||
|
||||
private predicate finalStats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples
|
||||
@@ -4574,7 +4583,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
*
|
||||
* To use this in a `path-problem` query, import the module `PartialPathGraph`.
|
||||
*/
|
||||
predicate hasPartialFlow(PartialPathNode source, PartialPathNode node, int dist) {
|
||||
predicate partialFlow(PartialPathNode source, PartialPathNode node, int dist) {
|
||||
partialFlow(source, node) and
|
||||
dist = node.getSourceDistance()
|
||||
}
|
||||
@@ -4594,7 +4603,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
* Note that reverse flow has slightly lower precision than the corresponding
|
||||
* forward flow, as reverse flow disregards type pruning among other features.
|
||||
*/
|
||||
predicate hasPartialFlowRev(PartialPathNode node, PartialPathNode sink, int dist) {
|
||||
predicate partialFlowRev(PartialPathNode node, PartialPathNode sink, int dist) {
|
||||
revPartialFlow(node, sink) and
|
||||
dist = node.getSinkDistance()
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* DEPRECATED: Use `Make` and `MakeWithState` instead.
|
||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
||||
*
|
||||
* Provides a `Configuration` class backwards-compatible interface to the data
|
||||
* flow library.
|
||||
@@ -11,6 +11,7 @@ import DataFlowImplSpecific::Public
|
||||
private import DataFlowImpl
|
||||
import DataFlowImplCommonPublic
|
||||
import FlowStateString
|
||||
private import codeql.util.Unit
|
||||
|
||||
/**
|
||||
* A configuration of interprocedural data flow analysis. This defines
|
||||
@@ -328,7 +329,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +379,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +390,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
hasFlowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* DEPRECATED: Use `Make` and `MakeWithState` instead.
|
||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
||||
*
|
||||
* Provides a `Configuration` class backwards-compatible interface to the data
|
||||
* flow library.
|
||||
@@ -11,6 +11,7 @@ import DataFlowImplSpecific::Public
|
||||
private import DataFlowImpl
|
||||
import DataFlowImplCommonPublic
|
||||
import FlowStateString
|
||||
private import codeql.util.Unit
|
||||
|
||||
/**
|
||||
* A configuration of interprocedural data flow analysis. This defines
|
||||
@@ -328,7 +329,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +379,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +390,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
hasFlowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* DEPRECATED: Use `Make` and `MakeWithState` instead.
|
||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
||||
*
|
||||
* Provides a `Configuration` class backwards-compatible interface to the data
|
||||
* flow library.
|
||||
@@ -11,6 +11,7 @@ import DataFlowImplSpecific::Public
|
||||
private import DataFlowImpl
|
||||
import DataFlowImplCommonPublic
|
||||
import FlowStateString
|
||||
private import codeql.util.Unit
|
||||
|
||||
/**
|
||||
* A configuration of interprocedural data flow analysis. This defines
|
||||
@@ -328,7 +329,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +379,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +390,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
hasFlowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* DEPRECATED: Use `Make` and `MakeWithState` instead.
|
||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
||||
*
|
||||
* Provides a `Configuration` class backwards-compatible interface to the data
|
||||
* flow library.
|
||||
@@ -11,6 +11,7 @@ import DataFlowImplSpecific::Public
|
||||
private import DataFlowImpl
|
||||
import DataFlowImplCommonPublic
|
||||
import FlowStateString
|
||||
private import codeql.util.Unit
|
||||
|
||||
/**
|
||||
* A configuration of interprocedural data flow analysis. This defines
|
||||
@@ -328,7 +329,6 @@ private module Config implements FullStateConfigSig {
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
@@ -379,6 +379,8 @@ class PathNode instanceof I::PathNode {
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
@@ -388,7 +390,7 @@ private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
hasFlowPath(source, sink) and source.getConfiguration() = config
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
@@ -140,10 +140,8 @@ private module LambdaFlow {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private TReturnPositionSimple viableReturnPosLambda(
|
||||
DataFlowCall call, DataFlowCallOption lastCall, ReturnKind kind
|
||||
) {
|
||||
result = TReturnPositionSimple0(viableCallableLambda(call, lastCall), kind)
|
||||
private TReturnPositionSimple viableReturnPosLambda(DataFlowCall call, ReturnKind kind) {
|
||||
result = TReturnPositionSimple0(viableCallableLambda(call, _), kind)
|
||||
}
|
||||
|
||||
private predicate viableReturnPosOutNonLambda(
|
||||
@@ -155,11 +153,12 @@ private module LambdaFlow {
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate viableReturnPosOutLambda(
|
||||
DataFlowCall call, DataFlowCallOption lastCall, TReturnPositionSimple pos, OutNode out
|
||||
DataFlowCall call, TReturnPositionSimple pos, OutNode out
|
||||
) {
|
||||
exists(ReturnKind kind |
|
||||
pos = viableReturnPosLambda(call, lastCall, kind) and
|
||||
pos = viableReturnPosLambda(call, kind) and
|
||||
out = getAnOutNode(call, kind)
|
||||
)
|
||||
}
|
||||
@@ -188,6 +187,7 @@ private module LambdaFlow {
|
||||
else any()
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
pragma[nomagic]
|
||||
predicate revLambdaFlow0(
|
||||
DataFlowCall lambdaCall, LambdaCallKind kind, Node node, DataFlowType t, boolean toReturn,
|
||||
@@ -274,6 +274,7 @@ private module LambdaFlow {
|
||||
)
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
pragma[nomagic]
|
||||
predicate revLambdaFlowOut(
|
||||
DataFlowCall lambdaCall, LambdaCallKind kind, TReturnPositionSimple pos, DataFlowType t,
|
||||
@@ -285,7 +286,7 @@ private module LambdaFlow {
|
||||
or
|
||||
// non-linear recursion
|
||||
revLambdaFlowOutLambdaCall(lambdaCall, kind, out, t, toJump, call, lastCall) and
|
||||
viableReturnPosOutLambda(call, _, pos, out)
|
||||
viableReturnPosOutLambda(call, pos, out)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ private import DataFlowImplConsistency
|
||||
private import semmle.code.cpp.ir.internal.IRCppLanguage
|
||||
private import SsaInternals as Ssa
|
||||
private import DataFlowImplCommon as DataFlowImplCommon
|
||||
private import codeql.util.Unit
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
@@ -799,15 +800,6 @@ int accessPathLimit() { result = 5 }
|
||||
*/
|
||||
predicate forceHighPrecision(Content c) { none() }
|
||||
|
||||
/** The unit type. */
|
||||
private newtype TUnit = TMkUnit()
|
||||
|
||||
/** The trivial type with a single element. */
|
||||
class Unit extends TUnit {
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = "unit" }
|
||||
}
|
||||
|
||||
/** Holds if `n` should be hidden from path explanations. */
|
||||
predicate nodeIsHidden(Node n) {
|
||||
n instanceof OperandNode and
|
||||
|
||||
@@ -103,7 +103,7 @@ private module DefaultTaintTrackingConfig implements DataFlow::ConfigSig {
|
||||
}
|
||||
}
|
||||
|
||||
private module DefaultTaintTrackingFlow = TaintTracking::Make<DefaultTaintTrackingConfig>;
|
||||
private module DefaultTaintTrackingFlow = TaintTracking::Global<DefaultTaintTrackingConfig>;
|
||||
|
||||
private module ToGlobalVarTaintTrackingConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source = getNodeForSource(_) }
|
||||
@@ -121,13 +121,13 @@ private module ToGlobalVarTaintTrackingConfig implements DataFlow::ConfigSig {
|
||||
predicate isBarrierIn(DataFlow::Node node) { nodeIsBarrierIn(node) }
|
||||
}
|
||||
|
||||
private module ToGlobalVarTaintTrackingFlow = TaintTracking::Make<ToGlobalVarTaintTrackingConfig>;
|
||||
private module ToGlobalVarTaintTrackingFlow = TaintTracking::Global<ToGlobalVarTaintTrackingConfig>;
|
||||
|
||||
private module FromGlobalVarTaintTrackingConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
// This set of sources should be reasonably small, which is good for
|
||||
// performance since the set of sinks is very large.
|
||||
ToGlobalVarTaintTrackingFlow::hasFlowTo(source)
|
||||
ToGlobalVarTaintTrackingFlow::flowTo(source)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { exists(adjustedSink(sink)) }
|
||||
@@ -145,7 +145,7 @@ private module FromGlobalVarTaintTrackingConfig implements DataFlow::ConfigSig {
|
||||
}
|
||||
|
||||
private module FromGlobalVarTaintTrackingFlow =
|
||||
TaintTracking::Make<FromGlobalVarTaintTrackingConfig>;
|
||||
TaintTracking::Global<FromGlobalVarTaintTrackingConfig>;
|
||||
|
||||
private predicate readsVariable(LoadInstruction load, Variable var) {
|
||||
load.getSourceAddress().(VariableAddressInstruction).getAstVariable() = var
|
||||
@@ -331,7 +331,7 @@ private import Cached
|
||||
cached
|
||||
predicate tainted(Expr source, Element tainted) {
|
||||
exists(DataFlow::Node sink |
|
||||
DefaultTaintTrackingFlow::hasFlow(getNodeForSource(source), sink) and
|
||||
DefaultTaintTrackingFlow::flow(getNodeForSource(source), sink) and
|
||||
tainted = adjustedSink(sink)
|
||||
)
|
||||
}
|
||||
@@ -360,8 +360,8 @@ predicate taintedIncludingGlobalVars(Expr source, Element tainted, string global
|
||||
DataFlow::VariableNode variableNode, GlobalOrNamespaceVariable global, DataFlow::Node sink
|
||||
|
|
||||
global = variableNode.getVariable() and
|
||||
ToGlobalVarTaintTrackingFlow::hasFlow(getNodeForSource(source), variableNode) and
|
||||
FromGlobalVarTaintTrackingFlow::hasFlow(variableNode, sink) and
|
||||
ToGlobalVarTaintTrackingFlow::flow(getNodeForSource(source), variableNode) and
|
||||
FromGlobalVarTaintTrackingFlow::flow(variableNode, sink) and
|
||||
tainted = adjustedSink(sink) and
|
||||
global = globalVarFromId(globalVar)
|
||||
)
|
||||
@@ -450,7 +450,7 @@ module TaintedWithPath {
|
||||
predicate isBarrierIn(DataFlow::Node node) { nodeIsBarrierIn(node) }
|
||||
}
|
||||
|
||||
private module AdjustedFlow = TaintTracking::Make<AdjustedConfig>;
|
||||
private module AdjustedFlow = TaintTracking::Global<AdjustedConfig>;
|
||||
|
||||
/*
|
||||
* A sink `Element` may map to multiple `DataFlowX::PathNode`s via (the
|
||||
@@ -472,7 +472,7 @@ module TaintedWithPath {
|
||||
// that makes it easiest to deal with the case where source = sink.
|
||||
TEndpointPathNode(Element e) {
|
||||
exists(DataFlow::Node sourceNode, DataFlow::Node sinkNode |
|
||||
AdjustedFlow::hasFlow(sourceNode, sinkNode)
|
||||
AdjustedFlow::flow(sourceNode, sinkNode)
|
||||
|
|
||||
sourceNode = getNodeForExpr(e) and
|
||||
exists(TaintTrackingConfiguration ttCfg | ttCfg.isSource(e))
|
||||
@@ -634,7 +634,7 @@ module TaintedWithPath {
|
||||
exists(DataFlow::Node flowSource, DataFlow::Node flowSink |
|
||||
source = sourceNode.(InitialPathNode).inner() and
|
||||
flowSource = getNodeForExpr(source) and
|
||||
AdjustedFlow::hasFlow(flowSource, flowSink) and
|
||||
AdjustedFlow::flow(flowSource, flowSink) and
|
||||
tainted = adjustedSink(flowSink) and
|
||||
tainted = sinkNode.(FinalPathNode).inner()
|
||||
)
|
||||
|
||||
@@ -33,9 +33,9 @@ private module AddTaintDefaults<DataFlowInternal::FullStateConfigSig Config> imp
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a standard taint tracking computation.
|
||||
* Constructs a global taint tracking computation.
|
||||
*/
|
||||
module Make<DataFlow::ConfigSig Config> implements DataFlow::DataFlowSig {
|
||||
module Global<DataFlow::ConfigSig Config> implements DataFlow::GlobalFlowSig {
|
||||
private module Config0 implements DataFlowInternal::FullStateConfigSig {
|
||||
import DataFlowInternal::DefaultState<Config>
|
||||
import Config
|
||||
@@ -48,10 +48,15 @@ module Make<DataFlow::ConfigSig Config> implements DataFlow::DataFlowSig {
|
||||
import DataFlowInternal::Impl<C>
|
||||
}
|
||||
|
||||
/** DEPRECATED: Use `Global` instead. */
|
||||
deprecated module Make<DataFlow::ConfigSig Config> implements DataFlow::GlobalFlowSig {
|
||||
import Global<Config>
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a taint tracking computation using flow state.
|
||||
* Constructs a global taint tracking computation using flow state.
|
||||
*/
|
||||
module MakeWithState<DataFlow::StateConfigSig Config> implements DataFlow::DataFlowSig {
|
||||
module GlobalWithState<DataFlow::StateConfigSig Config> implements DataFlow::GlobalFlowSig {
|
||||
private module Config0 implements DataFlowInternal::FullStateConfigSig {
|
||||
import Config
|
||||
}
|
||||
@@ -62,3 +67,8 @@ module MakeWithState<DataFlow::StateConfigSig Config> implements DataFlow::DataF
|
||||
|
||||
import DataFlowInternal::Impl<C>
|
||||
}
|
||||
|
||||
/** DEPRECATED: Use `GlobalWithState` instead. */
|
||||
deprecated module MakeWithState<DataFlow::StateConfigSig Config> implements DataFlow::GlobalFlowSig {
|
||||
import GlobalWithState<Config>
|
||||
}
|
||||
|
||||
@@ -1105,3 +1105,49 @@ class TranslatedAsmStmt extends TranslatedStmt {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TranslatedVlaDimensionStmt extends TranslatedStmt {
|
||||
override VlaDimensionStmt stmt;
|
||||
|
||||
override TranslatedExpr getChild(int id) {
|
||||
id = 0 and
|
||||
result = getTranslatedExpr(stmt.getDimensionExpr().getFullyConverted())
|
||||
}
|
||||
|
||||
override Instruction getFirstInstruction() { result = this.getChild(0).getFirstInstruction() }
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
none()
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
child = this.getChild(0) and
|
||||
result = this.getParent().getChildSuccessor(this)
|
||||
}
|
||||
}
|
||||
|
||||
class TranslatedVlaDeclarationStmt extends TranslatedStmt {
|
||||
override VlaDeclStmt stmt;
|
||||
|
||||
override TranslatedExpr getChild(int id) { none() }
|
||||
|
||||
override Instruction getFirstInstruction() { result = this.getInstruction(OnlyInstructionTag()) }
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
// TODO: This needs a new kind of instruction that represents initialization of a VLA.
|
||||
// For now we just emit a `NoOp` instruction so that the CFG isn't incomplete.
|
||||
tag = OnlyInstructionTag() and
|
||||
opcode instanceof Opcode::NoOp and
|
||||
resultType = getVoidType()
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
tag = OnlyInstructionTag() and
|
||||
result = this.getParent().getChildSuccessor(this) and
|
||||
kind instanceof GotoEdge
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) { none() }
|
||||
}
|
||||
|
||||
@@ -29,7 +29,23 @@ abstract class BufferAccess extends Expr {
|
||||
*/
|
||||
abstract Expr getBuffer(string bufferDesc, int accessType);
|
||||
|
||||
abstract int getSize();
|
||||
/**
|
||||
* Gets the expression that represents the size of the buffer access. The
|
||||
* actual size is typically the value of this expression multiplied by the
|
||||
* result of `getSizeMult()`, in bytes.
|
||||
*/
|
||||
Expr getSizeExpr() { none() }
|
||||
|
||||
/**
|
||||
* Gets a constant multiplier for the buffer access size given by
|
||||
* `getSizeExpr`, in bytes.
|
||||
*/
|
||||
int getSizeMult() { none() }
|
||||
|
||||
/**
|
||||
* Gets the buffer access size in bytes.
|
||||
*/
|
||||
int getSize() { result = this.getSizeExpr().getValue().toInt() * this.getSizeMult() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,10 +79,10 @@ class MemcpyBA extends BufferAccess {
|
||||
accessType = 1
|
||||
}
|
||||
|
||||
override int getSize() {
|
||||
result =
|
||||
this.(FunctionCall).getArgument(2).getValue().toInt() *
|
||||
getPointedSize(this.(FunctionCall).getTarget().getParameter(0).getType())
|
||||
override Expr getSizeExpr() { result = this.(FunctionCall).getArgument(2) }
|
||||
|
||||
override int getSizeMult() {
|
||||
result = getPointedSize(this.(FunctionCall).getTarget().getParameter(0).getType())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,10 +105,10 @@ class BCopyBA extends BufferAccess {
|
||||
accessType = 1
|
||||
}
|
||||
|
||||
override int getSize() {
|
||||
result =
|
||||
this.(FunctionCall).getArgument(2).getValue().toInt() *
|
||||
getPointedSize(this.(FunctionCall).getTarget().getParameter(0).getType())
|
||||
override Expr getSizeExpr() { result = this.(FunctionCall).getArgument(2) }
|
||||
|
||||
override int getSizeMult() {
|
||||
result = getPointedSize(this.(FunctionCall).getTarget().getParameter(0).getType())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,10 +131,10 @@ class StrncpyBA extends BufferAccess {
|
||||
accessType = 2
|
||||
}
|
||||
|
||||
override int getSize() {
|
||||
result =
|
||||
this.(FunctionCall).getArgument(2).getValue().toInt() *
|
||||
getPointedSize(this.(FunctionCall).getTarget().getParameter(0).getType())
|
||||
override Expr getSizeExpr() { result = this.(FunctionCall).getArgument(2) }
|
||||
|
||||
override int getSizeMult() {
|
||||
result = getPointedSize(this.(FunctionCall).getTarget().getParameter(0).getType())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,10 +157,10 @@ class MemccpyBA extends BufferAccess {
|
||||
accessType = 2
|
||||
}
|
||||
|
||||
override int getSize() {
|
||||
result =
|
||||
this.(FunctionCall).getArgument(3).getValue().toInt() *
|
||||
getPointedSize(this.(FunctionCall).getTarget().getParameter(0).getType())
|
||||
override Expr getSizeExpr() { result = this.(FunctionCall).getArgument(3) }
|
||||
|
||||
override int getSizeMult() {
|
||||
result = getPointedSize(this.(FunctionCall).getTarget().getParameter(0).getType())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,10 +188,10 @@ class MemcmpBA extends BufferAccess {
|
||||
accessType = 2
|
||||
}
|
||||
|
||||
override int getSize() {
|
||||
result =
|
||||
this.(FunctionCall).getArgument(2).getValue().toInt() *
|
||||
getPointedSize(this.(FunctionCall).getTarget().getParameter(0).getType())
|
||||
override Expr getSizeExpr() { result = this.(FunctionCall).getArgument(2) }
|
||||
|
||||
override int getSizeMult() {
|
||||
result = getPointedSize(this.(FunctionCall).getTarget().getParameter(0).getType())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,10 +215,10 @@ class SwabBA extends BufferAccess {
|
||||
accessType = 1
|
||||
}
|
||||
|
||||
override int getSize() {
|
||||
result =
|
||||
this.(FunctionCall).getArgument(2).getValue().toInt() *
|
||||
getPointedSize(this.(FunctionCall).getTarget().getParameter(0).getType())
|
||||
override Expr getSizeExpr() { result = this.(FunctionCall).getArgument(2) }
|
||||
|
||||
override int getSizeMult() {
|
||||
result = getPointedSize(this.(FunctionCall).getTarget().getParameter(0).getType())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,10 +238,10 @@ class MemsetBA extends BufferAccess {
|
||||
accessType = 1
|
||||
}
|
||||
|
||||
override int getSize() {
|
||||
result =
|
||||
this.(FunctionCall).getArgument(2).getValue().toInt() *
|
||||
getPointedSize(this.(FunctionCall).getTarget().getParameter(0).getType())
|
||||
override Expr getSizeExpr() { result = this.(FunctionCall).getArgument(2) }
|
||||
|
||||
override int getSizeMult() {
|
||||
result = getPointedSize(this.(FunctionCall).getTarget().getParameter(0).getType())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,7 +260,9 @@ class ZeroMemoryBA extends BufferAccess {
|
||||
accessType = 1
|
||||
}
|
||||
|
||||
override int getSize() { result = this.(FunctionCall).getArgument(1).getValue().toInt() }
|
||||
override Expr getSizeExpr() { result = this.(FunctionCall).getArgument(1) }
|
||||
|
||||
override int getSizeMult() { result = 1 }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -263,10 +281,10 @@ class MemchrBA extends BufferAccess {
|
||||
accessType = 2
|
||||
}
|
||||
|
||||
override int getSize() {
|
||||
result =
|
||||
this.(FunctionCall).getArgument(2).getValue().toInt() *
|
||||
getPointedSize(this.(FunctionCall).getTarget().getParameter(0).getType())
|
||||
override Expr getSizeExpr() { result = this.(FunctionCall).getArgument(2) }
|
||||
|
||||
override int getSizeMult() {
|
||||
result = getPointedSize(this.(FunctionCall).getTarget().getParameter(0).getType())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -285,11 +303,9 @@ class FreadBA extends BufferAccess {
|
||||
accessType = 2
|
||||
}
|
||||
|
||||
override int getSize() {
|
||||
result =
|
||||
this.(FunctionCall).getArgument(1).getValue().toInt() *
|
||||
this.(FunctionCall).getArgument(2).getValue().toInt()
|
||||
}
|
||||
override Expr getSizeExpr() { result = this.(FunctionCall).getArgument(1) }
|
||||
|
||||
override int getSizeMult() { result = this.(FunctionCall).getArgument(2).getValue().toInt() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -318,11 +334,13 @@ class ArrayExprBA extends BufferAccess {
|
||||
accessType = 3
|
||||
}
|
||||
|
||||
override Expr getSizeExpr() { result = this.(ArrayExpr).getArrayOffset() }
|
||||
|
||||
override int getSize() {
|
||||
// byte size of the buffer that would be required to support this
|
||||
// access
|
||||
result =
|
||||
(1 + this.(ArrayExpr).getArrayOffset().getValue().toInt()) *
|
||||
this.(ArrayExpr).getType().getSize()
|
||||
result = (1 + this.getSizeExpr().getValue().toInt()) * this.getSizeMult()
|
||||
}
|
||||
|
||||
override int getSizeMult() { result = this.(ArrayExpr).getType().getSize() }
|
||||
}
|
||||
|
||||
@@ -394,12 +394,12 @@ module BoostorgAsio {
|
||||
* Constructs a standard data flow computation for protocol values to the first argument
|
||||
* of a context constructor.
|
||||
*/
|
||||
module SslContextCallMake<SslContextCallConfigSig Config> {
|
||||
module SslContextCallGlobal<SslContextCallConfigSig Config> {
|
||||
private module C implements DataFlow::ConfigSig {
|
||||
import Config
|
||||
}
|
||||
|
||||
import DataFlow::Make<C>
|
||||
import DataFlow::Global<C>
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -428,7 +428,7 @@ module BoostorgAsio {
|
||||
}
|
||||
}
|
||||
|
||||
module SslContextCallFlow = SslContextCallMake<SslContextCallConfig>;
|
||||
module SslContextCallFlow = SslContextCallGlobal<SslContextCallConfig>;
|
||||
|
||||
/**
|
||||
* A banned protocol value that flows to the first argument of a context constructor.
|
||||
@@ -458,7 +458,8 @@ module BoostorgAsio {
|
||||
}
|
||||
}
|
||||
|
||||
module SslContextCallBannedProtocolFlow = SslContextCallMake<SslContextCallBannedProtocolConfig>;
|
||||
module SslContextCallBannedProtocolFlow =
|
||||
SslContextCallGlobal<SslContextCallBannedProtocolConfig>;
|
||||
|
||||
/**
|
||||
* A TLS 1.2 protocol value that flows to the first argument of a context constructor.
|
||||
@@ -488,7 +489,7 @@ module BoostorgAsio {
|
||||
}
|
||||
}
|
||||
|
||||
module SslContextCallTls12ProtocolFlow = SslContextCallMake<SslContextCallTls12ProtocolConfig>;
|
||||
module SslContextCallTls12ProtocolFlow = SslContextCallGlobal<SslContextCallTls12ProtocolConfig>;
|
||||
|
||||
/**
|
||||
* A TLS 1.3 protocol value that flows to the first argument of a context constructor.
|
||||
@@ -518,7 +519,7 @@ module BoostorgAsio {
|
||||
}
|
||||
}
|
||||
|
||||
module SslContextCallTls13ProtocolFlow = SslContextCallMake<SslContextCallTls13ProtocolConfig>;
|
||||
module SslContextCallTls13ProtocolFlow = SslContextCallGlobal<SslContextCallTls13ProtocolConfig>;
|
||||
|
||||
/**
|
||||
* A generic TLS protocol value that flows to the first argument of a context constructor.
|
||||
@@ -548,7 +549,7 @@ module BoostorgAsio {
|
||||
}
|
||||
}
|
||||
|
||||
module SslContextCallTlsProtocolFlow = SslContextCallMake<SslContextCallTlsProtocolConfig>;
|
||||
module SslContextCallTlsProtocolFlow = SslContextCallGlobal<SslContextCallTlsProtocolConfig>;
|
||||
|
||||
/**
|
||||
* A context constructor call that flows to a call to `SetOptions()`.
|
||||
@@ -596,7 +597,7 @@ module BoostorgAsio {
|
||||
}
|
||||
}
|
||||
|
||||
module SslContextFlowsToSetOptionFlow = DataFlow::Make<SslContextFlowsToSetOptionConfig>;
|
||||
module SslContextFlowsToSetOptionFlow = DataFlow::Global<SslContextFlowsToSetOptionConfig>;
|
||||
|
||||
/**
|
||||
* An option value that flows to the first parameter of a call to `SetOptions()`.
|
||||
@@ -640,5 +641,5 @@ module BoostorgAsio {
|
||||
}
|
||||
}
|
||||
|
||||
module SslOptionFlow = DataFlow::Make<SslOptionConfig>;
|
||||
module SslOptionFlow = DataFlow::Global<SslOptionConfig>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user