1414import cpp
1515import semmle.code.cpp.security.SensitiveExprs
1616import semmle.code.cpp.dataflow.TaintTracking
17+ import semmle.code.cpp.valuenumbering.GlobalValueNumbering
1718import semmle.code.cpp.models.interfaces.FlowSource
1819import DataFlow:: PathGraph
1920
2021/**
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.
2224 */
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 {
2440 /**
2541 * 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).
2743 */
28- abstract Expr getSocketExpr ( ) ;
44+ abstract Expr getSocketExpr ( Call call ) ;
2945
3046 /**
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`.
3249 */
33- abstract Expr getDataExpr ( ) ;
50+ abstract Expr getDataExpr ( Call call ) ;
3451}
3552
3653/**
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.
4055 */
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
4759 exists ( FunctionInput input , int arg |
48- target .hasSocketInput ( input ) and
60+ super .hasSocketInput ( input ) and
4961 input .isParameter ( arg ) and
50- result = this .getArgument ( arg )
62+ result = call .getArgument ( arg )
5163 )
5264 }
5365
54- override Expr getDataExpr ( ) {
66+ override Expr getDataExpr ( Call call ) {
67+ call .getTarget ( ) = this and
5568 exists ( FunctionInput input , int arg |
56- target .hasRemoteFlowSink ( input , _) and
69+ super .hasRemoteFlowSink ( input , _) and
5770 input .isParameterDeref ( arg ) and
58- result = this .getArgument ( arg )
71+ result = call .getArgument ( arg )
5972 )
6073 }
6174}
6275
6376/**
64- * A function call that receives data over a network.
77+ * A function that receives data over a network.
6578 */
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
7282 exists ( FunctionInput input , int arg |
73- target .hasSocketInput ( input ) and
83+ super .hasSocketInput ( input ) and
7484 input .isParameter ( arg ) and
75- result = this .getArgument ( arg )
85+ result = call .getArgument ( arg )
7686 )
7787 }
7888
79- override Expr getDataExpr ( ) {
89+ override Expr getDataExpr ( Call call ) {
90+ call .getTarget ( ) = this and
8091 exists ( FunctionOutput output , int arg |
81- target .hasRemoteFlowSource ( output , _) and
92+ super .hasRemoteFlowSource ( output , _) and
8293 output .isParameterDeref ( arg ) and
83- result = this .getArgument ( arg )
94+ result = call .getArgument ( arg )
8495 )
8596 }
8697}
8798
8899/**
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.
91110 */
92- class SensitiveSendRecvConfiguration extends TaintTracking :: Configuration {
93- SensitiveSendRecvConfiguration ( ) { this = "SensitiveSendRecvConfiguration" }
111+ abstract class NetworkSendRecv extends FunctionCall {
112+ SendRecv target ;
94113
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+ }
96131
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 ( )
104160 )
105161 )
106162 }
107163}
108164
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+
109185from
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
112188where
189+ // flow from sensitive -> network data
113190 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
116199 then
117200 msg =
118201 "This operation transmits '" + sink .toString ( ) +
@@ -121,4 +204,4 @@ where
121204 msg =
122205 "This operation receives into '" + sink .toString ( ) +
123206 "', 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