Skip to content

Commit 4e75236

Browse files
authored
Merge pull request github#12598 from jketema/default-config
C++: Adjust the internals of default taint tracking to use `DataFlow::ConfigSig`
2 parents cc46d7f + 7cdd2b6 commit 4e75236

File tree

1 file changed

+52
-55
lines changed

1 file changed

+52
-55
lines changed

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DefaultTaintTrackingImpl.qll

Lines changed: 52 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import cpp
99
import semmle.code.cpp.security.Security
1010
private import semmle.code.cpp.ir.dataflow.DataFlow
1111
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
12-
private import semmle.code.cpp.ir.dataflow.DataFlow3
1312
private import semmle.code.cpp.ir.IR
1413
private import semmle.code.cpp.ir.dataflow.ResolveCall
1514
private import semmle.code.cpp.controlflow.IRGuards
@@ -90,65 +89,64 @@ private predicate conflatePointerAndPointee(DataFlow::Node nodeFrom, DataFlow::N
9089
)
9190
}
9291

93-
private class DefaultTaintTrackingCfg extends TaintTracking::Configuration {
94-
DefaultTaintTrackingCfg() { this = "DefaultTaintTrackingCfg" }
92+
private module DefaultTaintTrackingConfig implements DataFlow::ConfigSig {
93+
predicate isSource(DataFlow::Node source) { source = getNodeForSource(_) }
9594

96-
override predicate isSource(DataFlow::Node source) { source = getNodeForSource(_) }
95+
predicate isSink(DataFlow::Node sink) { exists(adjustedSink(sink)) }
9796

98-
override predicate isSink(DataFlow::Node sink) { exists(adjustedSink(sink)) }
97+
predicate isBarrier(DataFlow::Node node) { nodeIsBarrier(node) }
9998

100-
override predicate isSanitizer(DataFlow::Node node) { nodeIsBarrier(node) }
99+
predicate isBarrierIn(DataFlow::Node node) { nodeIsBarrierIn(node) }
101100

102-
override predicate isSanitizerIn(DataFlow::Node node) { nodeIsBarrierIn(node) }
103-
104-
override predicate isAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
101+
predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
105102
conflatePointerAndPointee(nodeFrom, nodeTo)
106103
}
107104
}
108105

