Skip to content

Commit 560ee8d

Browse files
author
Robert Marsh
committed
C++: taint tracking conf in DefaultTaintTracking
Switch from using additional flow steps with a DataFlow::Configuration in DefaultTaintTracking to using a TaintTracking::Configuration. This makes future improvements to TaintTracking::Configuration reflected in DefaultTaintTracking without further effort. It also removes the predictability constraint in DefaultTaintTracking, which increases the number of results, with both new true positives and new false positives. Those may need to be addressed on a per-query basis. There are some additional regressions from losing pointer/object conflation for arguments. Those can be worked around by adding that conflation to TaintTracking::Configuration until precise indirect parameter flow is ready.
1 parent 97f4cb6 commit 560ee8d

6 files changed

Lines changed: 41 additions & 270 deletions

File tree

cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ private import semmle.code.cpp.ir.IR
77
private import semmle.code.cpp.ir.dataflow.internal.DataFlowDispatch as Dispatch
88
private import semmle.code.cpp.models.interfaces.Taint
99
private import semmle.code.cpp.models.interfaces.DataFlow
10+
private import semmle.code.cpp.ir.dataflow.TaintTracking2
1011

1112
/**
1213
* A predictable instruction is one where an external user can predict
@@ -110,7 +111,7 @@ private class ToGlobalVarTaintTrackingCfg extends DataFlow::Configuration {
110111
override predicate isBarrierIn(DataFlow::Node node) { nodeIsBarrierIn(node) }
111112
}
112113

113-
private class FromGlobalVarTaintTrackingCfg extends DataFlow2::Configuration {
114+
private class FromGlobalVarTaintTrackingCfg extends DataFlow3::Configuration {
114115
FromGlobalVarTaintTrackingCfg() { this = "FromGlobalVarTaintTrackingCfg" }
115116

116117
override predicate isSource(DataFlow::Node source) {
@@ -503,7 +504,7 @@ module TaintedWithPath {
503504
string toString() { result = "TaintTrackingConfiguration" }
504505
}
505506

506-
private class AdjustedConfiguration extends DataFlow3::Configuration {
507+
private class AdjustedConfiguration extends TaintTracking2::Configuration {
507508
AdjustedConfiguration() { this = "AdjustedConfiguration" }
508509

509510
override predicate isSource(DataFlow::Node source) { source = getNodeForSource(_) }
@@ -512,19 +513,17 @@ module TaintedWithPath {
512513
exists(TaintTrackingConfiguration cfg | cfg.isSink(adjustedSink(sink)))
513514
}
514515

515-
override predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
516-
instructionTaintStep(n1.asInstruction(), n2.asInstruction())
517-
or
516+
override predicate isAdditionalTaintStep(DataFlow::Node n1, DataFlow::Node n2) {
518517
exists(TaintTrackingConfiguration cfg | cfg.taintThroughGlobals() |
519518
writesVariable(n1.asInstruction(), n2.asVariable().(GlobalOrNamespaceVariable))
520519
or
521520
readsVariable(n2.asInstruction(), n1.asVariable().(GlobalOrNamespaceVariable))
522521
)
523522
}
524523

525-
override predicate isBarrier(DataFlow::Node node) { nodeIsBarrier(node) }
524+
override predicate isSanitizer(DataFlow::Node node) { nodeIsBarrier(node) }
526525

527-
override predicate isBarrierIn(DataFlow::Node node) { nodeIsBarrierIn(node) }
526+
override predicate isSanitizerIn(DataFlow::Node node) { nodeIsBarrierIn(node) }
528527
}
529528

530529
/*
@@ -542,11 +541,11 @@ module TaintedWithPath {
542541
*/
543542

