Merge pull request #5843 from JLLeitschuh/feat/JLL/improve_kryo_support

[Java] Fix Kryo FP & Kryo 5 Support
This commit is contained in:
Anders Schack-Mulligen
2021-05-12 09:52:24 +02:00
committed by GitHub
8 changed files with 194 additions and 2 deletions

View File

@@ -292,6 +292,7 @@ private predicate summaryModelCsv(string row) {
"java.util;StringTokenizer;false;StringTokenizer;;;Argument[0];Argument[-1];taint",
"java.beans;XMLDecoder;false;XMLDecoder;;;Argument[0];Argument[-1];taint",
"com.esotericsoftware.kryo.io;Input;false;Input;;;Argument[0];Argument[-1];taint",
"com.esotericsoftware.kryo5.io;Input;false;Input;;;Argument[0];Argument[-1];taint",
"java.io;BufferedInputStream;false;BufferedInputStream;;;Argument[0];Argument[-1];taint",
"java.io;DataInputStream;false;DataInputStream;;;Argument[0];Argument[-1];taint",
"java.io;ByteArrayInputStream;false;ByteArrayInputStream;;;Argument[0];Argument[-1];taint",

View File

@@ -3,19 +3,60 @@
*/
import java
private import semmle.code.java.dataflow.DataFlow
private import semmle.code.java.dataflow.FlowSteps
/**
* The type `com.esotericsoftware.kryo.Kryo`.
*/
class Kryo extends RefType {
Kryo() { this.hasQualifiedName("com.esotericsoftware.kryo", "Kryo") }
Kryo() {
hasQualifiedName("com.esotericsoftware.kryo", "Kryo") or
hasQualifiedName("com.esotericsoftware.kryo5", "Kryo")
}
}
/**
* A Kryo input stream.
*/
class KryoInput extends RefType {
KryoInput() { this.hasQualifiedName("com.esotericsoftware.kryo.io", "Input") }
KryoInput() {
hasQualifiedName("com.esotericsoftware.kryo.io", "Input") or
hasQualifiedName("com.esotericsoftware.kryo5.io", "Input")
}
}
/**
* A Kryo pool.
*/
class KryoPool extends RefType {
KryoPool() {
hasQualifiedName("com.esotericsoftware.kryo.pool", "KryoPool") or
hasQualifiedName("com.esotericsoftware.kryo5.pool", "KryoPool")
}
}
/**
* A Kryo pool builder.
*/
class KryoPoolBuilder extends RefType {
KryoPoolBuilder() {
hasQualifiedName("com.esotericsoftware.kryo.pool", "KryoPool$Builder") or
hasQualifiedName("com.esotericsoftware.kryo5.pool", "KryoPool$Builder")
}
}
/**
* A Kryo pool builder method used in a fluent API call chain.
*/
class KryoPoolBuilderMethod extends Method {
KryoPoolBuilderMethod() {
getDeclaringType() instanceof KryoPoolBuilder and
(
getReturnType() instanceof KryoPoolBuilder or
getReturnType() instanceof KryoPool
)
}
}
/**
@@ -45,3 +86,13 @@ class KryoEnableWhiteListing extends MethodAccess {
)
}
}
/**
* A KryoPool method that uses a Kryo instance.
*/
class KryoPoolRunMethod extends Method {
KryoPoolRunMethod() {
getDeclaringType() instanceof KryoPool and
hasName("run")
}
}

View File

@@ -48,6 +48,65 @@ class SafeKryo extends DataFlow2::Configuration {
ma.getMethod() instanceof KryoReadObjectMethod
)
}
override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
stepKryoPoolBuilderFactoryArgToConstructor(node1, node2) or
stepKryoPoolRunMethodAccessQualifierToFunctionalArgument(node1, node2) or
stepKryoPoolBuilderChainMethod(node1, node2) or
stepKryoPoolBorrowMethod(node1, node2)
}
/**
* Holds when a functional expression is used to create a `KryoPool.Builder`.
* Eg. `new KryoPool.Builder(() -> new Kryo())`
*/
private predicate stepKryoPoolBuilderFactoryArgToConstructor(
DataFlow::Node node1, DataFlow::Node node2
) {
exists(ConstructorCall cc, FunctionalExpr fe |
cc.getConstructedType() instanceof KryoPoolBuilder and
fe.asMethod().getBody().getAStmt().(ReturnStmt).getResult() = node1.asExpr() and
node2.asExpr() = cc and
cc.getArgument(0) = fe
)
}
/**
* Holds when a `KryoPool.run` is called to use a `Kryo` instance.
* Eg. `pool.run(kryo -> ...)`
*/
private predicate stepKryoPoolRunMethodAccessQualifierToFunctionalArgument(
DataFlow::Node node1, DataFlow::Node node2
) {
exists(MethodAccess ma |
ma.getMethod() instanceof KryoPoolRunMethod and
node1.asExpr() = ma.getQualifier() and
ma.getArgument(0).(FunctionalExpr).asMethod().getParameter(0) = node2.asParameter()
)
}
/**
* Holds when a `KryoPool.Builder` method is called fluently.
*/
private predicate stepKryoPoolBuilderChainMethod(DataFlow::Node node1, DataFlow::Node node2) {
exists(MethodAccess ma |
ma.getMethod() instanceof KryoPoolBuilderMethod and
ma = node2.asExpr() and
ma.getQualifier() = node1.asExpr()
)
}
/**
* Holds when a `KryoPool.borrow` method is called.
*/
private predicate stepKryoPoolBorrowMethod(DataFlow::Node node1, DataFlow::Node node2) {
exists(MethodAccess ma |
ma.getMethod() =
any(Method m | m.getDeclaringType() instanceof KryoPool and m.hasName("borrow")) and
node1.asExpr() = ma.getQualifier() and
node2.asExpr() = ma
)
}
}
predicate unsafeDeserialization(MethodAccess ma, Expr sink) {