@@ -19,9 +19,9 @@ import semmle.code.cpp.security.Security
1919import semmle.code.cpp.valuenumbering.GlobalValueNumbering
2020import semmle.code.cpp.ir.IR
2121import semmle.code.cpp.ir.dataflow.TaintTracking
22- import semmle.code.cpp.ir.dataflow.TaintTracking2
2322import semmle.code.cpp.security.FlowSources
2423import semmle.code.cpp.models.implementations.Strcat
24+ import DataFlow:: PathGraph
2525
2626Expr sinkAsArgumentIndirection ( DataFlow:: Node sink ) {
2727 result =
@@ -66,154 +66,69 @@ predicate interestingConcatenation(DataFlow::Node fst, DataFlow::Node snd) {
6666 )
6767}
6868
69- class TaintToConcatenationConfiguration extends TaintTracking:: Configuration {
70- TaintToConcatenationConfiguration ( ) { this = "TaintToConcatenationConfiguration" }
71-
72- override predicate isSource ( DataFlow:: Node source ) { source instanceof FlowSource }
73-
74- override predicate isSink ( DataFlow:: Node sink ) { interestingConcatenation ( sink , _) }
75-
76- override predicate isSanitizer ( DataFlow:: Node node ) {
77- node .asInstruction ( ) .getResultType ( ) instanceof IntegralType
78- or
79- node .asInstruction ( ) .getResultType ( ) instanceof FloatingPointType
80- }
69+ class ConcatState extends DataFlow:: FlowState {
70+ ConcatState ( ) { this = "ConcatState" }
8171}
8272
83- class ExecTaintConfiguration extends TaintTracking2:: Configuration {
84- ExecTaintConfiguration ( ) { this = "ExecTaintConfiguration" }
73+ class ExecState extends DataFlow:: FlowState {
74+ DataFlow:: Node fst ;
75+ DataFlow:: Node snd ;
8576
86- override predicate isSource ( DataFlow:: Node source ) {
87- exists ( DataFlow:: Node prevSink , TaintToConcatenationConfiguration conf |
88- conf .hasFlow ( _, prevSink ) and
89- interestingConcatenation ( prevSink , source )
90- )
77+ ExecState ( ) {
78+ this = "ExecState (" + fst .getLocation ( ) + ", " + snd .getLocation ( ) + ")" and
79+ interestingConcatenation ( fst , snd )
9180 }
9281
93- override predicate isSink ( DataFlow:: Node sink ) {
94- shellCommand ( sinkAsArgumentIndirection ( sink ) , _)
95- }
82+ DataFlow:: Node getFstNode ( ) { result = fst }
9683
97- override predicate isSanitizerOut ( DataFlow:: Node node ) {
98- isSink ( node ) // Prevent duplicates along a call chain, since `shellCommand` will include wrappers
99- }
84+ DataFlow:: Node getSndNode ( ) { result = snd }
10085}
10186
102- module StitchedPathGraph {
103- // There's a different PathNode class for each DataFlowImplN.qll, so we can't simply combine the
104- // PathGraph predicates directly. Instead, we use a newtype so there's a single type that
105- // contains both sets of PathNodes.
106- newtype TMergedPathNode =
107- TPathNode1 ( DataFlow:: PathNode node ) or
108- TPathNode2 ( DataFlow2:: PathNode node )
109-
110- // this wraps the toString and location predicates so we can use the merged node type in a
111- // selection
112- class MergedPathNode extends TMergedPathNode {
113- string toString ( ) {
114- exists ( DataFlow:: PathNode n |
115- this = TPathNode1 ( n ) and
116- result = n .toString ( )
117- )
118- or
119- exists ( DataFlow2:: PathNode n |
120- this = TPathNode2 ( n ) and
121- result = n .toString ( )
122- )
123- }
124-
125- DataFlow:: Node getNode ( ) {
126- exists ( DataFlow:: PathNode n |
127- this = TPathNode1 ( n ) and
128- result = n .getNode ( )
129- )
130- or
131- exists ( DataFlow2:: PathNode n |
132- this = TPathNode2 ( n ) and
133- result = n .getNode ( )
134- )
135- }
136-
137- DataFlow:: PathNode getPathNode1 ( ) { this = TPathNode1 ( result ) }
87+ class ExecTaintConfiguration extends TaintTracking:: Configuration {
88+ ExecTaintConfiguration ( ) { this = "ExecTaintConfiguration" }
13889
139- DataFlow2:: PathNode getPathNode2 ( ) { this = TPathNode2 ( result ) }
90+ override predicate isSource ( DataFlow:: Node source , DataFlow:: FlowState state ) {
91+ source instanceof FlowSource and
92+ state instanceof ConcatState
93+ }
14094
141- predicate hasLocationInfo (
142- string filepath , int startline , int startcolumn , int endline , int endcolumn
143- ) {
144- exists ( DataFlow:: PathNode n |
145- this = TPathNode1 ( n ) and
146- n .hasLocationInfo ( filepath , startline , startcolumn , endline , endcolumn )
147- )
148- or
149- exists ( DataFlow2:: PathNode n |
150- this = TPathNode2 ( n ) and
151- n .hasLocationInfo ( filepath , startline , startcolumn , endline , endcolumn )
152- )
153- }
95+ override predicate isSink ( DataFlow:: Node sink , DataFlow:: FlowState state ) {
96+ shellCommand ( sinkAsArgumentIndirection ( sink ) , _) and
97+ state instanceof ExecState
15498 }
15599
156- query predicate edges ( MergedPathNode a , MergedPathNode b ) {
157- exists ( DataFlow:: PathNode an , DataFlow:: PathNode bn |
158- a = TPathNode1 ( an ) and
159- b = TPathNode1 ( bn ) and
160- DataFlow:: PathGraph:: edges ( an , bn )
161- )
162- or
163- exists ( DataFlow2:: PathNode an , DataFlow2:: PathNode bn |
164- a = TPathNode2 ( an ) and
165- b = TPathNode2 ( bn ) and
166- DataFlow2:: PathGraph:: edges ( an , bn )
167- )
168- or
169- // This is where paths from the two configurations are connected. `interestingConcatenation`
170- // is the only thing in this module that's actually specific to the query - everything else is
171- // just using types and predicates from the DataFlow library.
172- interestingConcatenation ( a .getNode ( ) , b .getNode ( ) ) and
173- a instanceof TPathNode1 and
174- b instanceof TPathNode2
100+ override predicate isAdditionalTaintStep (
101+ DataFlow:: Node node1 , DataFlow:: FlowState state1 , DataFlow:: Node node2 ,
102+ DataFlow:: FlowState state2
103+ ) {
104+ state1 instanceof ConcatState and
105+ state2 .( ExecState ) .getFstNode ( ) = node1 and
106+ state2 .( ExecState ) .getSndNode ( ) = node2
175107 }
176108
177- query predicate nodes ( MergedPathNode mpn , string key , string val ) {
178- // here we just need the union of the underlying `nodes` predicates
179- exists ( DataFlow:: PathNode n |
180- mpn = TPathNode1 ( n ) and
181- DataFlow:: PathGraph:: nodes ( n , key , val )
182- )
183- or
184- exists ( DataFlow2:: PathNode n |
185- mpn = TPathNode2 ( n ) and
186- DataFlow2:: PathGraph:: nodes ( n , key , val )
187- )
109+ override predicate isSanitizer ( DataFlow:: Node node , DataFlow:: FlowState state ) {
110+ (
111+ node .asInstruction ( ) .getResultType ( ) instanceof IntegralType
112+ or
113+ node .asInstruction ( ) .getResultType ( ) instanceof FloatingPointType
114+ ) and
115+ state instanceof ConcatState
188116 }
189117
190- query predicate subpaths (
191- MergedPathNode arg , MergedPathNode par , MergedPathNode ret , MergedPathNode out
192- ) {
193- // just forward subpaths from the underlying libraries. This might be slightly awkward when
194- // the concatenation is deep in a call chain.
195- DataFlow:: PathGraph:: subpaths ( arg .getPathNode1 ( ) , par .getPathNode1 ( ) , ret .getPathNode1 ( ) ,
196- out .getPathNode1 ( ) )
197- or
198- DataFlow2:: PathGraph:: subpaths ( arg .getPathNode2 ( ) , par .getPathNode2 ( ) , ret .getPathNode2 ( ) ,
199- out .getPathNode2 ( ) )
118+ override predicate isSanitizerOut ( DataFlow:: Node node , DataFlow:: FlowState state ) {
119+ isSink ( node , state ) // Prevent duplicates along a call chain, since `shellCommand` will include wrappers
200120 }
201121}
202122
203- import StitchedPathGraph
204-
205123from
206- DataFlow:: PathNode sourceNode , DataFlow:: PathNode concatSink , DataFlow2:: PathNode concatSource ,
207- DataFlow2:: PathNode sinkNode , string taintCause , string callChain ,
208- TaintToConcatenationConfiguration conf1 , ExecTaintConfiguration conf2
124+ ExecTaintConfiguration conf , DataFlow:: PathNode sourceNode , DataFlow:: PathNode sinkNode ,
125+ string taintCause , string callChain , DataFlow:: Node concatResult
209126where
127+ conf .hasFlowPath ( sourceNode , sinkNode ) and
210128 taintCause = sourceNode .getNode ( ) .( FlowSource ) .getSourceType ( ) and
211- conf1 .hasFlowPath ( sourceNode , concatSink ) and
212- interestingConcatenation ( concatSink .getNode ( ) , concatSource .getNode ( ) ) and // this loses call context
213- conf2 .hasFlowPath ( concatSource , sinkNode ) and
214- shellCommand ( sinkAsArgumentIndirection ( sinkNode .getNode ( ) ) , callChain )
215- select sinkAsArgumentIndirection ( sinkNode .getNode ( ) ) , TPathNode1 ( sourceNode ) .( MergedPathNode ) ,
216- TPathNode2 ( sinkNode ) .( MergedPathNode ) ,
129+ shellCommand ( sinkAsArgumentIndirection ( sinkNode .getNode ( ) ) , callChain ) and
130+ concatResult = sinkNode .getState ( ) .( ExecState ) .getSndNode ( )
131+ select sinkAsArgumentIndirection ( sinkNode .getNode ( ) ) , sourceNode , sinkNode ,
217132 "This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to "
218- + callChain , sourceNode , "user input (" + taintCause + ")" , concatSource ,
219- concatSource .toString ( )
133+ + callChain , sourceNode , "user input (" + taintCause + ")" , concatResult ,
134+ concatResult .toString ( )
0 commit comments