@@ -2,15 +2,159 @@ import java
22import semmle.code.java.dataflow.DefUse
33import semmle.code.java.dataflow.DataFlow
44
5+ /**
6+ * The `java.security.SecureRandom` class.
7+ */
58class SecureRandomNumberGenerator extends RefType {
69 SecureRandomNumberGenerator ( ) { this .hasQualifiedName ( "java.security" , "SecureRandom" ) }
710}
811
9- class GetRandomData extends MethodAccess {
10- GetRandomData ( ) {
11- this .getMethod ( ) .getName ( ) .matches ( "next%" ) and
12- this .getQualifier ( ) .getType ( ) instanceof SecureRandomNumberGenerator
12+ /**
13+ * A method access that returns random data or writes random data to an argument.
14+ */
15+ abstract class RandomDataSource extends MethodAccess {
16+ /**
17+ * Gets the integer lower bound, inclusive, of the values returned by this call,
18+ * if applicable to this method's type and a constant bound is known.
19+ */
20+ int getLowerBound ( ) { result = this .getLowerBoundExpr ( ) .( CompileTimeConstantExpr ) .getIntValue ( ) }
21+
22+ /**
23+ * Gets the integer lower bound, inclusive, of the values returned by this call,
24+ * if applicable to this method's type and a bound is known.
25+ */
26+ Expr getLowerBoundExpr ( ) { none ( ) }
27+
28+ /**
29+ * Gets the integer upper bound, exclusive, of the values returned by this call,
30+ * if applicable to this method's type and a constant bound is known.
31+ */
32+ int getUpperBound ( ) { result = this .getUpperBoundExpr ( ) .( CompileTimeConstantExpr ) .getIntValue ( ) }
33+
34+ /**
35+ * Gets the integer upper bound, exclusive, of the values returned by this call,
36+ * if applicable to this method's type and a bound is known.
37+ */
38+ Expr getUpperBoundExpr ( ) { none ( ) }
39+
40+ /**
41+ * Holds if this source of random data may return bounded values (e.g. integers between 1 and 10).
42+ * If it does not hold, it may return any value in the range of its result type (e.g., any possible integer).
43+ */
44+ predicate resultMayBeBounded ( ) { none ( ) }
45+
46+ /**
47+ * Gets the result of this source of randomness: either the method access itself, or some argument
48+ * in the case where it writes random data to that argument.
49+ */
50+ abstract Expr getOutput ( ) ;
51+ }
52+
53+ /**
54+ * A method access calling a method declared on `java.util.Random`
55+ * that returns random data or writes random data to an argument.
56+ */
57+ class StdlibRandomSource extends RandomDataSource {
58+ Method m ;
59+
60+ StdlibRandomSource ( ) {
61+ m = this .getMethod ( ) and
62+ m .getName ( ) .matches ( "next%" ) and
63+ m .getDeclaringType ( ) .getAnAncestor ( ) .hasQualifiedName ( "java.util" , "Random" )
64+ }
65+
66+ // Note for the following bounds functions: `java.util.Random` only defines no-arg versions
67+ // of `nextInt` and `nextLong` plus `nextInt(int x)`, bounded to the range [0, x)
68+ // However `ThreadLocalRandom` provides one- and two-arg versions of `nextInt` and `nextLong`
69+ // which allow both lower and upper bounds for both types.
70+ override int getLowerBound ( ) {
71+ // If this call is to `nextInt(int)` or `nextLong(long), the lower bound is zero.
72+ m .hasName ( [ "nextInt" , "nextLong" ] ) and
73+ m .getNumberOfParameters ( ) = 1 and
74+ result = 0
75+ or
76+ result = super .getLowerBound ( ) // Include a lower bound provided via `getLowerBoundExpr`
77+ }
78+
79+ override Expr getLowerBoundExpr ( ) {
80+ // If this call is to `nextInt(int, int)` or `nextLong(long, long)`, the lower bound is the first argument.
81+ m .hasName ( [ "nextInt" , "nextLong" ] ) and
82+ m .getNumberOfParameters ( ) = 2 and
83+ result = this .getArgument ( 0 )
84+ }
85+
86+ override Expr getUpperBoundExpr ( ) {
87+ // If this call is to `nextInt(int)` or `nextLong(long)`, the upper bound is the first argument.
88+ // If it calls `nextInt(int, int)` or `nextLong(long, long)`, the upper bound is the second argument.
89+ m .hasName ( [ "nextInt" , "nextLong" ] ) and
90+ (
91+ m .getNumberOfParameters ( ) = 1 and
92+ result = this .getArgument ( 0 )
93+ or
94+ m .getNumberOfParameters ( ) = 2 and
95+ result = this .getArgument ( 1 )
96+ )
97+ }
98+
99+ override predicate resultMayBeBounded ( ) {
100+ // `next` may be restricted by its `bits` argument,
101+ // `nextBoolean` can't possibly be usefully bounded,
102+ // `nextDouble` and `nextFloat` are between 0 and 1,
103+ // `nextGaussian` is extremely unlikely to hit max values.
104+ m .hasName ( [ "next" , "nextBoolean" , "nextDouble" , "nextFloat" , "nextGaussian" ] )
105+ or
106+ m .hasName ( [ "nextInt" , "nextLong" ] ) and
107+ m .getNumberOfParameters ( ) = [ 1 , 2 ]
108+ }
109+
110+ override Expr getOutput ( ) {
111+ if m .hasName ( "getBytes" ) then result = this .getArgument ( 0 ) else result = this
112+ }
113+ }
114+
115+ /**
116+ * A method access calling a method declared on `org.apache.commons.lang3.RandomUtils`
117+ * that returns random data or writes random data to an argument.
118+ */
119+ class ApacheCommonsRandomSource extends RandomDataSource {
120+ Method m ;
121+
122+ ApacheCommonsRandomSource ( ) {
123+ m = this .getMethod ( ) and
124+ m .getName ( ) .matches ( "next%" ) and
125+ m .getDeclaringType ( ) .hasQualifiedName ( "org.apache.commons.lang3" , "RandomUtils" )
126+ }
127+
128+ override Expr getLowerBoundExpr ( ) {
129+ // If this call is to `nextInt(int, int)` or `nextLong(long, long)`, the lower bound is the first argument.
130+ m .hasName ( [ "nextInt" , "nextLong" ] ) and
131+ m .getNumberOfParameters ( ) = 2 and
132+ result = this .getArgument ( 0 )
133+ }
134+
135+ override Expr getUpperBoundExpr ( ) {
136+ // If this call is to `nextInt(int, int)` or `nextLong(long, long)`, the upper bound is the second argument.
137+ m .hasName ( [ "nextInt" , "nextLong" ] ) and
138+ m .getNumberOfParameters ( ) = 2 and
139+ result = this .getArgument ( 1 )
13140 }
141+
142+ override predicate resultMayBeBounded ( ) {
143+ m .hasName ( [ "nextDouble" , "nextFloat" ] )
144+ or
145+ m .hasName ( [ "nextInt" , "nextLong" ] ) and
146+ m .getNumberOfParameters ( ) = 2
147+ }
148+
149+ override Expr getOutput ( ) { result = this }
150+ }
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 }
14158}
15159
16160private predicate isSeeded ( RValue use ) {
0 commit comments