@@ -22,8 +22,6 @@ import semmle.code.cpp.ir.IR
2222import semmle.code.cpp.security.FlowSources
2323import semmle.code.cpp.models.implementations.Strcat
2424
25- import DataFlow:: PathGraph
26-
2725Expr sinkAsArgumentIndirection ( DataFlow:: Node sink ) {
2826 result =
2927 sink .asOperand ( )
@@ -54,7 +52,7 @@ predicate interestingConcatenation(DataFlow::Node fst, DataFlow::Node snd) {
5452 rse .getArgumentDef ( ) = call .getArgument ( strcatFunc .getParamSrc ( ) ) and
5553 fst .asOperand ( ) = rse .getSideEffectOperand ( ) and
5654 snd .asInstruction ( ) .( WriteSideEffectInstruction ) .getDestinationAddress ( ) =
57- call .getArgument ( strcatFunc .getParamDest ( ) )
55+ call .getArgument ( strcatFunc .getParamDest ( ) )
5856 )
5957 or
6058 exists ( CallInstruction call , Operator op , ReadSideEffectInstruction rse |
@@ -63,22 +61,17 @@ predicate interestingConcatenation(DataFlow::Node fst, DataFlow::Node snd) {
6361 op .getType ( ) .( UserType ) .hasQualifiedName ( "std" , "basic_string" ) and
6462 call .getArgument ( 1 ) = rse .getArgumentOperand ( ) .getAnyDef ( ) and // left operand
6563 fst .asOperand ( ) = rse .getSideEffectOperand ( ) and
66- call =
67- snd .asInstruction ( )
64+ call = snd .asInstruction ( )
6865 )
6966}
7067
7168// TODO: maybe we can drop this?
7269class TaintToConcatenationConfiguration extends TaintTracking:: Configuration {
7370 TaintToConcatenationConfiguration ( ) { this = "TaintToConcatenationConfiguration" }
7471
75- override predicate isSource ( DataFlow:: Node source ) {
76- source instanceof FlowSource
77- }
72+ override predicate isSource ( DataFlow:: Node source ) { source instanceof FlowSource }
7873
79- override predicate isSink ( DataFlow:: Node sink ) {
80- interestingConcatenation ( sink , _)
81- }
74+ override predicate isSink ( DataFlow:: Node sink ) { interestingConcatenation ( sink , _) }
8275
8376 override predicate isSanitizer ( DataFlow:: Node node ) {
8477 node .asInstruction ( ) .getResultType ( ) instanceof IntegralType
@@ -90,9 +83,7 @@ class TaintToConcatenationConfiguration extends TaintTracking::Configuration {
9083class ExecTaintConfiguration extends TaintTracking2:: Configuration {
9184 ExecTaintConfiguration ( ) { this = "ExecTaintConfiguration" }
9285
93- override predicate isSource ( DataFlow:: Node source ) {
94- interestingConcatenation ( _, source )
95- }
86+ override predicate isSource ( DataFlow:: Node source ) { interestingConcatenation ( _, source ) }
9687
9788 override predicate isSink ( DataFlow:: Node sink ) {
9889 shellCommand ( sinkAsArgumentIndirection ( sink ) , _)
@@ -103,16 +94,105 @@ class ExecTaintConfiguration extends TaintTracking2::Configuration {
10394 }
10495}
10596
97+ module StitchedPathGraph {
98+ // There's a different PathNode class for each DataFlowImplN.qll, so we can't simply combine the
99+ // PathGraph predicates directly. Instead, we use a newtype so there's a single type that
100+ // contains both sets of PathNodes.
101+ newtype TMergedPathNode =
102+ TPathNode1 ( DataFlow:: PathNode node ) or
103+ TPathNode2 ( DataFlow2:: PathNode node )
104+
105+ // this wraps the toString and location predicates so we can use the merged node type in a
106+ // selection
107+ class MergedPathNode extends TMergedPathNode {
108+ string toString ( ) {
109+ exists ( DataFlow:: PathNode n |
110+ this = TPathNode1 ( n ) and
111+ result = n .toString ( )
112+ )
113+ or
114+ exists ( DataFlow2:: PathNode n |
115+ this = TPathNode2 ( n ) and
116+ result = n .toString ( )
117+ )
118+ }
119+
120+ DataFlow:: Node getNode ( ) {
121+ exists ( DataFlow:: PathNode n |
122+ this = TPathNode1 ( n ) and
123+ result = n .getNode ( )
124+ )
125+ or
126+ exists ( DataFlow2:: PathNode n |
127+ this = TPathNode2 ( n ) and
128+ result = n .getNode ( )
129+ )
130+ }
131+
132+ predicate hasLocationInfo (
133+ string filepath , int startline , int startcolumn , int endline , int endcolumn
134+ ) {
135+ exists ( DataFlow:: PathNode n |
136+ this = TPathNode1 ( n ) and
137+ n .hasLocationInfo ( filepath , startline , startcolumn , endline , endcolumn )
138+ )
139+ or
140+ exists ( DataFlow2:: PathNode n |
141+ this = TPathNode2 ( n ) and
142+ n .hasLocationInfo ( filepath , startline , startcolumn , endline , endcolumn )
143+ )
144+ }
145+ }
146+
147+ query predicate edges ( MergedPathNode a , MergedPathNode b ) {
148+ exists ( DataFlow:: PathNode an , DataFlow:: PathNode bn |
149+ a = TPathNode1 ( an ) and
150+ b = TPathNode1 ( bn ) and
151+ DataFlow:: PathGraph:: edges ( an , bn )
152+ )
153+ or
154+ exists ( DataFlow2:: PathNode an , DataFlow2:: PathNode bn |
155+ a = TPathNode2 ( an ) and
156+ b = TPathNode2 ( bn ) and
157+ DataFlow2:: PathGraph:: edges ( an , bn )
158+ )
159+ or
160+ // This is where paths from the two configurations are connected. `interestingConcatenation`
161+ // is the only thing in this module that's actually specific to the query - everything else is
162+ // just using types and predicates from the DataFlow library.
163+ interestingConcatenation ( a .getNode ( ) , b .getNode ( ) ) and
164+ a instanceof TPathNode1 and
165+ b instanceof TPathNode2
166+ }
167+
168+ query predicate nodes ( MergedPathNode mpn , string key , string val ) {
169+ // here we just need the union of the underlying `nodes` predicates
170+ exists ( DataFlow:: PathNode n |
171+ mpn = TPathNode1 ( n ) and
172+ DataFlow:: PathGraph:: nodes ( n , key , val )
173+ )
174+ or
175+ exists ( DataFlow2:: PathNode n |
176+ mpn = TPathNode2 ( n ) and
177+ DataFlow2:: PathGraph:: nodes ( n , key , val )
178+ )
179+ }
180+ }
181+
182+ import StitchedPathGraph
183+
106184from
107- DataFlow:: PathNode sourceNode , DataFlow:: PathNode concatSink , DataFlow2:: PathNode concatSource , DataFlow2:: PathNode sinkNode , string taintCause , string callChain ,
185+ DataFlow:: PathNode sourceNode , DataFlow:: PathNode concatSink , DataFlow2:: PathNode concatSource ,
186+ DataFlow2:: PathNode sinkNode , string taintCause , string callChain ,
108187 TaintToConcatenationConfiguration conf1 , ExecTaintConfiguration conf2
109188where
110189 taintCause = sourceNode .getNode ( ) .( FlowSource ) .getSourceType ( ) and
111- conf1 .hasFlowPath ( sourceNode , concatSink ) and // TODO: can we link these better?
112- interestingConcatenation ( concatSink .getNode ( ) , concatSource .getNode ( ) ) and
190+ conf1 .hasFlowPath ( sourceNode , concatSink ) and
191+ interestingConcatenation ( concatSink .getNode ( ) , concatSource .getNode ( ) ) and // this loses call context
113192 conf2 .hasFlowPath ( concatSource , sinkNode ) and
114193 shellCommand ( sinkAsArgumentIndirection ( sinkNode .getNode ( ) ) , callChain )
115- select sinkAsArgumentIndirection ( sinkNode .getNode ( ) ) , sourceNode , sinkNode ,
116- "This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to " + callChain , sourceNode ,
117- "user input (" + taintCause + ")" , concatSource , concatSource .toString ( )
118-
194+ select sinkAsArgumentIndirection ( sinkNode .getNode ( ) ) , TPathNode1 ( sourceNode ) .( MergedPathNode ) ,
195+ TPathNode2 ( sinkNode ) .( MergedPathNode ) ,
196+ "This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to "
197+ + callChain , sourceNode , "user input (" + taintCause + ")" , concatSource ,
198+ concatSource .toString ( )
0 commit comments