mirror of
https://github.com/github/codeql.git
synced 2025-12-22 11:46:32 +01:00
Add support for Commons-Lang's RandomUtils
This is realised by somewhat generalising our interfaces for modelling RNGs. We also add tests for randomness-related queries that didn't have any, and addtest cases checking the Apache random-number generators are interchangeable with the stdlib ones.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import semmle.code.java.dataflow.DefUse
|
||||
import semmle.code.java.security.Random
|
||||
private import BoundingChecks
|
||||
|
||||
/**
|
||||
@@ -124,33 +125,16 @@ abstract class BoundedFlowSource extends DataFlow::Node {
|
||||
}
|
||||
|
||||
/**
|
||||
* Input that is constructed using a `Random` value.
|
||||
* Input that is constructed using a random value.
|
||||
*/
|
||||
class RandomValueFlowSource extends BoundedFlowSource {
|
||||
RandomValueFlowSource() {
|
||||
exists(RefType random, MethodAccess nextAccess |
|
||||
random.hasQualifiedName("java.util", "Random")
|
||||
|
|
||||
nextAccess.getCallee().getDeclaringType().getAnAncestor() = random and
|
||||
nextAccess.getCallee().getName().matches("next%") and
|
||||
nextAccess = this.asExpr()
|
||||
)
|
||||
}
|
||||
RandomDataSource nextAccess;
|
||||
|
||||
override int lowerBound() {
|
||||
// If this call is to `nextInt()`, the lower bound is zero.
|
||||
this.asExpr().(MethodAccess).getCallee().hasName("nextInt") and
|
||||
this.asExpr().(MethodAccess).getNumArgument() = 1 and
|
||||
result = 0
|
||||
}
|
||||
RandomValueFlowSource() { this.asExpr() = nextAccess }
|
||||
|
||||
override int upperBound() {
|
||||
// If this call specified an argument to `nextInt()`, and that argument is a compile time constant,
|
||||
// it forms the upper bound.
|
||||
this.asExpr().(MethodAccess).getCallee().hasName("nextInt") and
|
||||
this.asExpr().(MethodAccess).getNumArgument() = 1 and
|
||||
result = this.asExpr().(MethodAccess).getArgument(0).(CompileTimeConstantExpr).getIntValue()
|
||||
}
|
||||
override int lowerBound() { result = nextAccess.getLowerBound() }
|
||||
|
||||
override int upperBound() { result = nextAccess.getUpperBound() }
|
||||
|
||||
override string getDescription() { result = "Random value" }
|
||||
}
|
||||
|
||||
@@ -13,34 +13,14 @@
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.security.Random
|
||||
import semmle.code.java.security.SecurityTests
|
||||
import ArithmeticCommon
|
||||
import DataFlow::PathGraph
|
||||
|
||||
class TaintSource extends DataFlow::ExprNode {
|
||||
TaintSource() {
|
||||
// Either this is an access to a random number generating method of the right kind, ...
|
||||
exists(Method def |
|
||||
def = this.getExpr().(MethodAccess).getMethod() and
|
||||
(
|
||||
// Some random-number methods are omitted:
|
||||
// `nextDouble` and `nextFloat` are between 0 and 1,
|
||||
// `nextGaussian` is extremely unlikely to hit max values.
|
||||
def.getName() = "nextInt" or
|
||||
def.getName() = "nextLong"
|
||||
) and
|
||||
def.getNumberOfParameters() = 0 and
|
||||
def.getDeclaringType().hasQualifiedName("java.util", "Random")
|
||||
)
|
||||
or
|
||||
// ... or this is the array parameter of `nextBytes`, which is filled with random bytes.
|
||||
exists(MethodAccess m, Method def |
|
||||
m.getAnArgument() = this.getExpr() and
|
||||
m.getMethod() = def and
|
||||
def.getName() = "nextBytes" and
|
||||
def.getNumberOfParameters() = 1 and
|
||||
def.getDeclaringType().hasQualifiedName("java.util", "Random")
|
||||
)
|
||||
exists(RandomDataSource m | not m.resultMayBeBounded() | m.getOutput() = this.getExpr())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user