forked from github/codeql
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAlgToAVCFlow.qll
More file actions
170 lines (140 loc) · 5.71 KB
/
AlgToAVCFlow.qll
File metadata and controls
170 lines (140 loc) · 5.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
import cpp
import semmle.code.cpp.dataflow.new.DataFlow
import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmConstants
import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
/**
* Traces 'known algorithms' to AVCs, specifically
* algorithms that are in the set of known algorithm constants.
* Padding-specific consumers exist that have their own values that
* overlap with the known algorithm constants.
* Padding consumers (specific padding consumers) are excluded from the set of sinks.
*/
module KnownOpenSSLAlgorithmToAlgorithmValueConsumerConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source.asExpr() instanceof KnownOpenSSLAlgorithmConstant
}
predicate isSink(DataFlow::Node sink) {
exists(OpenSSLAlgorithmValueConsumer c |
c.getInputNode() = sink and
not c instanceof PaddingAlgorithmValueConsumer
)
}
predicate isBarrier(DataFlow::Node node) {
// False positive reducer, don't flow out through argv
exists(VariableAccess va, Variable v |
v.getAnAccess() = va and va = node.asExpr()
or
va = node.asIndirectExpr()
|
v.getName().matches("%argv")
)
}
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
knownPassThroughStep(node1, node2)
}
}
module KnownOpenSSLAlgorithmToAlgorithmValueConsumerFlow =
DataFlow::Global<KnownOpenSSLAlgorithmToAlgorithmValueConsumerConfig>;
module RSAPaddingAlgorithmToPaddingAlgorithmValueConsumerConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source.asExpr() instanceof KnownOpenSSLAlgorithmConstant
}
predicate isSink(DataFlow::Node sink) {
exists(PaddingAlgorithmValueConsumer c | c.getInputNode() = sink)
}
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
knownPassThroughStep(node1, node2)
}
}
module RSAPaddingAlgorithmToPaddingAlgorithmValueConsumerFlow =
DataFlow::Global<RSAPaddingAlgorithmToPaddingAlgorithmValueConsumerConfig>;
class OpenSSLAlgorithmAdditionalFlowStep extends AdditionalFlowInputStep {
OpenSSLAlgorithmAdditionalFlowStep() { exists(AlgorithmPassthroughCall c | c.getInNode() = this) }
override DataFlow::Node getOutput() {
exists(AlgorithmPassthroughCall c | c.getInNode() = this and c.getOutNode() = result)
}
}
abstract class AlgorithmPassthroughCall extends Call {
abstract DataFlow::Node getInNode();
abstract DataFlow::Node getOutNode();
}
class CopyAndDupAlgorithmPassthroughCall extends AlgorithmPassthroughCall {
DataFlow::Node inNode;
DataFlow::Node outNode;
CopyAndDupAlgorithmPassthroughCall() {
// Flow out through any return or other argument of the same type
// Assume flow in and out is asIndirectExpr or asDefinitingArgument since a pointer is assumed
// to be involved
// NOTE: not attempting to detect openssl specific copy/dup functions, but anything suspected to be copy/dup
this.getTarget().getName().toLowerCase().matches(["%_dup%", "%_copy%"]) and
exists(Expr inArg, Type t |
inArg = this.getAnArgument() and t = inArg.getUnspecifiedType().stripType()
|
inNode.asIndirectExpr() = inArg and
(
// Case 1: flow through another argument as an out arg of the same type
exists(Expr outArg |
outArg = this.getAnArgument() and
outArg != inArg and
outArg.getUnspecifiedType().stripType() = t
|
outNode.asDefiningArgument() = outArg
)
or
// Case 2: flow through the return value if the result is the same as the intput type
exists(Expr outArg | outArg = this and outArg.getUnspecifiedType().stripType() = t |
outNode.asIndirectExpr() = outArg
)
)
)
}
override DataFlow::Node getInNode() { result = inNode }
override DataFlow::Node getOutNode() { result = outNode }
}
class NIDToPointerPassthroughCall extends AlgorithmPassthroughCall {
DataFlow::Node inNode;
DataFlow::Node outNode;
NIDToPointerPassthroughCall() {
this.getTarget().getName() in ["OBJ_nid2obj", "OBJ_nid2ln", "OBJ_nid2sn"] and
inNode.asExpr() = this.getArgument(0) and
outNode.asExpr() = this
//outNode.asIndirectExpr() = this
}
override DataFlow::Node getInNode() { result = inNode }
override DataFlow::Node getOutNode() { result = outNode }
}
class PointerToPointerPassthroughCall extends AlgorithmPassthroughCall {
DataFlow::Node inNode;
DataFlow::Node outNode;
PointerToPointerPassthroughCall() {
this.getTarget().getName() = "OBJ_txt2obj" and
inNode.asIndirectExpr() = this.getArgument(0) and
outNode.asIndirectExpr() = this
or
//outNode.asExpr() = this
this.getTarget().getName() in ["OBJ_obj2txt", "i2t_ASN1_OBJECT"] and
inNode.asIndirectExpr() = this.getArgument(2) and
outNode.asDefiningArgument() = this.getArgument(0)
}
override DataFlow::Node getInNode() { result = inNode }
override DataFlow::Node getOutNode() { result = outNode }
}
class PointerToNIDPassthroughCall extends AlgorithmPassthroughCall {
DataFlow::Node inNode;
DataFlow::Node outNode;
PointerToNIDPassthroughCall() {
this.getTarget().getName() in ["OBJ_obj2nid", "OBJ_ln2nid", "OBJ_sn2nid", "OBJ_txt2nid"] and
(
inNode.asIndirectExpr() = this.getArgument(0)
or
inNode.asExpr() = this.getArgument(0)
) and
outNode.asExpr() = this
}
override DataFlow::Node getInNode() { result = inNode }
override DataFlow::Node getOutNode() { result = outNode }
}
// TODO: pkeys pass through EVP_PKEY_CTX_new and any similar variant
predicate knownPassThroughStep(DataFlow::Node node1, DataFlow::Node node2) {
exists(AlgorithmPassthroughCall c | c.getInNode() = node1 and c.getOutNode() = node2)
}