merge in main

This commit is contained in:
yoff
2022-06-23 09:05:32 +00:00
committed by GitHub
parent 8bf60301da
commit 140dc1a61e
4448 changed files with 340100 additions and 31408 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,3 @@
description: Add relation for tracking C++ braced initializers
compatibility: full
braced_initialisers.rel: delete

View File

@@ -1,3 +1,21 @@
## 0.2.3
### New Features
* An `isBraced` predicate was added to the `Initializer` class which holds when a C++ braced initializer was used in the initialization.
## 0.2.2
### Deprecated APIs
* The `AnalysedString` class in the `StringAnalysis` module has been replaced with `AnalyzedString`, to follow our style guide. The old name still exists as a deprecated alias.
### New Features
* A `getInitialization` predicate was added to the `ConstexprIfStmt`, `IfStmt`, and `SwitchStmt` classes that yields the C++17-style initializer of the `if` or `switch` statement when it exists.
## 0.2.1
## 0.2.0
### Breaking Changes

View File

@@ -1,4 +0,0 @@
---
category: feature
---
* A `getInitialization` predicate was added to the `ConstexprIfStmt`, `IfStmt`, and `SwitchStmt` classes that yields the C++17-style initializer of the `if` or `switch` statement when it exists.

View File

@@ -1,4 +0,0 @@
---
category: deprecated
---
* The `AnalysedString` class in the `StringAnalysis` module has been replaced with `AnalyzedString`, to follow our style guide. The old name still exists as a deprecated alias.

View File

@@ -0,0 +1,4 @@
---
category: feature
---
* An `isBraced` predicate was added to the `Initializer` class which holds when a C++ braced initializer was used in the initialization.

View File

@@ -0,0 +1,4 @@
---
category: deprecated
---
* The `BarrierGuard` class has been deprecated. Such barriers and sanitizers can now instead be created using the new `BarrierGuard` parameterized module.

View File

@@ -0,0 +1,4 @@
---
category: fix
---
* `UserType.getADeclarationEntry()` now yields all forward declarations when the user type is a `class`, `struct`, or `union`.

View File

@@ -0,0 +1 @@
## 0.2.1

View File

@@ -0,0 +1,9 @@
## 0.2.2
### Deprecated APIs
* The `AnalysedString` class in the `StringAnalysis` module has been replaced with `AnalyzedString`, to follow our style guide. The old name still exists as a deprecated alias.
### New Features
* A `getInitialization` predicate was added to the `ConstexprIfStmt`, `IfStmt`, and `SwitchStmt` classes that yields the C++17-style initializer of the `if` or `switch` statement when it exists.

View File

@@ -0,0 +1,5 @@
## 0.2.3
### New Features
* An `isBraced` predicate was added to the `Initializer` class which holds when a C++ braced initializer was used in the initialization.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.2.0
lastReleaseVersion: 0.2.3

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-all
version: 0.2.1-dev
version: 0.3.0-dev
groups: cpp
dbscheme: semmlecode.cpp.dbscheme
extractor: cpp

View File

@@ -31,7 +31,7 @@ class Field extends MemberVariable {
int getByteOffset() { fieldoffsets(underlyingElement(this), result, _) }
/**
* Gets the byte offset within `mostDerivedClass` of each occurence of this
* Gets the byte offset within `mostDerivedClass` of each occurrence of this
* field within `mostDerivedClass` itself or a base class subobject of
* `mostDerivedClass`.
* Note that for fields of virtual base classes, and non-virtual base classes

View File

@@ -51,4 +51,7 @@ class Initializer extends ControlFlowNode, @initialiser {
override Function getControlFlowScope() { result = this.getExpr().getEnclosingFunction() }
override Stmt getEnclosingStmt() { result = this.getExpr().getEnclosingStmt() }
/** Holds if the initializer used the C++ braced initializer notation. */
predicate isBraced() { braced_initialisers(underlyingElement(this)) }
}

View File

@@ -48,8 +48,8 @@ class UserType extends Type, Declaration, NameQualifyingElement, AccessHolder, @
}
override TypeDeclarationEntry getADeclarationEntry() {
if type_decls(_, underlyingElement(this), _)
then type_decls(unresolveElement(result), underlyingElement(this), _)
if type_decls(_, unresolveElement(this), _)
then type_decls(underlyingElement(result), unresolveElement(this), _)
else exists(Class t | this.(Class).isConstructedFrom(t) and result = t.getADeclarationEntry())
}

View File