109-
private class ToGlobalVarTaintTrackingCfg extends TaintTracking::Configuration {
110-
ToGlobalVarTaintTrackingCfg() { this = "GlobalVarTaintTrackingCfg" }
106+
private module DefaultTaintTrackingFlow = TaintTracking::Make<DefaultTaintTrackingConfig>;
111107

112-
override predicate isSource(DataFlow::Node source) { source = getNodeForSource(_) }
108+
private module ToGlobalVarTaintTrackingConfig implements DataFlow::ConfigSig {
109+
predicate isSource(DataFlow::Node source) { source = getNodeForSource(_) }
113110

114-
override predicate isSink(DataFlow::Node sink) {
115-
sink.asVariable() instanceof GlobalOrNamespaceVariable
116-
}
111+
predicate isSink(DataFlow::Node sink) { sink.asVariable() instanceof GlobalOrNamespaceVariable }
117112

118-
override predicate isAdditionalTaintStep(DataFlow::Node n1, DataFlow::Node n2) {
113+
predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
119114
writesVariable(n1.asInstruction(), n2.asVariable().(GlobalOrNamespaceVariable))
120115
or
121116
readsVariable(n2.asInstruction(), n1.asVariable().(GlobalOrNamespaceVariable))
122117
}
123118

124-
override predicate isSanitizer(DataFlow::Node node) { nodeIsBarrier(node) }
119+
predicate isBarrier(DataFlow::Node node) { nodeIsBarrier(node) }
125120

126-
override predicate isSanitizerIn(DataFlow::Node node) { nodeIsBarrierIn(node) }
121+
predicate isBarrierIn(DataFlow::Node node) { nodeIsBarrierIn(node) }
127122
}
128123

129-
private class FromGlobalVarTaintTrackingCfg extends TaintTracking2::Configuration {
130-
FromGlobalVarTaintTrackingCfg() { this = "FromGlobalVarTaintTrackingCfg" }
124+
private module ToGlobalVarTaintTrackingFlow = TaintTracking::Make<ToGlobalVarTaintTrackingConfig>;
131125

132-
override predicate isSource(DataFlow::Node source) {
126+
private module FromGlobalVarTaintTrackingConfig implements DataFlow::ConfigSig {
127+
predicate isSource(DataFlow::Node source) {
133128
// This set of sources should be reasonably small, which is good for
134129
// performance since the set of sinks is very large.
135-
exists(ToGlobalVarTaintTrackingCfg otherCfg | otherCfg.hasFlowTo(source))
130+
ToGlobalVarTaintTrackingFlow::hasFlowTo(source)
136131
}
137132

138-
override predicate isSink(DataFlow::Node sink) { exists(adjustedSink(sink)) }
133+
predicate isSink(DataFlow::Node sink) { exists(adjustedSink(sink)) }
139134

140-
override predicate isAdditionalTaintStep(DataFlow::Node n1, DataFlow::Node n2) {
135+
predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
141136
// Additional step for flow out of variables. There is no flow _into_
142137
// variables in this configuration, so this step only serves to take flow
143138
// out of a variable that's a source.
144139
readsVariable(n2.asInstruction(), n1.asVariable())
145140
}
146141

147-
override predicate isSanitizer(DataFlow::Node node) { nodeIsBarrier(node) }
142+
predicate isBarrier(DataFlow::Node node) { nodeIsBarrier(node) }
148143

149-
override predicate isSanitizerIn(DataFlow::Node node) { nodeIsBarrierIn(node) }
144+
predicate isBarrierIn(DataFlow::Node node) { nodeIsBarrierIn(node) }
150145
}
151146

147+
private module FromGlobalVarTaintTrackingFlow =
148+
TaintTracking::Make<FromGlobalVarTaintTrackingConfig>;
149+
152150
private predicate readsVariable(LoadInstruction load, Variable var) {
153151
load.getSourceAddress().(VariableAddressInstruction).getAstVariable() = var
154152
}
@@ -332,8 +330,8 @@ private import Cached
332330
*/
333331
cached
334332
predicate tainted(Expr source, Element tainted) {
335-
exists(DefaultTaintTrackingCfg cfg, DataFlow::Node sink |
336-
cfg.hasFlow(getNodeForSource(source), sink) and
333+
exists(DataFlow::Node sink |
334+
DefaultTaintTrackingFlow::hasFlow(getNodeForSource(source), sink) and
337335
tainted = adjustedSink(sink)
338336
)
339337
}
@@ -359,12 +357,11 @@ predicate taintedIncludingGlobalVars(Expr source, Element tainted, string global
359357
globalVar = ""
360358
or
361359
exists(
362-
ToGlobalVarTaintTrackingCfg toCfg, FromGlobalVarTaintTrackingCfg fromCfg,
363360
DataFlow::VariableNode variableNode, GlobalOrNamespaceVariable global, DataFlow::Node sink
364361
|
365362
global = variableNode.getVariable() and
366-
toCfg.hasFlow(getNodeForSource(source), variableNode) and
367-
fromCfg.hasFlow(variableNode, sink) and
363+
ToGlobalVarTaintTrackingFlow::hasFlow(getNodeForSource(source), variableNode) and
364+
FromGlobalVarTaintTrackingFlow::hasFlow(variableNode, sink) and
368365
tainted = adjustedSink(sink) and
369366
global = globalVarFromId(globalVar)
370367
)
@@ -422,20 +419,18 @@ module TaintedWithPath {
422419
string toString() { result = "TaintTrackingConfiguration" }
423420
}
424421

425-
private class AdjustedConfiguration extends TaintTracking3::Configuration {
426-
AdjustedConfiguration() { this = "AdjustedConfiguration" }
427-
428-
override predicate isSource(DataFlow::Node source) {
422+
private module AdjustedConfig implements DataFlow::ConfigSig {
423+
predicate isSource(DataFlow::Node source) {
429424
exists(TaintTrackingConfiguration cfg, Expr e |
430425
cfg.isSource(e) and source = getNodeForExpr(e)
431426
)
432427
}
433428

434-
override predicate isSink(DataFlow::Node sink) {
429+
predicate isSink(DataFlow::Node sink) {
435430
exists(TaintTrackingConfiguration cfg | cfg.isSink(adjustedSink(sink)))
436431
}
437432

438-
override predicate isAdditionalTaintStep(DataFlow::Node n1, DataFlow::Node n2) {
433+
predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
439434
conflatePointerAndPointee(n1, n2)
440435
or
441436
// Steps into and out of global variables
@@ -448,13 +443,15 @@ module TaintedWithPath {
448443
additionalTaintStep(n1, n2)
449444
}
450445

451-
override predicate isSanitizer(DataFlow::Node node) {
446+
predicate isBarrier(DataFlow::Node node) {
452447
exists(TaintTrackingConfiguration cfg, Expr e | cfg.isBarrier(e) and node = getNodeForExpr(e))
453448
}
454449

455-
override predicate isSanitizerIn(DataFlow::Node node) { nodeIsBarrierIn(node) }
450+
predicate isBarrierIn(DataFlow::Node node) { nodeIsBarrierIn(node) }
456451
}
457452

453+
private module AdjustedFlow = TaintTracking::Make<AdjustedConfig>;
454+
458455
/*
459456
* A sink `Element` may map to multiple `DataFlowX::PathNode`s via (the
460457
* inverse of) `adjustedSink`. For example, an `Expr` maps to all its
@@ -470,12 +467,12 @@ module TaintedWithPath {
470467
*/
471468

472469
private newtype TPathNode =
473-
TWrapPathNode(DataFlow3::PathNode n) or
470+
TWrapPathNode(AdjustedFlow::PathNode n) or
474471
// There's a single newtype constructor for both sources and sinks since
475472
// that makes it easiest to deal with the case where source = sink.
476473
TEndpointPathNode(Element e) {
477-
exists(AdjustedConfiguration cfg, DataFlow3::Node sourceNode, DataFlow3::Node sinkNode |
478-
cfg.hasFlow(sourceNode, sinkNode)
474+
exists(DataFlow::Node sourceNode, DataFlow::Node sinkNode |
475+
AdjustedFlow::hasFlow(sourceNode, sinkNode)
479476
|
480477
sourceNode = getNodeForExpr(e) and
481478
exists(TaintTrackingConfiguration ttCfg | ttCfg.isSource(e))
@@ -524,7 +521,7 @@ module TaintedWithPath {
524521
}
525522

526523
private class WrapPathNode extends PathNode, TWrapPathNode {
527-
DataFlow3::PathNode inner() { this = TWrapPathNode(result) }
524+
AdjustedFlow::PathNode inner() { this = TWrapPathNode(result) }
528525

529526
override string toString() { result = this.inner().toString() }
530527

@@ -561,25 +558,25 @@ module TaintedWithPath {
561558

562559
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
563560
query predicate edges(PathNode a, PathNode b) {
564-
DataFlow3::PathGraph::edges(a.(WrapPathNode).inner(), b.(WrapPathNode).inner())
561+
AdjustedFlow::PathGraph::edges(a.(WrapPathNode).inner(), b.(WrapPathNode).inner())
565562
or
566563
// To avoid showing trivial-looking steps, we _replace_ the last node instead
567564
// of adding an edge out of it.
568565
exists(WrapPathNode sinkNode |
569-
DataFlow3::PathGraph::edges(a.(WrapPathNode).inner(), sinkNode.inner()) and
566+
AdjustedFlow::PathGraph::edges(a.(WrapPathNode).inner(), sinkNode.inner()) and
570567
b.(FinalPathNode).inner() = adjustedSink(sinkNode.inner().getNode())
571568
)
572569
or
573570
// Same for the first node
574571
exists(WrapPathNode sourceNode |
575-
DataFlow3::PathGraph::edges(sourceNode.inner(), b.(WrapPathNode).inner()) and
572+
AdjustedFlow::PathGraph::edges(sourceNode.inner(), b.(WrapPathNode).inner()) and
576573
sourceNode.inner().getNode() = getNodeForExpr(a.(InitialPathNode).inner())
577574
)
578575
or
579576
// Finally, handle the case where the path goes directly from a source to a
580577
// sink, meaning that they both need to be translated.
581578
exists(WrapPathNode sinkNode, WrapPathNode sourceNode |
582-
DataFlow3::PathGraph::edges(sourceNode.inner(), sinkNode.inner()) and
579+
AdjustedFlow::PathGraph::edges(sourceNode.inner(), sinkNode.inner()) and
583580
sourceNode.inner().getNode() = getNodeForExpr(a.(InitialPathNode).inner()) and
584581
b.(FinalPathNode).inner() = adjustedSink(sinkNode.inner().getNode())
585582
)
@@ -590,28 +587,28 @@ module TaintedWithPath {
590587
* from `par` to `ret` within it, in the graph of data flow path explanations.
591588
*/
592589
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
593-
DataFlow3::PathGraph::subpaths(arg.(WrapPathNode).inner(), par.(WrapPathNode).inner(),
590+
AdjustedFlow::PathGraph::subpaths(arg.(WrapPathNode).inner(), par.(WrapPathNode).inner(),
594591
ret.(WrapPathNode).inner(), out.(WrapPathNode).inner())
595592
or
596593
// To avoid showing trivial-looking steps, we _replace_ the last node instead
597594
// of adding an edge out of it.
598595
exists(WrapPathNode sinkNode |
599-
DataFlow3::PathGraph::subpaths(arg.(WrapPathNode).inner(), par.(WrapPathNode).inner(),
596+
AdjustedFlow::PathGraph::subpaths(arg.(WrapPathNode).inner(), par.(WrapPathNode).inner(),
600597
ret.(WrapPathNode).inner(), sinkNode.inner()) and
601598
out.(FinalPathNode).inner() = adjustedSink(sinkNode.inner().getNode())
602599
)
603600
or
604601
// Same for the first node
605602
exists(WrapPathNode sourceNode |
606-
DataFlow3::PathGraph::subpaths(sourceNode.inner(), par.(WrapPathNode).inner(),
603+
AdjustedFlow::PathGraph::subpaths(sourceNode.inner(), par.(WrapPathNode).inner(),
607604
ret.(WrapPathNode).inner(), out.(WrapPathNode).inner()) and
608605
sourceNode.inner().getNode() = getNodeForExpr(arg.(InitialPathNode).inner())
609606
)
610607
or
611608
// Finally, handle the case where the path goes directly from a source to a
612609
// sink, meaning that they both need to be translated.
613610
exists(WrapPathNode sinkNode, WrapPathNode sourceNode |
614-
DataFlow3::PathGraph::subpaths(sourceNode.inner(), par.(WrapPathNode).inner(),
611+
AdjustedFlow::PathGraph::subpaths(sourceNode.inner(), par.(WrapPathNode).inner(),
615612
ret.(WrapPathNode).inner(), sinkNode.inner()) and
616613
sourceNode.inner().getNode() = getNodeForExpr(arg.(InitialPathNode).inner()) and
617614
out.(FinalPathNode).inner() = adjustedSink(sinkNode.inner().getNode())
@@ -634,10 +631,10 @@ module TaintedWithPath {
634631
* the computation.
635632
*/
636633
predicate taintedWithPath(Expr source, Element tainted, PathNode sourceNode, PathNode sinkNode) {
637-
exists(AdjustedConfiguration cfg, DataFlow3::Node flowSource, DataFlow3::Node flowSink |
634+
exists(DataFlow::Node flowSource, DataFlow::Node flowSink |
638635
source = sourceNode.(InitialPathNode).inner() and
639636
flowSource = getNodeForExpr(source) and
640-
cfg.hasFlow(flowSource, flowSink) and
637+
AdjustedFlow::hasFlow(flowSource, flowSink) and
641638
tainted = adjustedSink(flowSink) and
642639
tainted = sinkNode.(FinalPathNode).inner()
643640
)
@@ -660,8 +657,8 @@ module TaintedWithPath {
660657
* through a global variable.
661658
*/
662659
predicate taintedWithoutGlobals(Element tainted) {
663-
exists(AdjustedConfiguration cfg, PathNode sourceNode, FinalPathNode sinkNode |
664-
cfg.isSource(sourceNode.(WrapPathNode).inner().getNode()) and
660+
exists(PathNode sourceNode, FinalPathNode sinkNode |
661+
AdjustedConfig::isSource(sourceNode.(WrapPathNode).inner().getNode()) and
665662
edgesWithoutGlobals+(sourceNode, sinkNode) and
666663
tainted = sinkNode.inner()
667664
)

0 commit comments

Comments
 (0)