Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 36da2d1

Browse files
committed
C++: Manipulate the source end of paths too
Without this, we get duplicate alerts in some cases and unnatural-looking source nodes in other cases. The source nodes were often `Conversion`s.
1 parent e916f07 commit 36da2d1

7 files changed

Lines changed: 224 additions & 81 deletions

File tree

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

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -440,13 +440,23 @@ module TaintedWithPath {
440440
* coming from the data-flow library with a node that matches exactly the
441441
* `Element` sink that's requested.
442442
*
443-
* The same should ideally be done with the source, but we haven't seen a
444-
* need for it yet.
443+
* The same is done for sources.
445444
*/
446445

447446
private newtype TPathNode =
448447
TWrapPathNode(DataFlow3::PathNode n) or
449-
TFinalPathNode(Element e) { exists(TaintTrackingConfiguration cfg | cfg.isSink(e)) }
448+
// There's a single newtype constructor for both sources and sinks since
449+
// that makes it easiest to deal with the case where source = sink.
450+
TEndpointPathNode(Element e) {
451+
exists(AdjustedConfiguration cfg, DataFlow3::Node sourceNode, DataFlow3::Node sinkNode |
452+
cfg.hasFlow(sourceNode, sinkNode)
453+
|
454+
sourceNode = getNodeForSource(e)
455+
or
456+
e = adjustedSink(sinkNode) and
457+
exists(TaintTrackingConfiguration ttCfg | ttCfg.isSink(e))
458+
)
459+
}
450460

451461
/** An opaque type used for the nodes of a data-flow path. */
452462
class PathNode extends TPathNode {
@@ -479,8 +489,8 @@ module TaintedWithPath {
479489
}
480490
}
481491

482-
private class FinalPathNode extends PathNode, TFinalPathNode {
483-
Element inner() { this = TFinalPathNode(result) }
492+
private class EndpointPathNode extends PathNode, TEndpointPathNode {
493+
Expr inner() { this = TEndpointPathNode(result) }
484494

485495
override string toString() { result = this.inner().toString() }
486496

@@ -494,15 +504,39 @@ module TaintedWithPath {
494504
}
495505
}
496506

507+
/** A PathNode whose `Element` is a source. It may also be a sink. */
508+
private class InitialPathNode extends EndpointPathNode {
509+
InitialPathNode() { exists(getNodeForSource(this.inner())) }
510+
}
511+
512+
/** A PathNode whose `Element` is a sink. It may also be a source. */
513+
private class FinalPathNode extends EndpointPathNode {
514+
FinalPathNode() { exists(TaintTrackingConfiguration cfg | cfg.isSink(this.inner())) }
515+
}
516+
497517
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
498518
query predicate edges(PathNode a, PathNode b) {
499519
DataFlow3::PathGraph::edges(a.(WrapPathNode).inner(), b.(WrapPathNode).inner())
500520
or
501-
// To avoid showing trivial-looking steps, we replace the last node instead
521+
// To avoid showing trivial-looking steps, we _replace_ the last node instead
502522
// of adding an edge out of it.
503-
exists(WrapPathNode replaced |
504-
DataFlow3::PathGraph::edges(a.(WrapPathNode).inner(), replaced.inner()) and
505-
b.(FinalPathNode).inner() = adjustedSink(replaced.inner().getNode())
523+
exists(WrapPathNode sinkNode |
524+
DataFlow3::PathGraph::edges(a.(WrapPathNode).inner(), sinkNode.inner()) and
525+
b.(FinalPathNode).inner() = adjustedSink(sinkNode.inner().getNode())
526+
)
527+
or
528+
// Same for the first node
529+
exists(WrapPathNode sourceNode |
530+
DataFlow3::PathGraph::edges(sourceNode.inner(), b.(WrapPathNode).inner()) and
531+
sourceNode.inner().getNode() = getNodeForSource(a.(InitialPathNode).inner())
532+
)
533+
or
534+
// Finally, handle the case where the path goes directly from a source to a
535+
// sink, meaning that they both need to be translated.
536+
exists(WrapPathNode sinkNode, WrapPathNode sourceNode |
537+
DataFlow3::PathGraph::edges(sourceNode.inner(), sinkNode.inner()) and
538+
sourceNode.inner().getNode() = getNodeForSource(a.(InitialPathNode).inner()) and
539+
b.(FinalPathNode).inner() = adjustedSink(sinkNode.inner().getNode())
506540
)
507541
}
508542

@@ -522,10 +556,11 @@ module TaintedWithPath {
522556
* the computation.
523557
*/
524558
predicate taintedWithPath(Expr source, Element tainted, PathNode sourceNode, PathNode sinkNode) {
525-
exists(AdjustedConfiguration cfg, DataFlow3::PathNode sinkInner |
526-
sourceNode.(WrapPathNode).inner().getNode() = getNodeForSource(source) and
527-
cfg.hasFlowPath(sourceNode.(WrapPathNode).inner(), sinkInner) and
528-
tainted = adjustedSink(sinkInner.getNode()) and
559+
exists(AdjustedConfiguration cfg, DataFlow3::Node flowSource, DataFlow3::Node flowSink |
560+
source = sourceNode.(InitialPathNode).inner() and
561+
flowSource = getNodeForSource(source) and
562+
cfg.hasFlow(flowSource, flowSink) and
563+
tainted = adjustedSink(flowSink) and
529564
tainted = sinkNode.(FinalPathNode).inner()
530565
)
531566
}
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
edges
22
| 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 |
35
| test.c:9:23:9:26 | argv | test.c:17:11:17:18 | fileName |
46
nodes
57
| test.c:9:23:9:26 | argv | semmle.label | argv |
8+
| test.c:9:23:9:26 | argv | semmle.label | argv |
69
| test.c:17:11:17:18 | (const char *)... | semmle.label | (const char *)... |
710
| test.c:17:11:17:18 | (const char *)... | semmle.label | (const char *)... |
811
| test.c:17:11:17:18 | fileName | semmle.label | fileName |
9-
| test.c:27:11:27:18 | fileName | semmle.label | fileName |
1012
#select
1113
| 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)