14
14
import cpp
15
15
import semmle.code.cpp.security.SensitiveExprs
16
16
import semmle.code.cpp.dataflow.TaintTracking
17
+ import semmle.code.cpp.valuenumbering.GlobalValueNumbering
17
18
import semmle.code.cpp.models.interfaces.FlowSource
18
19
import DataFlow:: PathGraph
19
20
20
21
/**
21
- * A function call that sends or receives data over a network.
22
+ * A DataFlow node corresponding to a variable or function call that
23
+ * might contain or return a password or other sensitive information.
22
24
*/
23
- abstract class NetworkSendRecv extends FunctionCall {
25
+ class SensitiveNode extends DataFlow:: Node {
26
+ SensitiveNode ( ) {
27
+ this .asExpr ( ) = any ( SensitiveVariable sv ) .getInitializer ( ) .getExpr ( ) or
28
+ this .asExpr ( ) .( VariableAccess ) .getTarget ( ) =
29
+ any ( SensitiveVariable sv ) .( GlobalOrNamespaceVariable ) or
30
+ this .asUninitialized ( ) instanceof SensitiveVariable or
31
+ this .asParameter ( ) instanceof SensitiveVariable or
32
+ this .asExpr ( ) .( FunctionCall ) .getTarget ( ) instanceof SensitiveFunction
33
+ }
34
+ }
35
+
36
+ /**
37
+ * A function that sends or receives data over a network.
38
+ */
39
+ abstract class SendRecv extends Function {
24
40
/**
25
41
* Gets the expression for the socket or similar object used for sending or
26
- * receiving data (if any).
42
+ * receiving data through the function call `call` (if any).
27
43
*/
28
- abstract Expr getSocketExpr ( ) ;
44
+ abstract Expr getSocketExpr ( Call call ) ;
29
45
30
46
/**
31
- * Gets the expression for the buffer to be sent from / received into.
47
+ * Gets the expression for the buffer to be sent from / received into through
48
+ * the function call `call`.
32
49
*/
33
- abstract Expr getDataExpr ( ) ;
50
+ abstract Expr getDataExpr ( Call call ) ;
34
51
}
35
52
36
53
/**
37
- * A function call that sends data over a network.
38
- *
39
- * note: functions such as `write` may be writing to a network source or a file. We could attempt to determine which, and sort results into `cpp/cleartext-transmission` and perhaps `cpp/cleartext-storage-file`. In practice it usually isn't very important which query reports a result as long as its reported exactly once.
54
+ * A function that sends data over a network.
40
55
*/
41
- class NetworkSend extends NetworkSendRecv {
42
- RemoteFlowSinkFunction target ;
43
-
44
- NetworkSend ( ) { target = this .getTarget ( ) }
45
-
46
- override Expr getSocketExpr ( ) {
56
+ class Send extends SendRecv instanceof RemoteFlowSinkFunction {
57
+ override Expr getSocketExpr ( Call call ) {
58
+ call .getTarget ( ) = this and
47
59
exists ( FunctionInput input , int arg |
48
- target .hasSocketInput ( input ) and
60
+ super .hasSocketInput ( input ) and
49
61
input .isParameter ( arg ) and
50
- result = this .getArgument ( arg )
62
+ result = call .getArgument ( arg )
51
63
)
52
64
}
53
65
54
- override Expr getDataExpr ( ) {
66
+ override Expr getDataExpr ( Call call ) {
67
+ call .getTarget ( ) = this and
55
68
exists ( FunctionInput input , int arg |
56
- target .hasRemoteFlowSink ( input , _) and
69
+ super .hasRemoteFlowSink ( input , _) and
57
70
input .isParameterDeref ( arg ) and
58
- result = this .getArgument ( arg )
71
+ result = call .getArgument ( arg )
59
72
)
60
73
}
61
74
}
62
75
63
76
/**
64
- * A function call that receives data over a network.
77
+ * A function that receives data over a network.
65
78
*/
66
- class NetworkRecv extends NetworkSendRecv {
67
- RemoteFlowSourceFunction target ;
68
-
69
- NetworkRecv ( ) { target = this .getTarget ( ) }
70
-
71
- override Expr getSocketExpr ( ) {
79
+ class Recv extends SendRecv instanceof RemoteFlowSourceFunction {
80
+ override Expr getSocketExpr ( Call call ) {
81
+ call .getTarget ( ) = this and
72
82
exists ( FunctionInput input , int arg |
73
- target .hasSocketInput ( input ) and
83
+ super .hasSocketInput ( input ) and
74
84
input .isParameter ( arg ) and
75
- result = this .getArgument ( arg )
85
+ result = call .getArgument ( arg )
76
86
)
77
87
}
78
88
79
- override Expr getDataExpr ( ) {
89
+ override Expr getDataExpr ( Call call ) {
90
+ call .getTarget ( ) = this and
80
91
exists ( FunctionOutput output , int arg |
81
- target .hasRemoteFlowSource ( output , _) and
92
+ super .hasRemoteFlowSource ( output , _) and
82
93
output .isParameterDeref ( arg ) and
83
- result = this .getArgument ( arg )
94
+ result = call .getArgument ( arg )
84
95
)
85
96
}
86
97
}
87
98
88
99
/**
89
- * Taint flow from a sensitive expression to a network operation with data
90
- * tainted by that expression.
100
+ * A function call that sends or receives data over a network.
101
+ *
102
+ * note: function calls such as `write` may be writing to a network source
103
+ * or a file. We could attempt to determine which, and sort results into
104
+ * `cpp/cleartext-transmission` and perhaps `cpp/cleartext-storage-file`. In
105
+ * practice it usually isn't very important which query reports a result as
106
+ * long as its reported exactly once.
107
+ *
108
+ * We do exclude function calls that specify a constant socket, which is
109
+ * likely to mean standard input, standard output or a similar channel.
91
110
*/
92
- class SensitiveSendRecvConfiguration extends TaintTracking :: Configuration {
93
- SensitiveSendRecvConfiguration ( ) { this = "SensitiveSendRecvConfiguration" }
111
+ abstract class NetworkSendRecv extends FunctionCall {
112
+ SendRecv target ;
94
113
95
- override predicate isSource ( DataFlow:: Node source ) { source .asExpr ( ) instanceof SensitiveExpr }
114
+ NetworkSendRecv ( ) {
115
+ this .getTarget ( ) = target and
116
+ // exclude calls based on the socket...
117
+ not exists ( GVN g |
118
+ g = globalValueNumber ( target .getSocketExpr ( this ) ) and
119
+ (
120
+ // literal constant
121
+ globalValueNumber ( any ( Literal l ) ) = g
122
+ or
123
+ // variable (such as a global) initialized to a literal constant
124
+ exists ( Variable v |
125
+ v .getInitializer ( ) .getExpr ( ) instanceof Literal and
126
+ g = globalValueNumber ( v .getAnAccess ( ) )
127
+ )
128
+ )
129
+ )
130
+ }
96
131
97
- override predicate isSink ( DataFlow:: Node sink ) {
98
- exists ( NetworkSendRecv transmission |
99
- sink .asExpr ( ) = transmission .getDataExpr ( ) and
100
- // a zero socket descriptor is standard input, which is not interesting for this query.
101
- not exists ( Zero zero |
102
- DataFlow:: localFlow ( DataFlow:: exprNode ( zero ) ,
103
- DataFlow:: exprNode ( transmission .getSocketExpr ( ) ) )
132
+ final Expr getDataExpr ( ) { result = target .getDataExpr ( this ) }
133
+ }
134
+
135
+ /**
136
+ * A function call that sends data over a network.
137
+ */
138
+ class NetworkSend extends NetworkSendRecv {
139
+ override Send target ;
140
+ }
141
+
142
+ /**
143
+ * A function call that receives data over a network.
144
+ */
145
+ class NetworkRecv extends NetworkSendRecv {
146
+ override Recv target ;
147
+ }
148
+
149
+ /**
150
+ * An expression that is an argument or return value from an encryption or
151
+ * decryption call.
152
+ */
153
+ class Encrypted extends Expr {
154
+ Encrypted ( ) {
155
+ exists ( FunctionCall fc |
156
+ fc .getTarget ( ) .getName ( ) .toLowerCase ( ) .regexpMatch ( ".*(crypt|encode|decode).*" ) and
157
+ (
158
+ this = fc or
159
+ this = fc .getAnArgument ( )
104
160
)
105
161
)
106
162
}
107
163
}
108
164
165
+ /**
166
+ * Taint flow from a sensitive expression.
167
+ */
168
+ class FromSensitiveConfiguration extends TaintTracking:: Configuration {
169
+ FromSensitiveConfiguration ( ) { this = "FromSensitiveConfiguration" }
170
+
171
+ override predicate isSource ( DataFlow:: Node source ) { source instanceof SensitiveNode }
172
+
173
+ override predicate isSink ( DataFlow:: Node sink ) {
174
+ sink .asExpr ( ) = any ( NetworkSendRecv nsr ) .getDataExpr ( )
175
+ or
176
+ sink .asExpr ( ) instanceof Encrypted
177
+ }
178
+
179
+ override predicate isAdditionalTaintStep ( DataFlow:: Node node1 , DataFlow:: Node node2 ) {
180
+ // flow through encryption functions to the return value (in case we can reach other sinks)
181
+ node2 .asExpr ( ) .( Encrypted ) .( FunctionCall ) .getAnArgument ( ) = node1 .asExpr ( )
182
+ }
183
+ }
184
+
109
185
from
110
- SensitiveSendRecvConfiguration config , DataFlow:: PathNode source , DataFlow:: PathNode sink ,
111
- NetworkSendRecv transmission , string msg
186
+ FromSensitiveConfiguration config , DataFlow:: PathNode source , DataFlow:: PathNode sink ,
187
+ NetworkSendRecv networkSendRecv , string msg
112
188
where
189
+ // flow from sensitive -> network data
113
190
config .hasFlowPath ( source , sink ) and
114
- sink .getNode ( ) .asExpr ( ) = transmission .getDataExpr ( ) and
115
- if transmission instanceof NetworkSend
191
+ sink .getNode ( ) .asExpr ( ) = networkSendRecv .getDataExpr ( ) and
192
+ // no flow from sensitive -> evidence of encryption
193
+ not exists ( DataFlow:: Node encrypted |
194
+ config .hasFlow ( source .getNode ( ) , encrypted ) and
195
+ encrypted .asExpr ( ) instanceof Encrypted
196
+ ) and
197
+ // construct result
198
+ if networkSendRecv instanceof NetworkSend
116
199
then
117
200
msg =
118
201
"This operation transmits '" + sink .toString ( ) +
@@ -121,4 +204,4 @@ where
121
204
msg =
122
205
"This operation receives into '" + sink .toString ( ) +
123
206
"', which may put unencrypted sensitive data into $@"
124
- select transmission , source , sink , msg , source , source .getNode ( ) . asExpr ( ) .toString ( )
207
+ select networkSendRecv , source , sink , msg , source , source .getNode ( ) .toString ( )
0 commit comments