544543
private newtype TPathNode =
545-
TWrapPathNode(DataFlow3::PathNode n) or
544+
TWrapPathNode(DataFlow2::PathNode n) or
546545
// There's a single newtype constructor for both sources and sinks since
547546
// that makes it easiest to deal with the case where source = sink.
548547
TEndpointPathNode(Element e) {
549-
exists(AdjustedConfiguration cfg, DataFlow3::Node sourceNode, DataFlow3::Node sinkNode |
548+
exists(AdjustedConfiguration cfg, DataFlow2::Node sourceNode, DataFlow2::Node sinkNode |
550549
cfg.hasFlow(sourceNode, sinkNode)
551550
|
552551
sourceNode = getNodeForSource(e)
@@ -576,7 +575,7 @@ module TaintedWithPath {
576575
}
577576

578577
private class WrapPathNode extends PathNode, TWrapPathNode {
579-
DataFlow3::PathNode inner() { this = TWrapPathNode(result) }
578+
DataFlow2::PathNode inner() { this = TWrapPathNode(result) }
580579

581580
override string toString() { result = this.inner().toString() }
582581

@@ -614,25 +613,25 @@ module TaintedWithPath {
614613

615614
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
616615
query predicate edges(PathNode a, PathNode b) {
617-
DataFlow3::PathGraph::edges(a.(WrapPathNode).inner(), b.(WrapPathNode).inner())
616+
DataFlow2::PathGraph::edges(a.(WrapPathNode).inner(), b.(WrapPathNode).inner())
618617
or
619618
// To avoid showing trivial-looking steps, we _replace_ the last node instead
620619
// of adding an edge out of it.
621620
exists(WrapPathNode sinkNode |
622-
DataFlow3::PathGraph::edges(a.(WrapPathNode).inner(), sinkNode.inner()) and
621+
DataFlow2::PathGraph::edges(a.(WrapPathNode).inner(), sinkNode.inner()) and
623622
b.(FinalPathNode).inner() = adjustedSink(sinkNode.inner().getNode())
624623
)
625624
or
626625
// Same for the first node
627626
exists(WrapPathNode sourceNode |
628-
DataFlow3::PathGraph::edges(sourceNode.inner(), b.(WrapPathNode).inner()) and
627+
DataFlow2::PathGraph::edges(sourceNode.inner(), b.(WrapPathNode).inner()) and
629628
sourceNode.inner().getNode() = getNodeForSource(a.(InitialPathNode).inner())
630629
)
631630
or
632631
// Finally, handle the case where the path goes directly from a source to a
633632
// sink, meaning that they both need to be translated.
634633
exists(WrapPathNode sinkNode, WrapPathNode sourceNode |
635-
DataFlow3::PathGraph::edges(sourceNode.inner(), sinkNode.inner()) and
634+
DataFlow2::PathGraph::edges(sourceNode.inner(), sinkNode.inner()) and
636635
sourceNode.inner().getNode() = getNodeForSource(a.(InitialPathNode).inner()) and
637636
b.(FinalPathNode).inner() = adjustedSink(sinkNode.inner().getNode())
638637
)
@@ -654,7 +653,7 @@ module TaintedWithPath {
654653
* the computation.
655654
*/
656655
predicate taintedWithPath(Expr source, Element tainted, PathNode sourceNode, PathNode sinkNode) {
657-
exists(AdjustedConfiguration cfg, DataFlow3::Node flowSource, DataFlow3::Node flowSink |
656+
exists(AdjustedConfiguration cfg, DataFlow2::Node flowSource, DataFlow2::Node flowSink |
658657
source = sourceNode.(InitialPathNode).inner() and
659658
flowSource = getNodeForSource(source) and
660659
cfg.hasFlow(flowSource, flowSink) and
Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,3 @@
11
edges
2-
| test.c:9:23:9:26 | argv | test.c:17:11:17:18 | (const char *)... |
3-
| test.c:9:23:9:26 | argv | test.c:17:11:17:18 | (const char *)... |
4-
| test.c:9:23:9:26 | argv | test.c:17:11:17:18 | fileName |
5-
| test.c:9:23:9:26 | argv | test.c:17:11:17:18 | fileName |
62
nodes
7-
| test.c:9:23:9:26 | argv | semmle.label | argv |
8-
| test.c:9:23:9:26 | argv | semmle.label | argv |
9-
| test.c:17:11:17:18 | (const char *)... | semmle.label | (const char *)... |
10-
| test.c:17:11:17:18 | (const char *)... | semmle.label | (const char *)... |
11-
| test.c:17:11:17:18 | fileName | semmle.label | fileName |
123
#select
13-
| test.c:17:11:17:18 | fileName | test.c:9:23:9:26 | argv | test.c:17:11:17:18 | fileName | This argument to a file access function is derived from $@ and then passed to fopen(filename) | test.c:9:23:9:26 | argv | user input (argv) |

0 commit comments

Comments
 (0)