@@ -168,7 +168,7 @@ private predicate callsVariadicFormatter(
) {
// calls a variadic formatter with `formatParamIndex`, `outputParamIndex` linked
exists(FunctionCall fc, int format, int output |
variadicFormatter(fc.getTarget(), type, format, output) and
variadicFormatter(pragma[only_bind_into](fc.getTarget()), type, format, output) and
fc.getEnclosingFunction() = f and
fc.getArgument(format) = f.getParameter(formatParamIndex).getAnAccess() and
fc.getArgument(output) = f.getParameter(outputParamIndex).getAnAccess()
@@ -176,7 +176,7 @@ private predicate callsVariadicFormatter(
or
// calls a variadic formatter with only `formatParamIndex` linked
exists(FunctionCall fc, string calledType, int format, int output |
variadicFormatter(fc.getTarget(), calledType, format, output) and
variadicFormatter(pragma[only_bind_into](fc.getTarget()), calledType, format, output) and
fc.getEnclosingFunction() = f and
fc.getArgument(format) = f.getParameter(formatParamIndex).getAnAccess() and
not fc.getArgument(output) = f.getParameter(_).getAnAccess() and
@@ -872,7 +872,7 @@ class FormatLiteral extends Literal {
private Type getConversionType1(int n) {
exists(string cnv | cnv = this.getConversionChar(n) |
cnv.regexpMatch("d|i") and
cnv = ["d", "i"] and
result = this.getIntegralConversion(n) and
not result.getUnderlyingType().(IntegralType).isExplicitlySigned() and
not result.getUnderlyingType().(IntegralType).isExplicitlyUnsigned()
@@ -912,7 +912,7 @@ class FormatLiteral extends Literal {
private Type getConversionType2(int n) {
exists(string cnv | cnv = this.getConversionChar(n) |
cnv.regexpMatch("o|u|x|X") and
cnv = ["o", "u", "x", "X"] and
result = this.getIntegralConversion(n) and
result.getUnderlyingType().(IntegralType).isUnsigned()
)
@@ -920,7 +920,7 @@ class FormatLiteral extends Literal {
private Type getConversionType3(int n) {
exists(string cnv | cnv = this.getConversionChar(n) |
cnv.regexpMatch("a|A|e|E|f|F|g|G") and result = this.getFloatingPointConversion(n)
cnv = ["a", "A", "e", "E", "f", "F", "g", "G"] and result = this.getFloatingPointConversion(n)
)
}

View File

@@ -970,7 +970,7 @@ private predicate subEdge(Pos p1, Node n1, Node n2, Pos p2) {
private predicate subEdgeIncludingDestructors(Pos p1, Node n1, Node n2, Pos p2) {
subEdge(p1, n1, n2, p2)
or
// If `n1` has sub-nodes to accomodate destructors, but there are none to be
// If `n1` has sub-nodes to accommodate destructors, but there are none to be
// called, connect the "before destructors" node directly to the "after
// destructors" node. For performance, only do this when the nodes exist.
exists(Pos afterDtors | afterDtors.isAfterDestructors() | subEdge(afterDtors, n1, _, _)) and

View File

@@ -90,14 +90,20 @@ abstract class Configuration extends string {
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
@@ -335,6 +341,29 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -348,10 +377,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
not config.isSink(n) and
not config.isSink(n, _)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}
@@ -360,10 +386,7 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
)
}
@@ -3854,16 +3877,11 @@ class PathNode extends TPathNode {
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
private PathNode getASuccessorIfHidden() {
this.(PathNodeImpl).isHidden() and
result = this.(PathNodeImpl).getASuccessorImpl()
}
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
not this.(PathNodeImpl).isHidden() and
not result.(PathNodeImpl).isHidden()
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */
@@ -3871,7 +3889,18 @@ class PathNode extends TPathNode {
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNode getASuccessorImpl();
abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() {
this.isHidden() and
result = this.getASuccessorImpl()
}
final PathNodeImpl getANonHiddenSuccessor() {
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
not this.isHidden() and
not result.isHidden()
}
abstract NodeEx getNodeEx();
@@ -3914,15 +3943,17 @@ abstract private class PathNodeImpl extends PathNode {
}
/** Holds if `n` can reach a sink. */
private predicate directReach(PathNode n) {
n instanceof PathNodeSink or directReach(n.getASuccessor())
private predicate directReach(PathNodeImpl n) {
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
}
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and directReach(n2) }
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
}
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
@@ -3931,7 +3962,7 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
*/
module PathGraph {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b and reach(a) and reach(b) }
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b }
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
@@ -4049,7 +4080,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
override Configuration getConfiguration() { result = config }
override PathNode getASuccessorImpl() { none() }
override PathNodeImpl getASuccessorImpl() { none() }
override predicate isSource() { sourceNode(node, state, config) }
}
@@ -4365,8 +4396,8 @@ private module Subpaths {
}
pragma[nomagic]
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getASuccessor() and
private predicate hasSuccessor(PathNodeImpl pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getANonHiddenSuccessor() and
succNode = succ.getNodeEx()
}
@@ -4375,9 +4406,9 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
hasSuccessor(pragma[only_bind_into](arg), par, p) and
not ret.isHidden() and
@@ -4390,12 +4421,12 @@ private module Subpaths {
/**
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/
predicate retReach(PathNode n) {
predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or
exists(PathNode mid |
exists(PathNodeImpl mid |
retReach(mid) and
n.getASuccessor() = mid and
n.getANonHiddenSuccessor() = mid and
not subpaths(_, mid, _, _)
)
}

View File

@@ -90,14 +90,20 @@ abstract class Configuration extends string {
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
@@ -335,6 +341,29 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -348,10 +377,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
not config.isSink(n) and
not config.isSink(n, _)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}
@@ -360,10 +386,7 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
)
}
@@ -3854,16 +3877,11 @@ class PathNode extends TPathNode {
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
private PathNode getASuccessorIfHidden() {
this.(PathNodeImpl).isHidden() and
result = this.(PathNodeImpl).getASuccessorImpl()
}
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
not this.(PathNodeImpl).isHidden() and
not result.(PathNodeImpl).isHidden()
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */
@@ -3871,7 +3889,18 @@ class PathNode extends TPathNode {
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNode getASuccessorImpl();
abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() {
this.isHidden() and
result = this.getASuccessorImpl()
}
final PathNodeImpl getANonHiddenSuccessor() {
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
not this.isHidden() and
not result.isHidden()
}
abstract NodeEx getNodeEx();
@@ -3914,15 +3943,17 @@ abstract private class PathNodeImpl extends PathNode {
}
/** Holds if `n` can reach a sink. */
private predicate directReach(PathNode n) {
n instanceof PathNodeSink or directReach(n.getASuccessor())
private predicate directReach(PathNodeImpl n) {
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
}
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and directReach(n2) }
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
}
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
@@ -3931,7 +3962,7 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
*/
module PathGraph {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b and reach(a) and reach(b) }
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b }
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
@@ -4049,7 +4080,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
override Configuration getConfiguration() { result = config }
override PathNode getASuccessorImpl() { none() }
override PathNodeImpl getASuccessorImpl() { none() }
override predicate isSource() { sourceNode(node, state, config) }
}
@@ -4365,8 +4396,8 @@ private module Subpaths {
}
pragma[nomagic]
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getASuccessor() and
private predicate hasSuccessor(PathNodeImpl pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getANonHiddenSuccessor() and
succNode = succ.getNodeEx()
}
@@ -4375,9 +4406,9 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
hasSuccessor(pragma[only_bind_into](arg), par, p) and
not ret.isHidden() and
@@ -4390,12 +4421,12 @@ private module Subpaths {
/**
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/
predicate retReach(PathNode n) {
predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or
exists(PathNode mid |
exists(PathNodeImpl mid |
retReach(mid) and
n.getASuccessor() = mid and
n.getANonHiddenSuccessor() = mid and
not subpaths(_, mid, _, _)
)
}

View File

@@ -90,14 +90,20 @@ abstract class Configuration extends string {
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
@@ -335,6 +341,29 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -348,10 +377,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
not config.isSink(n) and
not config.isSink(n, _)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}
@@ -360,10 +386,7 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
)
}
@@ -3854,16 +3877,11 @@ class PathNode extends TPathNode {
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
private PathNode getASuccessorIfHidden() {
this.(PathNodeImpl).isHidden() and
result = this.(PathNodeImpl).getASuccessorImpl()
}
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
not this.(PathNodeImpl).isHidden() and
not result.(PathNodeImpl).isHidden()
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */
@@ -3871,7 +3889,18 @@ class PathNode extends TPathNode {
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNode getASuccessorImpl();
abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() {
this.isHidden() and
result = this.getASuccessorImpl()
}
final PathNodeImpl getANonHiddenSuccessor() {
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
not this.isHidden() and
not result.isHidden()
}
abstract NodeEx getNodeEx();
@@ -3914,15 +3943,17 @@ abstract private class PathNodeImpl extends PathNode {
}
/** Holds if `n` can reach a sink. */
private predicate directReach(PathNode n) {
n instanceof PathNodeSink or directReach(n.getASuccessor())
private predicate directReach(PathNodeImpl n) {
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
}
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and directReach(n2) }
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
}
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
@@ -3931,7 +3962,7 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
*/
module PathGraph {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b and reach(a) and reach(b) }
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b }
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
@@ -4049,7 +4080,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
override Configuration getConfiguration() { result = config }
override PathNode getASuccessorImpl() { none() }
override PathNodeImpl getASuccessorImpl() { none() }
override predicate isSource() { sourceNode(node, state, config) }
}
@@ -4365,8 +4396,8 @@ private module Subpaths {
}
pragma[nomagic]
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getASuccessor() and
private predicate hasSuccessor(PathNodeImpl pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getANonHiddenSuccessor() and
succNode = succ.getNodeEx()
}
@@ -4375,9 +4406,9 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
hasSuccessor(pragma[only_bind_into](arg), par, p) and
not ret.isHidden() and
@@ -4390,12 +4421,12 @@ private module Subpaths {
/**
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/
predicate retReach(PathNode n) {
predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or
exists(PathNode mid |
exists(PathNodeImpl mid |
retReach(mid) and
n.getASuccessor() = mid and
n.getANonHiddenSuccessor() = mid and
not subpaths(_, mid, _, _)
)
}

View File

@@ -90,14 +90,20 @@ abstract class Configuration extends string {
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
@@ -335,6 +341,29 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -348,10 +377,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
not config.isSink(n) and
not config.isSink(n, _)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}
@@ -360,10 +386,7 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
)
}
@@ -3854,16 +3877,11 @@ class PathNode extends TPathNode {
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
private PathNode getASuccessorIfHidden() {
this.(PathNodeImpl).isHidden() and
result = this.(PathNodeImpl).getASuccessorImpl()
}
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
not this.(PathNodeImpl).isHidden() and
not result.(PathNodeImpl).isHidden()
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */
@@ -3871,7 +3889,18 @@ class PathNode extends TPathNode {
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNode getASuccessorImpl();
abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() {
this.isHidden() and
result = this.getASuccessorImpl()
}
final PathNodeImpl getANonHiddenSuccessor() {
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
not this.isHidden() and
not result.isHidden()
}
abstract NodeEx getNodeEx();
@@ -3914,15 +3943,17 @@ abstract private class PathNodeImpl extends PathNode {
}
/** Holds if `n` can reach a sink. */
private predicate directReach(PathNode n) {
n instanceof PathNodeSink or directReach(n.getASuccessor())
private predicate directReach(PathNodeImpl n) {
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
}
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and directReach(n2) }
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
}
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
@@ -3931,7 +3962,7 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
*/
module PathGraph {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b and reach(a) and reach(b) }
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b }
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
@@ -4049,7 +4080,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
override Configuration getConfiguration() { result = config }
override PathNode getASuccessorImpl() { none() }
override PathNodeImpl getASuccessorImpl() { none() }
override predicate isSource() { sourceNode(node, state, config) }
}
@@ -4365,8 +4396,8 @@ private module Subpaths {
}
pragma[nomagic]
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getASuccessor() and
private predicate hasSuccessor(PathNodeImpl pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getANonHiddenSuccessor() and
succNode = succ.getNodeEx()
}
@@ -4375,9 +4406,9 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
hasSuccessor(pragma[only_bind_into](arg), par, p) and
not ret.isHidden() and
@@ -4390,12 +4421,12 @@ private module Subpaths {
/**
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/
predicate retReach(PathNode n) {
predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or
exists(PathNode mid |
exists(PathNodeImpl mid |
retReach(mid) and
n.getASuccessor() = mid and
n.getANonHiddenSuccessor() = mid and
not subpaths(_, mid, _, _)
)
}

View File

@@ -216,10 +216,9 @@ private module LambdaFlow {
or
// jump step
exists(Node mid, DataFlowType t0 |
revLambdaFlow(lambdaCall, kind, mid, t0, _, _, _) and
revLambdaFlow(lambdaCall, kind, mid, t0, _, _, lastCall) and
toReturn = false and
toJump = true and
lastCall = TDataFlowCallNone()
toJump = true
|
jumpStepCached(node, mid) and
t = t0
@@ -305,7 +304,7 @@ cached
private module Cached {
/**
* If needed, call this predicate from `DataFlowImplSpecific.qll` in order to
* force a stage-dependency on the `DataFlowImplCommon.qll` stage and therby
* force a stage-dependency on the `DataFlowImplCommon.qll` stage and thereby
* collapsing the two stages.
*/
cached
@@ -789,24 +788,31 @@ private module Cached {
cached
predicate readSet(Node node1, ContentSet c, Node node2) { readStep(node1, c, node2) }
cached
predicate storeSet(
Node node1, ContentSet c, Node node2, DataFlowType contentType, DataFlowType containerType
) {
storeStep(node1, c, node2) and
contentType = getNodeDataFlowType(node1) and
containerType = getNodeDataFlowType(node2)
or
exists(Node n1, Node n2 |
n1 = node1.(PostUpdateNode).getPreUpdateNode() and
n2 = node2.(PostUpdateNode).getPreUpdateNode()
|
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1)
or
readSet(n2, c, n1) and
contentType = getNodeDataFlowType(n1) and
containerType = getNodeDataFlowType(n2)
)
}
private predicate store(
Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType
) {
exists(ContentSet cs | c = cs.getAStoreContent() |
storeStep(node1, cs, node2) and
contentType = getNodeDataFlowType(node1) and
containerType = getNodeDataFlowType(node2)
or
exists(Node n1, Node n2 |
n1 = node1.(PostUpdateNode).getPreUpdateNode() and
n2 = node2.(PostUpdateNode).getPreUpdateNode()
|
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, cs, contentType), n1)
or
readSet(n2, cs, n1) and
contentType = getNodeDataFlowType(n1) and
containerType = getNodeDataFlowType(n2)
)
exists(ContentSet cs |
c = cs.getAStoreContent() and storeSet(node1, cs, node2, contentType, containerType)
)
}

View File

@@ -90,14 +90,20 @@ abstract class Configuration extends string {
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
@@ -335,6 +341,29 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -348,10 +377,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
not config.isSink(n) and
not config.isSink(n, _)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}
@@ -360,10 +386,7 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
)
}
@@ -3854,16 +3877,11 @@ class PathNode extends TPathNode {
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
private PathNode getASuccessorIfHidden() {
this.(PathNodeImpl).isHidden() and
result = this.(PathNodeImpl).getASuccessorImpl()
}
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
not this.(PathNodeImpl).isHidden() and
not result.(PathNodeImpl).isHidden()
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */
@@ -3871,7 +3889,18 @@ class PathNode extends TPathNode {
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNode getASuccessorImpl();
abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() {
this.isHidden() and
result = this.getASuccessorImpl()
}
final PathNodeImpl getANonHiddenSuccessor() {
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
not this.isHidden() and
not result.isHidden()
}
abstract NodeEx getNodeEx();
@@ -3914,15 +3943,17 @@ abstract private class PathNodeImpl extends PathNode {
}
/** Holds if `n` can reach a sink. */
private predicate directReach(PathNode n) {
n instanceof PathNodeSink or directReach(n.getASuccessor())
private predicate directReach(PathNodeImpl n) {
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
}
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and directReach(n2) }
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
}
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
@@ -3931,7 +3962,7 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
*/
module PathGraph {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b and reach(a) and reach(b) }
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b }
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
@@ -4049,7 +4080,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
override Configuration getConfiguration() { result = config }
override PathNode getASuccessorImpl() { none() }
override PathNodeImpl getASuccessorImpl() { none() }
override predicate isSource() { sourceNode(node, state, config) }
}
@@ -4365,8 +4396,8 @@ private module Subpaths {
}
pragma[nomagic]
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getASuccessor() and
private predicate hasSuccessor(PathNodeImpl pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getANonHiddenSuccessor() and
succNode = succ.getNodeEx()
}
@@ -4375,9 +4406,9 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
hasSuccessor(pragma[only_bind_into](arg), par, p) and
not ret.isHidden() and
@@ -4390,12 +4421,12 @@ private module Subpaths {
/**
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/
predicate retReach(PathNode n) {
predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or
exists(PathNode mid |
exists(PathNodeImpl mid |
retReach(mid) and
n.getASuccessor() = mid and
n.getANonHiddenSuccessor() = mid and
not subpaths(_, mid, _, _)
)
}

View File

@@ -850,6 +850,34 @@ class ContentSet instanceof Content {
}
/**
* Holds if the guard `g` validates the expression `e` upon evaluating to `branch`.
*
* The expression `e` is expected to be a syntactic part of the guard `g`.
* For example, the guard `g` might be a call `isSafe(x)` and the expression `e`
* the argument `x`.
*/
signature predicate guardChecksSig(GuardCondition g, Expr e, boolean branch);
/**
* Provides a set of barrier nodes for a guard that validates an expression.
*
* This is expected to be used in `isBarrier`/`isSanitizer` definitions
* in data flow and taint tracking.
*/
module BarrierGuard<guardChecksSig/3 guardChecks> {
/** Gets a node that is safely guarded by the given guard check. */
ExprNode getABarrierNode() {
exists(GuardCondition g, SsaDefinition def, Variable v, boolean branch |
result.getExpr() = def.getAUse(v) and
guardChecks(g, def.getAUse(v), branch) and
g.controls(result.getExpr().getBasicBlock(), branch)
)
}
}
/**
* DEPRECATED: Use `BarrierGuard` module instead.
*
* A guard that validates some expression.
*
* To use this in a configuration, extend the class and provide a
@@ -858,7 +886,7 @@ class ContentSet instanceof Content {
*
* It is important that all extending classes in scope are disjoint.
*/
class BarrierGuard extends GuardCondition {
deprecated class BarrierGuard extends GuardCondition {
/** Override this predicate to hold if this guard validates `e` upon evaluating to `b`. */
abstract predicate checks(Expr e, boolean b);

View File

@@ -549,7 +549,7 @@ module FlowVar_internal {
bb = this.(Loop).getStmt() and
v = this.getARelevantVariable()
or
this.reachesWithoutAssignment(bb.getAPredecessor(), v) and
this.reachesWithoutAssignment(pragma[only_bind_out](bb.getAPredecessor()), v) and
this.bbInLoop(bb)
) and
not assignsToVar(bb, v)

View File

@@ -47,12 +47,6 @@ predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::Content c) { n
*/
predicate defaultTaintSanitizer(DataFlow::Node node) { none() }
/**
* Holds if `guard` should be a sanitizer guard in all global taint flow configurations
* but not in local taint.
*/
predicate defaultTaintSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
/**
* Holds if taint can flow in one local step from `nodeFrom` to `nodeTo` excluding
* local data flow steps. That is, `nodeFrom` and `nodeTo` are likely to represent

View File

@@ -116,20 +116,30 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
deprecated final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard)
}
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
none()
}
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
deprecated final override predicate isBarrierGuard(
DataFlow::BarrierGuard guard, DataFlow::FlowState state
) {
this.isSanitizerGuard(guard, state)
}

View File

@@ -116,20 +116,30 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
deprecated final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard)
}
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
none()
}
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
deprecated final override predicate isBarrierGuard(
DataFlow::BarrierGuard guard, DataFlow::FlowState state
) {
this.isSanitizerGuard(guard, state)
}

View File

@@ -49,6 +49,9 @@ class Expr extends StmtParent, @expr {
/** Gets the enclosing variable of this expression, if any. */
Variable getEnclosingVariable() { result = exprEnclosingElement(this) }
/** Gets the enclosing variable or function of this expression. */
Declaration getEnclosingDeclaration() { result = exprEnclosingElement(this) }
/** Gets a child of this expression. */
Expr getAChild() { exists(int n | result = this.getChild(n)) }

View File

@@ -4,11 +4,7 @@
* qualified.
*
* This file contains classes that mirror the standard AST classes for C++, but
* these classes are only concerned with naming. The other difference is that
* these classes don't use the `ResolveClass.qll` mechanisms like
* `unresolveElement` because these classes should eventually be part of the
* implementation of `ResolveClass.qll`, allowing it to match up classes when
* their qualified names and parameters match.
* these classes are only concerned with naming.
*/
private import semmle.code.cpp.Declaration as D

View File

@@ -115,15 +115,13 @@ private module Cached {
*/
cached
predicate isClass(@usertype t) {
(
usertypes(t, _, 1) or
usertypes(t, _, 2) or
usertypes(t, _, 3) or
usertypes(t, _, 6) or
usertypes(t, _, 10) or
usertypes(t, _, 11) or
usertypes(t, _, 12)
)
usertypes(t, _, 1) or
usertypes(t, _, 2) or
usertypes(t, _, 3) or
usertypes(t, _, 6) or
usertypes(t, _, 10) or
usertypes(t, _, 11) or
usertypes(t, _, 12)
}
cached

View File

@@ -90,14 +90,20 @@ abstract class Configuration extends string {
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
@@ -335,6 +341,29 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -348,10 +377,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
not config.isSink(n) and
not config.isSink(n, _)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}
@@ -360,10 +386,7 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
)
}
@@ -3854,16 +3877,11 @@ class PathNode extends TPathNode {
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
private PathNode getASuccessorIfHidden() {
this.(PathNodeImpl).isHidden() and
result = this.(PathNodeImpl).getASuccessorImpl()
}
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
not this.(PathNodeImpl).isHidden() and
not result.(PathNodeImpl).isHidden()
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */
@@ -3871,7 +3889,18 @@ class PathNode extends TPathNode {
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNode getASuccessorImpl();
abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() {
this.isHidden() and
result = this.getASuccessorImpl()
}
final PathNodeImpl getANonHiddenSuccessor() {
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
not this.isHidden() and
not result.isHidden()
}
abstract NodeEx getNodeEx();
@@ -3914,15 +3943,17 @@ abstract private class PathNodeImpl extends PathNode {
}
/** Holds if `n` can reach a sink. */
private predicate directReach(PathNode n) {
n instanceof PathNodeSink or directReach(n.getASuccessor())
private predicate directReach(PathNodeImpl n) {
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
}
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and directReach(n2) }
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
}
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
@@ -3931,7 +3962,7 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
*/
module PathGraph {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b and reach(a) and reach(b) }
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b }
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
@@ -4049,7 +4080,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
override Configuration getConfiguration() { result = config }
override PathNode getASuccessorImpl() { none() }
override PathNodeImpl getASuccessorImpl() { none() }
override predicate isSource() { sourceNode(node, state, config) }
}
@@ -4365,8 +4396,8 @@ private module Subpaths {
}
pragma[nomagic]
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getASuccessor() and
private predicate hasSuccessor(PathNodeImpl pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getANonHiddenSuccessor() and
succNode = succ.getNodeEx()
}
@@ -4375,9 +4406,9 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
hasSuccessor(pragma[only_bind_into](arg), par, p) and
not ret.isHidden() and
@@ -4390,12 +4421,12 @@ private module Subpaths {
/**
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/
predicate retReach(PathNode n) {
predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or
exists(PathNode mid |
exists(PathNodeImpl mid |
retReach(mid) and
n.getASuccessor() = mid and
n.getANonHiddenSuccessor() = mid and
not subpaths(_, mid, _, _)
)
}

View File

@@ -90,14 +90,20 @@ abstract class Configuration extends string {
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
@@ -335,6 +341,29 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -348,10 +377,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
not config.isSink(n) and
not config.isSink(n, _)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}
@@ -360,10 +386,7 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
)
}
@@ -3854,16 +3877,11 @@ class PathNode extends TPathNode {
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
private PathNode getASuccessorIfHidden() {
this.(PathNodeImpl).isHidden() and
result = this.(PathNodeImpl).getASuccessorImpl()
}
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
not this.(PathNodeImpl).isHidden() and
not result.(PathNodeImpl).isHidden()
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */
@@ -3871,7 +3889,18 @@ class PathNode extends TPathNode {
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNode getASuccessorImpl();
abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() {
this.isHidden() and
result = this.getASuccessorImpl()
}
final PathNodeImpl getANonHiddenSuccessor() {
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
not this.isHidden() and
not result.isHidden()
}
abstract NodeEx getNodeEx();
@@ -3914,15 +3943,17 @@ abstract private class PathNodeImpl extends PathNode {
}
/** Holds if `n` can reach a sink. */
private predicate directReach(PathNode n) {
n instanceof PathNodeSink or directReach(n.getASuccessor())
private predicate directReach(PathNodeImpl n) {
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
}
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and directReach(n2) }
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
}
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
@@ -3931,7 +3962,7 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
*/
module PathGraph {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b and reach(a) and reach(b) }
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b }
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
@@ -4049,7 +4080,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
override Configuration getConfiguration() { result = config }
override PathNode getASuccessorImpl() { none() }
override PathNodeImpl getASuccessorImpl() { none() }
override predicate isSource() { sourceNode(node, state, config) }
}
@@ -4365,8 +4396,8 @@ private module Subpaths {
}
pragma[nomagic]
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getASuccessor() and
private predicate hasSuccessor(PathNodeImpl pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getANonHiddenSuccessor() and
succNode = succ.getNodeEx()
}
@@ -4375,9 +4406,9 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
hasSuccessor(pragma[only_bind_into](arg), par, p) and
not ret.isHidden() and
@@ -4390,12 +4421,12 @@ private module Subpaths {
/**
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/
predicate retReach(PathNode n) {
predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or
exists(PathNode mid |
exists(PathNodeImpl mid |
retReach(mid) and
n.getASuccessor() = mid and
n.getANonHiddenSuccessor() = mid and
not subpaths(_, mid, _, _)
)
}

View File

@@ -90,14 +90,20 @@ abstract class Configuration extends string {
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
@@ -335,6 +341,29 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -348,10 +377,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
not config.isSink(n) and
not config.isSink(n, _)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}
@@ -360,10 +386,7 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
)
}
@@ -3854,16 +3877,11 @@ class PathNode extends TPathNode {
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
private PathNode getASuccessorIfHidden() {
this.(PathNodeImpl).isHidden() and
result = this.(PathNodeImpl).getASuccessorImpl()
}
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
not this.(PathNodeImpl).isHidden() and
not result.(PathNodeImpl).isHidden()
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */
@@ -3871,7 +3889,18 @@ class PathNode extends TPathNode {
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNode getASuccessorImpl();
abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() {
this.isHidden() and
result = this.getASuccessorImpl()
}
final PathNodeImpl getANonHiddenSuccessor() {
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
not this.isHidden() and
not result.isHidden()
}
abstract NodeEx getNodeEx();
@@ -3914,15 +3943,17 @@ abstract private class PathNodeImpl extends PathNode {
}
/** Holds if `n` can reach a sink. */
private predicate directReach(PathNode n) {
n instanceof PathNodeSink or directReach(n.getASuccessor())
private predicate directReach(PathNodeImpl n) {
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
}
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and directReach(n2) }
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
}
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
@@ -3931,7 +3962,7 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
*/
module PathGraph {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b and reach(a) and reach(b) }
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b }
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
@@ -4049,7 +4080,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
override Configuration getConfiguration() { result = config }
override PathNode getASuccessorImpl() { none() }
override PathNodeImpl getASuccessorImpl() { none() }
override predicate isSource() { sourceNode(node, state, config) }
}
@@ -4365,8 +4396,8 @@ private module Subpaths {
}
pragma[nomagic]
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getASuccessor() and
private predicate hasSuccessor(PathNodeImpl pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getANonHiddenSuccessor() and
succNode = succ.getNodeEx()
}
@@ -4375,9 +4406,9 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
hasSuccessor(pragma[only_bind_into](arg), par, p) and
not ret.isHidden() and
@@ -4390,12 +4421,12 @@ private module Subpaths {
/**
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/
predicate retReach(PathNode n) {
predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or
exists(PathNode mid |
exists(PathNodeImpl mid |
retReach(mid) and
n.getASuccessor() = mid and
n.getANonHiddenSuccessor() = mid and
not subpaths(_, mid, _, _)
)
}

View File

@@ -90,14 +90,20 @@ abstract class Configuration extends string {
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
@@ -335,6 +341,29 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -348,10 +377,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
not config.isSink(n) and
not config.isSink(n, _)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}
@@ -360,10 +386,7 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
)
}
@@ -3854,16 +3877,11 @@ class PathNode extends TPathNode {
/** Gets the associated configuration. */
Configuration getConfiguration() { none() }
private PathNode getASuccessorIfHidden() {
this.(PathNodeImpl).isHidden() and
result = this.(PathNodeImpl).getASuccessorImpl()
}
/** Gets a successor of this node, if any. */
final PathNode getASuccessor() {
result = this.(PathNodeImpl).getASuccessorImpl().getASuccessorIfHidden*() and
not this.(PathNodeImpl).isHidden() and
not result.(PathNodeImpl).isHidden()
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
reach(this) and
reach(result)
}
/** Holds if this node is a source. */
@@ -3871,7 +3889,18 @@ class PathNode extends TPathNode {
}
abstract private class PathNodeImpl extends PathNode {
abstract PathNode getASuccessorImpl();
abstract PathNodeImpl getASuccessorImpl();
private PathNodeImpl getASuccessorIfHidden() {
this.isHidden() and
result = this.getASuccessorImpl()
}
final PathNodeImpl getANonHiddenSuccessor() {
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
not this.isHidden() and
not result.isHidden()
}
abstract NodeEx getNodeEx();
@@ -3914,15 +3943,17 @@ abstract private class PathNodeImpl extends PathNode {
}
/** Holds if `n` can reach a sink. */
private predicate directReach(PathNode n) {
n instanceof PathNodeSink or directReach(n.getASuccessor())
private predicate directReach(PathNodeImpl n) {
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
}
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
private predicate pathSucc(PathNode n1, PathNode n2) { n1.getASuccessor() = n2 and directReach(n2) }
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
}
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
@@ -3931,7 +3962,7 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
*/
module PathGraph {
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b and reach(a) and reach(b) }
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b }
/** Holds if `n` is a node in the graph of data flow path explanations. */
query predicate nodes(PathNode n, string key, string val) {
@@ -4049,7 +4080,7 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
override Configuration getConfiguration() { result = config }
override PathNode getASuccessorImpl() { none() }
override PathNodeImpl getASuccessorImpl() { none() }
override predicate isSource() { sourceNode(node, state, config) }
}
@@ -4365,8 +4396,8 @@ private module Subpaths {
}
pragma[nomagic]
private predicate hasSuccessor(PathNode pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getASuccessor() and
private predicate hasSuccessor(PathNodeImpl pred, PathNodeMid succ, NodeEx succNode) {
succ = pred.getANonHiddenSuccessor() and
succNode = succ.getNodeEx()
}
@@ -4375,9 +4406,9 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
pragma[only_bind_into](arg).getASuccessor() = pragma[only_bind_into](out0) and
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
hasSuccessor(pragma[only_bind_into](arg), par, p) and
not ret.isHidden() and
@@ -4390,12 +4421,12 @@ private module Subpaths {
/**
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
*/
predicate retReach(PathNode n) {
predicate retReach(PathNodeImpl n) {
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
or
exists(PathNode mid |
exists(PathNodeImpl mid |
retReach(mid) and
n.getASuccessor() = mid and
n.getANonHiddenSuccessor() = mid and
not subpaths(_, mid, _, _)
)
}

View File

@@ -216,10 +216,9 @@ private module LambdaFlow {
or
// jump step
exists(Node mid, DataFlowType t0 |
revLambdaFlow(lambdaCall, kind, mid, t0, _, _, _) and
revLambdaFlow(lambdaCall, kind, mid, t0, _, _, lastCall) and
toReturn = false and
toJump = true and
lastCall = TDataFlowCallNone()
toJump = true
|
jumpStepCached(node, mid) and
t = t0
@@ -305,7 +304,7 @@ cached
private module Cached {
/**
* If needed, call this predicate from `DataFlowImplSpecific.qll` in order to
* force a stage-dependency on the `DataFlowImplCommon.qll` stage and therby
* force a stage-dependency on the `DataFlowImplCommon.qll` stage and thereby
* collapsing the two stages.
*/
cached
@@ -789,24 +788,31 @@ private module Cached {
cached
predicate readSet(Node node1, ContentSet c, Node node2) { readStep(node1, c, node2) }
cached
predicate storeSet(
Node node1, ContentSet c, Node node2, DataFlowType contentType, DataFlowType containerType
) {
storeStep(node1, c, node2) and
contentType = getNodeDataFlowType(node1) and
containerType = getNodeDataFlowType(node2)
or
exists(Node n1, Node n2 |
n1 = node1.(PostUpdateNode).getPreUpdateNode() and
n2 = node2.(PostUpdateNode).getPreUpdateNode()
|
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1)
or
readSet(n2, c, n1) and
contentType = getNodeDataFlowType(n1) and
containerType = getNodeDataFlowType(n2)
)
}
private predicate store(
Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType
) {
exists(ContentSet cs | c = cs.getAStoreContent() |
storeStep(node1, cs, node2) and
contentType = getNodeDataFlowType(node1) and
containerType = getNodeDataFlowType(node2)
or
exists(Node n1, Node n2 |
n1 = node1.(PostUpdateNode).getPreUpdateNode() and
n2 = node2.(PostUpdateNode).getPreUpdateNode()
|
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, cs, contentType), n1)
or
readSet(n2, cs, n1) and
contentType = getNodeDataFlowType(n1) and
containerType = getNodeDataFlowType(n2)
)
exists(ContentSet cs |
c = cs.getAStoreContent() and storeSet(node1, cs, node2, contentType, containerType)
)
}

View File

@@ -37,7 +37,7 @@ private module Cached {
* along the chain of addresses computed by `StoreNodeInstr.getInner` to identify field writes
* and call `storeStep` accordingly (i.e., for an expression like `a.b.c = x`, we visit `c`, then
* `b`, then `a`).
* 2. Flow is transfered from a `WriteSideEffectInstruction` to a `StoreNodeOperand` after flow
* 2. Flow is transferred from a `WriteSideEffectInstruction` to a `StoreNodeOperand` after flow
* returns to a caller. Flow will then proceed to the defining instruction of the operand (because
* the `StoreNodeInstr` computed by `StoreNodeOperand.getInner()` is the `StoreNode` containing
* the defining instruction), and then along the chain computed by `StoreNodeInstr.getInner` like
@@ -100,7 +100,7 @@ class Node extends TIRDataFlowNode {
Declaration getEnclosingCallable() { none() } // overridden in subclasses
/** Gets the function to which this node belongs, if any. */
Function getFunction() { none() } // overridden in subclasses
Declaration getFunction() { none() } // overridden in subclasses
/** Gets the type of this node. */
IRType getType() { none() } // overridden in subclasses
@@ -196,7 +196,7 @@ class InstructionNode extends Node, TInstructionNode {
override Declaration getEnclosingCallable() { result = this.getFunction() }
override Function getFunction() { result = instr.getEnclosingFunction() }
override Declaration getFunction() { result = instr.getEnclosingFunction() }
override IRType getType() { result = instr.getResultIRType() }
@@ -222,7 +222,7 @@ class OperandNode extends Node, TOperandNode {
override Declaration getEnclosingCallable() { result = this.getFunction() }
override Function getFunction() { result = op.getUse().getEnclosingFunction() }
override Declaration getFunction() { result = op.getUse().getEnclosingFunction() }
override IRType getType() { result = op.getIRType() }
@@ -274,7 +274,7 @@ class StoreNodeInstr extends StoreNode, TStoreNodeInstr {
/** Gets the underlying instruction. */
Instruction getInstruction() { result = instr }
override Function getFunction() { result = this.getInstruction().getEnclosingFunction() }
override Declaration getFunction() { result = this.getInstruction().getEnclosingFunction() }
override IRType getType() { result = this.getInstruction().getResultIRType() }
@@ -328,7 +328,7 @@ class StoreNodeOperand extends StoreNode, TStoreNodeOperand {
/** Gets the underlying operand. */
Operand getOperand() { result = operand }
override Function getFunction() { result = operand.getDef().getEnclosingFunction() }
override Declaration getFunction() { result = operand.getDef().getEnclosingFunction() }
override IRType getType() { result = operand.getIRType() }
@@ -384,7 +384,7 @@ class ReadNode extends Node, TReadNode {
override Declaration getEnclosingCallable() { result = this.getFunction() }
override Function getFunction() { result = this.getInstruction().getEnclosingFunction() }
override Declaration getFunction() { result = this.getInstruction().getEnclosingFunction() }
override IRType getType() { result = this.getInstruction().getResultIRType() }
@@ -436,7 +436,7 @@ class SsaPhiNode extends Node, TSsaPhiNode {
override Declaration getEnclosingCallable() { result = this.getFunction() }
override Function getFunction() { result = phi.getBasicBlock().getEnclosingFunction() }
override Declaration getFunction() { result = phi.getBasicBlock().getEnclosingFunction() }
override IRType getType() { result instanceof IRVoidType }
@@ -673,7 +673,7 @@ class VariableNode extends Node, TVariableNode {
/** Gets the variable corresponding to this node. */
Variable getVariable() { result = v }
override Function getFunction() { none() }
override Declaration getFunction() { none() }
override Declaration getEnclosingCallable() {
// When flow crosses from one _enclosing callable_ to another, the
@@ -1092,6 +1092,56 @@ class ContentSet instanceof Content {
}
/**
* Holds if the guard `g` validates the expression `e` upon evaluating to `branch`.
*
* The expression `e` is expected to be a syntactic part of the guard `g`.
* For example, the guard `g` might be a call `isSafe(x)` and the expression `e`
* the argument `x`.
*/
signature predicate guardChecksSig(IRGuardCondition g, Expr e, boolean branch);
/**
* Provides a set of barrier nodes for a guard that validates an expression.
*
* This is expected to be used in `isBarrier`/`isSanitizer` definitions
* in data flow and taint tracking.
*/
module BarrierGuard<guardChecksSig/3 guardChecks> {
/** Gets a node that is safely guarded by the given guard check. */
ExprNode getABarrierNode() {
exists(IRGuardCondition g, ValueNumber value, boolean edge |
guardChecks(g, value.getAnInstruction().getConvertedResultExpression(), edge) and
result.asInstruction() = value.getAnInstruction() and
g.controls(result.asInstruction().getBlock(), edge)
)
}
}
/**
* Holds if the guard `g` validates the instruction `instr` upon evaluating to `branch`.
*/
signature predicate instructionGuardChecksSig(IRGuardCondition g, Instruction instr, boolean branch);
/**
* Provides a set of barrier nodes for a guard that validates an instruction.
*
* This is expected to be used in `isBarrier`/`isSanitizer` definitions
* in data flow and taint tracking.
*/
module InstructionBarrierGuard<instructionGuardChecksSig/3 instructionGuardChecks> {
/** Gets a node that is safely guarded by the given guard check. */
ExprNode getABarrierNode() {
exists(IRGuardCondition g, ValueNumber value, boolean edge |
instructionGuardChecks(g, value.getAnInstruction(), edge) and
result.asInstruction() = value.getAnInstruction() and
g.controls(result.asInstruction().getBlock(), edge)
)
}
}
/**
* DEPRECATED: Use `BarrierGuard` module instead.
*
* A guard that validates some instruction.
*
* To use this in a configuration, extend the class and provide a
@@ -1100,7 +1150,7 @@ class ContentSet instanceof Content {
*
* It is important that all extending classes in scope are disjoint.
*/
class BarrierGuard extends IRGuardCondition {
deprecated class BarrierGuard extends IRGuardCondition {
/** Override this predicate to hold if this guard validates `instr` upon evaluating to `b`. */
predicate checksInstr(Instruction instr, boolean b) { none() }

View File

@@ -94,12 +94,6 @@ private string getNodeProperty(DataFlow::Node node, string key) {
any(DataFlow::Configuration cfg).isBarrierIn(node) and kind = "in"
or
any(DataFlow::Configuration cfg).isBarrierOut(node) and kind = "out"
or
exists(DataFlow::BarrierGuard guard |
any(DataFlow::Configuration cfg).isBarrierGuard(guard) and
node = guard.getAGuardedNode() and
kind = "guard(" + guard.getResultId() + ")"
)
|
kind, ", "
)

View File

@@ -163,12 +163,6 @@ predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::Content c) { n
*/
predicate defaultTaintSanitizer(DataFlow::Node node) { none() }
/**
* Holds if `guard` should be a sanitizer guard in all global taint flow configurations
* but not in local taint.
*/
predicate defaultTaintSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
/**
* Holds if taint can flow from `instrIn` to `instrOut` through a call to a
* modeled function.

View File

@@ -116,20 +116,30 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
deprecated final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard)
}
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
none()
}
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
deprecated final override predicate isBarrierGuard(
DataFlow::BarrierGuard guard, DataFlow::FlowState state
) {
this.isSanitizerGuard(guard, state)
}

View File

@@ -116,20 +116,30 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
deprecated final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard)
}
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
none()
}
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
deprecated final override predicate isBarrierGuard(
DataFlow::BarrierGuard guard, DataFlow::FlowState state
) {
this.isSanitizerGuard(guard, state)
}

View File

@@ -116,20 +116,30 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
deprecated final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard)
}
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
none()
}
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
deprecated final override predicate isBarrierGuard(
DataFlow::BarrierGuard guard, DataFlow::FlowState state
) {
this.isSanitizerGuard(guard, state)
}

View File

@@ -67,7 +67,7 @@ class DefaultEdge extends EdgeKind, TDefaultEdge {
/**
* A "case" edge, representing the successor of a `Switch` instruction when the
* the condition value matches a correponding `case` label.
* the condition value matches a corresponding `case` label.
*/
class CaseEdge extends EdgeKind, TCaseEdge {
string minValue;

View File

@@ -16,7 +16,7 @@ class IRConfiguration extends TIRConfiguration {
/**
* Holds if IR should be created for function `func`. By default, holds for all functions.
*/
predicate shouldCreateIRForFunction(Language::Function func) { any() }
predicate shouldCreateIRForFunction(Language::Declaration func) { any() }
/**
* Holds if the strings used as part of an IR dump should be generated for function `func`.
@@ -25,7 +25,7 @@ class IRConfiguration extends TIRConfiguration {
* of debug strings for IR that will not be dumped. We still generate the actual IR for these
* functions, however, to preserve the results of any interprocedural analysis.
*/
predicate shouldEvaluateDebugStringsForFunction(Language::Function func) { any() }
predicate shouldEvaluateDebugStringsForFunction(Language::Declaration func) { any() }
}
private newtype TIREscapeAnalysisConfiguration = MkIREscapeAnalysisConfiguration()

View File

@@ -97,7 +97,7 @@ class IRBlockBase extends TIRBlock {
/**
* Gets the `Function` that contains this block.
*/
final Language::Function getEnclosingFunction() {
final Language::Declaration getEnclosingFunction() {
result = getFirstInstruction(this).getEnclosingFunction()
}
}

View File

@@ -524,4 +524,23 @@ module InstructionConsistency {
"' has a `this` argument operand that is not an address, in function '$@'." and
irFunc = getInstructionIRFunction(instr, irFuncText)
}
query predicate nonUniqueIRVariable(
Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText
) {
exists(VariableInstruction vi, IRVariable v1, IRVariable v2 |
instr = vi and vi.getIRVariable() = v1 and vi.getIRVariable() = v2 and v1 != v2
) and
message =
"Variable instruction '" + instr.toString() +
"' has multiple associated variables, in function '$@'." and
irFunc = getInstructionIRFunction(instr, irFuncText)
or
instr.getOpcode() instanceof Opcode::VariableAddress and
not instr instanceof VariableInstruction and
message =
"Variable address instruction '" + instr.toString() +
"' has no associated variable, in function '$@'." and
irFunc = getInstructionIRFunction(instr, irFuncText)
}
}

View File

@@ -18,7 +18,7 @@ private import Imports::IRType
* by the AST-to-IR translation (`IRTempVariable`).
*/
class IRVariable extends TIRVariable {
Language::Function func;
Language::Declaration func;
IRVariable() {
this = TIRUserVariable(_, _, func) or
@@ -79,7 +79,7 @@ class IRVariable extends TIRVariable {
/**
* Gets the function that references this variable.
*/
final Language::Function getEnclosingFunction() { result = func }
final Language::Declaration getEnclosingFunction() { result = func }
}
/**
@@ -246,7 +246,7 @@ class IREllipsisVariable extends IRTempVariable, IRParameter {
final override string toString() { result = "#ellipsis" }
final override int getIndex() { result = func.getNumberOfParameters() }
final override int getIndex() { result = func.(Language::Function).getNumberOfParameters() }
}
/**

View File

@@ -194,7 +194,7 @@ class Instruction extends Construction::TStageInstruction {
/**
* Gets the function that contains this instruction.
*/
final Language::Function getEnclosingFunction() {
final Language::Declaration getEnclosingFunction() {
result = this.getEnclosingIRFunction().getFunction()
}

View File

@@ -26,20 +26,20 @@ class PrintIRConfiguration extends TPrintIRConfiguration {
* Holds if the IR for `func` should be printed. By default, holds for all
* functions.
*/
predicate shouldPrintFunction(Language::Function func) { any() }
predicate shouldPrintFunction(Language::Declaration decl) { any() }
}
/**
* Override of `IRConfiguration` to only evaluate debug strings for the functions that are to be dumped.
*/
private class FilteredIRConfiguration extends IRConfiguration {
override predicate shouldEvaluateDebugStringsForFunction(Language::Function func) {
override predicate shouldEvaluateDebugStringsForFunction(Language::Declaration func) {
shouldPrintFunction(func)
}
}
private predicate shouldPrintFunction(Language::Function func) {
exists(PrintIRConfiguration config | config.shouldPrintFunction(func))
private predicate shouldPrintFunction(Language::Declaration decl) {
exists(PrintIRConfiguration config | config.shouldPrintFunction(decl))
}
private string getAdditionalInstructionProperty(Instruction instr, string key) {

View File

@@ -34,7 +34,7 @@ class ValueNumber extends TValueNumber {
final Instruction getAnInstruction() { this = valueNumber(result) }
/**
* Gets one of the instructions that was assigned this value number. The chosen instuction is
* Gets one of the instructions that was assigned this value number. The chosen instruction is
* deterministic but arbitrary. Intended for use only in debugging.
*/
final Instruction getExampleInstruction() {

View File

@@ -1005,7 +1005,7 @@ predicate canReuseSsaForMemoryResult(Instruction instruction) {
deprecated predicate canReuseSSAForMemoryResult = canReuseSsaForMemoryResult/1;
/**
* Expose some of the internal predicates to PrintSSA.qll. We do this by publically importing those modules in the
* Expose some of the internal predicates to PrintSSA.qll. We do this by publicly importing those modules in the
* `DebugSSA` module, which is then imported by PrintSSA.
*/
module DebugSsa {

View File

@@ -5,23 +5,28 @@
private import IRFunctionBaseInternal
private newtype TIRFunction =
MkIRFunction(Language::Function func) { IRConstruction::Raw::functionHasIR(func) }
TFunctionIRFunction(Language::Function func) { IRConstruction::Raw::functionHasIR(func) } or
TVarInitIRFunction(Language::GlobalVariable var) { IRConstruction::Raw::varHasIRFunc(var) }
/**
* The IR for a function. This base class contains only the predicates that are the same between all
* phases of the IR. Each instantiation of `IRFunction` extends this class.
*/
class IRFunctionBase extends TIRFunction {
Language::Function func;
Language::Declaration decl;
IRFunctionBase() { this = MkIRFunction(func) }
IRFunctionBase() {
this = TFunctionIRFunction(decl)
or
this = TVarInitIRFunction(decl)
}
/** Gets a textual representation of this element. */
final string toString() { result = "IR: " + func.toString() }
final string toString() { result = "IR: " + decl.toString() }
/** Gets the function whose IR is represented. */
final Language::Function getFunction() { result = func }
final Language::Declaration getFunction() { result = decl }
/** Gets the location of the function. */
final Language::Location getLocation() { result = func.getLocation() }
final Language::Location getLocation() { result = decl.getLocation() }
}

View File

@@ -2,21 +2,21 @@ private import TIRVariableInternal
private import Imports::TempVariableTag
newtype TIRVariable =
TIRUserVariable(Language::Variable var, Language::LanguageType type, Language::Function func) {
TIRUserVariable(Language::Variable var, Language::LanguageType type, Language::Declaration func) {
Construction::hasUserVariable(func, var, type)
} or
TIRTempVariable(
Language::Function func, Language::AST ast, TempVariableTag tag, Language::LanguageType type
Language::Declaration func, Language::AST ast, TempVariableTag tag, Language::LanguageType type
) {
Construction::hasTempVariable(func, ast, tag, type)
} or
TIRDynamicInitializationFlag(
Language::Function func, Language::Variable var, Language::LanguageType type
Language::Declaration func, Language::Variable var, Language::LanguageType type
) {
Construction::hasDynamicInitializationFlag(func, var, type)
} or
TIRStringLiteral(
Language::Function func, Language::AST ast, Language::LanguageType type,
Language::Declaration func, Language::AST ast, Language::LanguageType type,
Language::StringLiteral literal
) {
Construction::hasStringLiteral(func, ast, type, literal)

View File

@@ -97,7 +97,7 @@ class IRBlockBase extends TIRBlock {
/**
* Gets the `Function` that contains this block.
*/
final Language::Function getEnclosingFunction() {
final Language::Declaration getEnclosingFunction() {
result = getFirstInstruction(this).getEnclosingFunction()
}
}

View File

@@ -524,4 +524,23 @@ module InstructionConsistency {
"' has a `this` argument operand that is not an address, in function '$@'." and
irFunc = getInstructionIRFunction(instr, irFuncText)
}
query predicate nonUniqueIRVariable(
Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText
) {
exists(VariableInstruction vi, IRVariable v1, IRVariable v2 |
instr = vi and vi.getIRVariable() = v1 and vi.getIRVariable() = v2 and v1 != v2
) and
message =
"Variable instruction '" + instr.toString() +
"' has multiple associated variables, in function '$@'." and
irFunc = getInstructionIRFunction(instr, irFuncText)
or
instr.getOpcode() instanceof Opcode::VariableAddress and
not instr instanceof VariableInstruction and
message =
"Variable address instruction '" + instr.toString() +
"' has no associated variable, in function '$@'." and
irFunc = getInstructionIRFunction(instr, irFuncText)
}
}

View File

@@ -18,7 +18,7 @@ private import Imports::IRType
* by the AST-to-IR translation (`IRTempVariable`).
*/
class IRVariable extends TIRVariable {
Language::Function func;
Language::Declaration func;
IRVariable() {
this = TIRUserVariable(_, _, func) or
@@ -79,7 +79,7 @@ class IRVariable extends TIRVariable {
/**
* Gets the function that references this variable.
*/
final Language::Function getEnclosingFunction() { result = func }
final Language::Declaration getEnclosingFunction() { result = func }
}
/**
@@ -246,7 +246,7 @@ class IREllipsisVariable extends IRTempVariable, IRParameter {
final override string toString() { result = "#ellipsis" }
final override int getIndex() { result = func.getNumberOfParameters() }
final override int getIndex() { result = func.(Language::Function).getNumberOfParameters() }
}
/**

View File

@@ -194,7 +194,7 @@ class Instruction extends Construction::TStageInstruction {
/**
* Gets the function that contains this instruction.
*/
final Language::Function getEnclosingFunction() {
final Language::Declaration getEnclosingFunction() {
result = this.getEnclosingIRFunction().getFunction()
}

View File

@@ -26,20 +26,20 @@ class PrintIRConfiguration extends TPrintIRConfiguration {
* Holds if the IR for `func` should be printed. By default, holds for all
* functions.
*/
predicate shouldPrintFunction(Language::Function func) { any() }
predicate shouldPrintFunction(Language::Declaration decl) { any() }
}
/**
* Override of `IRConfiguration` to only evaluate debug strings for the functions that are to be dumped.
*/
private class FilteredIRConfiguration extends IRConfiguration {
override predicate shouldEvaluateDebugStringsForFunction(Language::Function func) {
override predicate shouldEvaluateDebugStringsForFunction(Language::Declaration func) {
shouldPrintFunction(func)
}
}
private predicate shouldPrintFunction(Language::Function func) {
exists(PrintIRConfiguration config | config.shouldPrintFunction(func))
private predicate shouldPrintFunction(Language::Declaration decl) {
exists(PrintIRConfiguration config | config.shouldPrintFunction(decl))
}
private string getAdditionalInstructionProperty(Instruction instr, string key) {

View File

@@ -34,7 +34,7 @@ class ValueNumber extends TValueNumber {
final Instruction getAnInstruction() { this = valueNumber(result) }
/**
* Gets one of the instructions that was assigned this value number. The chosen instuction is
* Gets one of the instructions that was assigned this value number. The chosen instruction is
* deterministic but arbitrary. Intended for use only in debugging.
*/
final Instruction getExampleInstruction() {

View File

@@ -13,6 +13,7 @@ private import TranslatedElement
private import TranslatedExpr
private import TranslatedStmt
private import TranslatedFunction
private import TranslatedGlobalVar
TranslatedElement getInstructionTranslatedElement(Instruction instruction) {
instruction = TRawInstruction(result, _)
@@ -35,29 +36,41 @@ module Raw {
cached
predicate functionHasIR(Function func) { exists(getTranslatedFunction(func)) }
cached
predicate varHasIRFunc(GlobalOrNamespaceVariable var) {
var.hasInitializer() and
(
not var.getType().isDeeplyConst()
or
var.getInitializer().getExpr() instanceof StringLiteral
)
}
cached
predicate hasInstruction(TranslatedElement element, InstructionTag tag) {
element.hasInstruction(_, tag, _)
}
cached
predicate hasUserVariable(Function func, Variable var, CppType type) {
getTranslatedFunction(func).hasUserVariable(var, type)
predicate hasUserVariable(Declaration decl, Variable var, CppType type) {
getTranslatedFunction(decl).hasUserVariable(var, type)
or
getTranslatedVarInit(decl).hasUserVariable(var, type)
}
cached
predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag, CppType type) {
predicate hasTempVariable(Declaration decl, Locatable ast, TempVariableTag tag, CppType type) {
exists(TranslatedElement element |
element.getAst() = ast and
func = element.getFunction() and
decl = element.getFunction() and
element.hasTempVariable(tag, type)
)
}
cached
predicate hasStringLiteral(Function func, Locatable ast, CppType type, StringLiteral literal) {
predicate hasStringLiteral(Declaration decl, Locatable ast, CppType type, StringLiteral literal) {
literal = ast and
literal.getEnclosingFunction() = func and
literal.getEnclosingDeclaration() = decl and
getTypeForPRValue(literal.getType()) = type
}

View File

@@ -180,7 +180,7 @@ abstract class TranslatedSideEffects extends TranslatedElement {
/** DEPRECATED: Alias for getAst */
deprecated override Locatable getAST() { result = getAst() }
final override Function getFunction() { result = getExpr().getEnclosingFunction() }
final override Declaration getFunction() { result = getExpr().getEnclosingDeclaration() }
final override TranslatedElement getChild(int i) {
result =
@@ -375,7 +375,7 @@ abstract class TranslatedSideEffect extends TranslatedElement {
kind instanceof GotoEdge
}
final override Function getFunction() { result = getParent().getFunction() }
final override Declaration getFunction() { result = getParent().getFunction() }
final override Instruction getPrimaryInstructionForSideEffect(InstructionTag tag) {
tag = OnlyInstructionTag() and
@@ -436,13 +436,6 @@ abstract class TranslatedArgumentSideEffect extends TranslatedSideEffect {
result = index
}
/**
* Gets the `TranslatedFunction` containing this expression.
*/
final TranslatedFunction getEnclosingFunction() {
result = getTranslatedFunction(call.getEnclosingFunction())
}
final override predicate sideEffectInstruction(Opcode opcode, CppType type) {
opcode = sideEffectOpcode and
(

View File

@@ -25,9 +25,9 @@ private Element getRealParent(Expr expr) {
result.(Destructor).getADestruction() = expr
}
IRUserVariable getIRUserVariable(Function func, Variable var) {
IRUserVariable getIRUserVariable(Declaration decl, Variable var) {
result.getVariable() = var and
result.getEnclosingFunction() = func
result.getEnclosingFunction() = decl
}
IRTempVariable getIRTempVariable(Locatable ast, TempVariableTag tag) {
@@ -67,7 +67,8 @@ private predicate ignoreExprAndDescendants(Expr expr) {
exists(Initializer init, StaticStorageDurationVariable var |
init = var.getInitializer() and
not var.hasDynamicInitialization() and
expr = init.getExpr().getFullyConverted()
expr = init.getExpr().getFullyConverted() and
not var instanceof GlobalOrNamespaceVariable
)
or
// Ignore descendants of `__assume` expressions, since we translated these to `NoOp`.
@@ -117,7 +118,8 @@ private predicate ignoreExprOnly(Expr expr) {
// should not be translated.
exists(NewOrNewArrayExpr new | expr = new.getAllocatorCall().getArgument(0))
or
not translateFunction(expr.getEnclosingFunction())
not translateFunction(expr.getEnclosingFunction()) and
not Raw::varHasIRFunc(expr.getEnclosingVariable())
or
// We do not yet translate destructors properly, so for now we ignore the
// destructor call. We do, however, translate the expression being
@@ -662,7 +664,8 @@ newtype TTranslatedElement =
opcode = getASideEffectOpcode(call, -1)
} or
// The side effect that initializes newly-allocated memory.
TTranslatedAllocationSideEffect(AllocationExpr expr) { not ignoreSideEffects(expr) }
TTranslatedAllocationSideEffect(AllocationExpr expr) { not ignoreSideEffects(expr) } or
TTranslatedGlobalOrNamespaceVarInit(GlobalOrNamespaceVariable var) { Raw::varHasIRFunc(var) }
/**
* Gets the index of the first explicitly initialized element in `initList`
@@ -792,7 +795,7 @@ abstract class TranslatedElement extends TTranslatedElement {
/**
* Gets the `Function` that contains this element.
*/
abstract Function getFunction();
abstract Declaration getFunction();
/**
* Gets the successor instruction of the instruction that was generated by
@@ -942,3 +945,14 @@ abstract class TranslatedElement extends TTranslatedElement {
*/
final TranslatedElement getParent() { result.getAChild() = this }
}
/**
* Represents the IR translation of a root element, either a function or a global variable.
*/
abstract class TranslatedRootElement extends TranslatedElement {
TranslatedRootElement() {
this instanceof TTranslatedFunction
or
this instanceof TTranslatedGlobalOrNamespaceVarInit
}
}

View File

@@ -12,6 +12,7 @@ private import TranslatedElement
private import TranslatedFunction
private import TranslatedInitialization
private import TranslatedStmt
private import TranslatedGlobalVar
import TranslatedCall
/**
@@ -78,7 +79,7 @@ abstract class TranslatedExpr extends TranslatedElement {
/** DEPRECATED: Alias for getAst */
deprecated override Locatable getAST() { result = this.getAst() }
final override Function getFunction() { result = expr.getEnclosingFunction() }
final override Declaration getFunction() { result = expr.getEnclosingDeclaration() }
/**
* Gets the expression from which this `TranslatedExpr` is generated.
@@ -88,8 +89,10 @@ abstract class TranslatedExpr extends TranslatedElement {
/**
* Gets the `TranslatedFunction` containing this expression.
*/
final TranslatedFunction getEnclosingFunction() {
final TranslatedRootElement getEnclosingFunction() {
result = getTranslatedFunction(expr.getEnclosingFunction())
or
result = getTranslatedVarInit(expr.getEnclosingVariable())
}
}
@@ -787,7 +790,7 @@ class TranslatedThisExpr extends TranslatedNonConstantExpr {
override IRVariable getInstructionVariable(InstructionTag tag) {
tag = ThisAddressTag() and
result = this.getEnclosingFunction().getThisVariable()
result = this.getEnclosingFunction().(TranslatedFunction).getThisVariable()
}
}
@@ -838,7 +841,7 @@ class TranslatedNonFieldVariableAccess extends TranslatedVariableAccess {
override IRVariable getInstructionVariable(InstructionTag tag) {
tag = OnlyInstructionTag() and
result = getIRUserVariable(expr.getEnclosingFunction(), expr.getTarget())
result = getIRUserVariable(expr.getEnclosingDeclaration(), expr.getTarget())
}
}
@@ -2522,7 +2525,7 @@ class TranslatedVarArgsStart extends TranslatedNonConstantExpr {
final override IRVariable getInstructionVariable(InstructionTag tag) {
tag = VarArgsStartEllipsisAddressTag() and
result = this.getEnclosingFunction().getEllipsisVariable()
result = this.getEnclosingFunction().(TranslatedFunction).getEllipsisVariable()
}
final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {

View File

@@ -58,7 +58,7 @@ predicate hasReturnValue(Function func) { not func.getUnspecifiedType() instance
* Represents the IR translation of a function. This is the root elements for
* all other elements associated with this function.
*/
class TranslatedFunction extends TranslatedElement, TTranslatedFunction {
class TranslatedFunction extends TranslatedRootElement, TTranslatedFunction {
Function func;
TranslatedFunction() { this = TTranslatedFunction(func) }

View File

@@ -0,0 +1,132 @@
import semmle.code.cpp.ir.implementation.raw.internal.TranslatedElement
private import cpp
private import semmle.code.cpp.ir.implementation.IRType
private import semmle.code.cpp.ir.implementation.Opcode
private import semmle.code.cpp.ir.implementation.internal.OperandTag
private import semmle.code.cpp.ir.internal.CppType
private import TranslatedInitialization
private import InstructionTag
private import semmle.code.cpp.ir.internal.IRUtilities
class TranslatedGlobalOrNamespaceVarInit extends TranslatedRootElement,
TTranslatedGlobalOrNamespaceVarInit, InitializationContext {
GlobalOrNamespaceVariable var;
TranslatedGlobalOrNamespaceVarInit() { this = TTranslatedGlobalOrNamespaceVarInit(var) }
override string toString() { result = var.toString() }
final override GlobalOrNamespaceVariable getAst() { result = var }
final override Declaration getFunction() { result = var }
final Location getLocation() { result = var.getLocation() }
override Instruction getFirstInstruction() { result = this.getInstruction(EnterFunctionTag()) }
override TranslatedElement getChild(int n) {
n = 1 and
result = getTranslatedInitialization(var.getInitializer().getExpr().getFullyConverted())
}
override predicate hasInstruction(Opcode op, InstructionTag tag, CppType type) {
op instanceof Opcode::EnterFunction and
tag = EnterFunctionTag() and
type = getVoidType()
or
op instanceof Opcode::AliasedDefinition and
tag = AliasedDefinitionTag() and
type = getUnknownType()
or
op instanceof Opcode::VariableAddress and
tag = InitializerVariableAddressTag() and
type = getTypeForGLValue(var.getType())
or
op instanceof Opcode::ReturnVoid and
tag = ReturnTag() and
type = getVoidType()
or
op instanceof Opcode::AliasedUse and
tag = AliasedUseTag() and
type = getVoidType()
or
op instanceof Opcode::ExitFunction and
tag = ExitFunctionTag() and
type = getVoidType()
}
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
kind instanceof GotoEdge and
(
tag = EnterFunctionTag() and
result = this.getInstruction(AliasedDefinitionTag())
or
tag = AliasedDefinitionTag() and
result = this.getInstruction(InitializerVariableAddressTag())
or
tag = InitializerVariableAddressTag() and
result = getChild(1).getFirstInstruction()
or
tag = ReturnTag() and
result = this.getInstruction(AliasedUseTag())
or
tag = AliasedUseTag() and
result = this.getInstruction(ExitFunctionTag())
)
}
override Instruction getChildSuccessor(TranslatedElement child) {
child = this.getChild(1) and
result = this.getInstruction(ReturnTag())
}
final override CppType getInstructionMemoryOperandType(
InstructionTag tag, TypedOperandTag operandTag
) {
tag = AliasedUseTag() and
operandTag instanceof SideEffectOperandTag and
result = getUnknownType()
}
override IRUserVariable getInstructionVariable(InstructionTag tag) {
tag = InitializerVariableAddressTag() and
result.getVariable() = var and
result.getEnclosingFunction() = var
}
override Instruction getTargetAddress() {
result = this.getInstruction(InitializerVariableAddressTag())
}
override Type getTargetType() { result = var.getUnspecifiedType() }
/**
* Holds if this variable defines or accesses variable `var` with type `type`. This includes all
* parameters and local variables, plus any global variables or static data members that are
* directly accessed by the function.
*/
final predicate hasUserVariable(Variable varUsed, CppType type) {
(
(
varUsed instanceof GlobalOrNamespaceVariable
or
varUsed instanceof MemberVariable and not varUsed instanceof Field
) and
exists(VariableAccess access |
access.getTarget() = varUsed and
access.getEnclosingVariable() = var
)
or
var = varUsed
or
varUsed.(LocalScopeVariable).getEnclosingElement*() = var
or
varUsed.(Parameter).getCatchBlock().getEnclosingElement*() = var
) and
type = getTypeForPRValue(getVariableType(varUsed))
}
}
TranslatedGlobalOrNamespaceVarInit getTranslatedVarInit(GlobalOrNamespaceVariable var) {
result.getAst() = var
}

View File

@@ -137,7 +137,10 @@ abstract class TranslatedInitialization extends TranslatedElement, TTranslatedIn
final override string toString() { result = "init: " + expr.toString() }
final override Function getFunction() { result = expr.getEnclosingFunction() }
final override Declaration getFunction() {
result = expr.getEnclosingFunction() or
result = expr.getEnclosingVariable().(GlobalOrNamespaceVariable)
}
final override Locatable getAst() { result = expr }
@@ -486,7 +489,10 @@ abstract class TranslatedFieldInitialization extends TranslatedElement {
/** DEPRECATED: Alias for getAst */
deprecated override Locatable getAST() { result = getAst() }
final override Function getFunction() { result = ast.getEnclosingFunction() }
final override Declaration getFunction() {
result = ast.getEnclosingFunction() or
result = ast.getEnclosingVariable().(GlobalOrNamespaceVariable)
}
final override Instruction getFirstInstruction() { result = getInstruction(getFieldAddressTag()) }
@@ -633,7 +639,11 @@ abstract class TranslatedElementInitialization extends TranslatedElement {
/** DEPRECATED: Alias for getAst */
deprecated override Locatable getAST() { result = getAst() }
final override Function getFunction() { result = initList.getEnclosingFunction() }
final override Declaration getFunction() {
result = initList.getEnclosingFunction()
or
result = initList.getEnclosingVariable().(GlobalOrNamespaceVariable)
}
final override Instruction getFirstInstruction() { result = getInstruction(getElementIndexTag()) }

View File

@@ -97,7 +97,7 @@ class IRBlockBase extends TIRBlock {
/**
* Gets the `Function` that contains this block.
*/
final Language::Function getEnclosingFunction() {
final Language::Declaration getEnclosingFunction() {
result = getFirstInstruction(this).getEnclosingFunction()
}
}

View File

@@ -524,4 +524,23 @@ module InstructionConsistency {
"' has a `this` argument operand that is not an address, in function '$@'." and
irFunc = getInstructionIRFunction(instr, irFuncText)
}
query predicate nonUniqueIRVariable(
Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText
) {
exists(VariableInstruction vi, IRVariable v1, IRVariable v2 |
instr = vi and vi.getIRVariable() = v1 and vi.getIRVariable() = v2 and v1 != v2
) and
message =
"Variable instruction '" + instr.toString() +
"' has multiple associated variables, in function '$@'." and
irFunc = getInstructionIRFunction(instr, irFuncText)
or
instr.getOpcode() instanceof Opcode::VariableAddress and
not instr instanceof VariableInstruction and
message =
"Variable address instruction '" + instr.toString() +
"' has no associated variable, in function '$@'." and
irFunc = getInstructionIRFunction(instr, irFuncText)
}
}

View File

@@ -18,7 +18,7 @@ private import Imports::IRType
* by the AST-to-IR translation (`IRTempVariable`).
*/
class IRVariable extends TIRVariable {
Language::Function func;
Language::Declaration func;
IRVariable() {
this = TIRUserVariable(_, _, func) or
@@ -79,7 +79,7 @@ class IRVariable extends TIRVariable {
/**
* Gets the function that references this variable.
*/
final Language::Function getEnclosingFunction() { result = func }
final Language::Declaration getEnclosingFunction() { result = func }
}
/**
@@ -246,7 +246,7 @@ class IREllipsisVariable extends IRTempVariable, IRParameter {
final override string toString() { result = "#ellipsis" }
final override int getIndex() { result = func.getNumberOfParameters() }
final override int getIndex() { result = func.(Language::Function).getNumberOfParameters() }
}
/**

View File

@@ -194,7 +194,7 @@ class Instruction extends Construction::TStageInstruction {
/**
* Gets the function that contains this instruction.
*/
final Language::Function getEnclosingFunction() {
final Language::Declaration getEnclosingFunction() {
result = this.getEnclosingIRFunction().getFunction()
}

View File

@@ -26,20 +26,20 @@ class PrintIRConfiguration extends TPrintIRConfiguration {
* Holds if the IR for `func` should be printed. By default, holds for all
* functions.
*/
predicate shouldPrintFunction(Language::Function func) { any() }
predicate shouldPrintFunction(Language::Declaration decl) { any() }
}
/**
* Override of `IRConfiguration` to only evaluate debug strings for the functions that are to be dumped.
*/
private class FilteredIRConfiguration extends IRConfiguration {
override predicate shouldEvaluateDebugStringsForFunction(Language::Function func) {
override predicate shouldEvaluateDebugStringsForFunction(Language::Declaration func) {
shouldPrintFunction(func)
}
}
private predicate shouldPrintFunction(Language::Function func) {
exists(PrintIRConfiguration config | config.shouldPrintFunction(func))
private predicate shouldPrintFunction(Language::Declaration decl) {
exists(PrintIRConfiguration config | config.shouldPrintFunction(decl))
}
private string getAdditionalInstructionProperty(Instruction instr, string key) {

View File

@@ -34,7 +34,7 @@ class ValueNumber extends TValueNumber {
final Instruction getAnInstruction() { this = valueNumber(result) }
/**
* Gets one of the instructions that was assigned this value number. The chosen instuction is
* Gets one of the instructions that was assigned this value number. The chosen instruction is
* deterministic but arbitrary. Intended for use only in debugging.
*/
final Instruction getExampleInstruction() {

View File

@@ -1005,7 +1005,7 @@ predicate canReuseSsaForMemoryResult(Instruction instruction) {
deprecated predicate canReuseSSAForMemoryResult = canReuseSsaForMemoryResult/1;
/**
* Expose some of the internal predicates to PrintSSA.qll. We do this by publically importing those modules in the
* Expose some of the internal predicates to PrintSSA.qll. We do this by publicly importing those modules in the
* `DebugSSA` module, which is then imported by PrintSSA.
*/
module DebugSsa {

View File

@@ -50,12 +50,16 @@ class AutomaticVariable = Cpp::StackVariable;
class StaticVariable = Cpp::Variable;
class GlobalVariable = Cpp::GlobalOrNamespaceVariable;
class Parameter = Cpp::Parameter;
class Field = Cpp::Field;
class BuiltInOperation = Cpp::BuiltInOperation;
class Declaration = Cpp::Declaration;
// TODO: Remove necessity for these.
class Expr = Cpp::Expr;

View File

@@ -59,7 +59,7 @@ predicate isInsecureEncryption(string name) { name.regexpMatch(getInsecureAlgori
/**
* Holds if there is additional evidence that `name` looks like it might be
* related to operations with an encyption algorithm, besides the name of a
* specific algorithm. This can be used in conjuction with
* specific algorithm. This can be used in conjunction with
* `isInsecureEncryption` to produce a stronger heuristic.
*/
bindingset[name]

View File

@@ -1436,6 +1436,10 @@ initialisers(
int location: @location_expr ref
);
braced_initialisers(
int init: @initialiser ref
);
/**
* An ancestor for the expression, for cases in which we cannot
* otherwise find the expression's parent.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Add relation for tracking C++ braced initializers
compatibility: backwards

View File

@@ -1,3 +1,18 @@
## 0.1.4
## 0.1.3
### Minor Analysis Improvements
* The "XML external entity expansion" (`cpp/external-entity-expansion`) query precision has been increased to `high`.
* The `cpp/unused-local-variable` no longer ignores functions that include `if` and `switch` statements with C++17-style initializers.
## 0.1.2
### Minor Analysis Improvements
* The "XML external entity expansion" (`cpp/external-entity-expansion`) query has been extended to support a broader selection of XML libraries and interfaces.
## 0.1.1
### New Queries

View File

@@ -57,10 +57,10 @@ class ExtractionProblem extends TExtractionProblem {
/** Gets the problem message for this problem. */
string getProblemMessage() { none() }
/** Gets the file this problem occured in. */
/** Gets the file this problem occurred in. */
File getFile() { none() }
/** Gets the location this problem occured in. */
/** Gets the location this problem occurred in. */
Location getLocation() { none() }
/** Gets the SARIF severity of this problem. */

View File

@@ -57,10 +57,10 @@ class ExtractionError extends TExtractionError {
/** Gets the error message for this error. */
string getErrorMessage() { none() }
/** Gets the file this error occured in. */
/** Gets the file this error occurred in. */
File getFile() { none() }
/** Gets the location this error occured in. */
/** Gets the location this error occurred in. */
Location getLocation() { none() }
/** Gets the SARIF severity of this error. */

View File

@@ -19,7 +19,7 @@ predicate whitelist(Function f) {
"nearbyintl", "rint", "rintf", "rintl", "round", "roundf", "roundl", "trunc", "truncf",
"truncl"
] or
f.getName().matches("__builtin_%")
f.getName().matches("\\_\\_builtin\\_%")
}
predicate whitelistPow(FunctionCall fc) {

View File

@@ -13,7 +13,7 @@
* @deprecated This query is deprecated, use
* Potentially overrunning write (`cpp/overrunning-write`) and
* Potentially overrunning write with float to string conversion
* (`cpp/overrunning-write-with-float) instead.
* (`cpp/overrunning-write-with-float`) instead.
*/
import cpp

View File

@@ -0,0 +1,78 @@
/**
* Models the libxml2 XML library.
*/
import cpp
import XML
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
/**
* A call to a `libxml2` function that parses XML.
*/
class Libxml2ParseCall extends FunctionCall {
int optionsArg;
Libxml2ParseCall() {
exists(string fname | this.getTarget().getName() = fname |
fname = "xmlCtxtUseOptions" and optionsArg = 1
or
fname = "xmlReadFile" and optionsArg = 2
or
fname = ["xmlCtxtReadFile", "xmlParseInNodeContext", "xmlReadDoc", "xmlReadFd"] and
optionsArg = 3
or
fname = ["xmlCtxtReadDoc", "xmlCtxtReadFd", "xmlReadMemory"] and optionsArg = 4
or
fname = ["xmlCtxtReadMemory", "xmlReadIO"] and optionsArg = 5
or
fname = "xmlCtxtReadIO" and optionsArg = 6
)
}
/**
* Gets the argument that specifies `xmlParserOption`s.
*/
Expr getOptions() { result = this.getArgument(optionsArg) }
}
/**
* An `xmlParserOption` for `libxml2` that is considered unsafe.
*/
class Libxml2BadOption extends EnumConstant {
Libxml2BadOption() { this.getName() = ["XML_PARSE_NOENT", "XML_PARSE_DTDLOAD"] }
}
/**
* The libxml2 XML library.
*/
class LibXml2Library extends XmlLibrary {
LibXml2Library() { this = "LibXml2Library" }
override predicate configurationSource(DataFlow::Node node, string flowstate) {
// source is an `options` argument on a libxml2 parse call that specifies
// at least one unsafe option.
//
// note: we don't need to track an XML object for libxml2, so we don't
// really need data flow. Nevertheless we jam it into this configuration,
// with matching sources and sinks. This allows results to be presented by
// the same query, in a consistent way as other results with flow paths.
exists(Libxml2ParseCall call, Expr options |
options = call.getOptions() and
node.asExpr() = options and
flowstate = "libxml2" and
exists(Libxml2BadOption opt |
globalValueNumber(options).getAnExpr().getValue().toInt().bitAnd(opt.getValue().toInt()) !=
0
)
)
}
override predicate configurationSink(DataFlow::Node node, string flowstate) {
// sink is the `options` argument on a `libxml2` parse call.
exists(Libxml2ParseCall call, Expr options |
options = call.getOptions() and
node.asExpr() = options and
flowstate = "libxml2"
)
}
}

View File

@@ -0,0 +1,55 @@
/**
* Provides a abstract classes for modeling XML libraries. This design is
* currently specialized for the purposes of the XXE query.
*/
import cpp
import semmle.code.cpp.ir.dataflow.DataFlow
import Xerces
import Libxml2
/**
* A flow state representing a possible configuration of an XML object.
*/
abstract class XxeFlowState extends DataFlow::FlowState {
bindingset[this]
XxeFlowState() { any() } // required characteristic predicate
}
/**
* An XML library or interface.
*/
abstract class XmlLibrary extends string {
bindingset[this]
XmlLibrary() { any() } // required characteristic predicate
/**
* Holds if `node` is the source node for a potentially unsafe configuration
* object for this XML library, along with `flowstate` representing its
* initial state.
*/
abstract predicate configurationSource(DataFlow::Node node, string flowstate);
/**
* Holds if `node` is the sink node where an unsafe configuration object is
* used to interpret XML.
*/
abstract predicate configurationSink(DataFlow::Node node, string flowstate);
}
/**
* An `Expr` that changes the configuration of an XML object, transforming the
* `XxeFlowState` that flows through it.
*/
abstract class XxeFlowStateTransformer extends Expr {
/**
* Gets the flow state that `flowstate` is transformed into.
*
* Due to limitations of the implementation the transformation defined by this
* predicate must be idempotent, that is, for any input `x` it must be that:
* ```
* transform(transform(x)) = transform(x)
* ```
*/
abstract XxeFlowState transform(XxeFlowState flowstate);
}

View File

@@ -7,350 +7,14 @@
* @id cpp/external-entity-expansion
* @problem.severity warning
* @security-severity 9.1
* @precision medium
* @precision high
* @tags security
* external/cwe/cwe-611
*/
import cpp
import semmle.code.cpp.ir.dataflow.DataFlow
import XML
import DataFlow::PathGraph
import semmle.code.cpp.ir.IR
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
/**
* A flow state representing a possible configuration of an XML object.
*/
abstract class XXEFlowState extends DataFlow::FlowState {
bindingset[this]
XXEFlowState() { any() } // required characteristic predicate
}
/**
* An `Expr` that changes the configuration of an XML object, transforming the
* `XXEFlowState` that flows through it.
*/
abstract class XXEFlowStateTranformer extends Expr {
/**
* Gets the flow state that `flowstate` is transformed into.
*
* Due to limitations of the implementation the transformation defined by this
* predicate must be idempotent, that is, for any input `x` it must be that:
* ```
* transform(tranform(x)) = tranform(x)
* ```
*/
abstract XXEFlowState transform(XXEFlowState flowstate);
}
/**
* The `AbstractDOMParser` class.
*/
class AbstractDOMParserClass extends Class {
AbstractDOMParserClass() { this.hasName("AbstractDOMParser") }
}
/**
* The `XercesDOMParser` class.
*/
class XercesDOMParserClass extends Class {
XercesDOMParserClass() { this.hasName("XercesDOMParser") }
}
/**
* The `DOMLSParser` class.
*/
class DomLSParserClass extends Class {
DomLSParserClass() { this.hasName("DOMLSParser") }
}
/**
* The `SAXParser` class.
*/
class SaxParserClass extends Class {
SaxParserClass() { this.hasName("SAXParser") }
}
/**
* The `SAX2XMLReader` class.
*/
class Sax2XmlReader extends Class {
Sax2XmlReader() { this.hasName("SAX2XMLReader") }
}
/**
* Gets a valid flow state for `AbstractDOMParser` or `SAXParser` flow.
*
* These flow states take the form `Xerces-A-B`, where:
* - A is 1 if `setDisableDefaultEntityResolution` is `true`, 0 otherwise.
* - B is 1 if `setCreateEntityReferenceNodes` is `true`, 0 otherwise.
*/
predicate encodeXercesFlowState(
string flowstate, int disabledDefaultEntityResolution, int createEntityReferenceNodes
) {
flowstate = "Xerces-0-0" and
disabledDefaultEntityResolution = 0 and
createEntityReferenceNodes = 0
or
flowstate = "Xerces-0-1" and
disabledDefaultEntityResolution = 0 and
createEntityReferenceNodes = 1
or
flowstate = "Xerces-1-0" and
disabledDefaultEntityResolution = 1 and
createEntityReferenceNodes = 0
or
flowstate = "Xerces-1-1" and
disabledDefaultEntityResolution = 1 and
createEntityReferenceNodes = 1
}
/**
* A flow state representing the configuration of an `AbstractDOMParser` or
* `SAXParser` object.
*/
class XercesFlowState extends XXEFlowState {
XercesFlowState() { encodeXercesFlowState(this, _, _) }
}
/**
* A flow state transformer for a call to
* `AbstractDOMParser.setDisableDefaultEntityResolution` or
* `SAXParser.setDisableDefaultEntityResolution`. Transforms the flow
* state through the qualifier according to the setting in the parameter.
*/
class DisableDefaultEntityResolutionTranformer extends XXEFlowStateTranformer {
Expr newValue;
DisableDefaultEntityResolutionTranformer() {
exists(Call call, Function f |
call.getTarget() = f and
(
f.getDeclaringType() instanceof AbstractDOMParserClass or
f.getDeclaringType() instanceof SaxParserClass
) and
f.hasName("setDisableDefaultEntityResolution") and
this = call.getQualifier() and
newValue = call.getArgument(0)
)
}
final override XXEFlowState transform(XXEFlowState flowstate) {
exists(int createEntityReferenceNodes |
encodeXercesFlowState(flowstate, _, createEntityReferenceNodes) and
(
globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // true
encodeXercesFlowState(result, 1, createEntityReferenceNodes)
or
not globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // false or unknown
encodeXercesFlowState(result, 0, createEntityReferenceNodes)
)
)
}
}
/**
* A flow state transformer for a call to
* `AbstractDOMParser.setCreateEntityReferenceNodes`. Transforms the flow
* state through the qualifier according to the setting in the parameter.
*/
class CreateEntityReferenceNodesTranformer extends XXEFlowStateTranformer {
Expr newValue;
CreateEntityReferenceNodesTranformer() {
exists(Call call, Function f |
call.getTarget() = f and
f.getClassAndName("setCreateEntityReferenceNodes") instanceof AbstractDOMParserClass and
this = call.getQualifier() and
newValue = call.getArgument(0)
)
}
final override XXEFlowState transform(XXEFlowState flowstate) {
exists(int disabledDefaultEntityResolution |
encodeXercesFlowState(flowstate, disabledDefaultEntityResolution, _) and
(
globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // true
encodeXercesFlowState(result, disabledDefaultEntityResolution, 1)
or
not globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // false or unknown
encodeXercesFlowState(result, disabledDefaultEntityResolution, 0)
)
)
}
}
/**
* The `XMLUni.fgXercesDisableDefaultEntityResolution` constant.
*/
class FeatureDisableDefaultEntityResolution extends Variable {
FeatureDisableDefaultEntityResolution() {
this.getName() = "fgXercesDisableDefaultEntityResolution" and
this.getDeclaringType().getName() = "XMLUni"
}
}
/**
* A flow state transformer for a call to `SAX2XMLReader.setFeature`
* specifying the feature `XMLUni::fgXercesDisableDefaultEntityResolution`.
* Transforms the flow state through the qualifier according to this setting.
*/
class SetFeatureTranformer extends XXEFlowStateTranformer {
Expr newValue;
SetFeatureTranformer() {
exists(Call call, Function f |
call.getTarget() = f and
f.getClassAndName("setFeature") instanceof Sax2XmlReader and
this = call.getQualifier() and
globalValueNumber(call.getArgument(0)).getAnExpr().(VariableAccess).getTarget() instanceof
FeatureDisableDefaultEntityResolution and
newValue = call.getArgument(1)
)
}
final override XXEFlowState transform(XXEFlowState flowstate) {
exists(int createEntityReferenceNodes |
encodeXercesFlowState(flowstate, _, createEntityReferenceNodes) and
(
globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // true
encodeXercesFlowState(result, 1, createEntityReferenceNodes)
or
not globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // false or unknown
encodeXercesFlowState(result, 0, createEntityReferenceNodes)
)
)
}
}
/**
* The `DOMLSParser.getDomConfig` function.
*/
class GetDomConfig extends Function {
GetDomConfig() { this.getClassAndName("getDomConfig") instanceof DomLSParserClass }
}
/**
* The `DOMConfiguration.setParameter` function.
*/
class DomConfigurationSetParameter extends Function {
DomConfigurationSetParameter() {
this.getClassAndName("setParameter").getName() = "DOMConfiguration"
}
}
/**
* A flow state transformer for a call to `DOMConfiguration.setParameter`
* specifying the feature `XMLUni::fgXercesDisableDefaultEntityResolution`.
* This is a slightly more complex transformer because the qualifier is a
* `DOMConfiguration` pointer returned by `DOMLSParser.getDomConfig` - and it
* is *that* qualifier we want to transform the flow state of.
*/
class DomConfigurationSetParameterTranformer extends XXEFlowStateTranformer {
Expr newValue;
DomConfigurationSetParameterTranformer() {
exists(FunctionCall getDomConfigCall, FunctionCall setParameterCall |
// this is the qualifier of a call to `DOMLSParser.getDomConfig`.
getDomConfigCall.getTarget() instanceof GetDomConfig and
this = getDomConfigCall.getQualifier() and
// `setParameterCall` is a call to `setParameter` on the return value of
// the same call to `DOMLSParser.getDomConfig`.
setParameterCall.getTarget() instanceof DomConfigurationSetParameter and
globalValueNumber(setParameterCall.getQualifier()).getAnExpr() = getDomConfigCall and
// the parameter being set is
// `XMLUni::fgXercesDisableDefaultEntityResolution`.
globalValueNumber(setParameterCall.getArgument(0)).getAnExpr().(VariableAccess).getTarget()
instanceof FeatureDisableDefaultEntityResolution and
// the value being set is `newValue`.
newValue = setParameterCall.getArgument(1)
)
}
final override XXEFlowState transform(XXEFlowState flowstate) {
exists(int createEntityReferenceNodes |
encodeXercesFlowState(flowstate, _, createEntityReferenceNodes) and
(
globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // true
encodeXercesFlowState(result, 1, createEntityReferenceNodes)
or
not globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // false or unknown
encodeXercesFlowState(result, 0, createEntityReferenceNodes)
)
)
}
}
/**
* The `AbstractDOMParser.parse`, `DOMLSParserClass.parse`, `SAXParser.parse`
* or `SAX2XMLReader.parse` method.
*/
class ParseFunction extends Function {
ParseFunction() {
this.getClassAndName("parse") instanceof AbstractDOMParserClass or
this.getClassAndName("parse") instanceof DomLSParserClass or
this.getClassAndName("parse") instanceof SaxParserClass or
this.getClassAndName("parse") instanceof Sax2XmlReader
}
}
/**
* The `createLSParser` function that returns a newly created `DOMLSParser`
* object.
*/
class CreateLSParser extends Function {
CreateLSParser() {
this.hasName("createLSParser") and
this.getUnspecifiedType().(PointerType).getBaseType() instanceof DomLSParserClass // returns a `DOMLSParser *`.
}
}
/**
* The `createXMLReader` function that returns a newly created `SAX2XMLReader`
* object.
*/
class CreateXmlReader extends Function {
CreateXmlReader() {
this.hasName("createXMLReader") and
this.getUnspecifiedType().(PointerType).getBaseType() instanceof Sax2XmlReader // returns a `SAX2XMLReader *`.
}
}
/**
* A call to a `libxml2` function that parses XML.
*/
class Libxml2ParseCall extends FunctionCall {
int optionsArg;
Libxml2ParseCall() {
exists(string fname | this.getTarget().getName() = fname |
fname = "xmlCtxtUseOptions" and optionsArg = 1
or
fname = "xmlReadFile" and optionsArg = 2
or
fname = ["xmlCtxtReadFile", "xmlParseInNodeContext", "xmlReadDoc", "xmlReadFd"] and
optionsArg = 3
or
fname = ["xmlCtxtReadDoc", "xmlCtxtReadFd", "xmlReadMemory"] and optionsArg = 4
or
fname = ["xmlCtxtReadMemory", "xmlReadIO"] and optionsArg = 5
or
fname = "xmlCtxtReadIO" and optionsArg = 6
)
}
/**
* Gets the argument that specifies `xmlParserOption`s.
*/
Expr getOptions() { result = this.getArgument(optionsArg) }
}
/**
* An `xmlParserOption` for `libxml2` that is considered unsafe.
*/
class Libxml2BadOption extends EnumConstant {
Libxml2BadOption() { this.getName() = ["XML_PARSE_NOENT", "XML_PARSE_DTDLOAD"] }
}
/**
* A configuration for tracking XML objects and their states.
@@ -359,85 +23,25 @@ class XXEConfiguration extends DataFlow::Configuration {
XXEConfiguration() { this = "XXEConfiguration" }
override predicate isSource(DataFlow::Node node, string flowstate) {
// source is the write on `this` of a call to the `XercesDOMParser`
// constructor.
exists(CallInstruction call |
call.getStaticCallTarget() = any(XercesDOMParserClass c).getAConstructor() and
node.asInstruction().(WriteSideEffectInstruction).getDestinationAddress() =
call.getThisArgument() and
encodeXercesFlowState(flowstate, 0, 1) // default configuration
)
or
// source is the result of a call to `createLSParser`.
exists(Call call |
call.getTarget() instanceof CreateLSParser and
call = node.asExpr() and
encodeXercesFlowState(flowstate, 0, 1) // default configuration
)
or
// source is the write on `this` of a call to the `SAXParser`
// constructor.
exists(CallInstruction call |
call.getStaticCallTarget() = any(SaxParserClass c).getAConstructor() and
node.asInstruction().(WriteSideEffectInstruction).getDestinationAddress() =
call.getThisArgument() and
encodeXercesFlowState(flowstate, 0, 1) // default configuration
)
or
// source is the result of a call to `createXMLReader`.
exists(Call call |
call.getTarget() instanceof CreateXmlReader and
call = node.asExpr() and
encodeXercesFlowState(flowstate, 0, 1) // default configuration
)
or
// source is an `options` argument on a `libxml2` parse call that specifies
// at least one unsafe option.
//
// note: we don't need to track an XML object for `libxml2`, so we don't
// really need data flow. Nevertheless we jam it into this configuration,
// with matching sources and sinks. This allows results to be presented by
// the same query, in a consistent way as other results with flow paths.
exists(Libxml2ParseCall call, Expr options |
options = call.getOptions() and
node.asExpr() = options and
flowstate = "libxml2" and
exists(Libxml2BadOption opt |
globalValueNumber(options).getAnExpr().getValue().toInt().bitAnd(opt.getValue().toInt()) !=
0
)
)
any(XmlLibrary l).configurationSource(node, flowstate)
}
override predicate isSink(DataFlow::Node node, string flowstate) {
// sink is the read of the qualifier of a call to `parse`.
exists(Call call |
call.getTarget() instanceof ParseFunction and
call.getQualifier() = node.asConvertedExpr()
) and
flowstate instanceof XercesFlowState and
not encodeXercesFlowState(flowstate, 1, 1) // safe configuration
or
// sink is the `options` argument on a `libxml2` parse call.
exists(Libxml2ParseCall call, Expr options |
options = call.getOptions() and
node.asExpr() = options and
flowstate = "libxml2"
)
any(XmlLibrary l).configurationSink(node, flowstate)
}
override predicate isAdditionalFlowStep(
DataFlow::Node node1, string state1, DataFlow::Node node2, string state2
) {
// create additional flow steps for `XXEFlowStateTranformer`s
state2 = node2.asConvertedExpr().(XXEFlowStateTranformer).transform(state1) and
// create additional flow steps for `XxeFlowStateTransformer`s
state2 = node2.asConvertedExpr().(XxeFlowStateTransformer).transform(state1) and
DataFlow::simpleLocalFlowStep(node1, node2)
}
override predicate isBarrier(DataFlow::Node node, string flowstate) {
// when the flowstate is transformed at a call node, block the original
// flowstate value.
node.asConvertedExpr().(XXEFlowStateTranformer).transform(flowstate) != flowstate
node.asConvertedExpr().(XxeFlowStateTransformer).transform(flowstate) != flowstate
}
}

View File

@@ -0,0 +1,376 @@
/**
* Models the Xerces XML library.
*/
import cpp
import XML
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
import semmle.code.cpp.ir.IR
/**
* Gets a valid flow state for `AbstractDOMParser` or `SAXParser` flow.
*
* These flow states take the form `Xerces-A-B`, where:
* - A is 1 if `setDisableDefaultEntityResolution` is `true`, 0 otherwise.
* - B is 1 if `setCreateEntityReferenceNodes` is `true`, 0 otherwise.
*/
predicate encodeXercesFlowState(
string flowstate, int disabledDefaultEntityResolution, int createEntityReferenceNodes
) {
flowstate = "Xerces-0-0" and
disabledDefaultEntityResolution = 0 and
createEntityReferenceNodes = 0
or
flowstate = "Xerces-0-1" and
disabledDefaultEntityResolution = 0 and
createEntityReferenceNodes = 1
or
flowstate = "Xerces-1-0" and
disabledDefaultEntityResolution = 1 and
createEntityReferenceNodes = 0
or
flowstate = "Xerces-1-1" and
disabledDefaultEntityResolution = 1 and
createEntityReferenceNodes = 1
}
/**
* A flow state representing the configuration of an `AbstractDOMParser` or
* `SAXParser` object.
*/
class XercesFlowState extends XxeFlowState {
XercesFlowState() { encodeXercesFlowState(this, _, _) }
}
/**
* The `AbstractDOMParser` class.
*/
class AbstractDomParserClass extends Class {
AbstractDomParserClass() { this.hasName("AbstractDOMParser") }
}
/**
* The `XercesDOMParser` class.
*/
class XercesDomParserClass extends Class {
XercesDomParserClass() { this.hasName("XercesDOMParser") }
}
/**
* The `XercesDOMParser` interface for the Xerces XML library.
*/
class XercesDomParserLibrary extends XmlLibrary {
XercesDomParserLibrary() { this = "XercesDomParserLibrary" }
override predicate configurationSource(DataFlow::Node node, string flowstate) {
// source is the write on `this` of a call to the `XercesDOMParser`
// constructor.
exists(CallInstruction call |
call.getStaticCallTarget() = any(XercesDomParserClass c).getAConstructor() and
node.asInstruction().(WriteSideEffectInstruction).getDestinationAddress() =
call.getThisArgument() and
encodeXercesFlowState(flowstate, 0, 1) // default configuration
)
}
override predicate configurationSink(DataFlow::Node node, string flowstate) {
// sink is the read of the qualifier of a call to `AbstractDOMParser.parse`.
exists(Call call |
call.getTarget().getClassAndName("parse") instanceof AbstractDomParserClass and
call.getQualifier() = node.asConvertedExpr()
) and
flowstate instanceof XercesFlowState and
not encodeXercesFlowState(flowstate, 1, 1) // safe configuration
}
}
/**
* The `DOMLSParser` class.
*/
class DomLSParserClass extends Class {
DomLSParserClass() { this.hasName("DOMLSParser") }
}
/**
* The `createLSParser` function that returns a newly created `DOMLSParser`
* object.
*/
class CreateLSParser extends Function {
CreateLSParser() {
this.hasName("createLSParser") and
this.getUnspecifiedType().(PointerType).getBaseType() instanceof DomLSParserClass // returns a `DOMLSParser *`.
}
}
/**
* The createLSParser interface for the Xerces XML library.
*/
class CreateLSParserLibrary extends XmlLibrary {
CreateLSParserLibrary() { this = "CreateLSParserLibrary" }
override predicate configurationSource(DataFlow::Node node, string flowstate) {
// source is the result of a call to `createLSParser`.
exists(Call call |
call.getTarget() instanceof CreateLSParser and
call = node.asExpr() and
encodeXercesFlowState(flowstate, 0, 1) // default configuration
)
}
override predicate configurationSink(DataFlow::Node node, string flowstate) {
// sink is the read of the qualifier of a call to `DOMLSParserClass.parse`.
exists(Call call |
call.getTarget().getClassAndName("parse") instanceof DomLSParserClass and
call.getQualifier() = node.asConvertedExpr()
) and
flowstate instanceof XercesFlowState and
not encodeXercesFlowState(flowstate, 1, 1) // safe configuration
}
}
/**
* The `SAXParser` class.
*/
class SaxParserClass extends Class {
SaxParserClass() { this.hasName("SAXParser") }
}
/**
* The `SAX2XMLReader` class.
*/
class Sax2XmlReader extends Class {
Sax2XmlReader() { this.hasName("SAX2XMLReader") }
}
/**
* The SAXParser interface for the Xerces XML library.
*/
class SaxParserLibrary extends XmlLibrary {
SaxParserLibrary() { this = "SaxParserLibrary" }
override predicate configurationSource(DataFlow::Node node, string flowstate) {
// source is the write on `this` of a call to the `SAXParser`
// constructor.
exists(CallInstruction call |
call.getStaticCallTarget() = any(SaxParserClass c).getAConstructor() and
node.asInstruction().(WriteSideEffectInstruction).getDestinationAddress() =
call.getThisArgument() and
encodeXercesFlowState(flowstate, 0, 1) // default configuration
)
}
override predicate configurationSink(DataFlow::Node node, string flowstate) {
// sink is the read of the qualifier of a call to `SAXParser.parse`.
exists(Call call |
call.getTarget().getClassAndName("parse") instanceof SaxParserClass and
call.getQualifier() = node.asConvertedExpr()
) and
flowstate instanceof XercesFlowState and
not encodeXercesFlowState(flowstate, 1, 1) // safe configuration
}
}
/**
* The `createXMLReader` function that returns a newly created `SAX2XMLReader`
* object.
*/
class CreateXmlReader extends Function {
CreateXmlReader() {
this.hasName("createXMLReader") and
this.getUnspecifiedType().(PointerType).getBaseType() instanceof Sax2XmlReader // returns a `SAX2XMLReader *`.
}
}
/**
* The SAX2XMLReader interface for the Xerces XML library.
*/
class Sax2XmlReaderLibrary extends XmlLibrary {
Sax2XmlReaderLibrary() { this = "Sax2XmlReaderLibrary" }
override predicate configurationSource(DataFlow::Node node, string flowstate) {
// source is the result of a call to `createXMLReader`.
exists(Call call |
call.getTarget() instanceof CreateXmlReader and
call = node.asExpr() and
encodeXercesFlowState(flowstate, 0, 1) // default configuration
)
}
override predicate configurationSink(DataFlow::Node node, string flowstate) {
// sink is the read of the qualifier of a call to `SAX2XMLReader.parse`.
exists(Call call |
call.getTarget().getClassAndName("parse") instanceof Sax2XmlReader and
call.getQualifier() = node.asConvertedExpr()
) and
flowstate instanceof XercesFlowState and
not encodeXercesFlowState(flowstate, 1, 1) // safe configuration
}
}
/**
* A flow state transformer for a call to
* `AbstractDOMParser.setDisableDefaultEntityResolution` or
* `SAXParser.setDisableDefaultEntityResolution`. Transforms the flow
* state through the qualifier according to the setting in the parameter.
*/
class DisableDefaultEntityResolutionTransformer extends XxeFlowStateTransformer {
Expr newValue;
DisableDefaultEntityResolutionTransformer() {
exists(Call call, Function f |
call.getTarget() = f and
(
f.getDeclaringType() instanceof AbstractDomParserClass or
f.getDeclaringType() instanceof SaxParserClass
) and
f.hasName("setDisableDefaultEntityResolution") and
this = call.getQualifier() and
newValue = call.getArgument(0)
)
}
final override XxeFlowState transform(XxeFlowState flowstate) {
exists(int createEntityReferenceNodes |
encodeXercesFlowState(flowstate, _, createEntityReferenceNodes) and
(
globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // true
encodeXercesFlowState(result, 1, createEntityReferenceNodes)
or
not globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // false or unknown
encodeXercesFlowState(result, 0, createEntityReferenceNodes)
)
)
}
}
/**
* A flow state transformer for a call to
* `AbstractDOMParser.setCreateEntityReferenceNodes`. Transforms the flow
* state through the qualifier according to the setting in the parameter.
*/
class CreateEntityReferenceNodesTransformer extends XxeFlowStateTransformer {
Expr newValue;
CreateEntityReferenceNodesTransformer() {
exists(Call call, Function f |
call.getTarget() = f and
f.getClassAndName("setCreateEntityReferenceNodes") instanceof AbstractDomParserClass and
this = call.getQualifier() and
newValue = call.getArgument(0)
)
}
final override XxeFlowState transform(XxeFlowState flowstate) {
exists(int disabledDefaultEntityResolution |
encodeXercesFlowState(flowstate, disabledDefaultEntityResolution, _) and
(
globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // true
encodeXercesFlowState(result, disabledDefaultEntityResolution, 1)
or
not globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // false or unknown
encodeXercesFlowState(result, disabledDefaultEntityResolution, 0)
)
)
}
}
/**
* The `XMLUni.fgXercesDisableDefaultEntityResolution` constant.
*/
class FeatureDisableDefaultEntityResolution extends Variable {
FeatureDisableDefaultEntityResolution() {
this.getName() = "fgXercesDisableDefaultEntityResolution" and
this.getDeclaringType().getName() = "XMLUni"
}
}
/**
* A flow state transformer for a call to `SAX2XMLReader.setFeature`
* specifying the feature `XMLUni::fgXercesDisableDefaultEntityResolution`.
* Transforms the flow state through the qualifier according to this setting.
*/
class SetFeatureTransformer extends XxeFlowStateTransformer {
Expr newValue;
SetFeatureTransformer() {
exists(Call call, Function f |
call.getTarget() = f and
f.getClassAndName("setFeature") instanceof Sax2XmlReader and
this = call.getQualifier() and
globalValueNumber(call.getArgument(0)).getAnExpr().(VariableAccess).getTarget() instanceof
FeatureDisableDefaultEntityResolution and
newValue = call.getArgument(1)
)
}
final override XxeFlowState transform(XxeFlowState flowstate) {
exists(int createEntityReferenceNodes |
encodeXercesFlowState(flowstate, _, createEntityReferenceNodes) and
(
globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // true
encodeXercesFlowState(result, 1, createEntityReferenceNodes)
or
not globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // false or unknown
encodeXercesFlowState(result, 0, createEntityReferenceNodes)
)
)
}
}
/**
* The `DOMLSParser.getDomConfig` function.
*/
class GetDomConfig extends Function {
GetDomConfig() { this.getClassAndName("getDomConfig") instanceof DomLSParserClass }
}
/**
* The `DOMConfiguration.setParameter` function.
*/
class DomConfigurationSetParameter extends Function {
DomConfigurationSetParameter() {
this.getClassAndName("setParameter").getName() = "DOMConfiguration"
}
}
/**
* A flow state transformer for a call to `DOMConfiguration.setParameter`
* specifying the feature `XMLUni::fgXercesDisableDefaultEntityResolution`.
* This is a slightly more complex transformer because the qualifier is a
* `DOMConfiguration` pointer returned by `DOMLSParser.getDomConfig` - and it
* is *that* qualifier we want to transform the flow state of.
*/
class DomConfigurationSetParameterTransformer extends XxeFlowStateTransformer {
Expr newValue;
DomConfigurationSetParameterTransformer() {
exists(FunctionCall getDomConfigCall, FunctionCall setParameterCall |
// this is the qualifier of a call to `DOMLSParser.getDomConfig`.
getDomConfigCall.getTarget() instanceof GetDomConfig and
this = getDomConfigCall.getQualifier() and
// `setParameterCall` is a call to `setParameter` on the return value of
// the same call to `DOMLSParser.getDomConfig`.
setParameterCall.getTarget() instanceof DomConfigurationSetParameter and
globalValueNumber(setParameterCall.getQualifier()).getAnExpr() = getDomConfigCall and
// the parameter being set is
// `XMLUni::fgXercesDisableDefaultEntityResolution`.
globalValueNumber(setParameterCall.getArgument(0)).getAnExpr().(VariableAccess).getTarget()
instanceof FeatureDisableDefaultEntityResolution and
// the value being set is `newValue`.
newValue = setParameterCall.getArgument(1)
)
}
final override XxeFlowState transform(XxeFlowState flowstate) {
exists(int createEntityReferenceNodes |
encodeXercesFlowState(flowstate, _, createEntityReferenceNodes) and
(
globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // true
encodeXercesFlowState(result, 1, createEntityReferenceNodes)
or
not globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // false or unknown
encodeXercesFlowState(result, 0, createEntityReferenceNodes)
)
)
}
}

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* The `cpp/unused-local-variable` no longer ignores functions that include `if` and `switch` statements with C++17-style initializers.

View File

@@ -1,4 +1,5 @@
---
category: minorAnalysis
---
## 0.1.2
### Minor Analysis Improvements
* The "XML external entity expansion" (`cpp/external-entity-expansion`) query has been extended to support a broader selection of XML libraries and interfaces.

View File

@@ -0,0 +1,6 @@
## 0.1.3
### Minor Analysis Improvements
* The "XML external entity expansion" (`cpp/external-entity-expansion`) query precision has been increased to `high`.
* The `cpp/unused-local-variable` no longer ignores functions that include `if` and `switch` statements with C++17-style initializers.

View File

@@ -0,0 +1 @@
## 0.1.4

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.1.1
lastReleaseVersion: 0.1.4

View File

@@ -0,0 +1,7 @@
void test()
{
uint16_t j = 256;
char testSubject[122];
testSubject[j] = 12; // You can use a uint8 here
}

View File

@@ -0,0 +1,18 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>Find access to an array with a Uint16 when the array has a size lower than 256.</p>
</overview>
<recommendation>
<p>Use a int with a lower bit size instead. For instance in this example use a 8 bit int.</p>
</recommendation>
<example>
<sample src="WrongUintAccess.cpp" />
</example>
</qhelp>

View File

@@ -0,0 +1,25 @@
/**
* @id cpp/wrong-uint-access
* @name Wrong Uint
* @descripion Acess an array of size lower than 256 with a uint16.
* @kind problem
* @problem.severity recommendation
* @tags efficiency
*/
import cpp
from Variable var, ArrayExpr useExpr, ArrayType defLine, VariableAccess use
where
var.getUnspecifiedType() = defLine and
use = useExpr.getArrayBase() and
var = use.getTarget() and
(
useExpr.getArrayOffset().getType() instanceof UInt16_t or
useExpr.getArrayOffset().getType() instanceof UInt32_t or
useExpr.getArrayOffset().getType() instanceof UInt64_t
) and
defLine.getArraySize() <= 256
select useExpr,
"Using a " + useExpr.getArrayOffset().getType() + " to acess the array $@ of size " +
defLine.getArraySize() + ".", var, var.getName()

View File

@@ -17,6 +17,36 @@
import cpp
import semmle.code.cpp.dataflow.DataFlow
/**
* A Linux system call.
*/
class SystemCallFunction extends Function {
SystemCallFunction() {
exists(MacroInvocation m |
m.getMacro().getName().matches("SYSCALL\\_DEFINE%") and
this = m.getEnclosingFunction()
)
}
}
/**
* A value that comes from a Linux system call (sources).
*/
class SystemCallSource extends DataFlow::Node {
SystemCallSource() {
exists(FunctionCall fc |
fc.getTarget() instanceof SystemCallFunction and
(
this.asDefiningArgument() = fc.getAnArgument().getAChild*() or
this.asExpr() = fc
)
)
}
}
/**
* Macros used to check the value (barriers).
*/
class WriteAccessCheckMacro extends Macro {
VariableAccess va;
@@ -28,6 +58,9 @@ class WriteAccessCheckMacro extends Macro {
VariableAccess getArgument() { result = va }
}
/**
* The `unsafe_put_user` macro and its uses (sinks).
*/
class UnSafePutUserMacro extends Macro {
PointerDereferenceExpr writeUserPtr;
@@ -42,15 +75,13 @@ class UnSafePutUserMacro extends Macro {
}
}
class ExploitableUserModePtrParam extends Parameter {
class ExploitableUserModePtrParam extends SystemCallSource {
ExploitableUserModePtrParam() {
not exists(WriteAccessCheckMacro writeAccessCheck |
DataFlow::localFlow(DataFlow::parameterNode(this),
DataFlow::exprNode(writeAccessCheck.getArgument()))
) and
exists(UnSafePutUserMacro unsafePutUser |
DataFlow::localFlow(DataFlow::parameterNode(this),
DataFlow::exprNode(unsafePutUser.getUserModePtr()))
DataFlow::localFlow(this, DataFlow::exprNode(unsafePutUser.getUserModePtr()))
) and
not exists(WriteAccessCheckMacro writeAccessCheck |
DataFlow::localFlow(this, DataFlow::exprNode(writeAccessCheck.getArgument()))
)
}
}

Some files were not shown because too many files have changed in this diff Show More