mirror of
https://github.com/github/codeql.git
synced 2026-05-02 04:05:14 +02:00
Split up Random.qll
This prevents bringing a dataflow config into scope from utility libraries.
This commit is contained in:
@@ -11,7 +11,7 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.security.Random
|
||||
import semmle.code.java.security.RandomQuery
|
||||
|
||||
from MethodAccess ma, Method abs, Method nextIntOrLong, RandomDataSource nma
|
||||
where
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.security.Random
|
||||
import semmle.code.java.security.RandomQuery
|
||||
|
||||
from RandomDataSource ma
|
||||
where ma.getQualifier() instanceof ClassInstanceExpr
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import semmle.code.java.dataflow.DefUse
|
||||
import semmle.code.java.security.Random
|
||||
import semmle.code.java.security.RandomDataSource
|
||||
private import BoundingChecks
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.security.Random
|
||||
import semmle.code.java.security.RandomQuery
|
||||
import semmle.code.java.security.SecurityTests
|
||||
import ArithmeticCommon
|
||||
import DataFlow::PathGraph
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.security.Random
|
||||
import semmle.code.java.security.RandomQuery
|
||||
|
||||
from GetRandomData da, RValue use, PredictableSeedExpr source
|
||||
where
|
||||
|
||||
@@ -68,7 +68,7 @@ private import SSA
|
||||
private import RangeUtils
|
||||
private import semmle.code.java.dataflow.internal.rangeanalysis.SsaReadPositionCommon
|
||||
private import semmle.code.java.controlflow.internal.GuardsLogic
|
||||
private import semmle.code.java.security.Random
|
||||
private import semmle.code.java.security.RandomDataSource
|
||||
private import SignAnalysis
|
||||
private import ModulusAnalysis
|
||||
private import semmle.code.java.Reflection
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.DefUse
|
||||
import semmle.code.java.dataflow.DataFlow6
|
||||
|
||||
/**
|
||||
* The `java.security.SecureRandom` class.
|
||||
* Defines classes representing random data sources.
|
||||
*/
|
||||
class SecureRandomNumberGenerator extends RefType {
|
||||
SecureRandomNumberGenerator() { this.hasQualifiedName("java.security", "SecureRandom") }
|
||||
}
|
||||
|
||||
import java
|
||||
|
||||
/**
|
||||
* A method access that returns random data or writes random data to an argument.
|
||||
@@ -148,149 +143,3 @@ class ApacheCommonsRandomSource extends RandomDataSource {
|
||||
|
||||
override Expr getOutput() { result = this }
|
||||
}
|
||||
|
||||
/**
|
||||
* A method access calling a method declared on `java.security.SecureRandom`
|
||||
* that returns random data or writes random data to an argument.
|
||||
*/
|
||||
class GetRandomData extends StdlibRandomSource {
|
||||
GetRandomData() { 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 DataFlow6::Configuration {
|
||||
PredictableSeedFlowConfiguration() { this = "Random::PredictableSeedFlowConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow6::Node source) {
|
||||
source.asExpr() instanceof PredictableSeedExpr
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow6::Node sink) { isSeeding(sink.asExpr(), _) }
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow6::Node node1, DataFlow6::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(DataFlow6::exprNode(source), DataFlow6::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")
|
||||
}
|
||||
}
|
||||
157
java/ql/src/semmle/code/java/security/RandomQuery.qll
Normal file
157
java/ql/src/semmle/code/java/security/RandomQuery.qll
Normal file
@@ -0,0 +1,157 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.DefUse
|
||||
import semmle.code.java.dataflow.DataFlow6
|
||||
import RandomDataSource
|
||||
|
||||
/**
|
||||
* The `java.security.SecureRandom` class.
|
||||
*/
|
||||
class SecureRandomNumberGenerator extends RefType {
|
||||
SecureRandomNumberGenerator() { this.hasQualifiedName("java.security", "SecureRandom") }
|
||||
}
|
||||
|
||||
/**
|
||||
* A method access calling a method declared on `java.security.SecureRandom`
|
||||
* that returns random data or writes random data to an argument.
|
||||
*/
|
||||
class GetRandomData extends StdlibRandomSource {
|
||||
GetRandomData() { 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 DataFlow6::Configuration {
|
||||
PredictableSeedFlowConfiguration() { this = "Random::PredictableSeedFlowConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow6::Node source) {
|
||||
source.asExpr() instanceof PredictableSeedExpr
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow6::Node sink) { isSeeding(sink.asExpr(), _) }
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow6::Node node1, DataFlow6::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(DataFlow6::exprNode(source), DataFlow6::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")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user