@@ -28,7 +28,7 @@ import semmle.code.cpp.dataflow.new.DataFlow
28
28
* - EVP_MD_CTX
29
29
* - EVP_PKEY_CTX
30
30
*/
31
- private class CtxType extends Type {
31
+ class CtxType extends Type {
32
32
CtxType ( ) {
33
33
// It is possible for users to use the underlying type of the CTX variables
34
34
// these have a name matching 'evp_%ctx_%st
@@ -47,7 +47,7 @@ private class CtxType extends Type {
47
47
/**
48
48
* A pointer to a CtxType
49
49
*/
50
- private class CtxPointerExpr extends Expr {
50
+ class CtxPointerExpr extends Expr {
51
51
CtxPointerExpr ( ) {
52
52
this .getType ( ) instanceof CtxType and
53
53
this .getType ( ) instanceof PointerType
@@ -57,7 +57,7 @@ private class CtxPointerExpr extends Expr {
57
57
/**
58
58
* A call argument of type CtxPointerExpr.
59
59
*/
60
- private class CtxPointerArgument extends CtxPointerExpr {
60
+ class CtxPointerArgument extends CtxPointerExpr {
61
61
CtxPointerArgument ( ) { exists ( Call c | c .getAnArgument ( ) = this ) }
62
62
63
63
Call getCall ( ) { result .getAnArgument ( ) = this }
@@ -83,32 +83,103 @@ private class CtxClearCall extends Call {
83
83
}
84
84
}
85
85
86
+ abstract private class CtxPassThroughCall extends Call {
87
+ abstract DataFlow:: Node getNode1 ( ) ;
88
+
89
+ abstract DataFlow:: Node getNode2 ( ) ;
90
+ }
91
+
86
92
/**
87
93
* A call whose target contains 'copy' and has an argument of type
88
94
* CtxPointerArgument.
89
95
*/
90
- private class CtxCopyOutArgCall extends Call {
96
+ private class CtxCopyOutArgCall extends CtxPassThroughCall {
97
+ DataFlow:: Node n1 ;
98
+ DataFlow:: Node n2 ;
99
+
91
100
CtxCopyOutArgCall ( ) {
92
101
this .getTarget ( ) .getName ( ) .toLowerCase ( ) .matches ( "%copy%" ) and
93
- this .getAnArgument ( ) instanceof CtxPointerArgument
102
+ n1 .asExpr ( ) = this .getAnArgument ( ) and
103
+ n1 .getType ( ) instanceof CtxType and
104
+ n2 .asDefiningArgument ( ) = this .getAnArgument ( ) and
105
+ n2 .getType ( ) instanceof CtxType and
106
+ n1 .asDefiningArgument ( ) != n2 .asExpr ( )
94
107
}
108
+
109
+ override DataFlow:: Node getNode1 ( ) { result = n1 }
110
+
111
+ override DataFlow:: Node getNode2 ( ) { result = n2 }
95
112
}
96
113
97
114
/**
98
115
* A call whose target contains 'dup' and has an argument of type
99
116
* CtxPointerArgument.
100
117
*/
101
- private class CtxCopyReturnCall extends Call , CtxPointerExpr {
118
+ private class CtxCopyReturnCall extends CtxPassThroughCall , CtxPointerExpr {
119
+ DataFlow:: Node n1 ;
120
+
102
121
CtxCopyReturnCall ( ) {
103
122
this .getTarget ( ) .getName ( ) .toLowerCase ( ) .matches ( "%dup%" ) and
104
- this .getAnArgument ( ) instanceof CtxPointerArgument
123
+ n1 .asExpr ( ) = this .getAnArgument ( ) and
124
+ n1 .getType ( ) instanceof CtxType
125
+ }
126
+
127
+ override DataFlow:: Node getNode1 ( ) { result = n1 }
128
+
129
+ override DataFlow:: Node getNode2 ( ) { result .asExpr ( ) = this }
130
+ }
131
+
132
+ /**
133
+ * A call to `EVP_PKEY_paramgen` acts as a kind of pass through.
134
+ * It's output pkey is eventually used in a new operation generating
135
+ * a fresh context pointer (e.g., `EVP_PKEY_CTX_new`).
136
+ * It is easier to model this as a pass through
137
+ * than to model the flow from the paramgen to the new key generation.
138
+ */
139
+ private class CtxParamGenCall extends CtxPassThroughCall {
140
+ DataFlow:: Node n1 ;
141
+ DataFlow:: Node n2 ;
142
+
143
+ CtxParamGenCall ( ) {
144
+ this .getTarget ( ) .getName ( ) = "EVP_PKEY_paramgen" and
145
+ n1 .asExpr ( ) = this .getArgument ( 0 ) and
146
+ (
147
+ n2 .asExpr ( ) = this .getArgument ( 1 )
148
+ or
149
+ n2 .asDefiningArgument ( ) = this .getArgument ( 1 )
150
+ )
105
151
}
152
+
153
+ override DataFlow:: Node getNode1 ( ) { result = n1 }
154
+
155
+ override DataFlow:: Node getNode2 ( ) { result = n2 }
156
+ }
157
+
158
+ /**
159
+ * If the current node gets is an argument to a function
160
+ * that returns a pointer type, immediately flow through.
161
+ * NOTE: this passthrough is required if we allow
162
+ * intermediate steps to go into variables that are not a CTX type.
163
+ * See for example `CtxParamGenCall`.
164
+ */
165
+ private class CallArgToCtxRet extends CtxPassThroughCall , CtxPointerExpr {
166
+ DataFlow:: Node n1 ;
167
+ DataFlow:: Node n2 ;
168
+
169
+ CallArgToCtxRet ( ) {
170
+ this .getAnArgument ( ) = n1 .asExpr ( ) and
171
+ n2 .asExpr ( ) = this
172
+ }
173
+
174
+ override DataFlow:: Node getNode1 ( ) { result = n1 }
175
+
176
+ override DataFlow:: Node getNode2 ( ) { result = n2 }
106
177
}
107
178
108
179
/**
109
180
* A source Ctx of interest is any argument or return of type CtxPointerExpr.
110
181
*/
111
- private class CtxPointerSource extends CtxPointerExpr {
182
+ class CtxPointerSource extends CtxPointerExpr {
112
183
CtxPointerSource ( ) {
113
184
this instanceof CtxPointerReturn or
114
185
this instanceof CtxPointerArgument
@@ -122,43 +193,31 @@ private class CtxPointerSource extends CtxPointerExpr {
122
193
}
123
194
124
195
/**
125
- * Flow from any CtxPointerSource to any CtxPointerArgument .
196
+ * Flow from any CtxPointerSource to other CtxPointerSource .
126
197
*/
127
- module OpenSSLCtxSourceToArgumentFlowConfig implements DataFlow:: ConfigSig {
198
+ module OpenSSLCtxSourceToSourceFlowConfig implements DataFlow:: ConfigSig {
128
199
predicate isSource ( DataFlow:: Node source ) { exists ( CtxPointerSource s | s .asNode ( ) = source ) }
129
200
130
- predicate isSink ( DataFlow:: Node sink ) { sink . asExpr ( ) instanceof CtxPointerArgument }
201
+ predicate isSink ( DataFlow:: Node sink ) { exists ( CtxPointerSource s | s . asNode ( ) = sink ) }
131
202
132
203
predicate isBarrier ( DataFlow:: Node node ) {
133
204
exists ( CtxClearCall c | c .getAnArgument ( ) = node .asExpr ( ) )
134
205
}
135
206
136
207
predicate isAdditionalFlowStep ( DataFlow:: Node node1 , DataFlow:: Node node2 ) {
137
- exists ( CtxCopyOutArgCall c |
138
- c .getAnArgument ( ) = node1 .asExpr ( ) and
139
- c .getAnArgument ( ) = node2 .asExpr ( ) and
140
- node1 .asExpr ( ) != node2 .asExpr ( ) and
141
- node2 .asExpr ( ) .getType ( ) instanceof CtxType
142
- )
143
- or
144
- exists ( CtxCopyReturnCall c |
145
- c .getAnArgument ( ) = node1 .asExpr ( ) and
146
- c = node2 .asExpr ( ) and
147
- node1 .asExpr ( ) != node2 .asExpr ( ) and
148
- node2 .asExpr ( ) .getType ( ) instanceof CtxType
149
- )
208
+ exists ( CtxPassThroughCall c | c .getNode1 ( ) = node1 and c .getNode2 ( ) = node2 )
150
209
}
151
210
}
152
211
153
- module OpenSSLCtxSourceToArgumentFlow = DataFlow:: Global< OpenSSLCtxSourceToArgumentFlowConfig > ;
212
+ module OpenSSLCtxSourceToArgumentFlow = DataFlow:: Global< OpenSSLCtxSourceToSourceFlowConfig > ;
154
213
155
214
/**
156
215
* Holds if there is a context flow from the source to the sink.
157
216
*/
158
- predicate ctxArgOrRetFlowsToCtxArg ( CtxPointerSource source , CtxPointerArgument sink ) {
217
+ predicate ctxSrcToSrcFlow ( CtxPointerSource source , CtxPointerSource sink ) {
159
218
exists ( DataFlow:: Node a , DataFlow:: Node b |
160
219
OpenSSLCtxSourceToArgumentFlow:: flow ( a , b ) and
161
220
a = source .asNode ( ) and
162
- b . asExpr ( ) = sink
221
+ b = sink . asNode ( )
163
222
)
164
223
}
0 commit comments