@@ -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 }
0 commit comments