Compare commits

..

1 Commits

Author SHA1 Message Date
github-actions[bot]
c190c9e780 use ATM model from training run classification_1664756959_0265f4e5 2022-10-03 07:12:15 +00:00
1177 changed files with 15933 additions and 25585 deletions

View File

@@ -43,7 +43,7 @@ jobs:
env QHELP_OUT_DIR=qhelp-out make qhelp-to-markdown
- name: Upload qhelp markdown
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v2
with:
name: qhelp-markdown
path: go/qhelp-out/**/*.md

View File

@@ -27,7 +27,7 @@ on:
- main
- "rc/*"
paths:
- "**/*.qhelp"
- "ruby/**/*.qhelp"
jobs:
qhelp:

View File

@@ -4,7 +4,8 @@ This open source repository contains the standard CodeQL libraries and queries t
## How do I learn CodeQL and run queries?
There is [extensive documentation](https://codeql.github.com/docs/) on getting started with writing CodeQL using the [CodeQL extension for Visual Studio Code](https://codeql.github.com/docs/codeql-for-visual-studio-code/) and the [CodeQL CLI](https://codeql.github.com/docs/codeql-cli/).
There is [extensive documentation](https://codeql.github.com/docs/) on getting started with writing CodeQL.
You can use the [CodeQL for Visual Studio Code](https://codeql.github.com/docs/codeql-for-visual-studio-code/) extension or the [interactive query console](https://lgtm.com/help/lgtm/using-query-console) on LGTM.com (Semmle Legacy product) to try out your queries on any open source project that's currently being analyzed.
## Contributing

View File

@@ -33,9 +33,8 @@
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForRegExp.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForLibraries.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForHttpClientLibraries.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForPathname.qll",
"swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll"
],
"DataFlow Java/C++/C#/Python Common": [
@@ -70,7 +69,7 @@
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking3/TaintTrackingImpl.qll",
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking4/TaintTrackingImpl.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/tainttrackingforregexp/TaintTrackingImpl.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/tainttrackingforlibraries/TaintTrackingImpl.qll",
"swift/ql/lib/codeql/swift/dataflow/internal/tainttracking1/TaintTrackingImpl.qll"
],
"DataFlow Java/C++/C#/Python Consistency checks": [

View File

@@ -1,22 +1,3 @@
## 0.4.1
No user-facing changes.
## 0.4.0
### Deprecated APIs
* Some classes/modules with upper-case acronyms in their name have been renamed to follow our style-guide.
The old name still exists as a deprecated alias.
### New Features
* Added subclasses of `BuiltInOperations` for `__is_same`, `__is_function`, `__is_layout_compatible`, `__is_pointer_interconvertible_base_of`, `__is_array`, `__array_rank`, `__array_extent`, `__is_arithmetic`, `__is_complete_type`, `__is_compound`, `__is_const`, `__is_floating_point`, `__is_fundamental`, `__is_integral`, `__is_lvalue_reference`, `__is_member_function_pointer`, `__is_member_object_pointer`, `__is_member_pointer`, `__is_object`, `__is_pointer`, `__is_reference`, `__is_rvalue_reference`, `__is_scalar`, `__is_signed`, `__is_unsigned`, `__is_void`, and `__is_volatile`.
### Bug Fixes
* Fixed an issue in the taint tracking analysis where implicit reads were not allowed by default in sinks or additional taint steps that used flow states.
## 0.3.5
## 0.3.4

View File

@@ -1,14 +1,4 @@
## 0.4.0
### Deprecated APIs
* Some classes/modules with upper-case acronyms in their name have been renamed to follow our style-guide.
The old name still exists as a deprecated alias.
### New Features
---
category: feature
---
* Added subclasses of `BuiltInOperations` for `__is_same`, `__is_function`, `__is_layout_compatible`, `__is_pointer_interconvertible_base_of`, `__is_array`, `__array_rank`, `__array_extent`, `__is_arithmetic`, `__is_complete_type`, `__is_compound`, `__is_const`, `__is_floating_point`, `__is_fundamental`, `__is_integral`, `__is_lvalue_reference`, `__is_member_function_pointer`, `__is_member_object_pointer`, `__is_member_pointer`, `__is_object`, `__is_pointer`, `__is_reference`, `__is_rvalue_reference`, `__is_scalar`, `__is_signed`, `__is_unsigned`, `__is_void`, and `__is_volatile`.
### Bug Fixes
* Fixed an issue in the taint tracking analysis where implicit reads were not allowed by default in sinks or additional taint steps that used flow states.

View File

@@ -0,0 +1,4 @@
---
category: fix
---
* Fixed an issue in the taint tracking analysis where implicit reads were not allowed by default in sinks or additional taint steps that used flow states.

View File

@@ -1,6 +1,5 @@
## 0.3.0
### Deprecated APIs
---
category: deprecated
---
* Some classes/modules with upper-case acronyms in their name have been renamed to follow our style-guide.
The old name still exists as a deprecated alias.
The old name still exists as a deprecated alias.

View File

@@ -1,3 +0,0 @@
## 0.4.1
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.4.1
lastReleaseVersion: 0.3.5

View File

@@ -20,8 +20,7 @@ module ProductFlow {
* `source1` and `source2` must belong to the same callable.
*/
predicate isSourcePair(
DataFlow::Node source1, DataFlow::FlowState state1, DataFlow::Node source2,
DataFlow::FlowState state2
DataFlow::Node source1, string state1, DataFlow::Node source2, string state2
) {
state1 = "" and
state2 = "" and
@@ -50,101 +49,6 @@ module ProductFlow {
this.isSinkPair(sink1, sink2)
}
/**
* Holds if data flow through `node` is prohibited through the first projection of the product
* dataflow graph when the flow state is `state`.
*/
predicate isBarrier1(DataFlow::Node node, DataFlow::FlowState state) {
this.isBarrier1(node) and state = ""
}
/**
* Holds if data flow through `node` is prohibited through the second projection of the product
* dataflow graph when the flow state is `state`.
*/
predicate isBarrier2(DataFlow::Node node, DataFlow::FlowState state) {
this.isBarrier2(node) and state = ""
}
/**
* Holds if data flow through `node` is prohibited through the first projection of the product
* dataflow graph.
*/
predicate isBarrier1(DataFlow::Node node) { none() }
/**
* Holds if data flow through `node` is prohibited through the second projection of the product
* dataflow graph.
*/
predicate isBarrier2(DataFlow::Node node) { none() }
/**
* Holds if data flow out of `node` is prohibited in the first projection of the product
* dataflow graph.
*/
predicate isBarrierOut1(DataFlow::Node node) { none() }
/**
* Holds if data flow out of `node` is prohibited in the second projection of the product
* dataflow graph.
*/
predicate isBarrierOut2(DataFlow::Node node) { none() }
/*
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps in
* the first projection of the product dataflow graph.
*/
predicate isAdditionalFlowStep1(DataFlow::Node node1, DataFlow::Node node2) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps in
* the first projection of the product dataflow graph.
*
* This step is only applicable in `state1` and updates the flow state to `state2`.
*/
predicate isAdditionalFlowStep1(
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
DataFlow::FlowState state2
) {
state1 instanceof DataFlow::FlowStateEmpty and
state2 instanceof DataFlow::FlowStateEmpty and
this.isAdditionalFlowStep1(node1, node2)
}
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps in
* the second projection of the product dataflow graph.
*/
predicate isAdditionalFlowStep2(DataFlow::Node node1, DataFlow::Node node2) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps in
* the second projection of the product dataflow graph.
*
* This step is only applicable in `state1` and updates the flow state to `state2`.
*/
predicate isAdditionalFlowStep2(
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
DataFlow::FlowState state2
) {
state1 instanceof DataFlow::FlowStateEmpty and
state2 instanceof DataFlow::FlowStateEmpty and
this.isAdditionalFlowStep2(node1, node2)
}
/**
* Holds if data flow into `node` is prohibited in the first projection of the product
* dataflow graph.
*/
predicate isBarrierIn1(DataFlow::Node node) { none() }
/**
* Holds if data flow into `node` is prohibited in the second projection of the product
* dataflow graph.
*/
predicate isBarrierIn2(DataFlow::Node node) { none() }
predicate hasFlowPath(
DataFlow::PathNode source1, DataFlow2::PathNode source2, DataFlow::PathNode sink1,
DataFlow2::PathNode sink2
@@ -159,78 +63,38 @@ module ProductFlow {
class Conf1 extends DataFlow::Configuration {
Conf1() { this = "Conf1" }
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) {
override predicate isSource(DataFlow::Node source, string state) {
exists(Configuration conf | conf.isSourcePair(source, state, _, _))
}
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) {
override predicate isSink(DataFlow::Node sink, string state) {
exists(Configuration conf | conf.isSinkPair(sink, state, _, _))
}
override predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) {
exists(Configuration conf | conf.isBarrier1(node, state))
}
override predicate isBarrierOut(DataFlow::Node node) {
exists(Configuration conf | conf.isBarrierOut1(node))
}
override predicate isAdditionalFlowStep(
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
DataFlow::FlowState state2
) {
exists(Configuration conf | conf.isAdditionalFlowStep1(node1, state1, node2, state2))
}
override predicate isBarrierIn(DataFlow::Node node) {
exists(Configuration conf | conf.isBarrierIn1(node))
}
}
class Conf2 extends DataFlow2::Configuration {
Conf2() { this = "Conf2" }
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) {
exists(Configuration conf, DataFlow::PathNode source1 |
conf.isSourcePair(source1.getNode(), source1.getState(), source, state) and
any(Conf1 c).hasFlowPath(source1, _)
override predicate isSource(DataFlow::Node source, string state) {
exists(Configuration conf, DataFlow::Node source1 |
conf.isSourcePair(source1, _, source, state) and
any(Conf1 c).hasFlow(source1, _)
)
}
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) {
exists(Configuration conf, DataFlow::PathNode sink1 |
conf.isSinkPair(sink1.getNode(), sink1.getState(), sink, state) and
any(Conf1 c).hasFlowPath(_, sink1)
override predicate isSink(DataFlow::Node sink, string state) {
exists(Configuration conf, DataFlow::Node sink1 |
conf.isSinkPair(sink1, _, sink, state) and any(Conf1 c).hasFlow(_, sink1)
)
}
override predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) {
exists(Configuration conf | conf.isBarrier2(node, state))
}
override predicate isBarrierOut(DataFlow::Node node) {
exists(Configuration conf | conf.isBarrierOut2(node))
}
override predicate isAdditionalFlowStep(
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
DataFlow::FlowState state2
) {
exists(Configuration conf | conf.isAdditionalFlowStep2(node1, state1, node2, state2))
}
override predicate isBarrierIn(DataFlow::Node node) {
exists(Configuration conf | conf.isBarrierIn2(node))
}
}
}
pragma[nomagic]
private predicate reachableInterprocEntry(
Configuration conf, DataFlow::PathNode source1, DataFlow2::PathNode source2,
DataFlow::PathNode node1, DataFlow2::PathNode node2
) {
conf.isSourcePair(node1.getNode(), node1.getState(), node2.getNode(), node2.getState()) and
conf.isSourcePair(node1.getNode(), _, node2.getNode(), _) and
node1 = source1 and
node2 = source2
or
@@ -293,7 +157,7 @@ module ProductFlow {
) {
exists(DataFlow::PathNode mid1, DataFlow2::PathNode mid2 |
reachableInterprocEntry(conf, source1, source2, mid1, mid2) and
conf.isSinkPair(sink1.getNode(), sink1.getState(), sink2.getNode(), sink2.getState()) and
conf.isSinkPair(sink1.getNode(), _, sink2.getNode(), _) and
localPathStep1*(mid1, sink1) and
localPathStep2*(mid2, sink2)
)

View File

@@ -558,16 +558,13 @@ private predicate expectsContentEx(NodeEx n, Content c) {
pragma[nomagic]
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
pragma[nomagic]
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
pragma[nomagic]
private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
contentType) and
hasReadStep(tc.getContent(), config) and
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
}
@@ -601,9 +598,13 @@ private predicate hasSinkCallCtx(Configuration config) {
}
private module Stage1 implements StageSig {
class ApApprox = Unit;
class Ap = Unit;
private class Cc = boolean;
class ApOption = Unit;
class Cc = boolean;
/* Begin: Stage 1 logic. */
/**
@@ -612,7 +613,7 @@ private module Stage1 implements StageSig {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
sourceNode(node, _, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
@@ -752,7 +753,7 @@ private module Stage1 implements StageSig {
* the enclosing callable in order to reach a sink.
*/
pragma[nomagic]
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
revFlow0(node, toReturn, config) and
fwdFlow(node, config)
}

View File

@@ -558,16 +558,13 @@ private predicate expectsContentEx(NodeEx n, Content c) {
pragma[nomagic]
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
pragma[nomagic]
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
pragma[nomagic]
private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
contentType) and
hasReadStep(tc.getContent(), config) and
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
}
@@ -601,9 +598,13 @@ private predicate hasSinkCallCtx(Configuration config) {
}
private module Stage1 implements StageSig {
class ApApprox = Unit;
class Ap = Unit;
private class Cc = boolean;
class ApOption = Unit;
class Cc = boolean;
/* Begin: Stage 1 logic. */
/**
@@ -612,7 +613,7 @@ private module Stage1 implements StageSig {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
sourceNode(node, _, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
@@ -752,7 +753,7 @@ private module Stage1 implements StageSig {
* the enclosing callable in order to reach a sink.
*/
pragma[nomagic]
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
revFlow0(node, toReturn, config) and
fwdFlow(node, config)
}

View File

@@ -558,16 +558,13 @@ private predicate expectsContentEx(NodeEx n, Content c) {
pragma[nomagic]
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
pragma[nomagic]
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
pragma[nomagic]
private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
contentType) and
hasReadStep(tc.getContent(), config) and
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
}
@@ -601,9 +598,13 @@ private predicate hasSinkCallCtx(Configuration config) {
}
private module Stage1 implements StageSig {
class ApApprox = Unit;
class Ap = Unit;
private class Cc = boolean;
class ApOption = Unit;
class Cc = boolean;
/* Begin: Stage 1 logic. */
/**
@@ -612,7 +613,7 @@ private module Stage1 implements StageSig {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
sourceNode(node, _, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
@@ -752,7 +753,7 @@ private module Stage1 implements StageSig {
* the enclosing callable in order to reach a sink.
*/
pragma[nomagic]
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
revFlow0(node, toReturn, config) and
fwdFlow(node, config)
}

View File

@@ -558,16 +558,13 @@ private predicate expectsContentEx(NodeEx n, Content c) {
pragma[nomagic]
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
pragma[nomagic]
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
pragma[nomagic]
private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
contentType) and
hasReadStep(tc.getContent(), config) and
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
}
@@ -601,9 +598,13 @@ private predicate hasSinkCallCtx(Configuration config) {
}
private module Stage1 implements StageSig {
class ApApprox = Unit;
class Ap = Unit;
private class Cc = boolean;
class ApOption = Unit;
class Cc = boolean;
/* Begin: Stage 1 logic. */
/**
@@ -612,7 +613,7 @@ private module Stage1 implements StageSig {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
sourceNode(node, _, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
@@ -752,7 +753,7 @@ private module Stage1 implements StageSig {
* the enclosing callable in order to reach a sink.
*/
pragma[nomagic]
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
revFlow0(node, toReturn, config) and
fwdFlow(node, config)
}

View File

@@ -416,21 +416,6 @@ class SsaPhiNode extends Node, TSsaPhiNode {
final override Location getLocationImpl() { result = phi.getBasicBlock().getLocation() }
override string toStringImpl() { result = "Phi" }
/**
* Gets a node that is used as input to this phi node.
* `fromBackEdge` is true if data flows along a back-edge,
* and `false` otherwise.
*/
final Node getAnInput(boolean fromBackEdge) {
localFlowStep(result, this) and
if phi.getBasicBlock().dominates(getBasicBlock(result))
then fromBackEdge = true
else fromBackEdge = false
}
/** Gets a node that is used as input to this phi node. */
final Node getAnInput() { result = this.getAnInput(_) }
}
/**

View File

@@ -301,12 +301,7 @@ private predicate defToNode(Node nodeFrom, Def def) {
nodeHasInstruction(nodeFrom, def.getDefiningInstruction(), def.getIndirectionIndex())
}
/**
* INTERNAL: Do not use.
*
* Holds if `nodeFrom` is the node that correspond to the definition or use `defOrUse`.
*/
predicate nodeToDefOrUse(Node nodeFrom, SsaDefOrUse defOrUse) {
private predicate nodeToDefOrUse(Node nodeFrom, SsaDefOrUse defOrUse) {
// Node -> Def
defToNode(nodeFrom, defOrUse)
or

View File

@@ -7,7 +7,6 @@ private import semmle.code.cpp.ir.IR as IR
private import Semantic
private import experimental.semmle.code.cpp.rangeanalysis.Bound as IRBound
private import semmle.code.cpp.controlflow.IRGuards as IRGuards
private import semmle.code.cpp.ir.ValueNumbering
module SemanticExprConfig {
class Location = Cpp::Location;
@@ -121,15 +120,7 @@ module SemanticExprConfig {
newtype TSsaVariable =
TSsaInstruction(IR::Instruction instr) { instr.hasMemoryResult() } or
TSsaOperand(IR::Operand op) { op.isDefinitionInexact() } or
TSsaPointerArithmeticGuard(IR::PointerArithmeticInstruction instr) {
exists(Guard g, IR::Operand use | use = instr.getAUse() |
g.comparesLt(use, _, _, _, _) or
g.comparesLt(_, use, _, _, _) or
g.comparesEq(use, _, _, _, _) or
g.comparesEq(_, use, _, _, _)
)
}
TSsaOperand(IR::Operand op) { op.isDefinitionInexact() }
class SsaVariable extends TSsaVariable {
string toString() { none() }
@@ -138,8 +129,6 @@ module SemanticExprConfig {
IR::Instruction asInstruction() { none() }
IR::PointerArithmeticInstruction asPointerArithGuard() { none() }
IR::Operand asOperand() { none() }
}
@@ -155,18 +144,6 @@ module SemanticExprConfig {
final override IR::Instruction asInstruction() { result = instr }
}
class SsaPointerArithmeticGuard extends SsaVariable, TSsaPointerArithmeticGuard {
IR::PointerArithmeticInstruction instr;
SsaPointerArithmeticGuard() { this = TSsaPointerArithmeticGuard(instr) }
final override string toString() { result = instr.toString() }
final override Location getLocation() { result = instr.getLocation() }
final override IR::PointerArithmeticInstruction asPointerArithGuard() { result = instr }
}
class SsaOperand extends SsaVariable, TSsaOperand {
IR::Operand op;
@@ -191,11 +168,7 @@ module SemanticExprConfig {
)
}
Expr getAUse(SsaVariable v) {
result.(IR::LoadInstruction).getSourceValue() = v.asInstruction()
or
result = valueNumber(v.asPointerArithGuard()).getAnInstruction()
}
Expr getAUse(SsaVariable v) { result.(IR::LoadInstruction).getSourceValue() = v.asInstruction() }
SemType getSsaVariableType(SsaVariable v) {
result = getSemanticType(v.asInstruction().getResultIRType())
@@ -235,9 +208,7 @@ module SemanticExprConfig {
final override predicate hasRead(SsaVariable v) {
exists(IR::Operand operand |
operand.getDef() = v.asInstruction() or
operand.getDef() = valueNumber(v.asPointerArithGuard()).getAnInstruction()
|
operand.getDef() = v.asInstruction() and
not operand instanceof IR::PhiInputOperand and
operand.getUse().getBlock() = block
)
@@ -256,9 +227,7 @@ module SemanticExprConfig {
final override predicate hasRead(SsaVariable v) {
exists(IR::PhiInputOperand operand |
operand.getDef() = v.asInstruction() or
operand.getDef() = valueNumber(v.asPointerArithGuard()).getAnInstruction()
|
operand.getDef() = v.asInstruction() and
operand.getPredecessorBlock() = pred and
operand.getUse().getBlock() = succ
)

View File

@@ -10,7 +10,7 @@ class SemSsaVariable instanceof Specific::SsaVariable {
final Specific::Location getLocation() { result = super.getLocation() }
final SemExpr getAUse() { result = Specific::getAUse(this) }
final SemLoadExpr getAUse() { result = Specific::getAUse(this) }
final SemType getType() { result = Specific::getSsaVariableType(this) }

View File

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

View File

@@ -6,7 +6,7 @@ import cpp
* A function that concatenates the string from its second argument
* to the string from its first argument, for example `strcat`.
*/
deprecated class StrcatFunction extends Function {
class StrcatFunction extends Function {
StrcatFunction() {
getName() =
[

View File

@@ -558,16 +558,13 @@ private predicate expectsContentEx(NodeEx n, Content c) {
pragma[nomagic]
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
pragma[nomagic]
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
pragma[nomagic]
private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
contentType) and
hasReadStep(tc.getContent(), config) and
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
}
@@ -601,9 +598,13 @@ private predicate hasSinkCallCtx(Configuration config) {
}
private module Stage1 implements StageSig {
class ApApprox = Unit;
class Ap = Unit;
private class Cc = boolean;
class ApOption = Unit;
class Cc = boolean;
/* Begin: Stage 1 logic. */
/**
@@ -612,7 +613,7 @@ private module Stage1 implements StageSig {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
sourceNode(node, _, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
@@ -752,7 +753,7 @@ private module Stage1 implements StageSig {
* the enclosing callable in order to reach a sink.
*/
pragma[nomagic]
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
revFlow0(node, toReturn, config) and
fwdFlow(node, config)
}

View File

@@ -558,16 +558,13 @@ private predicate expectsContentEx(NodeEx n, Content c) {
pragma[nomagic]
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
pragma[nomagic]
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
pragma[nomagic]
private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
contentType) and
hasReadStep(tc.getContent(), config) and
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
}
@@ -601,9 +598,13 @@ private predicate hasSinkCallCtx(Configuration config) {
}
private module Stage1 implements StageSig {
class ApApprox = Unit;
class Ap = Unit;
private class Cc = boolean;
class ApOption = Unit;
class Cc = boolean;
/* Begin: Stage 1 logic. */
/**
@@ -612,7 +613,7 @@ private module Stage1 implements StageSig {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
sourceNode(node, _, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
@@ -752,7 +753,7 @@ private module Stage1 implements StageSig {
* the enclosing callable in order to reach a sink.
*/
pragma[nomagic]
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
revFlow0(node, toReturn, config) and
fwdFlow(node, config)
}

View File

@@ -558,16 +558,13 @@ private predicate expectsContentEx(NodeEx n, Content c) {
pragma[nomagic]
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
pragma[nomagic]
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
pragma[nomagic]
private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
contentType) and
hasReadStep(tc.getContent(), config) and
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
}
@@ -601,9 +598,13 @@ private predicate hasSinkCallCtx(Configuration config) {
}
private module Stage1 implements StageSig {
class ApApprox = Unit;
class Ap = Unit;
private class Cc = boolean;
class ApOption = Unit;
class Cc = boolean;
/* Begin: Stage 1 logic. */
/**
@@ -612,7 +613,7 @@ private module Stage1 implements StageSig {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
sourceNode(node, _, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
@@ -752,7 +753,7 @@ private module Stage1 implements StageSig {
* the enclosing callable in order to reach a sink.
*/
pragma[nomagic]
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
revFlow0(node, toReturn, config) and
fwdFlow(node, config)
}

View File

@@ -558,16 +558,13 @@ private predicate expectsContentEx(NodeEx n, Content c) {
pragma[nomagic]
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
pragma[nomagic]
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
pragma[nomagic]
private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
contentType) and
hasReadStep(tc.getContent(), config) and
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
}
@@ -601,9 +598,13 @@ private predicate hasSinkCallCtx(Configuration config) {
}
private module Stage1 implements StageSig {
class ApApprox = Unit;
class Ap = Unit;
private class Cc = boolean;
class ApOption = Unit;
class Cc = boolean;
/* Begin: Stage 1 logic. */
/**
@@ -612,7 +613,7 @@ private module Stage1 implements StageSig {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
sourceNode(node, _, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
@@ -752,7 +753,7 @@ private module Stage1 implements StageSig {
* the enclosing callable in order to reach a sink.
*/
pragma[nomagic]
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
revFlow0(node, toReturn, config) and
fwdFlow(node, config)
}

View File

@@ -558,16 +558,13 @@ private predicate expectsContentEx(NodeEx n, Content c) {
pragma[nomagic]
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
pragma[nomagic]
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
pragma[nomagic]
private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
contentType) and
hasReadStep(tc.getContent(), config) and
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
}
@@ -601,9 +598,13 @@ private predicate hasSinkCallCtx(Configuration config) {
}
private module Stage1 implements StageSig {
class ApApprox = Unit;
class Ap = Unit;
private class Cc = boolean;
class ApOption = Unit;
class Cc = boolean;
/* Begin: Stage 1 logic. */
/**
@@ -612,7 +613,7 @@ private module Stage1 implements StageSig {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
sourceNode(node, _, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
@@ -752,7 +753,7 @@ private module Stage1 implements StageSig {
* the enclosing callable in order to reach a sink.
*/
pragma[nomagic]
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
revFlow0(node, toReturn, config) and
fwdFlow(node, config)
}

View File

@@ -558,16 +558,13 @@ private predicate expectsContentEx(NodeEx n, Content c) {
pragma[nomagic]
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
pragma[nomagic]
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
pragma[nomagic]
private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
contentType) and
hasReadStep(tc.getContent(), config) and
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
}
@@ -601,9 +598,13 @@ private predicate hasSinkCallCtx(Configuration config) {
}
private module Stage1 implements StageSig {
class ApApprox = Unit;
class Ap = Unit;
private class Cc = boolean;
class ApOption = Unit;
class Cc = boolean;
/* Begin: Stage 1 logic. */
/**
@@ -612,7 +613,7 @@ private module Stage1 implements StageSig {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
sourceNode(node, _, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
@@ -752,7 +753,7 @@ private module Stage1 implements StageSig {
* the enclosing callable in order to reach a sink.
*/
pragma[nomagic]
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
revFlow0(node, toReturn, config) and
fwdFlow(node, config)
}

View File

@@ -558,16 +558,13 @@ private predicate expectsContentEx(NodeEx n, Content c) {
pragma[nomagic]
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
pragma[nomagic]
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
pragma[nomagic]
private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
contentType) and
hasReadStep(tc.getContent(), config) and
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
}
@@ -601,9 +598,13 @@ private predicate hasSinkCallCtx(Configuration config) {
}
private module Stage1 implements StageSig {
class ApApprox = Unit;
class Ap = Unit;
private class Cc = boolean;
class ApOption = Unit;
class Cc = boolean;
/* Begin: Stage 1 logic. */
/**
@@ -612,7 +613,7 @@ private module Stage1 implements StageSig {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
sourceNode(node, _, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
@@ -752,7 +753,7 @@ private module Stage1 implements StageSig {
* the enclosing callable in order to reach a sink.
*/
pragma[nomagic]
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
revFlow0(node, toReturn, config) and
fwdFlow(node, config)
}

View File

@@ -558,16 +558,13 @@ private predicate expectsContentEx(NodeEx n, Content c) {
pragma[nomagic]
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
pragma[nomagic]
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
pragma[nomagic]
private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
contentType) and
hasReadStep(tc.getContent(), config) and
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
}
@@ -601,9 +598,13 @@ private predicate hasSinkCallCtx(Configuration config) {
}
private module Stage1 implements StageSig {
class ApApprox = Unit;
class Ap = Unit;
private class Cc = boolean;
class ApOption = Unit;
class Cc = boolean;
/* Begin: Stage 1 logic. */
/**
@@ -612,7 +613,7 @@ private module Stage1 implements StageSig {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
sourceNode(node, _, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
@@ -752,7 +753,7 @@ private module Stage1 implements StageSig {
* the enclosing callable in order to reach a sink.
*/
pragma[nomagic]
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
revFlow0(node, toReturn, config) and
fwdFlow(node, config)
}

View File

@@ -558,16 +558,13 @@ private predicate expectsContentEx(NodeEx n, Content c) {
pragma[nomagic]
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
pragma[nomagic]
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
pragma[nomagic]
private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
contentType) and
hasReadStep(tc.getContent(), config) and
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
}
@@ -601,9 +598,13 @@ private predicate hasSinkCallCtx(Configuration config) {
}
private module Stage1 implements StageSig {
class ApApprox = Unit;
class Ap = Unit;
private class Cc = boolean;
class ApOption = Unit;
class Cc = boolean;
/* Begin: Stage 1 logic. */
/**
@@ -612,7 +613,7 @@ private module Stage1 implements StageSig {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
sourceNode(node, _, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
@@ -752,7 +753,7 @@ private module Stage1 implements StageSig {
* the enclosing callable in order to reach a sink.
*/
pragma[nomagic]
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
revFlow0(node, toReturn, config) and
fwdFlow(node, config)
}

View File

@@ -267,6 +267,9 @@ Instruction getSourceAddressFromNode(Node node) {
result = getSourceAddress(node.asOperand().(SideEffectOperand).getUse())
}
/** Gets the source value of `instr` if it's an instruction that behaves like a `LoadInstruction`. */
Instruction getSourceValue(Instruction instr) { result = getSourceValueOperand(instr).getDef() }
/**
* Gets the operand that represents the source value of `instr` if it's an instruction
* that behaves like a `LoadInstruction`.

View File

@@ -143,6 +143,16 @@ private module Cached {
)
}
cached
Instruction getRegisterOperandDefinition(Instruction instruction, RegisterOperandTag tag) {
exists(OldInstruction oldInstruction, OldIR::RegisterOperand oldOperand |
oldInstruction = getOldInstruction(instruction) and
oldOperand = oldInstruction.getAnOperand() and
tag = oldOperand.getOperandTag() and
result = getNewInstruction(oldOperand.getAnyDef())
)
}
pragma[noopt]
private predicate hasMemoryOperandDefinition(
OldInstruction oldInstruction, OldIR::NonPhiMemoryOperand oldOperand, Overlap overlap,

View File

@@ -256,6 +256,12 @@ CppType getInstructionOperandType(Instruction instruction, TypedOperandTag tag)
.getInstructionMemoryOperandType(getInstructionTag(instruction), tag)
}
Instruction getPhiOperandDefinition(
PhiInstruction instruction, IRBlock predecessorBlock, Overlap overlap
) {
none()
}
Instruction getPhiInstructionBlockStart(PhiInstruction instr) { none() }
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {

View File

@@ -143,6 +143,16 @@ private module Cached {
)
}
cached
Instruction getRegisterOperandDefinition(Instruction instruction, RegisterOperandTag tag) {
exists(OldInstruction oldInstruction, OldIR::RegisterOperand oldOperand |
oldInstruction = getOldInstruction(instruction) and
oldOperand = oldInstruction.getAnOperand() and
tag = oldOperand.getOperandTag() and
result = getNewInstruction(oldOperand.getAnyDef())
)
}
pragma[noopt]
private predicate hasMemoryOperandDefinition(
OldInstruction oldInstruction, OldIR::NonPhiMemoryOperand oldOperand, Overlap overlap,

View File

@@ -205,149 +205,57 @@ private predicate deconstructSizeExpr(Expr sizeExpr, Expr lengthExpr, int sizeof
sizeof = 1
}
/** A `Function` that is a call target of an allocation. */
private signature class CallAllocationExprTarget extends Function;
/**
* This module abstracts over the type of allocation call-targets and provides a
* class `CallAllocationExprImpl` which contains the implementation of the various
* predicates required by the `Allocation` class.
*
* This module is then instantiated for two types of allocation call-targets:
* - `AllocationFunction`: Functions that we've explicitly modeled as functions that
* perform allocations (i.e., `malloc`).
* - `HeuristicAllocationFunction`: Functions that we deduce as behaving like an allocation
* function using various heuristics.
* An allocation expression that is a function call, such as call to `malloc`.
*/
private module CallAllocationExprBase<CallAllocationExprTarget Target> {
/** A module that contains the collection of member-predicates required on `Target`. */
signature module Param {
/**
* Gets the index of the input pointer argument to be reallocated, if
* this is a `realloc` function.
*/
int getReallocPtrArg(Target target);
private class CallAllocationExpr extends AllocationExpr, FunctionCall {
AllocationFunction target;
/**
* Gets the index of the argument for the allocation size, if any. The actual
* allocation size is the value of this argument multiplied by the result of
* `getSizeMult()`, in bytes.
*/
int getSizeArg(Target target);
/**
* Gets the index of an argument that multiplies the allocation size given
* by `getSizeArg`, if any.
*/
int getSizeMult(Target target);
/**
* Holds if this allocation requires a
* corresponding deallocation of some sort (most do, but `alloca` for example
* does not). If it is unclear, we default to no (for example a placement `new`
* allocation may or may not require a corresponding `delete`).
*/
predicate requiresDealloc(Target target);
CallAllocationExpr() {
target = this.getTarget() and
// realloc(ptr, 0) only frees the pointer
not (
exists(target.getReallocPtrArg()) and
this.getArgument(target.getSizeArg()).getValue().toInt() = 0
) and
// these are modeled directly (and more accurately), avoid duplication
not exists(NewOrNewArrayExpr new | new.getAllocatorCall() = this)
}
/**
* A module that abstracts over a collection of predicates in
* the `Param` module). This should really be member-predicates
* on `CallAllocationExprTarget`, but we cannot yet write this in QL.
*/
module With<Param P> {
private import P
/**
* An allocation expression that is a function call, such as call to `malloc`.
*/
class CallAllocationExprImpl instanceof FunctionCall {
Target target;
CallAllocationExprImpl() {
target = this.getTarget() and
// realloc(ptr, 0) only frees the pointer
not (
exists(getReallocPtrArg(target)) and
this.getArgument(getSizeArg(target)).getValue().toInt() = 0
) and
// these are modeled directly (and more accurately), avoid duplication
not exists(NewOrNewArrayExpr new | new.getAllocatorCall() = this)
}
string toString() { result = super.toString() }
Expr getSizeExprImpl() {
exists(Expr sizeExpr | sizeExpr = super.getArgument(getSizeArg(target)) |
if exists(getSizeMult(target))
then result = sizeExpr
else
exists(Expr lengthExpr |
deconstructSizeExpr(sizeExpr, lengthExpr, _) and
result = lengthExpr
)
override Expr getSizeExpr() {
exists(Expr sizeExpr | sizeExpr = this.getArgument(target.getSizeArg()) |
if exists(target.getSizeMult())
then result = sizeExpr
else
exists(Expr lengthExpr |
deconstructSizeExpr(sizeExpr, lengthExpr, _) and
result = lengthExpr
)
}
int getSizeMultImpl() {
// malloc with multiplier argument that is a constant
result = super.getArgument(getSizeMult(target)).getValue().toInt()
or
// malloc with no multiplier argument
not exists(getSizeMult(target)) and
deconstructSizeExpr(super.getArgument(getSizeArg(target)), _, result)
}
int getSizeBytesImpl() {
result = this.getSizeExprImpl().getValue().toInt() * this.getSizeMultImpl()
}
Expr getReallocPtrImpl() { result = super.getArgument(getReallocPtrArg(target)) }
Type getAllocatedElementTypeImpl() {
result =
super.getFullyConverted().getType().stripTopLevelSpecifiers().(PointerType).getBaseType() and
not result instanceof VoidType
}
predicate requiresDeallocImpl() { requiresDealloc(target) }
}
}
}
private module CallAllocationExpr {
private module Param implements CallAllocationExprBase<AllocationFunction>::Param {
int getReallocPtrArg(AllocationFunction f) { result = f.getReallocPtrArg() }
int getSizeArg(AllocationFunction f) { result = f.getSizeArg() }
int getSizeMult(AllocationFunction f) { result = f.getSizeMult() }
predicate requiresDealloc(AllocationFunction f) { f.requiresDealloc() }
)
}
/**
* A class that provides the implementation of `AllocationExpr` for an allocation
* that calls an `AllocationFunction`.
*/
private class Base =
CallAllocationExprBase<AllocationFunction>::With<Param>::CallAllocationExprImpl;
class CallAllocationExpr extends AllocationExpr, Base {
override Expr getSizeExpr() { result = super.getSizeExprImpl() }
override int getSizeMult() { result = super.getSizeMultImpl() }
override Type getAllocatedElementType() { result = super.getAllocatedElementTypeImpl() }
override predicate requiresDealloc() { super.requiresDeallocImpl() }
override int getSizeBytes() { result = super.getSizeBytesImpl() }
override Expr getReallocPtr() { result = super.getReallocPtrImpl() }
override string toString() { result = AllocationExpr.super.toString() }
override int getSizeMult() {
// malloc with multiplier argument that is a constant
result = this.getArgument(target.getSizeMult()).getValue().toInt()
or
// malloc with no multiplier argument
not exists(target.getSizeMult()) and
deconstructSizeExpr(this.getArgument(target.getSizeArg()), _, result)
}
override int getSizeBytes() {
result = this.getSizeExpr().getValue().toInt() * this.getSizeMult()
}
override Expr getReallocPtr() { result = this.getArgument(target.getReallocPtrArg()) }
override Type getAllocatedElementType() {
result =
this.getFullyConverted().getType().stripTopLevelSpecifiers().(PointerType).getBaseType() and
not result instanceof VoidType
}
override predicate requiresDealloc() { target.requiresDealloc() }
}
/**
@@ -386,99 +294,3 @@ private class NewArrayAllocationExpr extends AllocationExpr, NewArrayExpr {
override predicate requiresDealloc() { not exists(this.getPlacementPointer()) }
}
private module HeuristicAllocation {
/** A class that maps an `AllocationExpr` to an `HeuristicAllocationExpr`. */
private class HeuristicAllocationModeled extends HeuristicAllocationExpr instanceof AllocationExpr {
override Expr getSizeExpr() { result = AllocationExpr.super.getSizeExpr() }
override int getSizeMult() { result = AllocationExpr.super.getSizeMult() }
override int getSizeBytes() { result = AllocationExpr.super.getSizeBytes() }
override Expr getReallocPtr() { result = AllocationExpr.super.getReallocPtr() }
override Type getAllocatedElementType() {
result = AllocationExpr.super.getAllocatedElementType()
}
override predicate requiresDealloc() { AllocationExpr.super.requiresDealloc() }
}
/** A class that maps an `AllocationFunction` to an `HeuristicAllocationFunction`. */
private class HeuristicAllocationFunctionModeled extends HeuristicAllocationFunction instanceof AllocationFunction {
override int getSizeArg() { result = AllocationFunction.super.getSizeArg() }
override int getSizeMult() { result = AllocationFunction.super.getSizeMult() }
override int getReallocPtrArg() { result = AllocationFunction.super.getReallocPtrArg() }
override predicate requiresDealloc() { AllocationFunction.super.requiresDealloc() }
}
private int getAnUnsignedParameter(Function f) {
f.getParameter(result).getUnspecifiedType().(IntegralType).isUnsigned()
}
private int getAPointerParameter(Function f) {
f.getParameter(result).getUnspecifiedType() instanceof PointerType
}
/**
* A class that uses heuristics to find additional allocation functions. The required are as follows:
* 1. The word `alloc` must appear in the function name
* 2. The function must return a pointer type
* 3. There must be a unique parameter of unsigned integral type.
*/
private class HeuristicAllocationFunctionByName extends HeuristicAllocationFunction instanceof Function {
int sizeArg;
HeuristicAllocationFunctionByName() {
Function.super.getName().matches("%alloc%") and
Function.super.getUnspecifiedType() instanceof PointerType and
sizeArg = unique( | | getAnUnsignedParameter(this))
}
override int getSizeArg() { result = sizeArg }
override int getReallocPtrArg() {
Function.super.getName().matches("%realloc%") and
result = unique( | | getAPointerParameter(this))
}
override predicate requiresDealloc() { none() }
}
private module Param implements CallAllocationExprBase<HeuristicAllocationFunction>::Param {
int getReallocPtrArg(HeuristicAllocationFunction f) { result = f.getReallocPtrArg() }
int getSizeArg(HeuristicAllocationFunction f) { result = f.getSizeArg() }
int getSizeMult(HeuristicAllocationFunction f) { result = f.getSizeMult() }
predicate requiresDealloc(HeuristicAllocationFunction f) { f.requiresDealloc() }
}
/**
* A class that provides the implementation of `AllocationExpr` for an allocation
* that calls an `HeuristicAllocationFunction`.
*/
private class Base =
CallAllocationExprBase<HeuristicAllocationFunction>::With<Param>::CallAllocationExprImpl;
private class CallAllocationExpr extends HeuristicAllocationExpr, Base {
override Expr getSizeExpr() { result = super.getSizeExprImpl() }
override int getSizeMult() { result = super.getSizeMultImpl() }
override Type getAllocatedElementType() { result = super.getAllocatedElementTypeImpl() }
override predicate requiresDealloc() { super.requiresDeallocImpl() }
override int getSizeBytes() { result = super.getSizeBytesImpl() }
override Expr getReallocPtr() { result = super.getReallocPtrImpl() }
override string toString() { result = HeuristicAllocationExpr.super.toString() }
}
}

View File

@@ -113,84 +113,3 @@ class OperatorNewAllocationFunction extends AllocationFunction {
result = 1
}
}
/**
* An expression that _might_ allocate memory.
*
* Unlike `AllocationExpr`, this class uses heuristics (such as a call target's
* name and parameters) to include additional expressions.
*/
abstract class HeuristicAllocationExpr extends Expr {
/**
* Gets an expression for the allocation size, if any. The actual allocation
* size is the value of this expression multiplied by the result of
* `getSizeMult()`, in bytes.
*/
Expr getSizeExpr() { none() }
/**
* Gets a constant multiplier for the allocation size given by `getSizeExpr`,
* in bytes.
*/
int getSizeMult() { none() }
/**
* Gets the size of this allocation in bytes, if it is a fixed size and that
* size can be determined.
*/
int getSizeBytes() { none() }
/**
* Gets the expression for the input pointer argument to be reallocated, if
* this is a `realloc` function.
*/
Expr getReallocPtr() { none() }
/**
* Gets the type of the elements that are allocated, if it can be determined.
*/
Type getAllocatedElementType() { none() }
/**
* Whether or not this allocation requires a corresponding deallocation of
* some sort (most do, but `alloca` for example does not). If it is unclear,
* we default to no (for example a placement `new` allocation may or may not
* require a corresponding `delete`).
*/
predicate requiresDealloc() { any() }
}
/**
* An function that _might_ allocate memory.
*
* Unlike `AllocationFunction`, this class uses heuristics (such as the function's
* name and its parameters) to include additional functions.
*/
abstract class HeuristicAllocationFunction extends Function {
/**
* Gets the index of the argument for the allocation size, if any. The actual
* allocation size is the value of this argument multiplied by the result of
* `getSizeMult()`, in bytes.
*/
int getSizeArg() { none() }
/**
* Gets the index of an argument that multiplies the allocation size given by
* `getSizeArg`, if any.
*/
int getSizeMult() { none() }
/**
* Gets the index of the input pointer argument to be reallocated, if this
* is a `realloc` function.
*/
int getReallocPtrArg() { none() }
/**
* Whether or not this allocation requires a corresponding deallocation of
* some sort (most do, but `alloca` for example does not). If it is unclear,
* we default to no (for example a placement `new` allocation may or may not
* require a corresponding `delete`).
*/
predicate requiresDealloc() { any() }
}

View File

@@ -15,4 +15,4 @@ where
c.fromSource() and
c.isTopLevel() and
c.getParentScope() instanceof GlobalNamespace
select c, "This class is not declared in any namespace."
select c, "This class is not declared in any namespace"

View File

@@ -16,4 +16,4 @@ where
t.fromSource() and
n = t.getMetrics().getEfferentSourceCoupling() and
n > 10
select t as class_, "This class has too many dependencies (" + n.toString() + ")."
select t as class_, "This class has too many dependencies (" + n.toString() + ")"

View File

@@ -17,4 +17,4 @@ where
n = f.getMetrics().getNumberOfCalls() and
n > 99 and
not f.isMultiplyDefined()
select f as function, "This function makes too many calls (" + n.toString() + ")."
select f as function, "This function makes too many calls (" + n.toString() + ")"

View File

@@ -18,4 +18,4 @@ where
f.getMetrics().getNumberOfParameters() > 15
select f,
"This function has too many parameters (" + f.getMetrics().getNumberOfParameters().toString() +
")."
")"

View File

@@ -21,5 +21,5 @@ where
rhsType.getAMember() = m and
not m.(VirtualFunction).isPure()
) // add additional checks for concrete members in in-between supertypes
select e, "This assignment expression slices from type $@ to $@.", rhsType, rhsType.getName(),
select e, "This assignment expression slices from type $@ to $@", rhsType, rhsType.getName(),
lhsType, lhsType.getName()

View File

@@ -72,6 +72,18 @@ predicate floatTrivial(Literal lit) {
predicate charLiteral(Literal lit) { lit instanceof CharLiteral }
Type literalType(Literal literal) { result = literal.getType() }
predicate stringType(DerivedType t) {
t.getBaseType() instanceof CharType
or
exists(SpecifiedType constCharType |
t.getBaseType() = constCharType and
constCharType.isConst() and
constCharType.getBaseType() instanceof CharType
)
}
predicate numberType(Type t) { t instanceof FloatingPointType or t instanceof IntegralType }
predicate stringLiteral(Literal literal) { literal instanceof StringLiteral }

View File

@@ -18,4 +18,4 @@ where
f.hasSpecifier("virtual") and
f.getFile().fromSource() and
not f instanceof Destructor
select f, "Avoid having public virtual methods (NVI idiom)."
select f, "Avoid having public virtual methods (NVI idiom)"

View File

@@ -23,4 +23,4 @@ where
fclass = f.getDeclaringType() and
hubIndex = fclass.getMetrics().getAfferentCoupling() * fclass.getMetrics().getEfferentCoupling() and
hubIndex > 100
select f, "Avoid having public virtual methods (NVI idiom)."
select f, "Avoid having public virtual methods (NVI idiom)"

View File

@@ -38,5 +38,5 @@ where
sc = switch.getASwitchCase() and
tooLong(sc) and
switchCaseLength(sc, lines)
select switch, "Switch has at least one case that is too long: $@.", sc,
select switch, "Switch has at least one case that is too long: $@", sc,
sc.getExpr().toString() + " (" + lines.toString() + " lines)"

View File

@@ -58,4 +58,4 @@ where
not exists(AsmStmt s | f = s.getEnclosingFunction()) and
not v.getAnAttribute().getName() = "unused" and
not any(ErrorExpr e).getEnclosingFunction() = f // unextracted expr may use `v`
select v, "Variable " + v.getName() + " is not used."
select v, "Variable " + v.getName() + " is not used"

View File

@@ -27,4 +27,4 @@ where
not declarationHasSideEffects(v) and
not v.getAnAttribute().hasName("used") and
not v.getAnAttribute().hasName("unused")
select v, "Static variable " + v.getName() + " is never read."
select v, "Static variable " + v.getName() + " is never read"

View File

@@ -1,20 +1,3 @@
## 0.4.1
### Minor Analysis Improvements
* The alert message of many queries have been changed to better follow the style guide and make the message consistent with other languages.
## 0.4.0
### New Queries
* Added a new medium-precision query, `cpp/missing-check-scanf`, which detects `scanf` output variables that are used without a proper return-value check to see that they were actually written. A variation of this query was originally contributed as an [experimental query by @ihsinme](https://github.com/github/codeql/pull/8246).
### Minor Analysis Improvements
* Modernizations from "Cleartext storage of sensitive information in buffer" (`cpp/cleartext-storage-buffer`) have been ported to the "Cleartext storage of sensitive information in file" (`cpp/cleartext-storage-file`), "Cleartext transmission of sensitive information" (`cpp/cleartext-transmission`) and "Cleartext storage of sensitive information in an SQLite database" (`cpp/cleartext-storage-database`) queries. These changes may result in more correct results and fewer false positive results from these queries.
* The alert message of many queries have been changed to make the message consistent with other languages.
## 0.3.4
## 0.3.3

View File

@@ -64,5 +64,5 @@ where
) and
(if context = test then testresult = "succeed" else testresult = "fail")
select cond,
"Variable '" + v.getName() + "' is always " + context + ", this check will always " + testresult +
"."
"Variable '" + v.getName() + "' is always " + context + " here, this check will always " +
testresult + "."

View File

@@ -29,4 +29,4 @@ from Expr alloc
where
allocateDescriptorCall(alloc) and
not exists(ClosedExpr closed | closed.pointsTo() = alloc)
select alloc, "This file descriptor is never closed."
select alloc, "This file descriptor is never closed"

View File

@@ -164,4 +164,4 @@ where
fopenVariableReaches(v, def, ret) and
ret.getAChild*() = v.getAnAccess()
)
select def, "This file may not be closed at $@.", ret, "this exit point"
select def, "The file opened here may not be closed at $@.", ret, "this exit point"

View File

@@ -14,4 +14,4 @@ import FileClosed
from Expr alloc
where fopenCall(alloc) and not fopenCallMayBeClosed(alloc)
select alloc, "The file is never closed."
select alloc, "The file is never closed"

View File

@@ -27,4 +27,4 @@ where
definitionUsePair(v, other, unchecked)
)
select unchecked,
"This dereference is not guarded by a non-null check, whereas other dereferences are guarded."
"This dereference is not guarded by a non-null check, whereas other dereferences are guarded"

View File

@@ -49,4 +49,4 @@ where
select dangerous,
"Variable '" + v.getName() +
"' is used as an array-offset before it is tested for being negative (test on line " +
check.getLocation().getStartLine().toString() + ")."
check.getLocation().getStartLine().toString() + "). "

View File

@@ -190,4 +190,4 @@ where
allocatedVariableReaches(v, def, ret) and
ret.getAChild*() = v.getAnAccess()
)
select def, "This memory allocation may not be released at $@.", ret, "this exit point"
select def, "The memory allocated here may not be released at $@.", ret, "this exit point"

View File

@@ -16,4 +16,4 @@ from AllocationExpr alloc
where
alloc.requiresDealloc() and
not allocMayBeFreed(alloc)
select alloc, "This memory is never freed."
select alloc, "This memory is never freed"

View File

@@ -117,6 +117,6 @@ where
output.getCall() = call and
output.hasGuardedAccess(access, false)
select access,
"This variable is read, but may not have been written. " +
"$@ is read here, but may not have been written. " +
"It should be guarded by a check that the $@ returns at least " +
output.getMinimumGuardConstant() + ".", call, call.toString()
output.getMinimumGuardConstant() + ".", access, access.toString(), call, call.toString()

View File

@@ -14,4 +14,4 @@ from Expr alloc, Expr free, Expr freed
where
allocReaches(freed, alloc, "new[]") and
freeExprOrIndirect(free, freed, "delete")
select free, "This memory may have been allocated with $@, not 'new'.", alloc, "new[]"
select free, "This memory may have been allocated with '$@', not 'new'.", alloc, "new[]"

View File

@@ -14,4 +14,4 @@ from Expr alloc, Expr free, Expr freed
where
allocReaches(freed, alloc, "new") and
freeExprOrIndirect(free, freed, "delete[]")
select free, "This memory may have been allocated with $@, not 'new[]'.", alloc, "new"
select free, "This memory may have been allocated with '$@', not 'new[]'.", alloc, "new"

View File

@@ -30,4 +30,4 @@ where
not v.getType().getUnderlyingType() instanceof ReferenceType and
not exists(ScopeUtilityClass util | def = util.getAUse()) and
not def.isInMacroExpansion()
select def, "Variable '" + v.getName() + "' is assigned a value that is never used."
select def, "Variable '" + v.getName() + "' is assigned a value that is never used"

View File

@@ -62,5 +62,5 @@ class UseAfterFreeReachability extends StackVariableReachability {
from UseAfterFreeReachability r, StackVariable v, Expr free, Expr e
where r.reaches(free, v, e)
select e, "Memory pointed to by '" + v.getName().toString() + "' may have $@.", free,
"been previously freed"
select e, "Memory pointed to by '" + v.getName().toString() + "' may have been previously freed $@",
free, "here"

View File

@@ -3,7 +3,6 @@
* @description Lists all files in the source code directory that were extracted without encountering a problem in the file.
* @kind diagnostic
* @id cpp/diagnostics/successfully-extracted-files
* @tags successfully-extracted-files
*/
import cpp
@@ -13,4 +12,4 @@ from File f
where
not exists(ExtractionProblem e | e.getFile() = f) and
exists(f.getRelativePath())
select f, "File successfully extracted."
select f, "File successfully extracted"

View File

@@ -22,4 +22,4 @@ where
not overflowTest(cmp) and
not cmp.isFromTemplateInstantiation(_) and
not isFromMacroDefinition(cmp)
select cmp, "This expression compares an $@ to itself.", cmp.getLeftOperand(), "expression"
select cmp, "Self comparison."

View File

@@ -25,11 +25,8 @@ class CastToPointerArithFlow extends DataFlow::Configuration {
override predicate isSource(DataFlow::Node node) {
not node.asExpr() instanceof Conversion and
exists(Type baseType1, Type baseType2 |
hasBaseType(node.asExpr(), baseType1) and
hasBaseType(node.asExpr().getConversion*(), baseType2) and
introducesNewField(baseType1, baseType2)
)
introducesNewField(node.asExpr().getType().(DerivedType).getBaseType(),
node.asExpr().getConversion*().getType().(DerivedType).getBaseType())
}
override predicate isSink(DataFlow::Node node) {
@@ -38,17 +35,6 @@ class CastToPointerArithFlow extends DataFlow::Configuration {
}
}
/**
* Holds if the type of `e` is a `DerivedType` with `base` as its base type.
*
* This predicate ensures that joins go from `e` to `base` instead
* of the other way around.
*/
pragma[inline]
predicate hasBaseType(Expr e, Type base) {
pragma[only_bind_into](base) = e.getType().(DerivedType).getBaseType()
}
/**
* `derived` has a (possibly indirect) base class of `base`, and at least one new
* field has been introduced in the inheritance chain after `base`.
@@ -69,5 +55,5 @@ where
cfg.hasFlowPath(source, sink) and
source.getNode().asExpr().getFullyConverted().getUnspecifiedType() =
sink.getNode().asExpr().getFullyConverted().getUnspecifiedType()
select sink, source, sink, "This pointer arithmetic may be done with the wrong type because of $@.",
source, "this cast"
select sink, source, sink,
"Pointer arithmetic here may be done with the wrong type because of the cast $@.", source, "here"

View File

@@ -24,4 +24,4 @@ where
va.getExplicitlyConverted().getType().getSize() > fct.getSize() and
va.getTarget() = fi and
not fct.getUnspecifiedType() instanceof BoolType
select va, "Implicit downcast of bitfield $@.", fi, fi.toString()
select va, "Implicit downcast of bitfield $@", fi, fi.toString()

View File

@@ -49,4 +49,5 @@ where
c.hasImplicitConversion() and
not whiteListWrapped(c)
select c,
"Return value of type " + t1.toString() + " is implicitly converted to " + t2.toString() + "."
"Return value of type " + t1.toString() + " is implicitly converted to " + t2.toString() +
" here."

View File

@@ -173,4 +173,4 @@ where
not actual.getUnspecifiedType() instanceof ErroneousType
select arg,
"This argument should be of type '" + expected.getName() + "' but is of type '" +
actual.getUnspecifiedType().getName() + "'."
actual.getUnspecifiedType().getName() + "'"

View File

@@ -17,5 +17,5 @@ import LeapYear
from Expr source, Expr sink, PossibleYearArithmeticOperationCheckConfiguration config
where config.hasFlow(DataFlow::exprNode(source), DataFlow::exprNode(sink))
select sink,
"An arithmetic operation $@ that uses a constant value of 365 ends up modifying this date/time, without considering leap year scenarios.",
source, source.toString()
"This arithmetic operation $@ uses a constant value of 365 ends up modifying the date/time located at $@, without considering leap year scenarios.",
source, source.toString(), sink, sink.toString()

View File

@@ -13,4 +13,4 @@ import NtohlArrayNoBound
from NetworkToBufferSizeConfiguration bufConfig, DataFlow::Node source, DataFlow::Node sink
where bufConfig.hasFlow(source, sink)
select sink, "Unchecked use of data from network function $@.", source, source.toString()
select sink, "Unchecked use of data from network function $@", source, source.toString()

View File

@@ -81,4 +81,4 @@ from UninitialisedLocalReachability r, LocalVariable v, VariableAccess va
where
r.reaches(_, v, va) and
not va = commonException()
select va, "The variable $@ may not be initialized at this access.", v, v.getName()
select va, "The variable $@ may not be initialized here.", v, v.getName()

View File

@@ -399,5 +399,5 @@ where
) and
source.asStore() = store and
sink.asSink(_) = load
select sink, source, sink, "Stack variable $@ escapes at $@ and is used after it has expired.", var,
var.toString(), store, "this store"
select sink, source, sink, "Stack variable $@ escapes $@ and is used after it has expired.", var,
var.toString(), store, "here"

View File

@@ -83,4 +83,4 @@ where
c.getAMemberFunction().getAnOverriddenFunction() = call.getStaticCallTarget()
)
select call.getUnconvertedResultExpression(), source, sink,
"Call to pure virtual function during " + msg + "."
"Call to pure virtual function during " + msg

View File

@@ -92,6 +92,5 @@ where
isOptionSet(cc, BoostorgAsio::getShiftedSslOptionsNoTls1_2(), e) and
msg = "no_tlsv1_2 was set"
)
select cc,
"This usage of 'boost::asio::ssl::context::context' with protocol $@ is not configured correctly: The option $@.",
protocolSource, protocolSource.toString(), e, msg
select cc, "Usage of $@ with protocol $@ is not configured correctly: The option $@.", cc,
"boost::asio::ssl::context::context", protocolSource, protocolSource.toString(), e, msg

View File

@@ -67,5 +67,5 @@ where
// the pointer was null. To follow this idea to its full generality, we
// should also give an alert when `check` post-dominates `deref`.
deref.getBlock() = dominator
select checked, "This null check is redundant because $@ in any case.", deref,
"the value is dereferenced"
select checked, "This null check is redundant because the value is $@ in any case", deref,
"dereferenced here"

View File

@@ -60,5 +60,5 @@ where
taintedWithPath(taintSource, taintedArg, sourceNode, sinkNode) and
isUserInput(taintSource, taintCause)
select taintedArg, sourceNode, sinkNode,
"This argument to a file access function is derived from $@ and then passed to " + callChain + ".",
"This argument to a file access function is derived from $@ and then passed to " + callChain,
taintSource, "user input (" + taintCause + ")"

View File

@@ -158,5 +158,5 @@ where
concatResult = sinkNode.getState().(ExecState).getSndNode()
select sinkAsArgumentIndirection(sinkNode.getNode()), sourceNode, sinkNode,
"This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to "
+ callChain + ".", sourceNode, "user input (" + taintCause + ")", concatResult,
+ callChain, sourceNode, "user input (" + taintCause + ")", concatResult,
concatResult.toString()

View File

@@ -50,5 +50,5 @@ where
taintedWithPath(taintSource, taintedArg, sourceNode, sinkNode) and
isUserInput(taintSource, taintCause)
select taintedArg, sourceNode, sinkNode,
"This argument to a SQL query function is derived from $@ and then passed to " + callChain + ".",
"This argument to a SQL query function is derived from $@ and then passed to " + callChain,
taintSource, "user input (" + taintCause + ")"

View File

@@ -34,5 +34,5 @@ where
isProcessOperationExplanation(arg, processOperation) and
taintedWithPath(source, arg, sourceNode, sinkNode)
select arg, sourceNode, sinkNode,
"The value of this argument may come from $@ and is being passed to " + processOperation + ".",
source, source.toString()
"The value of this argument may come from $@ and is being passed to " + processOperation, source,
source.toString()

View File

@@ -116,10 +116,6 @@ class ImproperArrayIndexValidationConfig extends TaintTracking::Configuration {
}
}
/** Gets `str` where the first letter has been lowercased. */
bindingset[str]
string lowerFirst(string str) { result = str.prefix(1).toLowerCase() + str.suffix(1) }
from
ImproperArrayIndexValidationConfig conf, DataFlow::PathNode source, DataFlow::PathNode sink,
string sourceType
@@ -127,5 +123,5 @@ where
conf.hasFlowPath(source, sink) and
isFlowSource(source.getNode(), sourceType)
select sink.getNode(), source, sink,
"An array indexing expression depends on $@ that might be outside the bounds of the array.",
source.getNode(), lowerFirst(sourceType)
"$@ flows to here and is used in an array indexing expression, potentially causing an invalid access.",
source.getNode(), sourceType

View File

@@ -34,4 +34,4 @@ where
isUserInput(userValue, cause)
select arg, sourceNode, sinkNode,
"The value of this argument may come from $@ and is being used as a formatting argument to " +
printfFunction + ".", userValue, cause
printfFunction, userValue, cause

View File

@@ -37,4 +37,4 @@ where
isUserInput(userValue, cause)
select arg, sourceNode, sinkNode,
"The value of this argument may come from $@ and is being used as a formatting argument to " +
printfFunction + ".", userValue, cause
printfFunction, userValue, cause

View File

@@ -86,5 +86,4 @@ class TaintSource extends VariableAccess {
from TaintSource source, VariableAccess sink
where source.reaches(sink)
select sink, "String operation depends on a $@ that may not be null terminated.", source,
"user-provided value"
select sink, "$@ flows to here and may not be null terminated.", source, "User-provided value"

View File

@@ -50,5 +50,5 @@ where
op.getAnOperand() = e and
missingGuard(op, e, effect)
select e, sourceNode, sinkNode,
"$@ flows to an operand of an arithmetic expression, potentially causing an " + effect + ".",
origin, "User-provided value"
"$@ flows to here and is used in arithmetic, potentially causing an " + effect + ".", origin,
"User-provided value"

View File

@@ -135,5 +135,5 @@ where
sink.getNode().asExpr() = va and
missingGuard(va, effect)
select sink.getNode(), source, sink,
"Arithmetic expression depends on an $@, potentially causing an " + effect + ".",
getExpr(source.getNode()), "uncontrolled value"
"$@ flows to here and is used in arithmetic, potentially causing an " + effect + ".",
getExpr(source.getNode()), "Uncontrolled value"

View File

@@ -75,6 +75,5 @@ where
missingGuardAgainstOverflow(op, va) and effect = "overflow"
) and
causeEffectCorrespond(cause, effect)
select va,
"$@ flows to an operand of an arithmetic expression, potentially causing an " + effect + ".",
select va, "$@ flows to here and is used in arithmetic, potentially causing an " + effect + ".",
origin, "Extreme value"

View File

@@ -36,4 +36,5 @@ where
not inSystemMacroExpansion(use) and
// Avoid double-counting: don't include all the conversions of `use`.
not use instanceof Conversion
select use, "$@ flows an expression which might " + kind + ".", origin, "User-provided value"
select use, "$@ flows to here and is used in an expression which might " + kind + ".", origin,
"User-provided value"

View File

@@ -99,5 +99,5 @@ where
isFlowSource(source.getNode(), taintCause) and
conf.hasFlowPath(source, sink) and
allocSink(alloc, sink.getNode())
select alloc, source, sink, "This allocation size is derived from $@ and might overflow.",
select alloc, source, sink, "This allocation size is derived from $@ and might overflow",
source.getNode(), "user input (" + taintCause + ")"

View File

@@ -39,13 +39,9 @@ where
isHresultBooleanConverted(e1, e2) and
if e2.isImplicit()
then
msg =
"Implicit conversion from " + e1.getType().toString() + " to " + e2.getType().toString() +
"."
msg = "Implicit conversion from " + e1.getType().toString() + " to " + e2.getType().toString()
else
msg =
"Explicit conversion from " + e1.getType().toString() + " to " + e2.getType().toString() +
"."
msg = "Explicit conversion from " + e1.getType().toString() + " to " + e2.getType().toString()
)
or
exists(ControlStructure ctls |
@@ -53,7 +49,7 @@ where
e1.getType().(TypedefType).hasName("HRESULT") and
not isHresultBooleanConverted(e1) and
not ctls instanceof SwitchStmt and // not controlled by a boolean condition
msg = "Direct usage of a type " + e1.getType().toString() + " as a conditional expression."
msg = "Direct usage of a type " + e1.getType().toString() + " as a conditional expression"
)
or
(
@@ -61,14 +57,14 @@ where
e1.getType().(TypedefType).hasName("HRESULT") and
msg =
"Usage of a type " + e1.getType().toString() +
" as an argument of a binary logical operation."
" as an argument of a binary logical operation"
)
or
exists(UnaryLogicalOperation ulop | ulop.getAnOperand() = e1 |
e1.getType().(TypedefType).hasName("HRESULT") and
msg =
"Usage of a type " + e1.getType().toString() +
" as an argument of a unary logical operation."
" as an argument of a unary logical operation"
) and
not isHresultBooleanConverted(e1)
)

View File

@@ -44,5 +44,5 @@ where
w.getASource() = sinkNode.getNode().asExpr() and
dest = w.getDest()
select w, sourceNode, sinkNode,
"This write into buffer '" + dest.toString() + "' may contain unencrypted data from $@.", source,
"This write into buffer '" + dest.toString() + "' may contain unencrypted data from $@", source,
"user input (" + source.getSourceType() + ")"

View File

@@ -73,5 +73,5 @@ where
not isFileName(globalValueNumber(source)) and // file names are not passwords
not exists(string convChar | convChar = w.getSourceConvChar(mid) | not convChar = ["s", "S"]) // ignore things written with other conversion characters
select w, sourceNode, midNode,
"This write into file '" + dest.toString() + "' may contain unencrypted data from $@.", source,
"This write into file '" + dest.toString() + "' may contain unencrypted data from $@", source,
"this source."

View File

@@ -258,9 +258,9 @@ where
then
msg =
"This operation transmits '" + sink.toString() +
"', which may contain unencrypted sensitive data from $@."
"', which may contain unencrypted sensitive data from $@"
else
msg =
"This operation receives into '" + sink.toString() +
"', which may put unencrypted sensitive data into $@."
"', which may put unencrypted sensitive data into $@"
select networkSendRecv, source, sink, msg, source, source.getNode().toString()

View File

@@ -74,6 +74,5 @@ where
config.hasFlowPath(source, sink) and
source.getNode().asExpr() = sensitive and
sqliteCall.getASource() = sink.getNode().asExpr()
select sqliteCall, source, sink,
"This SQLite call may store $@ in a non-encrypted SQLite database.", sensitive,
"sensitive information"
select sqliteCall, source, sink, "This SQLite call may store $@ in a non-encrypted SQLite database",
sensitive, "sensitive information"

View File

@@ -97,4 +97,4 @@ from
where
config.hasFlowPath(source, sink) and
str = source.getNode().asExpr()
select str, source, sink, "This URL may be constructed with the HTTP protocol."
select str, source, sink, "A URL may be constructed with the HTTP protocol."

View File

@@ -10,6 +10,12 @@ private predicate reaches(ControlFlowNode a, ControlFlowNode b) = fastTC(success
private predicate successor(ControlFlowNode a, ControlFlowNode b) { b = a.getASuccessor() }
class WhitelistedCallsConfig extends string {
WhitelistedCallsConfig() { this = "config" }
abstract predicate isWhitelisted(Call c);
}
abstract class WhitelistedCall extends Call {
override Function getTarget() { none() }
}

View File

@@ -44,5 +44,5 @@ where
)
select dest,
"This pointer might have type $@ (size " + sourceBase.getSize() +
"), but this pointer arithmetic is done with type " + destType + " (size " + destBase.getSize() +
").", sourceLoc, sourceBase.toString()
"), but the pointer arithmetic here is done with type " + destType + " (size " +
destBase.getSize() + ").", sourceLoc, sourceBase.toString()

View File

@@ -51,5 +51,5 @@ where
destBase instanceof CharType
select dest,
"This pointer might have type $@ (size " + sourceBase.getSize() +
"), but this pointer arithmetic is done with type " + destType + " (size " + destBase.getSize() +
").", sourceLoc, sourceBase.toString()
"), but the pointer arithmetic here is done with type " + destType + " (size " +
destBase.getSize() + ").", sourceLoc, sourceBase.toString()

View File

@@ -26,4 +26,4 @@ where
destBase instanceof VoidType
select dest,
"This pointer might have type $@ (size " + sourceBase.getSize() +
"), but this pointer arithmetic is done with type void.", sourceLoc, sourceBase.toString()
"), but the pointer arithmetic here is done with type void", sourceLoc, sourceBase.toString()

View File

@@ -18,4 +18,4 @@ from FunctionCall call, Function target
where
call.getTarget() = target and
target.hasGlobalOrStdName("gets")
select call, "'gets' does not guard against buffer overflow."
select call, "gets does not guard against buffer overflow"

View File

@@ -16,7 +16,7 @@ import cpp
predicate potentiallyDangerousFunction(Function f, string message) {
exists(string name | f.hasGlobalName(name) |
name = ["gmtime", "localtime", "ctime", "asctime"] and
message = "Call to '" + name + "' is potentially dangerous."
message = "Call to " + name + " is potentially dangerous"
)
}

View File

@@ -16,4 +16,4 @@ import FilePermissions
from FileCreationWithOptionalModeExpr fc
where not fc.hasModeArgument()
select fc,
"This creates a file without providing a mode argument, which may leak bits from the stack."
"A file is created here without providing a mode argument, which may leak bits from the stack."

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