mirror of
https://github.com/github/codeql.git
synced 2025-12-21 03:06:31 +01:00
Merge pull request #14006 from MathiasVP/promote-invalid-pointer-deref-out-of-experimental
C++: Promote `cpp/invalid-pointer-deref` out of experimental
This commit is contained in:
@@ -550,11 +550,14 @@ class SsaPhiNode extends Node, TSsaPhiNode {
|
|||||||
* `fromBackEdge` is true if data flows along a back-edge,
|
* `fromBackEdge` is true if data flows along a back-edge,
|
||||||
* and `false` otherwise.
|
* and `false` otherwise.
|
||||||
*/
|
*/
|
||||||
|
cached
|
||||||
final Node getAnInput(boolean fromBackEdge) {
|
final Node getAnInput(boolean fromBackEdge) {
|
||||||
localFlowStep(result, this) and
|
localFlowStep(result, this) and
|
||||||
if phi.getBasicBlock().dominates(result.getBasicBlock())
|
exists(IRBlock bPhi, IRBlock bResult |
|
||||||
then fromBackEdge = true
|
bPhi = phi.getBasicBlock() and bResult = result.getBasicBlock()
|
||||||
else fromBackEdge = false
|
|
|
||||||
|
if bPhi.dominates(bResult) then fromBackEdge = true else fromBackEdge = false
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets a node that is used as input to this phi node. */
|
/** Gets a node that is used as input to this phi node. */
|
||||||
|
|||||||
@@ -87,6 +87,30 @@ module ProductFlow {
|
|||||||
* dataflow graph.
|
* dataflow graph.
|
||||||
*/
|
*/
|
||||||
default predicate isBarrierIn2(DataFlow::Node node) { none() }
|
default predicate isBarrierIn2(DataFlow::Node node) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the virtual dispatch branching limit when calculating field flow in the first
|
||||||
|
* projection of the product dataflow graph.
|
||||||
|
*
|
||||||
|
* This can be overridden to a smaller value to improve performance (a
|
||||||
|
* value of 0 disables field flow), or a larger value to get more results.
|
||||||
|
*/
|
||||||
|
default int fieldFlowBranchLimit1() {
|
||||||
|
// NOTE: This should be synchronized with the default value in the shared dataflow library
|
||||||
|
result = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the virtual dispatch branching limit when calculating field flow in the second
|
||||||
|
* projection of the product dataflow graph.
|
||||||
|
*
|
||||||
|
* This can be overridden to a smaller value to improve performance (a
|
||||||
|
* value of 0 disables field flow), or a larger value to get more results.
|
||||||
|
*/
|
||||||
|
default int fieldFlowBranchLimit2() {
|
||||||
|
// NOTE: This should be synchronized with the default value in the shared dataflow library
|
||||||
|
result = 2
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -272,6 +296,30 @@ module ProductFlow {
|
|||||||
* dataflow graph.
|
* dataflow graph.
|
||||||
*/
|
*/
|
||||||
default predicate isBarrierIn2(DataFlow::Node node) { none() }
|
default predicate isBarrierIn2(DataFlow::Node node) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the virtual dispatch branching limit when calculating field flow in the first
|
||||||
|
* projection of the product dataflow graph.
|
||||||
|
*
|
||||||
|
* This can be overridden to a smaller value to improve performance (a
|
||||||
|
* value of 0 disables field flow), or a larger value to get more results.
|
||||||
|
*/
|
||||||
|
default int fieldFlowBranchLimit1() {
|
||||||
|
// NOTE: This should be synchronized with the default value in the shared dataflow library
|
||||||
|
result = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the virtual dispatch branching limit when calculating field flow in the second
|
||||||
|
* projection of the product dataflow graph.
|
||||||
|
*
|
||||||
|
* This can be overridden to a smaller value to improve performance (a
|
||||||
|
* value of 0 disables field flow), or a larger value to get more results.
|
||||||
|
*/
|
||||||
|
default int fieldFlowBranchLimit2() {
|
||||||
|
// NOTE: This should be synchronized with the default value in the shared dataflow library
|
||||||
|
result = 2
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -335,6 +383,8 @@ module ProductFlow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate isBarrierIn(DataFlow::Node node) { Config::isBarrierIn1(node) }
|
predicate isBarrierIn(DataFlow::Node node) { Config::isBarrierIn1(node) }
|
||||||
|
|
||||||
|
int fieldFlowBranchLimit() { result = Config::fieldFlowBranchLimit1() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Flow1 = DataFlow::GlobalWithState<Config1>;
|
private module Flow1 = DataFlow::GlobalWithState<Config1>;
|
||||||
@@ -367,6 +417,8 @@ module ProductFlow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate isBarrierIn(DataFlow::Node node) { Config::isBarrierIn2(node) }
|
predicate isBarrierIn(DataFlow::Node node) { Config::isBarrierIn2(node) }
|
||||||
|
|
||||||
|
int fieldFlowBranchLimit() { result = Config::fieldFlowBranchLimit2() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Flow2 = DataFlow::GlobalWithState<Config2>;
|
private module Flow2 = DataFlow::GlobalWithState<Config2>;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* This file contains the range-analysis specific parts of the `cpp/invalid-pointer-deref` query
|
* This file contains the range-analysis specific parts of the `cpp/invalid-pointer-deref`
|
||||||
* that is used by both `AllocationToInvalidPointer.qll` and `InvalidPointerToDereference.qll`.
|
* and `cpp/overrun-write` query.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private import cpp
|
private import cpp
|
||||||
@@ -39,6 +39,7 @@ predicate semImplies_v2(SemGuard g1, boolean b1, SemGuard g2, boolean b2) {
|
|||||||
* Holds if `guard` directly controls the position `controlled` with the
|
* Holds if `guard` directly controls the position `controlled` with the
|
||||||
* value `testIsTrue`.
|
* value `testIsTrue`.
|
||||||
*/
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
predicate semGuardDirectlyControlsSsaRead(
|
predicate semGuardDirectlyControlsSsaRead(
|
||||||
SemGuard guard, SemSsaReadPosition controlled, boolean testIsTrue
|
SemGuard guard, SemSsaReadPosition controlled, boolean testIsTrue
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -17,19 +17,27 @@ private import RangeUtils
|
|||||||
private import RangeAnalysisStage
|
private import RangeAnalysisStage
|
||||||
|
|
||||||
module ModulusAnalysis<DeltaSig D, BoundSig<D> Bounds, UtilSig<D> U> {
|
module ModulusAnalysis<DeltaSig D, BoundSig<D> Bounds, UtilSig<D> U> {
|
||||||
/**
|
pragma[nomagic]
|
||||||
* Holds if `e + delta` equals `v` at `pos`.
|
private predicate valueFlowStepSsaEqFlowCond(
|
||||||
*/
|
SemSsaReadPosition pos, SemSsaVariable v, SemExpr e, int delta
|
||||||
private predicate valueFlowStepSsa(SemSsaVariable v, SemSsaReadPosition pos, SemExpr e, int delta) {
|
) {
|
||||||
U::semSsaUpdateStep(v, e, D::fromInt(delta)) and pos.hasReadOfVar(v)
|
|
||||||
or
|
|
||||||
exists(SemGuard guard, boolean testIsTrue |
|
exists(SemGuard guard, boolean testIsTrue |
|
||||||
pos.hasReadOfVar(v) and
|
|
||||||
guard = U::semEqFlowCond(v, e, D::fromInt(delta), true, testIsTrue) and
|
guard = U::semEqFlowCond(v, e, D::fromInt(delta), true, testIsTrue) and
|
||||||
semGuardDirectlyControlsSsaRead(guard, pos, testIsTrue)
|
semGuardDirectlyControlsSsaRead(guard, pos, testIsTrue)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `e + delta` equals `v` at `pos`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate valueFlowStepSsa(SemSsaVariable v, SemSsaReadPosition pos, SemExpr e, int delta) {
|
||||||
|
U::semSsaUpdateStep(v, e, D::fromInt(delta)) and pos.hasReadOfVar(v)
|
||||||
|
or
|
||||||
|
pos.hasReadOfVar(v) and
|
||||||
|
valueFlowStepSsaEqFlowCond(pos, v, e, delta)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `add` is the addition of `larg` and `rarg`, neither of which are
|
* Holds if `add` is the addition of `larg` and `rarg`, neither of which are
|
||||||
* `ConstantIntegerExpr`s.
|
* `ConstantIntegerExpr`s.
|
||||||
|
|||||||
@@ -660,7 +660,7 @@ module RangeStage<
|
|||||||
* - `upper = false` : `v >= b + delta`
|
* - `upper = false` : `v >= b + delta`
|
||||||
*/
|
*/
|
||||||
private predicate boundedSsa(
|
private predicate boundedSsa(
|
||||||
SemSsaVariable v, SemSsaReadPosition pos, SemBound b, D::Delta delta, boolean upper,
|
SemSsaVariable v, SemBound b, D::Delta delta, SemSsaReadPosition pos, boolean upper,
|
||||||
boolean fromBackEdge, D::Delta origdelta, SemReason reason
|
boolean fromBackEdge, D::Delta origdelta, SemReason reason
|
||||||
) {
|
) {
|
||||||
exists(SemExpr mid, D::Delta d1, D::Delta d2, SemReason r1, SemReason r2 |
|
exists(SemExpr mid, D::Delta d1, D::Delta d2, SemReason r1, SemReason r2 |
|
||||||
@@ -673,10 +673,13 @@ module RangeStage<
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(D::Delta d, SemReason r1, SemReason r2 |
|
exists(D::Delta d, SemReason r1, SemReason r2 |
|
||||||
boundedSsa(v, pos, b, d, upper, fromBackEdge, origdelta, r2) or
|
boundedSsa(pragma[only_bind_into](v), pragma[only_bind_into](b), pragma[only_bind_into](d),
|
||||||
boundedPhi(v, b, d, upper, fromBackEdge, origdelta, r2)
|
pragma[only_bind_into](pos), upper, fromBackEdge, origdelta, r2)
|
||||||
|
or
|
||||||
|
boundedPhi(pragma[only_bind_into](v), pragma[only_bind_into](b), pragma[only_bind_into](d),
|
||||||
|
upper, fromBackEdge, origdelta, r2)
|
||||||
|
|
|
|
||||||
unequalIntegralSsa(v, pos, b, d, r1) and
|
unequalIntegralSsa(v, b, d, pos, r1) and
|
||||||
(
|
(
|
||||||
upper = true and delta = D::fromFloat(D::toFloat(d) - 1)
|
upper = true and delta = D::fromFloat(D::toFloat(d) - 1)
|
||||||
or
|
or
|
||||||
@@ -694,7 +697,7 @@ module RangeStage<
|
|||||||
* Holds if `v != b + delta` at `pos` and `v` is of integral type.
|
* Holds if `v != b + delta` at `pos` and `v` is of integral type.
|
||||||
*/
|
*/
|
||||||
private predicate unequalIntegralSsa(
|
private predicate unequalIntegralSsa(
|
||||||
SemSsaVariable v, SemSsaReadPosition pos, SemBound b, D::Delta delta, SemReason reason
|
SemSsaVariable v, SemBound b, D::Delta delta, SemSsaReadPosition pos, SemReason reason
|
||||||
) {
|
) {
|
||||||
exists(SemExpr e, D::Delta d1, D::Delta d2 |
|
exists(SemExpr e, D::Delta d1, D::Delta d2 |
|
||||||
unequalFlowStepIntegralSsa(v, pos, e, d1, reason) and
|
unequalFlowStepIntegralSsa(v, pos, e, d1, reason) and
|
||||||
@@ -746,7 +749,7 @@ module RangeStage<
|
|||||||
) {
|
) {
|
||||||
edge.phiInput(phi, inp) and
|
edge.phiInput(phi, inp) and
|
||||||
exists(D::Delta d, boolean fromBackEdge0 |
|
exists(D::Delta d, boolean fromBackEdge0 |
|
||||||
boundedSsa(inp, edge, b, d, upper, fromBackEdge0, origdelta, reason)
|
boundedSsa(inp, b, d, edge, upper, fromBackEdge0, origdelta, reason)
|
||||||
or
|
or
|
||||||
boundedPhi(inp, b, d, upper, fromBackEdge0, origdelta, reason)
|
boundedPhi(inp, b, d, upper, fromBackEdge0, origdelta, reason)
|
||||||
or
|
or
|
||||||
@@ -1022,7 +1025,7 @@ module RangeStage<
|
|||||||
reason = TSemNoReason()
|
reason = TSemNoReason()
|
||||||
or
|
or
|
||||||
exists(SemSsaVariable v, SemSsaReadPositionBlock bb |
|
exists(SemSsaVariable v, SemSsaReadPositionBlock bb |
|
||||||
boundedSsa(v, bb, b, delta, upper, fromBackEdge, origdelta, reason) and
|
boundedSsa(v, b, delta, bb, upper, fromBackEdge, origdelta, reason) and
|
||||||
e = v.getAUse() and
|
e = v.getAUse() and
|
||||||
bb.getBlock() = e.getBasicBlock()
|
bb.getBlock() = e.getBasicBlock()
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ module RangeUtil<Range::DeltaSig D, Range::LangSig<D> Lang> implements Range::Ut
|
|||||||
* - `isEq = true` : `v == e + delta`
|
* - `isEq = true` : `v == e + delta`
|
||||||
* - `isEq = false` : `v != e + delta`
|
* - `isEq = false` : `v != e + delta`
|
||||||
*/
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
SemGuard semEqFlowCond(
|
SemGuard semEqFlowCond(
|
||||||
SemSsaVariable v, SemExpr e, D::Delta delta, boolean isEq, boolean testIsTrue
|
SemSsaVariable v, SemExpr e, D::Delta delta, boolean isEq, boolean testIsTrue
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ private import semmle.code.cpp.ir.dataflow.internal.ProductFlow
|
|||||||
private import semmle.code.cpp.ir.ValueNumbering
|
private import semmle.code.cpp.ir.ValueNumbering
|
||||||
private import semmle.code.cpp.controlflow.IRGuards
|
private import semmle.code.cpp.controlflow.IRGuards
|
||||||
private import codeql.util.Unit
|
private import codeql.util.Unit
|
||||||
private import RangeAnalysisUtil
|
private import semmle.code.cpp.rangeanalysis.new.RangeAnalysisUtil
|
||||||
|
|
||||||
private VariableAccess getAVariableAccess(Expr e) { e.getAChild*() = result }
|
private VariableAccess getAVariableAccess(Expr e) { e.getAChild*() = result }
|
||||||
|
|
||||||
@@ -77,6 +77,15 @@ predicate hasSize(HeuristicAllocationExpr alloc, DataFlow::Node n, int state) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the virtual dispatch branching limit when calculating field flow while searching
|
||||||
|
* for flow from an allocation to the construction of an out-of-bounds pointer.
|
||||||
|
*
|
||||||
|
* This can be overridden to a smaller value to improve performance (a
|
||||||
|
* value of 0 disables field flow), or a larger value to get more results.
|
||||||
|
*/
|
||||||
|
int allocationToInvalidPointerFieldFlowBranchLimit() { result = 0 }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A module that encapsulates a barrier guard to remove false positives from flow like:
|
* A module that encapsulates a barrier guard to remove false positives from flow like:
|
||||||
* ```cpp
|
* ```cpp
|
||||||
@@ -101,9 +110,12 @@ private module SizeBarrier {
|
|||||||
predicate isSource(DataFlow::Node source) {
|
predicate isSource(DataFlow::Node source) {
|
||||||
// The sources is the same as in the sources for the second
|
// The sources is the same as in the sources for the second
|
||||||
// projection in the `AllocToInvalidPointerConfig` module.
|
// projection in the `AllocToInvalidPointerConfig` module.
|
||||||
hasSize(_, source, _)
|
hasSize(_, source, _) and
|
||||||
|
InterestingPointerAddInstruction::isInterestingSize(source)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int fieldFlowBranchLimit() { result = allocationToInvalidPointerFieldFlowBranchLimit() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `small <= large + k` holds if `g` evaluates to `testIsTrue`.
|
* Holds if `small <= large + k` holds if `g` evaluates to `testIsTrue`.
|
||||||
*/
|
*/
|
||||||
@@ -201,6 +213,8 @@ private module InterestingPointerAddInstruction {
|
|||||||
hasSize(source.asConvertedExpr(), _, _)
|
hasSize(source.asConvertedExpr(), _, _)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int fieldFlowBranchLimit() { result = allocationToInvalidPointerFieldFlowBranchLimit() }
|
||||||
|
|
||||||
predicate isSink(DataFlow::Node sink) {
|
predicate isSink(DataFlow::Node sink) {
|
||||||
sink.asInstruction() = any(PointerAddInstruction pai).getLeft()
|
sink.asInstruction() = any(PointerAddInstruction pai).getLeft()
|
||||||
}
|
}
|
||||||
@@ -220,6 +234,19 @@ private module InterestingPointerAddInstruction {
|
|||||||
flowTo(n)
|
flowTo(n)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `n` is a size of an allocation whose result flows to the left operand
|
||||||
|
* of a pointer-arithmetic instruction.
|
||||||
|
*
|
||||||
|
* This predicate is used to reduce the set of tuples in `SizeBarrierConfig::isSource`.
|
||||||
|
*/
|
||||||
|
predicate isInterestingSize(DataFlow::Node n) {
|
||||||
|
exists(DataFlow::Node alloc |
|
||||||
|
hasSize(alloc.asConvertedExpr(), n, _) and
|
||||||
|
flow(alloc, _)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -244,6 +271,10 @@ private module Config implements ProductFlow::StateConfigSig {
|
|||||||
hasSize(allocSource.asConvertedExpr(), sizeSource, sizeAddend)
|
hasSize(allocSource.asConvertedExpr(), sizeSource, sizeAddend)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int fieldFlowBranchLimit1() { result = allocationToInvalidPointerFieldFlowBranchLimit() }
|
||||||
|
|
||||||
|
int fieldFlowBranchLimit2() { result = allocationToInvalidPointerFieldFlowBranchLimit() }
|
||||||
|
|
||||||
predicate isSinkPair(
|
predicate isSinkPair(
|
||||||
DataFlow::Node allocSink, FlowState1 unit, DataFlow::Node sizeSink, FlowState2 sizeAddend
|
DataFlow::Node allocSink, FlowState1 unit, DataFlow::Node sizeSink, FlowState2 sizeAddend
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -81,7 +81,17 @@ private import semmle.code.cpp.dataflow.new.DataFlow
|
|||||||
private import semmle.code.cpp.ir.ValueNumbering
|
private import semmle.code.cpp.ir.ValueNumbering
|
||||||
private import semmle.code.cpp.controlflow.IRGuards
|
private import semmle.code.cpp.controlflow.IRGuards
|
||||||
private import AllocationToInvalidPointer as AllocToInvalidPointer
|
private import AllocationToInvalidPointer as AllocToInvalidPointer
|
||||||
private import RangeAnalysisUtil
|
private import semmle.code.cpp.rangeanalysis.new.RangeAnalysisUtil
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the virtual dispatch branching limit when calculating field flow while
|
||||||
|
* searching for flow from an out-of-bounds pointer to a dereference of the
|
||||||
|
* pointer.
|
||||||
|
*
|
||||||
|
* This can be overridden to a smaller value to improve performance (a
|
||||||
|
* value of 0 disables field flow), or a larger value to get more results.
|
||||||
|
*/
|
||||||
|
int invalidPointerToDereferenceFieldFlowBranchLimit() { result = 0 }
|
||||||
|
|
||||||
private module InvalidPointerToDerefBarrier {
|
private module InvalidPointerToDerefBarrier {
|
||||||
private module BarrierConfig implements DataFlow::ConfigSig {
|
private module BarrierConfig implements DataFlow::ConfigSig {
|
||||||
@@ -101,6 +111,8 @@ private module InvalidPointerToDerefBarrier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate isSink(DataFlow::Node sink) { isSink(_, sink, _, _, _) }
|
predicate isSink(DataFlow::Node sink) { isSink(_, sink, _, _, _) }
|
||||||
|
|
||||||
|
int fieldFlowBranchLimit() { result = invalidPointerToDereferenceFieldFlowBranchLimit() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private module BarrierFlow = DataFlow::Global<BarrierConfig>;
|
private module BarrierFlow = DataFlow::Global<BarrierConfig>;
|
||||||
@@ -178,6 +190,8 @@ private module InvalidPointerToDerefConfig implements DataFlow::StateConfigSig {
|
|||||||
// Note that this is the only place where the `FlowState` is used in this configuration.
|
// Note that this is the only place where the `FlowState` is used in this configuration.
|
||||||
node = InvalidPointerToDerefBarrier::getABarrierNode(pai)
|
node = InvalidPointerToDerefBarrier::getABarrierNode(pai)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int fieldFlowBranchLimit() { result = invalidPointerToDereferenceFieldFlowBranchLimit() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private import DataFlow::GlobalWithState<InvalidPointerToDerefConfig>
|
private import DataFlow::GlobalWithState<InvalidPointerToDerefConfig>
|
||||||
|
|||||||
@@ -20,28 +20,10 @@ import semmle.code.cpp.models.interfaces.Allocation
|
|||||||
import semmle.code.cpp.models.interfaces.ArrayFunction
|
import semmle.code.cpp.models.interfaces.ArrayFunction
|
||||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysis
|
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysis
|
||||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
|
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
|
||||||
|
import semmle.code.cpp.rangeanalysis.new.RangeAnalysisUtil
|
||||||
import StringSizeFlow::PathGraph1
|
import StringSizeFlow::PathGraph1
|
||||||
import codeql.util.Unit
|
import codeql.util.Unit
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
Instruction getABoundIn(SemBound b, IRFunction func) {
|
|
||||||
getSemanticExpr(result) = b.getExpr(0) and
|
|
||||||
result.getEnclosingIRFunction() = func
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `i <= b + delta`.
|
|
||||||
*/
|
|
||||||
bindingset[i]
|
|
||||||
pragma[inline_late]
|
|
||||||
predicate bounded(Instruction i, Instruction b, int delta) {
|
|
||||||
exists(SemBound bound, IRFunction func |
|
|
||||||
semBounded(getSemanticExpr(i), bound, delta, true, _) and
|
|
||||||
b = getABoundIn(bound, func) and
|
|
||||||
i.getEnclosingIRFunction() = func
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
VariableAccess getAVariableAccess(Expr e) { e.getAChild*() = result }
|
VariableAccess getAVariableAccess(Expr e) { e.getAChild*() = result }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"qhelp.dtd">
|
"qhelp.dtd">
|
||||||
<qhelp>
|
<qhelp>
|
||||||
<overview>
|
<overview>
|
||||||
<p>The program performs an out-of-bounds read or write operation. In addition to causing program instability, techniques exist which may allow an attacker to use this vulnerability to execute arbitrary code.</p>
|
<p>The program performs an out-of-bounds read or write operation, which can cause program instability. In addition, attackers may take advantage of the situation, and implement techniques to use this vulnerability to execute arbitrary code.</p>
|
||||||
|
|
||||||
</overview>
|
</overview>
|
||||||
<recommendation>
|
<recommendation>
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
</recommendation>
|
</recommendation>
|
||||||
<example>
|
<example>
|
||||||
<p>The first example allocates a buffer of size <code>size</code> and creates a local variable that stores the location that is one byte past the end of the allocation.
|
<p>The first example allocates a buffer of size <code>size</code> and creates a local variable that stores the location that is one byte past the end of the allocation.
|
||||||
This local variable is then dereferenced which results in an out-of-bounds write.
|
This local variable is then dereferenced, which results in an out-of-bounds write.
|
||||||
The second example subtracts one from the <code>end</code> variable before dereferencing it. This subtraction ensures that the write correctly updates the final byte of the allocation.</p>
|
The second example subtracts one from the <code>end</code> variable before dereferencing it. This subtraction ensures that the write correctly updates the final byte of the allocation.</p>
|
||||||
<sample src="InvalidPointerDeref.cpp" />
|
<sample src="InvalidPointerDeref.cpp" />
|
||||||
|
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
/**
|
/**
|
||||||
* @name Invalid pointer dereference
|
* @name Invalid pointer dereference
|
||||||
* @description Dereferencing a pointer that points past it allocation is undefined behavior
|
* @description Dereferencing an out-of-bounds pointer is undefined behavior and may lead to security vulnerabilities.
|
||||||
* and may lead to security vulnerabilities.
|
|
||||||
* @kind path-problem
|
* @kind path-problem
|
||||||
* @problem.severity error
|
* @problem.severity error
|
||||||
* @precision high
|
* @security-severity 9.3
|
||||||
|
* @precision medium
|
||||||
* @id cpp/invalid-pointer-deref
|
* @id cpp/invalid-pointer-deref
|
||||||
* @tags reliability
|
* @tags reliability
|
||||||
* security
|
* security
|
||||||
@@ -94,6 +94,12 @@ module FinalConfig implements DataFlow::StateConfigSig {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int fieldFlowBranchLimit() {
|
||||||
|
result =
|
||||||
|
allocationToInvalidPointerFieldFlowBranchLimit()
|
||||||
|
.maximum(invalidPointerToDereferenceFieldFlowBranchLimit())
|
||||||
|
}
|
||||||
|
|
||||||
predicate isAdditionalFlowStep(
|
predicate isAdditionalFlowStep(
|
||||||
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
|
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
|
||||||
) {
|
) {
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
category: newQuery
|
||||||
|
---
|
||||||
|
* Added a new query, `cpp/invalid-pointer-deref`, to detect out-of-bounds pointer reads and writes.
|
||||||
@@ -1 +0,0 @@
|
|||||||
experimental/Security/CWE/CWE-193/InvalidPointerDeref.ql
|
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
failures
|
|
||||||
testFailures
|
testFailures
|
||||||
|
failures
|
||||||
@@ -45,58 +45,6 @@ edges
|
|||||||
| test.cpp:53:5:53:23 | ... = ... | test.cpp:51:33:51:35 | end |
|
| test.cpp:53:5:53:23 | ... = ... | test.cpp:51:33:51:35 | end |
|
||||||
| test.cpp:53:12:53:23 | ... + ... | test.cpp:53:5:53:23 | ... = ... |
|
| test.cpp:53:12:53:23 | ... + ... | test.cpp:53:5:53:23 | ... = ... |
|
||||||
| test.cpp:60:34:60:37 | mk_array output argument | test.cpp:67:9:67:14 | ... = ... |
|
| test.cpp:60:34:60:37 | mk_array output argument | test.cpp:67:9:67:14 | ... = ... |
|
||||||
| test.cpp:80:9:80:16 | mk_array indirection [end] | test.cpp:89:19:89:26 | call to mk_array [end] |
|
|
||||||
| test.cpp:80:9:80:16 | mk_array indirection [end] | test.cpp:119:18:119:25 | call to mk_array [end] |
|
|
||||||
| test.cpp:82:5:82:28 | ... = ... | test.cpp:82:9:82:13 | arr indirection [post update] [begin] |
|
|
||||||
| test.cpp:82:9:82:13 | arr indirection [post update] [begin] | test.cpp:83:15:83:17 | arr indirection [begin] |
|
|
||||||
| test.cpp:82:17:82:22 | call to malloc | test.cpp:82:5:82:28 | ... = ... |
|
|
||||||
| test.cpp:83:5:83:30 | ... = ... | test.cpp:83:9:83:11 | arr indirection [post update] [end] |
|
|
||||||
| test.cpp:83:9:83:11 | arr indirection [post update] [end] | test.cpp:80:9:80:16 | mk_array indirection [end] |
|
|
||||||
| test.cpp:83:15:83:17 | arr indirection [begin] | test.cpp:83:19:83:23 | begin indirection |
|
|
||||||
| test.cpp:83:15:83:30 | ... + ... | test.cpp:83:5:83:30 | ... = ... |
|
|
||||||
| test.cpp:83:19:83:23 | begin indirection | test.cpp:83:5:83:30 | ... = ... |
|
|
||||||
| test.cpp:83:19:83:23 | begin indirection | test.cpp:83:15:83:30 | ... + ... |
|
|
||||||
| test.cpp:89:19:89:26 | call to mk_array [end] | test.cpp:91:36:91:38 | arr indirection [end] |
|
|
||||||
| test.cpp:89:19:89:26 | call to mk_array [end] | test.cpp:95:36:95:38 | arr indirection [end] |
|
|
||||||
| test.cpp:91:36:91:38 | arr indirection [end] | test.cpp:91:40:91:42 | end indirection |
|
|
||||||
| test.cpp:91:36:91:38 | arr indirection [end] | test.cpp:96:9:96:14 | ... = ... |
|
|
||||||
| test.cpp:91:40:91:42 | end indirection | test.cpp:96:9:96:14 | ... = ... |
|
|
||||||
| test.cpp:95:36:95:38 | arr indirection [end] | test.cpp:95:40:95:42 | end indirection |
|
|
||||||
| test.cpp:95:36:95:38 | arr indirection [end] | test.cpp:96:9:96:14 | ... = ... |
|
|
||||||
| test.cpp:95:40:95:42 | end indirection | test.cpp:96:9:96:14 | ... = ... |
|
|
||||||
| test.cpp:104:27:104:29 | arr [end] | test.cpp:105:36:105:38 | arr indirection [end] |
|
|
||||||
| test.cpp:104:27:104:29 | arr [end] | test.cpp:109:36:109:38 | arr indirection [end] |
|
|
||||||
| test.cpp:105:36:105:38 | arr indirection [end] | test.cpp:105:40:105:42 | end indirection |
|
|
||||||
| test.cpp:105:36:105:38 | arr indirection [end] | test.cpp:110:9:110:14 | ... = ... |
|
|
||||||
| test.cpp:105:40:105:42 | end indirection | test.cpp:110:9:110:14 | ... = ... |
|
|
||||||
| test.cpp:109:36:109:38 | arr indirection [end] | test.cpp:109:40:109:42 | end indirection |
|
|
||||||
| test.cpp:109:36:109:38 | arr indirection [end] | test.cpp:110:9:110:14 | ... = ... |
|
|
||||||
| test.cpp:109:40:109:42 | end indirection | test.cpp:110:9:110:14 | ... = ... |
|
|
||||||
| test.cpp:119:18:119:25 | call to mk_array [end] | test.cpp:104:27:104:29 | arr [end] |
|
|
||||||
| test.cpp:141:10:141:19 | mk_array_p indirection [end] | test.cpp:150:20:150:29 | call to mk_array_p indirection [end] |
|
|
||||||
| test.cpp:141:10:141:19 | mk_array_p indirection [end] | test.cpp:180:19:180:28 | call to mk_array_p indirection [end] |
|
|
||||||
| test.cpp:143:5:143:29 | ... = ... | test.cpp:143:10:143:14 | arr indirection [post update] [begin] |
|
|
||||||
| test.cpp:143:10:143:14 | arr indirection [post update] [begin] | test.cpp:144:16:144:18 | arr indirection [begin] |
|
|
||||||
| test.cpp:143:18:143:23 | call to malloc | test.cpp:143:5:143:29 | ... = ... |
|
|
||||||
| test.cpp:144:5:144:32 | ... = ... | test.cpp:144:10:144:12 | arr indirection [post update] [end] |
|
|
||||||
| test.cpp:144:10:144:12 | arr indirection [post update] [end] | test.cpp:141:10:141:19 | mk_array_p indirection [end] |
|
|
||||||
| test.cpp:144:16:144:18 | arr indirection [begin] | test.cpp:144:21:144:25 | begin indirection |
|
|
||||||
| test.cpp:144:16:144:32 | ... + ... | test.cpp:144:5:144:32 | ... = ... |
|
|
||||||
| test.cpp:144:21:144:25 | begin indirection | test.cpp:144:5:144:32 | ... = ... |
|
|
||||||
| test.cpp:144:21:144:25 | begin indirection | test.cpp:144:16:144:32 | ... + ... |
|
|
||||||
| test.cpp:150:20:150:29 | call to mk_array_p indirection [end] | test.cpp:156:37:156:39 | arr indirection [end] |
|
|
||||||
| test.cpp:156:37:156:39 | arr indirection [end] | test.cpp:156:42:156:44 | end indirection |
|
|
||||||
| test.cpp:156:37:156:39 | arr indirection [end] | test.cpp:157:9:157:14 | ... = ... |
|
|
||||||
| test.cpp:156:42:156:44 | end indirection | test.cpp:157:9:157:14 | ... = ... |
|
|
||||||
| test.cpp:165:29:165:31 | arr indirection [end] | test.cpp:166:37:166:39 | arr indirection [end] |
|
|
||||||
| test.cpp:165:29:165:31 | arr indirection [end] | test.cpp:170:37:170:39 | arr indirection [end] |
|
|
||||||
| test.cpp:166:37:166:39 | arr indirection [end] | test.cpp:166:42:166:44 | end indirection |
|
|
||||||
| test.cpp:166:37:166:39 | arr indirection [end] | test.cpp:171:9:171:14 | ... = ... |
|
|
||||||
| test.cpp:166:42:166:44 | end indirection | test.cpp:171:9:171:14 | ... = ... |
|
|
||||||
| test.cpp:170:37:170:39 | arr indirection [end] | test.cpp:170:42:170:44 | end indirection |
|
|
||||||
| test.cpp:170:37:170:39 | arr indirection [end] | test.cpp:171:9:171:14 | ... = ... |
|
|
||||||
| test.cpp:170:42:170:44 | end indirection | test.cpp:171:9:171:14 | ... = ... |
|
|
||||||
| test.cpp:180:19:180:28 | call to mk_array_p indirection [end] | test.cpp:165:29:165:31 | arr indirection [end] |
|
|
||||||
| test.cpp:194:23:194:28 | call to malloc | test.cpp:195:17:195:23 | ... + ... |
|
| test.cpp:194:23:194:28 | call to malloc | test.cpp:195:17:195:23 | ... + ... |
|
||||||
| test.cpp:194:23:194:28 | call to malloc | test.cpp:195:17:195:23 | ... + ... |
|
| test.cpp:194:23:194:28 | call to malloc | test.cpp:195:17:195:23 | ... + ... |
|
||||||
| test.cpp:194:23:194:28 | call to malloc | test.cpp:201:5:201:19 | ... = ... |
|
| test.cpp:194:23:194:28 | call to malloc | test.cpp:201:5:201:19 | ... = ... |
|
||||||
@@ -233,6 +181,18 @@ edges
|
|||||||
| test.cpp:754:18:754:31 | new[] | test.cpp:772:16:772:29 | access to array |
|
| test.cpp:754:18:754:31 | new[] | test.cpp:772:16:772:29 | access to array |
|
||||||
| test.cpp:754:18:754:31 | new[] | test.cpp:772:16:772:29 | access to array |
|
| test.cpp:754:18:754:31 | new[] | test.cpp:772:16:772:29 | access to array |
|
||||||
| test.cpp:781:14:781:27 | new[] | test.cpp:786:18:786:27 | access to array |
|
| test.cpp:781:14:781:27 | new[] | test.cpp:786:18:786:27 | access to array |
|
||||||
|
| test.cpp:792:60:792:62 | end | test.cpp:800:40:800:43 | mk_array_no_field_flow output argument |
|
||||||
|
| test.cpp:792:60:792:62 | end | test.cpp:832:40:832:43 | mk_array_no_field_flow output argument |
|
||||||
|
| test.cpp:793:14:793:19 | call to malloc | test.cpp:794:5:794:24 | ... = ... |
|
||||||
|
| test.cpp:793:14:793:19 | call to malloc | test.cpp:794:12:794:24 | ... + ... |
|
||||||
|
| test.cpp:794:5:794:24 | ... = ... | test.cpp:792:60:792:62 | end |
|
||||||
|
| test.cpp:794:12:794:24 | ... + ... | test.cpp:794:5:794:24 | ... = ... |
|
||||||
|
| test.cpp:800:40:800:43 | mk_array_no_field_flow output argument | test.cpp:807:7:807:12 | ... = ... |
|
||||||
|
| test.cpp:815:52:815:54 | end | test.cpp:815:52:815:54 | end |
|
||||||
|
| test.cpp:815:52:815:54 | end | test.cpp:821:7:821:12 | ... = ... |
|
||||||
|
| test.cpp:815:52:815:54 | end | test.cpp:821:7:821:12 | ... = ... |
|
||||||
|
| test.cpp:832:40:832:43 | mk_array_no_field_flow output argument | test.cpp:833:37:833:39 | end |
|
||||||
|
| test.cpp:833:37:833:39 | end | test.cpp:815:52:815:54 | end |
|
||||||
nodes
|
nodes
|
||||||
| test.cpp:4:15:4:20 | call to malloc | semmle.label | call to malloc |
|
| test.cpp:4:15:4:20 | call to malloc | semmle.label | call to malloc |
|
||||||
| test.cpp:5:15:5:22 | ... + ... | semmle.label | ... + ... |
|
| test.cpp:5:15:5:22 | ... + ... | semmle.label | ... + ... |
|
||||||
@@ -260,48 +220,6 @@ nodes
|
|||||||
| test.cpp:53:12:53:23 | ... + ... | semmle.label | ... + ... |
|
| test.cpp:53:12:53:23 | ... + ... | semmle.label | ... + ... |
|
||||||
| test.cpp:60:34:60:37 | mk_array output argument | semmle.label | mk_array output argument |
|
| test.cpp:60:34:60:37 | mk_array output argument | semmle.label | mk_array output argument |
|
||||||
| test.cpp:67:9:67:14 | ... = ... | semmle.label | ... = ... |
|
| test.cpp:67:9:67:14 | ... = ... | semmle.label | ... = ... |
|
||||||
| test.cpp:80:9:80:16 | mk_array indirection [end] | semmle.label | mk_array indirection [end] |
|
|
||||||
| test.cpp:82:5:82:28 | ... = ... | semmle.label | ... = ... |
|
|
||||||
| test.cpp:82:9:82:13 | arr indirection [post update] [begin] | semmle.label | arr indirection [post update] [begin] |
|
|
||||||
| test.cpp:82:17:82:22 | call to malloc | semmle.label | call to malloc |
|
|
||||||
| test.cpp:83:5:83:30 | ... = ... | semmle.label | ... = ... |
|
|
||||||
| test.cpp:83:9:83:11 | arr indirection [post update] [end] | semmle.label | arr indirection [post update] [end] |
|
|
||||||
| test.cpp:83:15:83:17 | arr indirection [begin] | semmle.label | arr indirection [begin] |
|
|
||||||
| test.cpp:83:15:83:30 | ... + ... | semmle.label | ... + ... |
|
|
||||||
| test.cpp:83:19:83:23 | begin indirection | semmle.label | begin indirection |
|
|
||||||
| test.cpp:89:19:89:26 | call to mk_array [end] | semmle.label | call to mk_array [end] |
|
|
||||||
| test.cpp:91:36:91:38 | arr indirection [end] | semmle.label | arr indirection [end] |
|
|
||||||
| test.cpp:91:40:91:42 | end indirection | semmle.label | end indirection |
|
|
||||||
| test.cpp:95:36:95:38 | arr indirection [end] | semmle.label | arr indirection [end] |
|
|
||||||
| test.cpp:95:40:95:42 | end indirection | semmle.label | end indirection |
|
|
||||||
| test.cpp:96:9:96:14 | ... = ... | semmle.label | ... = ... |
|
|
||||||
| test.cpp:104:27:104:29 | arr [end] | semmle.label | arr [end] |
|
|
||||||
| test.cpp:105:36:105:38 | arr indirection [end] | semmle.label | arr indirection [end] |
|
|
||||||
| test.cpp:105:40:105:42 | end indirection | semmle.label | end indirection |
|
|
||||||
| test.cpp:109:36:109:38 | arr indirection [end] | semmle.label | arr indirection [end] |
|
|
||||||
| test.cpp:109:40:109:42 | end indirection | semmle.label | end indirection |
|
|
||||||
| test.cpp:110:9:110:14 | ... = ... | semmle.label | ... = ... |
|
|
||||||
| test.cpp:119:18:119:25 | call to mk_array [end] | semmle.label | call to mk_array [end] |
|
|
||||||
| test.cpp:141:10:141:19 | mk_array_p indirection [end] | semmle.label | mk_array_p indirection [end] |
|
|
||||||
| test.cpp:143:5:143:29 | ... = ... | semmle.label | ... = ... |
|
|
||||||
| test.cpp:143:10:143:14 | arr indirection [post update] [begin] | semmle.label | arr indirection [post update] [begin] |
|
|
||||||
| test.cpp:143:18:143:23 | call to malloc | semmle.label | call to malloc |
|
|
||||||
| test.cpp:144:5:144:32 | ... = ... | semmle.label | ... = ... |
|
|
||||||
| test.cpp:144:10:144:12 | arr indirection [post update] [end] | semmle.label | arr indirection [post update] [end] |
|
|
||||||
| test.cpp:144:16:144:18 | arr indirection [begin] | semmle.label | arr indirection [begin] |
|
|
||||||
| test.cpp:144:16:144:32 | ... + ... | semmle.label | ... + ... |
|
|
||||||
| test.cpp:144:21:144:25 | begin indirection | semmle.label | begin indirection |
|
|
||||||
| test.cpp:150:20:150:29 | call to mk_array_p indirection [end] | semmle.label | call to mk_array_p indirection [end] |
|
|
||||||
| test.cpp:156:37:156:39 | arr indirection [end] | semmle.label | arr indirection [end] |
|
|
||||||
| test.cpp:156:42:156:44 | end indirection | semmle.label | end indirection |
|
|
||||||
| test.cpp:157:9:157:14 | ... = ... | semmle.label | ... = ... |
|
|
||||||
| test.cpp:165:29:165:31 | arr indirection [end] | semmle.label | arr indirection [end] |
|
|
||||||
| test.cpp:166:37:166:39 | arr indirection [end] | semmle.label | arr indirection [end] |
|
|
||||||
| test.cpp:166:42:166:44 | end indirection | semmle.label | end indirection |
|
|
||||||
| test.cpp:170:37:170:39 | arr indirection [end] | semmle.label | arr indirection [end] |
|
|
||||||
| test.cpp:170:42:170:44 | end indirection | semmle.label | end indirection |
|
|
||||||
| test.cpp:171:9:171:14 | ... = ... | semmle.label | ... = ... |
|
|
||||||
| test.cpp:180:19:180:28 | call to mk_array_p indirection [end] | semmle.label | call to mk_array_p indirection [end] |
|
|
||||||
| test.cpp:194:23:194:28 | call to malloc | semmle.label | call to malloc |
|
| test.cpp:194:23:194:28 | call to malloc | semmle.label | call to malloc |
|
||||||
| test.cpp:195:17:195:23 | ... + ... | semmle.label | ... + ... |
|
| test.cpp:195:17:195:23 | ... + ... | semmle.label | ... + ... |
|
||||||
| test.cpp:195:17:195:23 | ... + ... | semmle.label | ... + ... |
|
| test.cpp:195:17:195:23 | ... + ... | semmle.label | ... + ... |
|
||||||
@@ -394,6 +312,17 @@ nodes
|
|||||||
| test.cpp:772:16:772:29 | access to array | semmle.label | access to array |
|
| test.cpp:772:16:772:29 | access to array | semmle.label | access to array |
|
||||||
| test.cpp:781:14:781:27 | new[] | semmle.label | new[] |
|
| test.cpp:781:14:781:27 | new[] | semmle.label | new[] |
|
||||||
| test.cpp:786:18:786:27 | access to array | semmle.label | access to array |
|
| test.cpp:786:18:786:27 | access to array | semmle.label | access to array |
|
||||||
|
| test.cpp:792:60:792:62 | end | semmle.label | end |
|
||||||
|
| test.cpp:793:14:793:19 | call to malloc | semmle.label | call to malloc |
|
||||||
|
| test.cpp:794:5:794:24 | ... = ... | semmle.label | ... = ... |
|
||||||
|
| test.cpp:794:12:794:24 | ... + ... | semmle.label | ... + ... |
|
||||||
|
| test.cpp:800:40:800:43 | mk_array_no_field_flow output argument | semmle.label | mk_array_no_field_flow output argument |
|
||||||
|
| test.cpp:807:7:807:12 | ... = ... | semmle.label | ... = ... |
|
||||||
|
| test.cpp:815:52:815:54 | end | semmle.label | end |
|
||||||
|
| test.cpp:815:52:815:54 | end | semmle.label | end |
|
||||||
|
| test.cpp:821:7:821:12 | ... = ... | semmle.label | ... = ... |
|
||||||
|
| test.cpp:832:40:832:43 | mk_array_no_field_flow output argument | semmle.label | mk_array_no_field_flow output argument |
|
||||||
|
| test.cpp:833:37:833:39 | end | semmle.label | end |
|
||||||
subpaths
|
subpaths
|
||||||
#select
|
#select
|
||||||
| test.cpp:6:14:6:15 | * ... | test.cpp:4:15:4:20 | call to malloc | test.cpp:6:14:6:15 | * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:4:15:4:20 | call to malloc | call to malloc | test.cpp:5:19:5:22 | size | size |
|
| test.cpp:6:14:6:15 | * ... | test.cpp:4:15:4:20 | call to malloc | test.cpp:6:14:6:15 | * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:4:15:4:20 | call to malloc | call to malloc | test.cpp:5:19:5:22 | size | size |
|
||||||
@@ -404,10 +333,6 @@ subpaths
|
|||||||
| test.cpp:42:14:42:15 | * ... | test.cpp:40:15:40:20 | call to malloc | test.cpp:42:14:42:15 | * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:40:15:40:20 | call to malloc | call to malloc | test.cpp:41:20:41:27 | ... - ... | ... - ... |
|
| test.cpp:42:14:42:15 | * ... | test.cpp:40:15:40:20 | call to malloc | test.cpp:42:14:42:15 | * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:40:15:40:20 | call to malloc | call to malloc | test.cpp:41:20:41:27 | ... - ... | ... - ... |
|
||||||
| test.cpp:44:14:44:21 | * ... | test.cpp:40:15:40:20 | call to malloc | test.cpp:44:14:44:21 | * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:40:15:40:20 | call to malloc | call to malloc | test.cpp:41:20:41:27 | ... - ... | ... - ... |
|
| test.cpp:44:14:44:21 | * ... | test.cpp:40:15:40:20 | call to malloc | test.cpp:44:14:44:21 | * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:40:15:40:20 | call to malloc | call to malloc | test.cpp:41:20:41:27 | ... - ... | ... - ... |
|
||||||
| test.cpp:67:9:67:14 | ... = ... | test.cpp:52:19:52:24 | call to malloc | test.cpp:67:9:67:14 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:52:19:52:24 | call to malloc | call to malloc | test.cpp:53:20:53:23 | size | size |
|
| test.cpp:67:9:67:14 | ... = ... | test.cpp:52:19:52:24 | call to malloc | test.cpp:67:9:67:14 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:52:19:52:24 | call to malloc | call to malloc | test.cpp:53:20:53:23 | size | size |
|
||||||
| test.cpp:96:9:96:14 | ... = ... | test.cpp:82:17:82:22 | call to malloc | test.cpp:96:9:96:14 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:82:17:82:22 | call to malloc | call to malloc | test.cpp:83:27:83:30 | size | size |
|
|
||||||
| test.cpp:110:9:110:14 | ... = ... | test.cpp:82:17:82:22 | call to malloc | test.cpp:110:9:110:14 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:82:17:82:22 | call to malloc | call to malloc | test.cpp:83:27:83:30 | size | size |
|
|
||||||
| test.cpp:157:9:157:14 | ... = ... | test.cpp:143:18:143:23 | call to malloc | test.cpp:157:9:157:14 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:143:18:143:23 | call to malloc | call to malloc | test.cpp:144:29:144:32 | size | size |
|
|
||||||
| test.cpp:171:9:171:14 | ... = ... | test.cpp:143:18:143:23 | call to malloc | test.cpp:171:9:171:14 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:143:18:143:23 | call to malloc | call to malloc | test.cpp:144:29:144:32 | size | size |
|
|
||||||
| test.cpp:201:5:201:19 | ... = ... | test.cpp:194:23:194:28 | call to malloc | test.cpp:201:5:201:19 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:194:23:194:28 | call to malloc | call to malloc | test.cpp:195:21:195:23 | len | len |
|
| test.cpp:201:5:201:19 | ... = ... | test.cpp:194:23:194:28 | call to malloc | test.cpp:201:5:201:19 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:194:23:194:28 | call to malloc | call to malloc | test.cpp:195:21:195:23 | len | len |
|
||||||
| test.cpp:213:5:213:13 | ... = ... | test.cpp:205:23:205:28 | call to malloc | test.cpp:213:5:213:13 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:205:23:205:28 | call to malloc | call to malloc | test.cpp:206:21:206:23 | len | len |
|
| test.cpp:213:5:213:13 | ... = ... | test.cpp:205:23:205:28 | call to malloc | test.cpp:213:5:213:13 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:205:23:205:28 | call to malloc | call to malloc | test.cpp:206:21:206:23 | len | len |
|
||||||
| test.cpp:232:3:232:20 | ... = ... | test.cpp:231:18:231:30 | new[] | test.cpp:232:3:232:20 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:231:18:231:30 | new[] | new[] | test.cpp:232:11:232:15 | index | index |
|
| test.cpp:232:3:232:20 | ... = ... | test.cpp:231:18:231:30 | new[] | test.cpp:232:3:232:20 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:231:18:231:30 | new[] | new[] | test.cpp:232:11:232:15 | index | index |
|
||||||
@@ -434,3 +359,5 @@ subpaths
|
|||||||
| test.cpp:772:16:772:29 | access to array | test.cpp:754:18:754:31 | new[] | test.cpp:772:16:772:29 | access to array | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:754:18:754:31 | new[] | new[] | test.cpp:767:22:767:28 | ... + ... | ... + ... |
|
| test.cpp:772:16:772:29 | access to array | test.cpp:754:18:754:31 | new[] | test.cpp:772:16:772:29 | access to array | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:754:18:754:31 | new[] | new[] | test.cpp:767:22:767:28 | ... + ... | ... + ... |
|
||||||
| test.cpp:772:16:772:29 | access to array | test.cpp:754:18:754:31 | new[] | test.cpp:772:16:772:29 | access to array | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:754:18:754:31 | new[] | new[] | test.cpp:772:22:772:28 | ... + ... | ... + ... |
|
| test.cpp:772:16:772:29 | access to array | test.cpp:754:18:754:31 | new[] | test.cpp:772:16:772:29 | access to array | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:754:18:754:31 | new[] | new[] | test.cpp:772:22:772:28 | ... + ... | ... + ... |
|
||||||
| test.cpp:786:18:786:27 | access to array | test.cpp:781:14:781:27 | new[] | test.cpp:786:18:786:27 | access to array | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:781:14:781:27 | new[] | new[] | test.cpp:786:20:786:26 | ... + ... | ... + ... |
|
| test.cpp:786:18:786:27 | access to array | test.cpp:781:14:781:27 | new[] | test.cpp:786:18:786:27 | access to array | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:781:14:781:27 | new[] | new[] | test.cpp:786:20:786:26 | ... + ... | ... + ... |
|
||||||
|
| test.cpp:807:7:807:12 | ... = ... | test.cpp:793:14:793:19 | call to malloc | test.cpp:807:7:807:12 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:793:14:793:19 | call to malloc | call to malloc | test.cpp:794:21:794:24 | size | size |
|
||||||
|
| test.cpp:821:7:821:12 | ... = ... | test.cpp:793:14:793:19 | call to malloc | test.cpp:821:7:821:12 | ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:793:14:793:19 | call to malloc | call to malloc | test.cpp:794:21:794:24 | size | size |
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Security/CWE/CWE-193/InvalidPointerDeref.ql
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
failures
|
|
||||||
testFailures
|
testFailures
|
||||||
|
failures
|
||||||
@@ -80,7 +80,7 @@ struct array_t {
|
|||||||
array_t mk_array(int size) {
|
array_t mk_array(int size) {
|
||||||
array_t arr;
|
array_t arr;
|
||||||
arr.begin = malloc(size);
|
arr.begin = malloc(size);
|
||||||
arr.end = arr.begin + size; // $ alloc=L82
|
arr.end = arr.begin + size; // $ MISSING: alloc=L82
|
||||||
|
|
||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
@@ -93,7 +93,7 @@ void test6(int size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (char* p = arr.begin; p <= arr.end; ++p) {
|
for (char* p = arr.begin; p <= arr.end; ++p) {
|
||||||
*p = 0; // $ deref=L83->L91->L96 deref=L83->L95->L96 // BAD
|
*p = 0; // $ MISSING: deref=L83->L91->L96 deref=L83->L95->L96 // BAD [NOT DETECTED]
|
||||||
}
|
}
|
||||||
|
|
||||||
for (char* p = arr.begin; p < arr.end; ++p) {
|
for (char* p = arr.begin; p < arr.end; ++p) {
|
||||||
@@ -107,7 +107,7 @@ void test7_callee(array_t arr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (char* p = arr.begin; p <= arr.end; ++p) {
|
for (char* p = arr.begin; p <= arr.end; ++p) {
|
||||||
*p = 0; // $ deref=L83->L105->L110 deref=L83->L109->L110 // BAD
|
*p = 0; // $ MISSING: deref=L83->L105->L110 deref=L83->L109->L110 // BAD [NOT DETECTED]
|
||||||
}
|
}
|
||||||
|
|
||||||
for (char* p = arr.begin; p < arr.end; ++p) {
|
for (char* p = arr.begin; p < arr.end; ++p) {
|
||||||
@@ -141,7 +141,7 @@ void test8(int size) {
|
|||||||
array_t *mk_array_p(int size) {
|
array_t *mk_array_p(int size) {
|
||||||
array_t *arr = (array_t*) malloc(sizeof(array_t));
|
array_t *arr = (array_t*) malloc(sizeof(array_t));
|
||||||
arr->begin = malloc(size);
|
arr->begin = malloc(size);
|
||||||
arr->end = arr->begin + size; // $ alloc=L143
|
arr->end = arr->begin + size; // $ MISSING: alloc=L143
|
||||||
|
|
||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
@@ -154,7 +154,7 @@ void test9(int size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (char* p = arr->begin; p <= arr->end; ++p) {
|
for (char* p = arr->begin; p <= arr->end; ++p) {
|
||||||
*p = 0; // $ deref=L144->L156->L157 // BAD
|
*p = 0; // $ MISSING: deref=L144->L156->L157 // BAD [NOT DETECTED]
|
||||||
}
|
}
|
||||||
|
|
||||||
for (char* p = arr->begin; p < arr->end; ++p) {
|
for (char* p = arr->begin; p < arr->end; ++p) {
|
||||||
@@ -168,7 +168,7 @@ void test10_callee(array_t *arr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (char* p = arr->begin; p <= arr->end; ++p) {
|
for (char* p = arr->begin; p <= arr->end; ++p) {
|
||||||
*p = 0; // $ deref=L144->L166->L171 deref=L144->L170->L171 // BAD
|
*p = 0; // $ MISSING: deref=L144->L166->L171 deref=L144->L170->L171 // BAD [NOT DETECTED]
|
||||||
}
|
}
|
||||||
|
|
||||||
for (char* p = arr->begin; p < arr->end; ++p) {
|
for (char* p = arr->begin; p < arr->end; ++p) {
|
||||||
@@ -788,3 +788,47 @@ void test38_simple(unsigned size, unsigned pos, unsigned numParams) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mk_array_no_field_flow(int size, char** begin, char** end) {
|
||||||
|
*begin = malloc(size);
|
||||||
|
*end = *begin + size; // $ alloc=L793
|
||||||
|
}
|
||||||
|
|
||||||
|
void test6_no_field_flow(int size) {
|
||||||
|
char* begin;
|
||||||
|
char* end;
|
||||||
|
mk_array_no_field_flow(size, &begin, &end);
|
||||||
|
|
||||||
|
for (char* p = begin; p != end; ++p) {
|
||||||
|
*p = 0; // GOOD
|
||||||
|
}
|
||||||
|
|
||||||
|
for (char* p = begin; p <= end; ++p) {
|
||||||
|
*p = 0; // $ deref=L794->L802->L807 deref=L794->L806->L807 // BAD
|
||||||
|
}
|
||||||
|
|
||||||
|
for (char* p = begin; p < end; ++p) {
|
||||||
|
*p = 0; // GOOD
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test7_callee_no_field_flow(char* begin, char* end) {
|
||||||
|
for (char* p = begin; p != end; ++p) {
|
||||||
|
*p = 0; // GOOD
|
||||||
|
}
|
||||||
|
|
||||||
|
for (char* p = begin; p <= end; ++p) {
|
||||||
|
*p = 0; // $ deref=L794->L815->L821 deref=L794->L816->L821 deref=L794->L820->L821 // BAD
|
||||||
|
}
|
||||||
|
|
||||||
|
for (char* p = begin; p < end; ++p) {
|
||||||
|
*p = 0; // GOOD
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test7_no_field_flow(int size) {
|
||||||
|
char* begin;
|
||||||
|
char* end;
|
||||||
|
mk_array_no_field_flow(size, &begin, &end);
|
||||||
|
test7_callee_no_field_flow(begin, end);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user