@@ -37,6 +37,61 @@ private class DefaultTaintTrackingCfg extends DataFlow::Configuration {
3737 }
3838}
3939
40+ private class ToGlobalVarTaintTrackingCfg extends DataFlow:: Configuration {
41+ ToGlobalVarTaintTrackingCfg ( ) { this = "GlobalVarTaintTrackingCfg" }
42+
43+ override predicate isSource ( DataFlow:: Node source ) { isUserInput ( source .asExpr ( ) , _) }
44+
45+ override predicate isSink ( DataFlow:: Node sink ) {
46+ exists ( GlobalOrNamespaceVariable gv |
47+ accessesVariable ( sink .asInstruction ( ) , gv ) and
48+ sink .asInstruction ( ) instanceof StoreInstruction
49+ )
50+ }
51+
52+ override predicate isAdditionalFlowStep ( DataFlow:: Node n1 , DataFlow:: Node n2 ) {
53+ instructionTaintStep ( n1 .asInstruction ( ) , n2 .asInstruction ( ) )
54+ or
55+ exists ( StoreInstruction i1 , LoadInstruction i2 , GlobalOrNamespaceVariable gv |
56+ accessesVariable ( i1 , gv ) and
57+ accessesVariable ( i2 , gv ) and
58+ i1 = n1 .asInstruction ( ) and
59+ i2 = n2 .asInstruction ( )
60+ )
61+ }
62+
63+ override predicate isBarrier ( DataFlow:: Node node ) {
64+ exists ( Variable checkedVar |
65+ accessesVariable ( node .asInstruction ( ) , checkedVar ) and
66+ hasUpperBoundsCheck ( checkedVar )
67+ )
68+ }
69+ }
70+
71+ private class FromGlobalVarTaintTrackingCfg extends DataFlow:: Configuration {
72+ FromGlobalVarTaintTrackingCfg ( ) { this = "FromGlobalVarTaintTrackingCfg" }
73+
74+ override predicate isSource ( DataFlow:: Node source ) {
75+ exists ( GlobalOrNamespaceVariable gv |
76+ accessesVariable ( source .asInstruction ( ) , gv ) and
77+ source .asInstruction ( ) instanceof LoadInstruction
78+ )
79+ }
80+
81+ override predicate isSink ( DataFlow:: Node sink ) { any ( ) }
82+
83+ override predicate isAdditionalFlowStep ( DataFlow:: Node n1 , DataFlow:: Node n2 ) {
84+ instructionTaintStep ( n1 .asInstruction ( ) , n2 .asInstruction ( ) )
85+ }
86+
87+ override predicate isBarrier ( DataFlow:: Node node ) {
88+ exists ( Variable checkedVar |
89+ accessesVariable ( node .asInstruction ( ) , checkedVar ) and
90+ hasUpperBoundsCheck ( checkedVar )
91+ )
92+ }
93+ }
94+
4095private predicate accessesVariable ( CopyInstruction copy , Variable var ) {
4196 exists ( VariableAddressInstruction va | va .getASTVariable ( ) = var |
4297 copy .( StoreInstruction ) .getDestinationAddress ( ) = va
@@ -99,35 +154,39 @@ private predicate instructionTaintStep(Instruction i1, Instruction i2) {
99154 // addition expression.
100155}
101156
157+ private Element adjustedSink ( DataFlow:: Node sink ) {
158+ // TODO: is it more appropriate to use asConvertedExpr here and avoid
159+ // `getConversion*`? Or will that cause us to miss some cases where there's
160+ // flow to a conversion (like a `ReferenceDereferenceExpr`) and we want to
161+ // pretend there was flow to the converted `Expr` for the sake of
162+ // compatibility.
163+ sink .asExpr ( ) .getConversion * ( ) = result
164+ or
165+ // For compatibility, send flow from arguments to parameters, even for
166+ // functions with no body.
167+ exists ( FunctionCall call , int i |
168+ sink .asExpr ( ) = call .getArgument ( i ) and
169+ result = resolveCall ( call ) .getParameter ( i )
170+ )
171+ or
172+ // For compatibility, send flow into a `Variable` if there is flow to any
173+ // Load or Store of that variable.
174+ exists ( CopyInstruction copy |
175+ copy .getSourceValue ( ) = sink .asInstruction ( ) and
176+ accessesVariable ( copy , result ) and
177+ not hasUpperBoundsCheck ( result )
178+ )
179+ or
180+ // For compatibility, send flow into a `NotExpr` even if it's part of a
181+ // short-circuiting condition and thus might get skipped.
182+ result .( NotExpr ) .getOperand ( ) = sink .asExpr ( )
183+ }
184+
102185predicate tainted ( Expr source , Element tainted ) {
103186 exists ( DefaultTaintTrackingCfg cfg , DataFlow:: Node sink |
104187 cfg .hasFlow ( DataFlow:: exprNode ( source ) , sink )
105188 |
106- // TODO: is it more appropriate to use asConvertedExpr here and avoid
107- // `getConversion*`? Or will that cause us to miss some cases where there's
108- // flow to a conversion (like a `ReferenceDereferenceExpr`) and we want to
109- // pretend there was flow to the converted `Expr` for the sake of
110- // compatibility.
111- sink .asExpr ( ) .getConversion * ( ) = tainted
112- or
113- // For compatibility, send flow from arguments to parameters, even for
114- // functions with no body.
115- exists ( FunctionCall call , int i |
116- sink .asExpr ( ) = call .getArgument ( i ) and
117- tainted = resolveCall ( call ) .getParameter ( i )
118- )
119- or
120- // For compatibility, send flow into a `Variable` if there is flow to any
121- // Load or Store of that variable.
122- exists ( CopyInstruction copy |
123- copy .getSourceValue ( ) = sink .asInstruction ( ) and
124- accessesVariable ( copy , tainted ) and
125- not hasUpperBoundsCheck ( tainted )
126- )
127- or
128- // For compatibility, send flow into a `NotExpr` even if it's part of a
129- // short-circuiting condition and thus might get skipped.
130- tainted .( NotExpr ) .getOperand ( ) = sink .asExpr ( )
189+ tainted = adjustedSink ( sink )
131190 )
132191}
133192
@@ -137,12 +196,24 @@ predicate taintedIncludingGlobalVars(Expr source, Element tainted, string global
137196 // global variable that taint has passed through. Also make sure we emulate
138197 // its behavior for interprocedural flow through globals.
139198 globalVar = ""
199+ or
200+ exists (
201+ ToGlobalVarTaintTrackingCfg toCfg , FromGlobalVarTaintTrackingCfg fromCfg , DataFlow:: Node store ,
202+ GlobalOrNamespaceVariable global , DataFlow:: Node load , DataFlow:: Node sink
203+ |
204+ toCfg .hasFlow ( DataFlow:: exprNode ( source ) , store ) and
205+ accessesVariable ( store .asInstruction ( ) , global ) and
206+ accessesVariable ( load .asInstruction ( ) , global ) and
207+ fromCfg .hasFlow ( load , sink ) and
208+ tainted = adjustedSink ( sink ) and
209+ globalVar = global .toString ( )
210+ )
140211}
141212
142213GlobalOrNamespaceVariable globalVarFromId ( string id ) {
143- // TODO: Implement this when `taintedIncludingGlobalVars` has support for
144- // global variables.
145- none ( )
214+ if result instanceof NamespaceVariable
215+ then id = result . getNamespace ( ) + "::" + result . getName ( )
216+ else id = result . getName ( )
146217}
147218
148219Function resolveCall ( Call call ) {
0 commit comments