Skip to content

Commit 643f7df

Browse files
committed
Split up Random.qll
This prevents bringing a dataflow config into scope from utility libraries.
1 parent 80124df commit 643f7df

File tree

8 files changed

+166
-160
lines changed

8 files changed

+166
-160
lines changed

java/ql/src/Likely Bugs/Arithmetic/BadAbsOfRandom.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
*/
1212

1313
import java
14-
import semmle.code.java.security.Random
14+
import semmle.code.java.security.RandomQuery
1515

1616
from MethodAccess ma, Method abs, Method nextIntOrLong, RandomDataSource nma
1717
where

java/ql/src/Likely Bugs/Arithmetic/RandomUsedOnce.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
*/
1414

1515
import java
16-
import semmle.code.java.security.Random
16+
import semmle.code.java.security.RandomQuery
1717

1818
from RandomDataSource ma
1919
where ma.getQualifier() instanceof ClassInstanceExpr

java/ql/src/Security/CWE/CWE-129/ArraySizing.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import java
22
import semmle.code.java.dataflow.DataFlow
33
import semmle.code.java.dataflow.DefUse
4-
import semmle.code.java.security.Random
4+
import semmle.code.java.security.RandomDataSource
55
private import BoundingChecks
66

77
/**

java/ql/src/Security/CWE/CWE-190/ArithmeticUncontrolled.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
import java
1616
import semmle.code.java.dataflow.TaintTracking
17-
import semmle.code.java.security.Random
17+
import semmle.code.java.security.RandomQuery
1818
import semmle.code.java.security.SecurityTests
1919
import ArithmeticCommon
2020
import DataFlow::PathGraph

java/ql/src/Security/CWE/CWE-335/PredictableSeed.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
*/
1212

1313
import java
14-
import semmle.code.java.security.Random
14+
import semmle.code.java.security.RandomQuery
1515

1616
from GetRandomData da, RValue use, PredictableSeedExpr source
1717
where

java/ql/src/semmle/code/java/dataflow/RangeAnalysis.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ private import SSA
6868
private import RangeUtils
6969
private import semmle.code.java.dataflow.internal.rangeanalysis.SsaReadPositionCommon
7070
private import semmle.code.java.controlflow.internal.GuardsLogic
71-
private import semmle.code.java.security.Random
71+
private import semmle.code.java.security.RandomDataSource
7272
private import SignAnalysis
7373
private import ModulusAnalysis
7474
private import semmle.code.java.Reflection
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,8 @@
1-
import java
2-
import semmle.code.java.dataflow.DefUse
3-
import semmle.code.java.dataflow.DataFlow6
4-
51
/**
6-
* The `java.security.SecureRandom` class.
2+
* Defines classes representing random data sources.
73
*/
8-
class SecureRandomNumberGenerator extends RefType {
9-
SecureRandomNumberGenerator() { this.hasQualifiedName("java.security", "SecureRandom") }
10-
}
4+
5+
import java
116

