Split up Random.qll

This prevents bringing a dataflow config into scope from utility libraries.
This commit is contained in:
Chris Smowton
2021-07-01 16:25:09 +01:00
parent 80124df78e
commit 643f7dfb87
8 changed files with 166 additions and 160 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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
/**

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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")
}
}

View 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")
}
}