forked from github/codeql
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathRandom.qll
More file actions
152 lines (135 loc) · 4.35 KB
/
Random.qll
File metadata and controls
152 lines (135 loc) · 4.35 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
import java
import semmle.code.java.dataflow.DefUse
import semmle.code.java.dataflow.DataFlow
class SecureRandomNumberGenerator extends RefType {
SecureRandomNumberGenerator() { this.hasQualifiedName("java.security", "SecureRandom") }
}
class GetRandomData extends MethodAccess {
GetRandomData() {
this.getMethod().getName().matches("next%") and
this.getQualifier().getType() instanceof SecureRandomNumberGenerator
}
}
private predicate isSeeded(RValue use) {
isSeeding(_, use)
or
exists(GetRandomData da, RValue seeduse |
da.getQualifier() = seeduse and
useUsePair(seeduse, use)
)
}
private class PredictableSeedFlowConfiguration extends DataFlow::Configuration {
PredictableSeedFlowConfiguration() { this = "Random::PredictableSeedFlowConfiguration" }
override predicate isSource(DataFlow::Node source) {
source.asExpr() instanceof PredictableSeedExpr
}
override predicate isSink(DataFlow::Node sink) { isSeeding(sink.asExpr(), _) }
override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
predictableCalcStep(node1.asExpr(), node2.asExpr())
}
}
private predicate predictableCalcStep(Expr e1, Expr e2) {
e2.(BinaryExpr).hasOperands(e1, any(PredictableSeedExpr p))
or
exists(AssignOp a | a = e2 | e1 = a.getDest() and a.getRhs() instanceof PredictableSeedExpr)
or
exists(ConstructorCall cc, TypeNumber t | cc = e2 |
cc.getArgument(0) = e1 and
t.hasSubtype*(cc.getConstructedType())
)
or
exists(Method m, MethodAccess ma |
ma = e2 and
e1 = ma.getQualifier() and
m = ma.getMethod() and
exists(TypeNumber t | hasSubtype*(t, m.getDeclaringType())) and
(
m.getName().matches("to%String") or
m.getName() = "toByteArray" or
m.getName().matches("%Value")
)
)
or
exists(Method m, MethodAccess ma |
ma = e2 and
e1 = ma.getArgument(0) and
m = ma.getMethod() and
exists(TypeNumber t | hasSubtype*(t, m.getDeclaringType())) and
(
m.getName().matches("parse%") or
m.getName().matches("valueOf%") or
m.getName().matches("to%String")
)
)
}
private predicate safelySeeded(RValue use) {
exists(Expr arg |
isSeeding(arg, use) and
not exists(PredictableSeedFlowConfiguration conf | conf.hasFlowToExpr(arg))
)
or
exists(GetRandomData da, RValue seeduse |
da.getQualifier() = seeduse and useUsePair(seeduse, use)
|
not exists(RValue prior | useUsePair(prior, seeduse) | isSeeded(prior))
)
}
predicate unsafelySeeded(RValue use, PredictableSeedExpr source) {
isSeedingSource(_, use, source) and
not safelySeeded(use)
}
private predicate isSeeding(Expr arg, RValue use) {
exists(Expr e, VariableAssign def |
def.getSource() = e and
isSeedingConstruction(e, arg)
|
defUsePair(def, use) or
def.getDestVar().(Field).getAnAccess() = use
)
or
exists(Expr e, RValue seeduse |
e.(MethodAccess).getQualifier() = seeduse and
isRandomSeeding(e, arg) and
useUsePair(seeduse, use)
)
}
private predicate isSeedingSource(Expr arg, RValue use, Expr source) {
isSeeding(arg, use) and
exists(PredictableSeedFlowConfiguration conf |
conf.hasFlow(DataFlow::exprNode(source), DataFlow::exprNode(arg))
)
}
private predicate isRandomSeeding(MethodAccess m, Expr arg) {
exists(Method def | m.getMethod() = def |
def.getDeclaringType() instanceof SecureRandomNumberGenerator and
def.getName() = "setSeed" and
arg = m.getArgument(0)
)
}
private predicate isSeedingConstruction(ClassInstanceExpr c, Expr arg) {
c.getConstructedType() instanceof SecureRandomNumberGenerator and
c.getNumArgument() = 1 and
c.getArgument(0) = arg
}
class PredictableSeedExpr extends Expr {
PredictableSeedExpr() {
this.(MethodAccess).getCallee() instanceof ReturnsPredictableExpr
or
this instanceof CompileTimeConstantExpr
or
this.(ArrayCreationExpr).getInit() instanceof PredictableSeedExpr
or
exists(ArrayInit init | init = this |
forall(Expr e | e = init.getAnInit() | e instanceof PredictableSeedExpr)
)
}
}
abstract class ReturnsPredictableExpr extends Method { }
class ReturnsSystemTime extends ReturnsPredictableExpr {
ReturnsSystemTime() {
this.getDeclaringType().hasQualifiedName("java.lang", "System") and
this.hasName("currentTimeMillis")
or
this.getDeclaringType().hasQualifiedName("java.lang", "System") and this.hasName("nanoTime")
}
}