127
/**
138
* A method access that returns random data or writes random data to an argument.
@@ -148,149 +143,3 @@ class ApacheCommonsRandomSource extends RandomDataSource {
148143

149144
override Expr getOutput() { result = this }
150145
}
151-
152-
/**
153-
* A method access calling a method declared on `java.security.SecureRandom`
154-
* that returns random data or writes random data to an argument.
155-
*/
156-
class GetRandomData extends StdlibRandomSource {
157-
GetRandomData() { this.getQualifier().getType() instanceof SecureRandomNumberGenerator }
158-
}
159-
160-
private predicate isSeeded(RValue use) {
161-
isSeeding(_, use)
162-
or
163-
exists(GetRandomData da, RValue seeduse |
164-
da.getQualifier() = seeduse and
165-
useUsePair(seeduse, use)
166-
)
167-
}
168-
169-
private class PredictableSeedFlowConfiguration extends DataFlow6::Configuration {
170-
PredictableSeedFlowConfiguration() { this = "Random::PredictableSeedFlowConfiguration" }
171-
172-
override predicate isSource(DataFlow6::Node source) {
173-
source.asExpr() instanceof PredictableSeedExpr
174-
}
175-
176-
override predicate isSink(DataFlow6::Node sink) { isSeeding(sink.asExpr(), _) }
177-
178-
override predicate isAdditionalFlowStep(DataFlow6::Node node1, DataFlow6::Node node2) {
179-
predictableCalcStep(node1.asExpr(), node2.asExpr())
180-
}
181-
}
182-
183-
private predicate predictableCalcStep(Expr e1, Expr e2) {
184-
e2.(BinaryExpr).hasOperands(e1, any(PredictableSeedExpr p))
185-
or
186-
exists(AssignOp a | a = e2 | e1 = a.getDest() and a.getRhs() instanceof PredictableSeedExpr)
187-
or
188-
exists(ConstructorCall cc, TypeNumber t | cc = e2 |
189-
cc.getArgument(0) = e1 and
190-
t.hasSubtype*(cc.getConstructedType())
191-
)
192-
or
193-
exists(Method m, MethodAccess ma |
194-
ma = e2 and
195-
e1 = ma.getQualifier() and
196-
m = ma.getMethod() and
197-
exists(TypeNumber t | hasSubtype*(t, m.getDeclaringType())) and
198-
(
199-
m.getName().matches("to%String") or
200-
m.getName() = "toByteArray" or
201-
m.getName().matches("%Value")
202-
)
203-
)
204-
or
205-
exists(Method m, MethodAccess ma |
206-
ma = e2 and
207-
e1 = ma.getArgument(0) and
208-
m = ma.getMethod() and
209-
exists(TypeNumber t | hasSubtype*(t, m.getDeclaringType())) and
210-
(
211-
m.getName().matches("parse%") or
212-
m.getName().matches("valueOf%") or
213-
m.getName().matches("to%String")
214-
)
215-
)
216-
}
217-
218-
private predicate safelySeeded(RValue use) {
219-
exists(Expr arg |
220-
isSeeding(arg, use) and
221-
not exists(PredictableSeedFlowConfiguration conf | conf.hasFlowToExpr(arg))
222-
)
223-
or
224-
exists(GetRandomData da, RValue seeduse |
225-
da.getQualifier() = seeduse and useUsePair(seeduse, use)
226-
|
227-
not exists(RValue prior | useUsePair(prior, seeduse) | isSeeded(prior))
228-
)
229-
}
230-
231-
predicate unsafelySeeded(RValue use, PredictableSeedExpr source) {
232-
isSeedingSource(_, use, source) and
233-
not safelySeeded(use)
234-
}
235-
236-
private predicate isSeeding(Expr arg, RValue use) {
237-
exists(Expr e, VariableAssign def |
238-
def.getSource() = e and
239-
isSeedingConstruction(e, arg)
240-
|
241-
defUsePair(def, use) or
242-
def.getDestVar().(Field).getAnAccess() = use
243-
)
244-
or
245-
exists(Expr e, RValue seeduse |
246-
e.(MethodAccess).getQualifier() = seeduse and
247-
isRandomSeeding(e, arg) and
248-
useUsePair(seeduse, use)
249-
)
250-
}
251-
252-
private predicate isSeedingSource(Expr arg, RValue use, Expr source) {
253-
isSeeding(arg, use) and
254-
exists(PredictableSeedFlowConfiguration conf |
255-
conf.hasFlow(DataFlow6::exprNode(source), DataFlow6::exprNode(arg))
256-
)
257-
}
258-
259-
private predicate isRandomSeeding(MethodAccess m, Expr arg) {
260-
exists(Method def | m.getMethod() = def |
261-
def.getDeclaringType() instanceof SecureRandomNumberGenerator and
262-
def.getName() = "setSeed" and
263-
arg = m.getArgument(0)
264-
)
265-
}
266-
267-
private predicate isSeedingConstruction(ClassInstanceExpr c, Expr arg) {
268-
c.getConstructedType() instanceof SecureRandomNumberGenerator and
269-
c.getNumArgument() = 1 and
270-
c.getArgument(0) = arg
271-
}
272-
273-
class PredictableSeedExpr extends Expr {
274-
PredictableSeedExpr() {
275-
this.(MethodAccess).getCallee() instanceof ReturnsPredictableExpr
276-
or
277-
this instanceof CompileTimeConstantExpr
278-
or
279-
this.(ArrayCreationExpr).getInit() instanceof PredictableSeedExpr
280-
or
281-
exists(ArrayInit init | init = this |
282-
forall(Expr e | e = init.getAnInit() | e instanceof PredictableSeedExpr)
283-
)
284-
}
285-
}
286-
287-
abstract class ReturnsPredictableExpr extends Method { }
288-
289-
class ReturnsSystemTime extends ReturnsPredictableExpr {
290-
ReturnsSystemTime() {
291-
this.getDeclaringType().hasQualifiedName("java.lang", "System") and
292-
this.hasName("currentTimeMillis")
293-
or
294-
this.getDeclaringType().hasQualifiedName("java.lang", "System") and this.hasName("nanoTime")
295-
}
296-
}
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
import java
2+
import semmle.code.java.dataflow.DefUse
3+
import semmle.code.java.dataflow.DataFlow6
4+
import RandomDataSource
5+
6+
/**
7+
* The `java.security.SecureRandom` class.
8+
*/
9+
class SecureRandomNumberGenerator extends RefType {
10+
SecureRandomNumberGenerator() { this.hasQualifiedName("java.security", "SecureRandom") }
11+
}
12+
13+
/**
14+
* A method access calling a method declared on `java.security.SecureRandom`
15+
* that returns random data or writes random data to an argument.
16+
*/
17+
class GetRandomData extends StdlibRandomSource {
18+
GetRandomData() { this.getQualifier().getType() instanceof SecureRandomNumberGenerator }
19+
}
20+
21+
private predicate isSeeded(RValue use) {
22+
isSeeding(_, use)
23+
or
24+
exists(GetRandomData da, RValue seeduse |
25+
da.getQualifier() = seeduse and
26+
useUsePair(seeduse, use)
27+
)
28+
}
29+
30+
private class PredictableSeedFlowConfiguration extends DataFlow6::Configuration {
31+
PredictableSeedFlowConfiguration() { this = "Random::PredictableSeedFlowConfiguration" }
32+
33+
override predicate isSource(DataFlow6::Node source) {
34+
source.asExpr() instanceof PredictableSeedExpr
35+
}
36+
37+
override predicate isSink(DataFlow6::Node sink) { isSeeding(sink.asExpr(), _) }
38+
39+
override predicate isAdditionalFlowStep(DataFlow6::Node node1, DataFlow6::Node node2) {
40+
predictableCalcStep(node1.asExpr(), node2.asExpr())
41+
}
42+
}
43+
44+
private predicate predictableCalcStep(Expr e1, Expr e2) {
45+
e2.(BinaryExpr).hasOperands(e1, any(PredictableSeedExpr p))
46+
or
47+
exists(AssignOp a | a = e2 | e1 = a.getDest() and a.getRhs() instanceof PredictableSeedExpr)
48+
or
49+
exists(ConstructorCall cc, TypeNumber t | cc = e2 |
50+
cc.getArgument(0) = e1 and
51+
t.hasSubtype*(cc.getConstructedType())
52+
)
53+
or
54+
exists(Method m, MethodAccess ma |
55+
ma = e2 and
56+
e1 = ma.getQualifier() and
57+
m = ma.getMethod() and
58+
exists(TypeNumber t | hasSubtype*(t, m.getDeclaringType())) and
59+
(
60+
m.getName().matches("to%String") or
61+
m.getName() = "toByteArray" or
62+
m.getName().matches("%Value")
63+
)
64+
)
65+
or
66+
exists(Method m, MethodAccess ma |
67+
ma = e2 and
68+
e1 = ma.getArgument(0) and
69+
m = ma.getMethod() and
70+
exists(TypeNumber t | hasSubtype*(t, m.getDeclaringType())) and
71+
(
72+
m.getName().matches("parse%") or
73+
m.getName().matches("valueOf%") or
74+
m.getName().matches("to%String")
75+
)
76+
)
77+
}
78+
79+
private predicate safelySeeded(RValue use) {
80+
exists(Expr arg |
81+
isSeeding(arg, use) and
82+
not exists(PredictableSeedFlowConfiguration conf | conf.hasFlowToExpr(arg))
83+
)
84+
or
85+
exists(GetRandomData da, RValue seeduse |
86+
da.getQualifier() = seeduse and useUsePair(seeduse, use)
87+
|
88+
not exists(RValue prior | useUsePair(prior, seeduse) | isSeeded(prior))
89+
)
90+
}
91+
92+
predicate unsafelySeeded(RValue use, PredictableSeedExpr source) {
93+
isSeedingSource(_, use, source) and
94+
not safelySeeded(use)
95+
}
96+
97+
private predicate isSeeding(Expr arg, RValue use) {
98+
exists(Expr e, VariableAssign def |
99+
def.getSource() = e and
100+
isSeedingConstruction(e, arg)
101+
|
102+
defUsePair(def, use) or
103+
def.getDestVar().(Field).getAnAccess() = use
104+
)
105+
or
106+
exists(Expr e, RValue seeduse |
107+
e.(MethodAccess).getQualifier() = seeduse and
108+
isRandomSeeding(e, arg) and
109+
useUsePair(seeduse, use)
110+
)
111+
}
112+
113+
private predicate isSeedingSource(Expr arg, RValue use, Expr source) {
114+
isSeeding(arg, use) and
115+
exists(PredictableSeedFlowConfiguration conf |
116+
conf.hasFlow(DataFlow6::exprNode(source), DataFlow6::exprNode(arg))
117+
)
118+
}
119+
120+
private predicate isRandomSeeding(MethodAccess m, Expr arg) {
121+
exists(Method def | m.getMethod() = def |
122+
def.getDeclaringType() instanceof SecureRandomNumberGenerator and
123+
def.getName() = "setSeed" and
124+
arg = m.getArgument(0)
125+
)
126+
}
127+
128+
private predicate isSeedingConstruction(ClassInstanceExpr c, Expr arg) {
129+
c.getConstructedType() instanceof SecureRandomNumberGenerator and
130+
c.getNumArgument() = 1 and
131+
c.getArgument(0) = arg
132+
}
133+
134+
class PredictableSeedExpr extends Expr {
135+
PredictableSeedExpr() {
136+
this.(MethodAccess).getCallee() instanceof ReturnsPredictableExpr
137+
or
138+
this instanceof CompileTimeConstantExpr
139+
or
140+
this.(ArrayCreationExpr).getInit() instanceof PredictableSeedExpr
141+
or
142+
exists(ArrayInit init | init = this |
143+
forall(Expr e | e = init.getAnInit() | e instanceof PredictableSeedExpr)
144+
)
145+
}
146+
}
147+
148+
abstract class ReturnsPredictableExpr extends Method { }
149+
150+
class ReturnsSystemTime extends ReturnsPredictableExpr {
151+
ReturnsSystemTime() {
152+
this.getDeclaringType().hasQualifiedName("java.lang", "System") and
153+
this.hasName("currentTimeMillis")
154+
or
155+
this.getDeclaringType().hasQualifiedName("java.lang", "System") and this.hasName("nanoTime")
156+
}
157+
}

0 commit comments

Comments
 (0)