mirror of
https://github.com/github/codeql.git
synced 2026-05-01 19:55:15 +02:00
Merge pull request #5900 from artem-smotrakov/unsafe-jackson-deserialization
Java: Unsafe deserialization with Jackson
This commit is contained in:
@@ -14,8 +14,8 @@ may have unforeseen effects, such as the execution of arbitrary code.
|
||||
</p>
|
||||
<p>
|
||||
There are many different serialization frameworks. This query currently
|
||||
supports Kryo, XmlDecoder, XStream, SnakeYaml, JYaml, JsonIO, YAMLBeans, HessianBurlap, Castor, Burlap
|
||||
and Java IO serialization through <code>ObjectInputStream</code>/<code>ObjectOutputStream</code>.
|
||||
supports Kryo, XmlDecoder, XStream, SnakeYaml, JYaml, JsonIO, YAMLBeans, HessianBurlap, Castor, Burlap,
|
||||
Jackson and Java IO serialization through <code>ObjectInputStream</code>/<code>ObjectOutputStream</code>.
|
||||
</p>
|
||||
</overview>
|
||||
|
||||
@@ -91,6 +91,15 @@ Remote code execution in JYaml library:
|
||||
JsonIO deserialization vulnerabilities:
|
||||
<a href="https://klezvirus.github.io/Advanced-Web-Hacking/Serialisation/">JsonIO deserialization</a>.
|
||||
</li>
|
||||
<li>
|
||||
Research by Moritz Bechler:
|
||||
<a href="https://www.github.com/mbechler/marshalsec/blob/master/marshalsec.pdf?raw=true">Java Unmarshaller Security - Turning your data into code execution</a>
|
||||
</li>
|
||||
<li>
|
||||
Blog posts by the developer of Jackson libraries:
|
||||
<a href="https://cowtowncoder.medium.com/on-jackson-cves-dont-panic-here-is-what-you-need-to-know-54cd0d6e8062">On Jackson CVEs: Don’t Panic — Here is what you need to know</a>
|
||||
<a href="https://cowtowncoder.medium.com/jackson-2-10-safe-default-typing-2d018f0ce2ba">Jackson 2.10: Safe Default Typing</a>
|
||||
</li>
|
||||
</references>
|
||||
|
||||
</qhelp>
|
||||
|
||||
@@ -12,51 +12,9 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.security.UnsafeDeserialization
|
||||
import semmle.code.java.security.UnsafeDeserializationQuery
|
||||
import DataFlow::PathGraph
|
||||
|
||||
class UnsafeDeserializationConfig extends TaintTracking::Configuration {
|
||||
UnsafeDeserializationConfig() { this = "UnsafeDeserializationConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof UnsafeDeserializationSink }
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(ClassInstanceExpr cie |
|
||||
cie.getArgument(0) = pred.asExpr() and
|
||||
cie = succ.asExpr() and
|
||||
(
|
||||
cie.getConstructor().getDeclaringType() instanceof JsonIoJsonReader or
|
||||
cie.getConstructor().getDeclaringType() instanceof YamlBeansReader or
|
||||
cie.getConstructor().getDeclaringType().getASupertype*() instanceof UnsafeHessianInput or
|
||||
cie.getConstructor().getDeclaringType() instanceof BurlapInput
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(MethodAccess ma |
|
||||
ma.getMethod() instanceof BurlapInputInitMethod and
|
||||
ma.getArgument(0) = pred.asExpr() and
|
||||
ma.getQualifier() = succ.asExpr()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
exists(ClassInstanceExpr cie |
|
||||
cie.getConstructor().getDeclaringType() instanceof JsonIoJsonReader and
|
||||
cie = node.asExpr() and
|
||||
exists(SafeJsonIoConfig sji | sji.hasFlowToExpr(cie.getArgument(1)))
|
||||
)
|
||||
or
|
||||
exists(MethodAccess ma |
|
||||
ma.getMethod() instanceof JsonIoJsonToJavaMethod and
|
||||
ma.getArgument(0) = node.asExpr() and
|
||||
exists(SafeJsonIoConfig sji | sji.hasFlowToExpr(ma.getArgument(1)))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, UnsafeDeserializationConfig conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
select sink.getNode().(UnsafeDeserializationSink).getMethodAccess(), source, sink,
|
||||
|
||||
174
java/ql/src/semmle/code/java/frameworks/Jackson.qll
Normal file
174
java/ql/src/semmle/code/java/frameworks/Jackson.qll
Normal file
@@ -0,0 +1,174 @@
|
||||
/**
|
||||
* Provides classes and predicates for working with the Jackson serialization framework.
|
||||
*/
|
||||
|
||||
import java
|
||||
private import semmle.code.java.Reflection
|
||||
private import semmle.code.java.dataflow.DataFlow
|
||||
|
||||
private class ObjectMapper extends RefType {
|
||||
ObjectMapper() {
|
||||
getASupertype*().hasQualifiedName("com.fasterxml.jackson.databind", "ObjectMapper")
|
||||
}
|
||||
}
|
||||
|
||||
/** A builder for building Jackson's `JsonMapper`. */
|
||||
class MapperBuilder extends RefType {
|
||||
MapperBuilder() {
|
||||
hasQualifiedName("com.fasterxml.jackson.databind.cfg", "MapperBuilder<JsonMapper,Builder>")
|
||||
}
|
||||
}
|
||||
|
||||
private class JsonFactory extends RefType {
|
||||
JsonFactory() { hasQualifiedName("com.fasterxml.jackson.core", "JsonFactory") }
|
||||
}
|
||||
|
||||
private class JsonParser extends RefType {
|
||||
JsonParser() { hasQualifiedName("com.fasterxml.jackson.core", "JsonParser") }
|
||||
}
|
||||
|
||||
/** A type descriptor in Jackson libraries. For example, `java.lang.Class`. */
|
||||
class JacksonTypeDescriptorType extends RefType {
|
||||
JacksonTypeDescriptorType() {
|
||||
this instanceof TypeClass or
|
||||
hasQualifiedName("com.fasterxml.jackson.databind", "JavaType") or
|
||||
hasQualifiedName("com.fasterxml.jackson.core.type", "TypeReference")
|
||||
}
|
||||
}
|
||||
|
||||
/** A method in `ObjectMapper` that deserialize data. */
|
||||
class ObjectMapperReadMethod extends Method {
|
||||
ObjectMapperReadMethod() {
|
||||
this.getDeclaringType() instanceof ObjectMapper and
|
||||
this.hasName(["readValue", "readValues", "treeToValue"])
|
||||
}
|
||||
}
|
||||
|
||||
/** A call that enables the default typing in `ObjectMapper`. */
|
||||
class EnableJacksonDefaultTyping extends MethodAccess {
|
||||
EnableJacksonDefaultTyping() {
|
||||
this.getMethod().getDeclaringType() instanceof ObjectMapper and
|
||||
this.getMethod().hasName("enableDefaultTyping")
|
||||
}
|
||||
}
|
||||
|
||||
/** A qualifier of a call to one of the methods in `ObjectMapper` that deserialize data. */
|
||||
class ObjectMapperReadQualifier extends DataFlow::ExprNode {
|
||||
ObjectMapperReadQualifier() {
|
||||
exists(MethodAccess ma | ma.getQualifier() = this.asExpr() |
|
||||
ma.getMethod() instanceof ObjectMapperReadMethod
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** A source that sets a type validator. */
|
||||
class SetPolymorphicTypeValidatorSource extends DataFlow::ExprNode {
|
||||
SetPolymorphicTypeValidatorSource() {
|
||||
exists(MethodAccess ma, Method m | m = ma.getMethod() |
|
||||
(
|
||||
m.getDeclaringType() instanceof ObjectMapper and
|
||||
m.hasName("setPolymorphicTypeValidator")
|
||||
or
|
||||
m.getDeclaringType() instanceof MapperBuilder and
|
||||
m.hasName("polymorphicTypeValidator")
|
||||
) and
|
||||
this.asExpr() = ma.getQualifier()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Holds if `fromNode` to `toNode` is a dataflow step that resolves a class. */
|
||||
predicate resolveClassStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
exists(ReflectiveClassIdentifierMethodAccess ma |
|
||||
ma.getArgument(0) = fromNode.asExpr() and
|
||||
ma = toNode.asExpr()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `fromNode` to `toNode` is a dataflow step that creates a Jackson parser.
|
||||
*
|
||||
* For example, a `createParser(userString)` call yields a `JsonParser`, which becomes dangerous
|
||||
* if passed to an unsafely-configured `ObjectMapper`'s `readValue` method.
|
||||
*/
|
||||
predicate createJacksonJsonParserStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
exists(MethodAccess ma, Method m | m = ma.getMethod() |
|
||||
(m.getDeclaringType() instanceof ObjectMapper or m.getDeclaringType() instanceof JsonFactory) and
|
||||
m.hasName("createParser") and
|
||||
ma.getArgument(0) = fromNode.asExpr() and
|
||||
ma = toNode.asExpr()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `fromNode` to `toNode` is a dataflow step that creates a Jackson `TreeNode`.
|
||||
*
|
||||
* These are parse trees of user-supplied JSON, which may lead to arbitrary code execution
|
||||
* if passed to an unsafely-configured `ObjectMapper`'s `treeToValue` method.
|
||||
*/
|
||||
predicate createJacksonTreeNodeStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
exists(MethodAccess ma, Method m | m = ma.getMethod() |
|
||||
m.getDeclaringType() instanceof ObjectMapper and
|
||||
m.hasName("readTree") and
|
||||
ma.getArgument(0) = fromNode.asExpr() and
|
||||
ma = toNode.asExpr()
|
||||
)
|
||||
or
|
||||
exists(MethodAccess ma, Method m | m = ma.getMethod() |
|
||||
m.getDeclaringType() instanceof JsonParser and
|
||||
m.hasName("readValueAsTree") and
|
||||
ma.getQualifier() = fromNode.asExpr() and
|
||||
ma = toNode.asExpr()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `type` or one of its supertypes has a field with `JsonTypeInfo` annotation
|
||||
* that enables polymorphic type handling.
|
||||
*/
|
||||
private predicate hasJsonTypeInfoAnnotation(RefType type) {
|
||||
hasFieldWithJsonTypeAnnotation(type.getASupertype*()) or
|
||||
hasJsonTypeInfoAnnotation(type.getAField().getType())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `type` has a field with `JsonTypeInfo` annotation
|
||||
* that enables polymorphic type handling.
|
||||
*/
|
||||
private predicate hasFieldWithJsonTypeAnnotation(RefType type) {
|
||||
exists(Annotation a |
|
||||
type.getAField().getAnAnnotation() = a and
|
||||
a.getType().hasQualifiedName("com.fasterxml.jackson.annotation", "JsonTypeInfo") and
|
||||
a.getValue("use").(VarAccess).getVariable().hasName(["CLASS", "MINIMAL_CLASS"])
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `call` is a method call to a Jackson deserialization method such as `ObjectMapper.readValue(String, Class)`,
|
||||
* and the target deserialized class has a field with a `JsonTypeInfo` annotation that enables polymorphic typing.
|
||||
*/
|
||||
predicate hasArgumentWithUnsafeJacksonAnnotation(MethodAccess call) {
|
||||
call.getMethod() instanceof ObjectMapperReadMethod and
|
||||
exists(RefType argType, int i | i > 0 and argType = call.getArgument(i).getType() |
|
||||
hasJsonTypeInfoAnnotation(argType.(ParameterizedType).getATypeArgument())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `fromNode` to `toNode` is a dataflow step that looks like resolving a class.
|
||||
* A method probably resolves a class if it takes a string, returns a type descriptor,
|
||||
* and its name contains "resolve", "load", etc.
|
||||
*
|
||||
* Any method call that satisfies the rule above is assumed to propagate taint from its string arguments,
|
||||
* so methods that accept user-controlled data but sanitize it or use it for some
|
||||
* completely different purpose before returning a type descriptor could result in false positives.
|
||||
*/
|
||||
predicate looksLikeResolveClassStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
exists(MethodAccess ma, Method m, Expr arg | m = ma.getMethod() and arg = ma.getAnArgument() |
|
||||
m.getReturnType() instanceof JacksonTypeDescriptorType and
|
||||
m.getName().toLowerCase().regexpMatch("(.*)(resolve|load|class|type)(.*)") and
|
||||
arg.getType() instanceof TypeString and
|
||||
arg = fromNode.asExpr() and
|
||||
ma = toNode.asExpr()
|
||||
)
|
||||
}
|
||||
@@ -1,172 +0,0 @@
|
||||
import semmle.code.java.frameworks.Kryo
|
||||
import semmle.code.java.frameworks.XStream
|
||||
import semmle.code.java.frameworks.SnakeYaml
|
||||
import semmle.code.java.frameworks.FastJson
|
||||
import semmle.code.java.frameworks.JYaml
|
||||
import semmle.code.java.frameworks.JsonIo
|
||||
import semmle.code.java.frameworks.YamlBeans
|
||||
import semmle.code.java.frameworks.HessianBurlap
|
||||
import semmle.code.java.frameworks.Castor
|
||||
import semmle.code.java.frameworks.apache.Lang
|
||||
|
||||
class ObjectInputStreamReadObjectMethod extends Method {
|
||||
ObjectInputStreamReadObjectMethod() {
|
||||
this.getDeclaringType().getASourceSupertype*().hasQualifiedName("java.io", "ObjectInputStream") and
|
||||
(this.hasName("readObject") or this.hasName("readUnshared"))
|
||||
}
|
||||
}
|
||||
|
||||
class XMLDecoderReadObjectMethod extends Method {
|
||||
XMLDecoderReadObjectMethod() {
|
||||
this.getDeclaringType().hasQualifiedName("java.beans", "XMLDecoder") and
|
||||
this.hasName("readObject")
|
||||
}
|
||||
}
|
||||
|
||||
class SafeXStream extends DataFlow2::Configuration {
|
||||
SafeXStream() { this = "UnsafeDeserialization::SafeXStream" }
|
||||
|
||||
override predicate isSource(DataFlow::Node src) {
|
||||
any(XStreamEnableWhiteListing ma).getQualifier().(VarAccess).getVariable().getAnAccess() =
|
||||
src.asExpr()
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodAccess ma |
|
||||
sink.asExpr() = ma.getQualifier() and
|
||||
ma.getMethod() instanceof XStreamReadObjectMethod
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class SafeKryo extends DataFlow2::Configuration {
|
||||
SafeKryo() { this = "UnsafeDeserialization::SafeKryo" }
|
||||
|
||||
override predicate isSource(DataFlow::Node src) {
|
||||
any(KryoEnableWhiteListing ma).getQualifier().(VarAccess).getVariable().getAnAccess() =
|
||||
src.asExpr()
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodAccess ma |
|
||||
sink.asExpr() = ma.getQualifier() and
|
||||
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) {
|
||||
exists(Method m | m = ma.getMethod() |
|
||||
m instanceof ObjectInputStreamReadObjectMethod and
|
||||
sink = ma.getQualifier() and
|
||||
not exists(DataFlow::ExprNode node |
|
||||
node.getExpr() = sink and
|
||||
node.getTypeBound()
|
||||
.(RefType)
|
||||
.hasQualifiedName("org.apache.commons.io.serialization", "ValidatingObjectInputStream")
|
||||
)
|
||||
or
|
||||
m instanceof XMLDecoderReadObjectMethod and
|
||||
sink = ma.getQualifier()
|
||||
or
|
||||
m instanceof XStreamReadObjectMethod and
|
||||
sink = ma.getAnArgument() and
|
||||
not exists(SafeXStream sxs | sxs.hasFlowToExpr(ma.getQualifier()))
|
||||
or
|
||||
m instanceof KryoReadObjectMethod and
|
||||
sink = ma.getAnArgument() and
|
||||
not exists(SafeKryo sk | sk.hasFlowToExpr(ma.getQualifier()))
|
||||
or
|
||||
m instanceof MethodApacheSerializationUtilsDeserialize and
|
||||
sink = ma.getArgument(0)
|
||||
or
|
||||
ma instanceof UnsafeSnakeYamlParse and
|
||||
sink = ma.getArgument(0)
|
||||
or
|
||||
ma.getMethod() instanceof FastJsonParseMethod and
|
||||
not fastJsonLooksSafe() and
|
||||
sink = ma.getArgument(0)
|
||||
or
|
||||
ma.getMethod() instanceof JYamlLoaderUnsafeLoadMethod and
|
||||
sink = ma.getArgument(0)
|
||||
or
|
||||
ma.getMethod() instanceof JsonIoJsonToJavaMethod and
|
||||
sink = ma.getArgument(0)
|
||||
or
|
||||
ma.getMethod() instanceof JsonIoReadObjectMethod and
|
||||
sink = ma.getQualifier()
|
||||
or
|
||||
ma.getMethod() instanceof YamlBeansReaderReadMethod and sink = ma.getQualifier()
|
||||
or
|
||||
ma.getMethod() instanceof UnsafeHessianInputReadObjectMethod and sink = ma.getQualifier()
|
||||
or
|
||||
ma.getMethod() instanceof CastorUnmarshalMethod and sink = ma.getAnArgument()
|
||||
or
|
||||
ma.getMethod() instanceof BurlapInputReadObjectMethod and sink = ma.getQualifier()
|
||||
)
|
||||
}
|
||||
|
||||
class UnsafeDeserializationSink extends DataFlow::ExprNode {
|
||||
UnsafeDeserializationSink() { unsafeDeserialization(_, this.getExpr()) }
|
||||
|
||||
MethodAccess getMethodAccess() { unsafeDeserialization(result, this.getExpr()) }
|
||||
}
|
||||
@@ -0,0 +1,318 @@
|
||||
/**
|
||||
* Provides classes and predicates for finding deserialization vulnerabilities.
|
||||
*/
|
||||
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
private import semmle.code.java.dataflow.TaintTracking2
|
||||
private import semmle.code.java.frameworks.Kryo
|
||||
private import semmle.code.java.frameworks.XStream
|
||||
private import semmle.code.java.frameworks.SnakeYaml
|
||||
private import semmle.code.java.frameworks.FastJson
|
||||
private import semmle.code.java.frameworks.JYaml
|
||||
private import semmle.code.java.frameworks.JsonIo
|
||||
private import semmle.code.java.frameworks.YamlBeans
|
||||
private import semmle.code.java.frameworks.HessianBurlap
|
||||
private import semmle.code.java.frameworks.Castor
|
||||
private import semmle.code.java.frameworks.Jackson
|
||||
private import semmle.code.java.frameworks.apache.Lang
|
||||
private import semmle.code.java.Reflection
|
||||
|
||||
private class ObjectInputStreamReadObjectMethod extends Method {
|
||||
ObjectInputStreamReadObjectMethod() {
|
||||
this.getDeclaringType().getASourceSupertype*().hasQualifiedName("java.io", "ObjectInputStream") and
|
||||
(this.hasName("readObject") or this.hasName("readUnshared"))
|
||||
}
|
||||
}
|
||||
|
||||
private class XMLDecoderReadObjectMethod extends Method {
|
||||
XMLDecoderReadObjectMethod() {
|
||||
this.getDeclaringType().hasQualifiedName("java.beans", "XMLDecoder") and
|
||||
this.hasName("readObject")
|
||||
}
|
||||
}
|
||||
|
||||
private class SafeXStream extends DataFlow2::Configuration {
|
||||
SafeXStream() { this = "UnsafeDeserialization::SafeXStream" }
|
||||
|
||||
override predicate isSource(DataFlow::Node src) {
|
||||
any(XStreamEnableWhiteListing ma).getQualifier().(VarAccess).getVariable().getAnAccess() =
|
||||
src.asExpr()
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodAccess ma |
|
||||
sink.asExpr() = ma.getQualifier() and
|
||||
ma.getMethod() instanceof XStreamReadObjectMethod
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class SafeKryo extends DataFlow2::Configuration {
|
||||
SafeKryo() { this = "UnsafeDeserialization::SafeKryo" }
|
||||
|
||||
override predicate isSource(DataFlow::Node src) {
|
||||
any(KryoEnableWhiteListing ma).getQualifier().(VarAccess).getVariable().getAnAccess() =
|
||||
src.asExpr()
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodAccess ma |
|
||||
sink.asExpr() = ma.getQualifier() and
|
||||
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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `ma` is a call that deserializes data from `sink`.
|
||||
*/
|
||||
predicate unsafeDeserialization(MethodAccess ma, Expr sink) {
|
||||
exists(Method m | m = ma.getMethod() |
|
||||
m instanceof ObjectInputStreamReadObjectMethod and
|
||||
sink = ma.getQualifier() and
|
||||
not exists(DataFlow::ExprNode node |
|
||||
node.getExpr() = sink and
|
||||
node.getTypeBound()
|
||||
.(RefType)
|
||||
.hasQualifiedName("org.apache.commons.io.serialization", "ValidatingObjectInputStream")
|
||||
)
|
||||
or
|
||||
m instanceof XMLDecoderReadObjectMethod and
|
||||
sink = ma.getQualifier()
|
||||
or
|
||||
m instanceof XStreamReadObjectMethod and
|
||||
sink = ma.getAnArgument() and
|
||||
not exists(SafeXStream sxs | sxs.hasFlowToExpr(ma.getQualifier()))
|
||||
or
|
||||
m instanceof KryoReadObjectMethod and
|
||||
sink = ma.getAnArgument() and
|
||||
not exists(SafeKryo sk | sk.hasFlowToExpr(ma.getQualifier()))
|
||||
or
|
||||
m instanceof MethodApacheSerializationUtilsDeserialize and
|
||||
sink = ma.getArgument(0)
|
||||
or
|
||||
ma instanceof UnsafeSnakeYamlParse and
|
||||
sink = ma.getArgument(0)
|
||||
or
|
||||
ma.getMethod() instanceof FastJsonParseMethod and
|
||||
not fastJsonLooksSafe() and
|
||||
sink = ma.getArgument(0)
|
||||
or
|
||||
ma.getMethod() instanceof JYamlLoaderUnsafeLoadMethod and
|
||||
sink = ma.getArgument(0)
|
||||
or
|
||||
ma.getMethod() instanceof JsonIoJsonToJavaMethod and
|
||||
sink = ma.getArgument(0)
|
||||
or
|
||||
ma.getMethod() instanceof JsonIoReadObjectMethod and
|
||||
sink = ma.getQualifier()
|
||||
or
|
||||
ma.getMethod() instanceof YamlBeansReaderReadMethod and sink = ma.getQualifier()
|
||||
or
|
||||
ma.getMethod() instanceof UnsafeHessianInputReadObjectMethod and sink = ma.getQualifier()
|
||||
or
|
||||
ma.getMethod() instanceof CastorUnmarshalMethod and sink = ma.getAnArgument()
|
||||
or
|
||||
ma.getMethod() instanceof BurlapInputReadObjectMethod and sink = ma.getQualifier()
|
||||
or
|
||||
ma.getMethod() instanceof ObjectMapperReadMethod and
|
||||
sink = ma.getArgument(0) and
|
||||
(
|
||||
exists(UnsafeTypeConfig config | config.hasFlowToExpr(ma.getAnArgument()))
|
||||
or
|
||||
exists(EnableJacksonDefaultTypingConfig config | config.hasFlowToExpr(ma.getQualifier()))
|
||||
or
|
||||
hasArgumentWithUnsafeJacksonAnnotation(ma)
|
||||
) and
|
||||
not exists(SafeObjectMapperConfig config | config.hasFlowToExpr(ma.getQualifier()))
|
||||
)
|
||||
}
|
||||
|
||||
/** A sink for unsafe deserialization. */
|
||||
class UnsafeDeserializationSink extends DataFlow::ExprNode {
|
||||
UnsafeDeserializationSink() { unsafeDeserialization(_, this.getExpr()) }
|
||||
|
||||
/** Gets a call that triggers unsafe deserialization. */
|
||||
MethodAccess getMethodAccess() { unsafeDeserialization(result, this.getExpr()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks flows from remote user input to a deserialization sink.
|
||||
*/
|
||||
class UnsafeDeserializationConfig extends TaintTracking::Configuration {
|
||||
UnsafeDeserializationConfig() { this = "UnsafeDeserializationConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof UnsafeDeserializationSink }
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(ClassInstanceExpr cie |
|
||||
cie.getArgument(0) = pred.asExpr() and
|
||||
cie = succ.asExpr() and
|
||||
(
|
||||
cie.getConstructor().getDeclaringType() instanceof JsonIoJsonReader or
|
||||
cie.getConstructor().getDeclaringType() instanceof YamlBeansReader or
|
||||
cie.getConstructor().getDeclaringType().getASupertype*() instanceof UnsafeHessianInput or
|
||||
cie.getConstructor().getDeclaringType() instanceof BurlapInput
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(MethodAccess ma |
|
||||
ma.getMethod() instanceof BurlapInputInitMethod and
|
||||
ma.getArgument(0) = pred.asExpr() and
|
||||
ma.getQualifier() = succ.asExpr()
|
||||
)
|
||||
or
|
||||
createJacksonJsonParserStep(pred, succ)
|
||||
or
|
||||
createJacksonTreeNodeStep(pred, succ)
|
||||
}
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
exists(ClassInstanceExpr cie |
|
||||
cie.getConstructor().getDeclaringType() instanceof JsonIoJsonReader and
|
||||
cie = node.asExpr() and
|
||||
exists(SafeJsonIoConfig sji | sji.hasFlowToExpr(cie.getArgument(1)))
|
||||
)
|
||||
or
|
||||
exists(MethodAccess ma |
|
||||
ma.getMethod() instanceof JsonIoJsonToJavaMethod and
|
||||
ma.getArgument(0) = node.asExpr() and
|
||||
exists(SafeJsonIoConfig sji | sji.hasFlowToExpr(ma.getArgument(1)))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks flow from a remote source to a type descriptor (e.g. a `java.lang.Class` instance)
|
||||
* passed to a Jackson deserialization method.
|
||||
*
|
||||
* If this is user-controlled, arbitrary code could be executed while instantiating the user-specified type.
|
||||
*/
|
||||
class UnsafeTypeConfig extends TaintTracking2::Configuration {
|
||||
UnsafeTypeConfig() { this = "UnsafeTypeConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodAccess ma, int i, Expr arg | i > 0 and ma.getArgument(i) = arg |
|
||||
ma.getMethod() instanceof ObjectMapperReadMethod and
|
||||
arg.getType() instanceof JacksonTypeDescriptorType and
|
||||
arg = sink.asExpr()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `fromNode` to `toNode` is a dataflow step that resolves a class
|
||||
* or at least looks like resolving a class.
|
||||
*/
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
resolveClassStep(fromNode, toNode) or
|
||||
looksLikeResolveClassStep(fromNode, toNode)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks flow from `enableDefaultTyping` calls to a subsequent Jackson deserialization method call.
|
||||
*/
|
||||
class EnableJacksonDefaultTypingConfig extends DataFlow2::Configuration {
|
||||
EnableJacksonDefaultTypingConfig() { this = "EnableJacksonDefaultTypingConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node src) {
|
||||
any(EnableJacksonDefaultTyping ma).getQualifier() = src.asExpr()
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof ObjectMapperReadQualifier }
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks flow from calls that set a type validator to a subsequent Jackson deserialization method call,
|
||||
* including across builder method calls.
|
||||
*
|
||||
* Such a Jackson deserialization method call is safe because validation will likely prevent instantiating unexpected types.
|
||||
*/
|
||||
class SafeObjectMapperConfig extends DataFlow2::Configuration {
|
||||
SafeObjectMapperConfig() { this = "SafeObjectMapperConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node src) {
|
||||
src instanceof SetPolymorphicTypeValidatorSource
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof ObjectMapperReadQualifier }
|
||||
|
||||
/**
|
||||
* Holds if `fromNode` to `toNode` is a dataflow step
|
||||
* that configures or creates an `ObjectMapper` via a builder.
|
||||
*/
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
exists(MethodAccess ma, Method m | m = ma.getMethod() |
|
||||
m.getDeclaringType() instanceof MapperBuilder and
|
||||
m.getReturnType()
|
||||
.(RefType)
|
||||
.hasQualifiedName("com.fasterxml.jackson.databind.json",
|
||||
["JsonMapper$Builder", "JsonMapper"]) and
|
||||
fromNode.asExpr() = ma.getQualifier() and
|
||||
ma = toNode.asExpr()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import default
|
||||
import semmle.code.java.security.UnsafeDeserialization
|
||||
import semmle.code.java.security.UnsafeDeserializationQuery
|
||||
|
||||
from Method m, MethodAccess ma
|
||||
where ma.getMethod() = m and unsafeDeserialization(ma, _)
|
||||
|
||||
@@ -12,34 +12,34 @@ public class A {
|
||||
public Object deserialize1(Socket sock) throws java.io.IOException, ClassNotFoundException {
|
||||
InputStream inputStream = sock.getInputStream();
|
||||
ObjectInputStream in = new ObjectInputStream(inputStream);
|
||||
return in.readObject(); // unsafe
|
||||
return in.readObject(); // $unsafeDeserialization
|
||||
}
|
||||
|
||||
public Object deserialize2(Socket sock) throws java.io.IOException, ClassNotFoundException {
|
||||
InputStream inputStream = sock.getInputStream();
|
||||
ObjectInputStream in = new ObjectInputStream(inputStream);
|
||||
return in.readUnshared(); // unsafe
|
||||
return in.readUnshared(); // $unsafeDeserialization
|
||||
}
|
||||
|
||||
public Object deserialize3(Socket sock) throws java.io.IOException {
|
||||
InputStream inputStream = sock.getInputStream();
|
||||
XMLDecoder d = new XMLDecoder(inputStream);
|
||||
return d.readObject(); // unsafe
|
||||
return d.readObject(); // $unsafeDeserialization
|
||||
}
|
||||
|
||||
public Object deserialize4(Socket sock) throws java.io.IOException {
|
||||
XStream xs = new XStream();
|
||||
InputStream inputStream = sock.getInputStream();
|
||||
Reader reader = new InputStreamReader(inputStream);
|
||||
return xs.fromXML(reader); // unsafe
|
||||
return xs.fromXML(reader); // $unsafeDeserialization
|
||||
}
|
||||
|
||||
public void deserialize5(Socket sock) throws java.io.IOException {
|
||||
Kryo kryo = new Kryo();
|
||||
Input input = new Input(sock.getInputStream());
|
||||
A a1 = kryo.readObject(input, A.class); // unsafe
|
||||
A a2 = kryo.readObjectOrNull(input, A.class); // unsafe
|
||||
Object o = kryo.readClassAndObject(input); // unsafe
|
||||
A a1 = kryo.readObject(input, A.class); // $unsafeDeserialization
|
||||
A a2 = kryo.readObjectOrNull(input, A.class); // $unsafeDeserialization
|
||||
Object o = kryo.readClassAndObject(input); // $unsafeDeserialization
|
||||
}
|
||||
|
||||
private Kryo getSafeKryo() throws java.io.IOException {
|
||||
@@ -58,21 +58,21 @@ public class A {
|
||||
public void deserializeSnakeYaml(Socket sock) throws java.io.IOException {
|
||||
Yaml yaml = new Yaml();
|
||||
InputStream input = sock.getInputStream();
|
||||
Object o = yaml.load(input); //unsafe
|
||||
Object o2 = yaml.loadAll(input); //unsafe
|
||||
Object o3 = yaml.parse(new InputStreamReader(input)); //unsafe
|
||||
A o4 = yaml.loadAs(input, A.class); //unsafe
|
||||
A o5 = yaml.loadAs(new InputStreamReader(input), A.class); //unsafe
|
||||
Object o = yaml.load(input); // $unsafeDeserialization
|
||||
Object o2 = yaml.loadAll(input); // $unsafeDeserialization
|
||||
Object o3 = yaml.parse(new InputStreamReader(input)); // $unsafeDeserialization
|
||||
A o4 = yaml.loadAs(input, A.class); // $unsafeDeserialization
|
||||
A o5 = yaml.loadAs(new InputStreamReader(input), A.class); // $unsafeDeserialization
|
||||
}
|
||||
|
||||
public void deserializeSnakeYaml2(Socket sock) throws java.io.IOException {
|
||||
Yaml yaml = new Yaml(new Constructor());
|
||||
InputStream input = sock.getInputStream();
|
||||
Object o = yaml.load(input); //unsafe
|
||||
Object o2 = yaml.loadAll(input); //unsafe
|
||||
Object o3 = yaml.parse(new InputStreamReader(input)); //unsafe
|
||||
A o4 = yaml.loadAs(input, A.class); //unsafe
|
||||
A o5 = yaml.loadAs(new InputStreamReader(input), A.class); //unsafe
|
||||
Object o = yaml.load(input); // $unsafeDeserialization
|
||||
Object o2 = yaml.loadAll(input); // $unsafeDeserialization
|
||||
Object o3 = yaml.parse(new InputStreamReader(input)); // $unsafeDeserialization
|
||||
A o4 = yaml.loadAs(input, A.class); // $unsafeDeserialization
|
||||
A o5 = yaml.loadAs(new InputStreamReader(input), A.class); // $unsafeDeserialization
|
||||
}
|
||||
|
||||
public void deserializeSnakeYaml3(Socket sock) throws java.io.IOException {
|
||||
@@ -88,10 +88,10 @@ public class A {
|
||||
public void deserializeSnakeYaml4(Socket sock) throws java.io.IOException {
|
||||
Yaml yaml = new Yaml(new Constructor(A.class));
|
||||
InputStream input = sock.getInputStream();
|
||||
Object o = yaml.load(input); //unsafe
|
||||
Object o2 = yaml.loadAll(input); //unsafe
|
||||
Object o3 = yaml.parse(new InputStreamReader(input)); //unsafe
|
||||
A o4 = yaml.loadAs(input, A.class); //unsafe
|
||||
A o5 = yaml.loadAs(new InputStreamReader(input), A.class); //unsafe
|
||||
Object o = yaml.load(input); // $unsafeDeserialization
|
||||
Object o2 = yaml.loadAll(input); // $unsafeDeserialization
|
||||
Object o3 = yaml.parse(new InputStreamReader(input)); // $unsafeDeserialization
|
||||
A o4 = yaml.loadAs(input, A.class); // $unsafeDeserialization
|
||||
A o5 = yaml.loadAs(new InputStreamReader(input), A.class); // $unsafeDeserialization
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,14 +5,14 @@ import com.alibaba.fastjson.JSON;
|
||||
public class B {
|
||||
public Object deserializeJson1(Socket sock) throws java.io.IOException {
|
||||
InputStream inputStream = sock.getInputStream();
|
||||
return JSON.parseObject(inputStream, null); // unsafe
|
||||
return JSON.parseObject(inputStream, null); // $unsafeDeserialization
|
||||
}
|
||||
|
||||
public Object deserializeJson2(Socket sock) throws java.io.IOException {
|
||||
InputStream inputStream = sock.getInputStream();
|
||||
byte[] bytes = new byte[100];
|
||||
inputStream.read(bytes);
|
||||
return JSON.parse(bytes); // unsafe
|
||||
return JSON.parse(bytes); // $unsafeDeserialization
|
||||
}
|
||||
|
||||
public Object deserializeJson3(Socket sock) throws java.io.IOException {
|
||||
@@ -20,7 +20,7 @@ public class B {
|
||||
byte[] bytes = new byte[100];
|
||||
inputStream.read(bytes);
|
||||
String s = new String(bytes);
|
||||
return JSON.parseObject(s); // unsafe
|
||||
return JSON.parseObject(s); // $unsafeDeserialization
|
||||
}
|
||||
|
||||
public Object deserializeJson4(Socket sock) throws java.io.IOException {
|
||||
@@ -28,6 +28,6 @@ public class B {
|
||||
byte[] bytes = new byte[100];
|
||||
inputStream.read(bytes);
|
||||
String s = new String(bytes);
|
||||
return JSON.parse(s); // unsafe
|
||||
return JSON.parse(s); // $unsafeDeserialization
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,16 +21,16 @@ public class C {
|
||||
@GetMapping(value = "jyaml")
|
||||
public void bad1(HttpServletRequest request) throws Exception {
|
||||
String data = request.getParameter("data");
|
||||
Yaml.load(data); //bad
|
||||
Yaml.loadStream(data); //bad
|
||||
Yaml.loadStreamOfType(data, Object.class); //bad
|
||||
Yaml.loadType(data, Object.class); //bad
|
||||
Yaml.load(data); // $unsafeDeserialization
|
||||
Yaml.loadStream(data); // $unsafeDeserialization
|
||||
Yaml.loadStreamOfType(data, Object.class); // $unsafeDeserialization
|
||||
Yaml.loadType(data, Object.class); // $unsafeDeserialization
|
||||
|
||||
org.ho.yaml.YamlConfig yamlConfig = new YamlConfig();
|
||||
yamlConfig.load(data); //bad
|
||||
yamlConfig.loadStream(data); //bad
|
||||
yamlConfig.loadStreamOfType(data, Object.class); //bad
|
||||
yamlConfig.loadType(data, Object.class); //bad
|
||||
yamlConfig.load(data); // $unsafeDeserialization
|
||||
yamlConfig.loadStream(data); // $unsafeDeserialization
|
||||
yamlConfig.loadStreamOfType(data, Object.class); // $unsafeDeserialization
|
||||
yamlConfig.loadType(data, Object.class); // $unsafeDeserialization
|
||||
}
|
||||
|
||||
@GetMapping(value = "jsonio")
|
||||
@@ -40,19 +40,19 @@ public class C {
|
||||
HashMap hashMap = new HashMap();
|
||||
hashMap.put("USE_MAPS", true);
|
||||
|
||||
JsonReader.jsonToJava(data); //bad
|
||||
JsonReader.jsonToJava(data); // $unsafeDeserialization
|
||||
|
||||
JsonReader jr = new JsonReader(data, null); //bad
|
||||
jr.readObject();
|
||||
JsonReader jr = new JsonReader(data, null);
|
||||
jr.readObject(); // $unsafeDeserialization
|
||||
}
|
||||
|
||||
@GetMapping(value = "yamlbeans")
|
||||
public void bad3(HttpServletRequest request) throws Exception {
|
||||
String data = request.getParameter("data");
|
||||
YamlReader r = new YamlReader(data);
|
||||
r.read(); //bad
|
||||
r.read(Object.class); //bad
|
||||
r.read(Object.class, Object.class); //bad
|
||||
r.read(); // $unsafeDeserialization
|
||||
r.read(Object.class); // $unsafeDeserialization
|
||||
r.read(Object.class, Object.class); // $unsafeDeserialization
|
||||
}
|
||||
|
||||
@GetMapping(value = "hessian")
|
||||
@@ -60,8 +60,8 @@ public class C {
|
||||
byte[] bytes = request.getParameter("data").getBytes();
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
|
||||
HessianInput hessianInput = new HessianInput(bis);
|
||||
hessianInput.readObject(); //bad
|
||||
hessianInput.readObject(Object.class); //bad
|
||||
hessianInput.readObject(); // $unsafeDeserialization
|
||||
hessianInput.readObject(Object.class); // $unsafeDeserialization
|
||||
}
|
||||
|
||||
@GetMapping(value = "hessian2")
|
||||
@@ -69,14 +69,14 @@ public class C {
|
||||
byte[] bytes = request.getParameter("data").getBytes();
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
|
||||
Hessian2Input hessianInput = new Hessian2Input(bis);
|
||||
hessianInput.readObject(); //bad
|
||||
hessianInput.readObject(Object.class); //bad
|
||||
hessianInput.readObject(); // $unsafeDeserialization
|
||||
hessianInput.readObject(Object.class); // $unsafeDeserialization
|
||||
}
|
||||
|
||||
@GetMapping(value = "castor")
|
||||
public void bad6(HttpServletRequest request) throws Exception {
|
||||
Unmarshaller unmarshaller = new Unmarshaller();
|
||||
unmarshaller.unmarshal(new StringReader(request.getParameter("data"))); //bad
|
||||
unmarshaller.unmarshal(new StringReader(request.getParameter("data"))); // $unsafeDeserialization
|
||||
}
|
||||
|
||||
@GetMapping(value = "burlap")
|
||||
@@ -84,11 +84,11 @@ public class C {
|
||||
byte[] serializedData = request.getParameter("data").getBytes();
|
||||
ByteArrayInputStream is = new ByteArrayInputStream(serializedData);
|
||||
BurlapInput burlapInput = new BurlapInput(is);
|
||||
burlapInput.readObject(); //bad
|
||||
burlapInput.readObject(); // $unsafeDeserialization
|
||||
|
||||
BurlapInput burlapInput1 = new BurlapInput();
|
||||
burlapInput1.init(is);
|
||||
burlapInput1.readObject(); //bad
|
||||
burlapInput1.readObject(); // $unsafeDeserialization
|
||||
}
|
||||
|
||||
@GetMapping(value = "jsonio1")
|
||||
|
||||
209
java/ql/test/query-tests/security/CWE-502/JacksonTest.java
Normal file
209
java/ql/test/query-tests/security/CWE-502/JacksonTest.java
Normal file
@@ -0,0 +1,209 @@
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
import com.fasterxml.jackson.databind.JavaType;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.json.JsonMapper;
|
||||
import com.fasterxml.jackson.databind.jsontype.BasicPolymorphicTypeValidator;
|
||||
import com.fasterxml.jackson.databind.jsontype.PolymorphicTypeValidator;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.util.List;
|
||||
|
||||
public class JacksonTest {
|
||||
|
||||
public static void withSocket(Action<String> action) throws Exception {
|
||||
try (ServerSocket serverSocket = new ServerSocket(0)) {
|
||||
try (Socket socket = serverSocket.accept()) {
|
||||
byte[] bytes = new byte[1024];
|
||||
int n = socket.getInputStream().read(bytes);
|
||||
String jexlExpr = new String(bytes, 0, n);
|
||||
action.run(jexlExpr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface Action<T> {
|
||||
void run(T object) throws Exception;
|
||||
}
|
||||
|
||||
abstract class PhoneNumber implements Serializable {
|
||||
public int areaCode;
|
||||
public int local;
|
||||
}
|
||||
|
||||
class DomesticNumber extends PhoneNumber {
|
||||
}
|
||||
|
||||
class InternationalNumber extends PhoneNumber {
|
||||
public int countryCode;
|
||||
}
|
||||
|
||||
class Employee extends Person {
|
||||
}
|
||||
|
||||
class Person {
|
||||
public String name;
|
||||
public int age;
|
||||
|
||||
// this annotation enables polymorphic type handling
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
|
||||
public Object phone;
|
||||
}
|
||||
|
||||
class Task {
|
||||
public Person assignee;
|
||||
}
|
||||
|
||||
class Tag implements Serializable {
|
||||
public String title;
|
||||
}
|
||||
|
||||
class Cat {
|
||||
public String name;
|
||||
public Serializable tag;
|
||||
}
|
||||
|
||||
class UnsafePersonDeserialization {
|
||||
|
||||
// BAD: Person has a field with an annotation that enables polymorphic type
|
||||
// handling
|
||||
private static void testUnsafeDeserialization() throws Exception {
|
||||
JacksonTest.withSocket(string -> {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
mapper.readValue(string, Person.class); // $unsafeDeserialization
|
||||
});
|
||||
}
|
||||
|
||||
// BAD: Employee extends Person that has a field with an annotation that enables
|
||||
// polymorphic type handling
|
||||
private static void testUnsafeDeserializationWithExtendedClass() throws Exception {
|
||||
JacksonTest.withSocket(string -> {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
mapper.readValue(string, Employee.class); // $unsafeDeserialization
|
||||
});
|
||||
}
|
||||
|
||||
// BAD: Task has a Person field that has a field with an annotation that enables
|
||||
// polymorphic type handling
|
||||
private static void testUnsafeDeserializationWithWrapper() throws Exception {
|
||||
JacksonTest.withSocket(string -> {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
mapper.readValue(string, Task.class); // $unsafeDeserialization
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class SaferPersonDeserialization {
|
||||
|
||||
// GOOD: Despite enabled polymorphic type handling, this is safe because ObjectMapper
|
||||
// has a validator
|
||||
private static void testSafeDeserializationWithValidator() throws Exception {
|
||||
JacksonTest.withSocket(string -> {
|
||||
PolymorphicTypeValidator ptv =
|
||||
BasicPolymorphicTypeValidator.builder()
|
||||
.allowIfSubType("only.allowed.package")
|
||||
.build();
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
mapper.setPolymorphicTypeValidator(ptv);
|
||||
|
||||
mapper.readValue(string, Person.class);
|
||||
});
|
||||
}
|
||||
|
||||
// GOOD: Despite enabled polymorphic type handling, this is safe because ObjectMapper
|
||||
// has a validator
|
||||
private static void testSafeDeserializationWithValidatorAndBuilder() throws Exception {
|
||||
JacksonTest.withSocket(string -> {
|
||||
PolymorphicTypeValidator ptv =
|
||||
BasicPolymorphicTypeValidator.builder()
|
||||
.allowIfSubType("only.allowed.package")
|
||||
.build();
|
||||
|
||||
ObjectMapper mapper = JsonMapper.builder()
|
||||
.polymorphicTypeValidator(ptv)
|
||||
.build();
|
||||
|
||||
mapper.readValue(string, Person.class);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class UnsafeCatDeserialization {
|
||||
|
||||
// BAD: deserializing untrusted input while polymorphic type handling is on
|
||||
private static void testUnsafeDeserialization() throws Exception {
|
||||
JacksonTest.withSocket(string -> {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
mapper.enableDefaultTyping(); // this enables polymorphic type handling
|
||||
mapper.readValue(string, Cat.class); // $unsafeDeserialization
|
||||
});
|
||||
}
|
||||
|
||||
// BAD: deserializing untrusted input while polymorphic type handling is on
|
||||
private static void testUnsafeDeserializationWithObjectMapperReadValues() throws Exception {
|
||||
JacksonTest.withSocket(string -> {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
mapper.enableDefaultTyping();
|
||||
mapper.readValues(new JsonFactory().createParser(string), Cat.class).readAll(); // $unsafeDeserialization
|
||||
});
|
||||
}
|
||||
|
||||
// BAD: deserializing untrusted input while polymorphic type handling is on
|
||||
private static void testUnsafeDeserializationWithObjectMapperTreeToValue() throws Exception {
|
||||
JacksonTest.withSocket(string -> {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
mapper.enableDefaultTyping();
|
||||
mapper.treeToValue(mapper.readTree(string), Cat.class); // $unsafeDeserialization
|
||||
});
|
||||
}
|
||||
|
||||
// BAD: an attacker can control both data and type of deserialized object
|
||||
private static void testUnsafeDeserializationWithUnsafeClass() throws Exception {
|
||||
JacksonTest.withSocket(input -> {
|
||||
String[] parts = input.split(";");
|
||||
String data = parts[0];
|
||||
String type = parts[1];
|
||||
Class clazz = Class.forName(type);
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
mapper.readValue(data, clazz); // $unsafeDeserialization
|
||||
});
|
||||
}
|
||||
|
||||
// BAD: an attacker can control both data and type of deserialized object
|
||||
private static void testUnsafeDeserializationWithUnsafeClassAndCustomTypeResolver() throws Exception {
|
||||
JacksonTest.withSocket(input -> {
|
||||
String[] parts = input.split(";");
|
||||
String data = parts[0];
|
||||
String type = parts[1];
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
mapper.readValue(data, resolveImpl(type, mapper)); // $unsafeDeserialization
|
||||
});
|
||||
}
|
||||
|
||||
private static JavaType resolveImpl(String type, ObjectMapper mapper) throws Exception {
|
||||
return mapper.constructType(Class.forName(type));
|
||||
}
|
||||
}
|
||||
|
||||
class SaferCatDeserialization {
|
||||
|
||||
// GOOD: Despite enabled polymorphic type handling, this is safe because ObjectMapper
|
||||
// has a validator
|
||||
private static void testUnsafeDeserialization() throws Exception {
|
||||
JacksonTest.withSocket(string -> {
|
||||
PolymorphicTypeValidator ptv =
|
||||
BasicPolymorphicTypeValidator.builder()
|
||||
.allowIfSubType("only.allowed.pachage")
|
||||
.build();
|
||||
|
||||
ObjectMapper mapper = JsonMapper.builder().polymorphicTypeValidator(ptv).build();
|
||||
mapper.enableDefaultTyping(); // this enables polymorphic type handling
|
||||
|
||||
mapper.readValue(string, Cat.class);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ public class TestMessageBodyReader implements MessageBodyReader<Object> {
|
||||
public Object readFrom(Class<Object> type, Type genericType, Annotation[] annotations, MediaType mediaType,
|
||||
MultivaluedMap<String, String> httpHeaders, InputStream entityStream) throws IOException {
|
||||
try {
|
||||
return new ObjectInputStream(entityStream).readObject();
|
||||
return new ObjectInputStream(entityStream).readObject(); // $unsafeDeserialization
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
@@ -1,229 +0,0 @@
|
||||
edges
|
||||
| A.java:13:31:13:51 | getInputStream(...) : InputStream | A.java:14:50:14:60 | inputStream : InputStream |
|
||||
| A.java:13:31:13:51 | getInputStream(...) : InputStream | A.java:15:12:15:13 | in |
|
||||
| A.java:14:28:14:61 | new ObjectInputStream(...) : ObjectInputStream | A.java:15:12:15:13 | in |
|
||||
| A.java:14:50:14:60 | inputStream : InputStream | A.java:14:28:14:61 | new ObjectInputStream(...) : ObjectInputStream |
|
||||
| A.java:19:31:19:51 | getInputStream(...) : InputStream | A.java:20:50:20:60 | inputStream : InputStream |
|
||||
| A.java:19:31:19:51 | getInputStream(...) : InputStream | A.java:21:12:21:13 | in |
|
||||
| A.java:20:28:20:61 | new ObjectInputStream(...) : ObjectInputStream | A.java:21:12:21:13 | in |
|
||||
| A.java:20:50:20:60 | inputStream : InputStream | A.java:20:28:20:61 | new ObjectInputStream(...) : ObjectInputStream |
|
||||
| A.java:25:31:25:51 | getInputStream(...) : InputStream | A.java:26:35:26:45 | inputStream : InputStream |
|
||||
| A.java:26:20:26:46 | new XMLDecoder(...) : XMLDecoder | A.java:27:12:27:12 | d |
|
||||
| A.java:26:35:26:45 | inputStream : InputStream | A.java:26:20:26:46 | new XMLDecoder(...) : XMLDecoder |
|
||||
| A.java:32:31:32:51 | getInputStream(...) : InputStream | A.java:33:43:33:53 | inputStream : InputStream |
|
||||
| A.java:33:21:33:54 | new InputStreamReader(...) : InputStreamReader | A.java:34:23:34:28 | reader |
|
||||
| A.java:33:43:33:53 | inputStream : InputStream | A.java:33:21:33:54 | new InputStreamReader(...) : InputStreamReader |
|
||||
| A.java:39:19:39:50 | new Input(...) : Input | A.java:40:28:40:32 | input |
|
||||
| A.java:39:19:39:50 | new Input(...) : Input | A.java:41:34:41:38 | input |
|
||||
| A.java:39:19:39:50 | new Input(...) : Input | A.java:42:40:42:44 | input |
|
||||
| A.java:39:29:39:49 | getInputStream(...) : InputStream | A.java:39:19:39:50 | new Input(...) : Input |
|
||||
| A.java:60:25:60:45 | getInputStream(...) : InputStream | A.java:61:26:61:30 | input |
|
||||
| A.java:60:25:60:45 | getInputStream(...) : InputStream | A.java:62:30:62:34 | input |
|
||||
| A.java:60:25:60:45 | getInputStream(...) : InputStream | A.java:63:50:63:54 | input : InputStream |
|
||||
| A.java:60:25:60:45 | getInputStream(...) : InputStream | A.java:64:24:64:28 | input |
|
||||
| A.java:60:25:60:45 | getInputStream(...) : InputStream | A.java:65:46:65:50 | input : InputStream |
|
||||
| A.java:63:50:63:54 | input : InputStream | A.java:63:28:63:55 | new InputStreamReader(...) |
|
||||
| A.java:65:46:65:50 | input : InputStream | A.java:65:24:65:51 | new InputStreamReader(...) |
|
||||
| A.java:70:25:70:45 | getInputStream(...) : InputStream | A.java:71:26:71:30 | input |
|
||||
| A.java:70:25:70:45 | getInputStream(...) : InputStream | A.java:72:30:72:34 | input |
|
||||
| A.java:70:25:70:45 | getInputStream(...) : InputStream | A.java:73:50:73:54 | input : InputStream |
|
||||
| A.java:70:25:70:45 | getInputStream(...) : InputStream | A.java:74:24:74:28 | input |
|
||||
| A.java:70:25:70:45 | getInputStream(...) : InputStream | A.java:75:46:75:50 | input : InputStream |
|
||||
| A.java:73:50:73:54 | input : InputStream | A.java:73:28:73:55 | new InputStreamReader(...) |
|
||||
| A.java:75:46:75:50 | input : InputStream | A.java:75:24:75:51 | new InputStreamReader(...) |
|
||||
| A.java:90:25:90:45 | getInputStream(...) : InputStream | A.java:91:26:91:30 | input |
|
||||
| A.java:90:25:90:45 | getInputStream(...) : InputStream | A.java:92:30:92:34 | input |
|
||||
| A.java:90:25:90:45 | getInputStream(...) : InputStream | A.java:93:50:93:54 | input : InputStream |
|
||||
| A.java:90:25:90:45 | getInputStream(...) : InputStream | A.java:94:24:94:28 | input |
|
||||
| A.java:90:25:90:45 | getInputStream(...) : InputStream | A.java:95:46:95:50 | input : InputStream |
|
||||
| A.java:93:50:93:54 | input : InputStream | A.java:93:28:93:55 | new InputStreamReader(...) |
|
||||
| A.java:95:46:95:50 | input : InputStream | A.java:95:24:95:51 | new InputStreamReader(...) |
|
||||
| B.java:7:31:7:51 | getInputStream(...) : InputStream | B.java:8:29:8:39 | inputStream |
|
||||
| B.java:12:31:12:51 | getInputStream(...) : InputStream | B.java:14:5:14:15 | inputStream : InputStream |
|
||||
| B.java:14:5:14:15 | inputStream : InputStream | B.java:14:22:14:26 | bytes [post update] : byte[] |
|
||||
| B.java:14:22:14:26 | bytes [post update] : byte[] | B.java:15:23:15:27 | bytes |
|
||||
| B.java:19:31:19:51 | getInputStream(...) : InputStream | B.java:21:5:21:15 | inputStream : InputStream |
|
||||
| B.java:21:5:21:15 | inputStream : InputStream | B.java:21:22:21:26 | bytes [post update] : byte[] |
|
||||
| B.java:21:22:21:26 | bytes [post update] : byte[] | B.java:23:29:23:29 | s |
|
||||
| B.java:27:31:27:51 | getInputStream(...) : InputStream | B.java:29:5:29:15 | inputStream : InputStream |
|
||||
| B.java:29:5:29:15 | inputStream : InputStream | B.java:29:22:29:26 | bytes [post update] : byte[] |
|
||||
| B.java:29:22:29:26 | bytes [post update] : byte[] | B.java:31:23:31:23 | s |
|
||||
| C.java:23:17:23:44 | getParameter(...) : String | C.java:24:13:24:16 | data |
|
||||
| C.java:23:17:23:44 | getParameter(...) : String | C.java:25:19:25:22 | data |
|
||||
| C.java:23:17:23:44 | getParameter(...) : String | C.java:26:25:26:28 | data |
|
||||
| C.java:23:17:23:44 | getParameter(...) : String | C.java:27:17:27:20 | data |
|
||||
| C.java:23:17:23:44 | getParameter(...) : String | C.java:30:19:30:22 | data |
|
||||
| C.java:23:17:23:44 | getParameter(...) : String | C.java:31:25:31:28 | data |
|
||||
| C.java:23:17:23:44 | getParameter(...) : String | C.java:32:31:32:34 | data |
|
||||
| C.java:23:17:23:44 | getParameter(...) : String | C.java:33:23:33:26 | data |
|
||||
| C.java:38:17:38:44 | getParameter(...) : String | C.java:43:25:43:28 | data |
|
||||
| C.java:38:17:38:44 | getParameter(...) : String | C.java:46:3:46:4 | jr |
|
||||
| C.java:51:17:51:44 | getParameter(...) : String | C.java:53:3:53:3 | r |
|
||||
| C.java:51:17:51:44 | getParameter(...) : String | C.java:54:3:54:3 | r |
|
||||
| C.java:51:17:51:44 | getParameter(...) : String | C.java:55:3:55:3 | r |
|
||||
| C.java:60:18:60:45 | getParameter(...) : String | C.java:61:55:61:59 | bytes : byte[] |
|
||||
| C.java:60:18:60:45 | getParameter(...) : String | C.java:63:3:63:14 | hessianInput |
|
||||
| C.java:60:18:60:45 | getParameter(...) : String | C.java:64:3:64:14 | hessianInput |
|
||||
| C.java:61:30:61:60 | new ByteArrayInputStream(...) : ByteArrayInputStream | C.java:63:3:63:14 | hessianInput |
|
||||
| C.java:61:30:61:60 | new ByteArrayInputStream(...) : ByteArrayInputStream | C.java:64:3:64:14 | hessianInput |
|
||||
| C.java:61:55:61:59 | bytes : byte[] | C.java:61:30:61:60 | new ByteArrayInputStream(...) : ByteArrayInputStream |
|
||||
| C.java:69:18:69:45 | getParameter(...) : String | C.java:70:55:70:59 | bytes : byte[] |
|
||||
| C.java:69:18:69:45 | getParameter(...) : String | C.java:72:3:72:14 | hessianInput |
|
||||
| C.java:69:18:69:45 | getParameter(...) : String | C.java:73:3:73:14 | hessianInput |
|
||||
| C.java:70:30:70:60 | new ByteArrayInputStream(...) : ByteArrayInputStream | C.java:72:3:72:14 | hessianInput |
|
||||
| C.java:70:30:70:60 | new ByteArrayInputStream(...) : ByteArrayInputStream | C.java:73:3:73:14 | hessianInput |
|
||||
| C.java:70:55:70:59 | bytes : byte[] | C.java:70:30:70:60 | new ByteArrayInputStream(...) : ByteArrayInputStream |
|
||||
| C.java:79:43:79:70 | getParameter(...) : String | C.java:79:26:79:71 | new StringReader(...) |
|
||||
| C.java:84:27:84:54 | getParameter(...) : String | C.java:85:54:85:67 | serializedData : byte[] |
|
||||
| C.java:84:27:84:54 | getParameter(...) : String | C.java:87:3:87:13 | burlapInput |
|
||||
| C.java:84:27:84:54 | getParameter(...) : String | C.java:91:3:91:14 | burlapInput1 |
|
||||
| C.java:85:29:85:68 | new ByteArrayInputStream(...) : ByteArrayInputStream | C.java:87:3:87:13 | burlapInput |
|
||||
| C.java:85:29:85:68 | new ByteArrayInputStream(...) : ByteArrayInputStream | C.java:91:3:91:14 | burlapInput1 |
|
||||
| C.java:85:54:85:67 | serializedData : byte[] | C.java:85:29:85:68 | new ByteArrayInputStream(...) : ByteArrayInputStream |
|
||||
| TestMessageBodyReader.java:20:55:20:78 | entityStream : InputStream | TestMessageBodyReader.java:22:18:22:52 | new ObjectInputStream(...) |
|
||||
| TestMessageBodyReader.java:20:55:20:78 | entityStream : InputStream | TestMessageBodyReader.java:22:40:22:51 | entityStream : InputStream |
|
||||
| TestMessageBodyReader.java:22:40:22:51 | entityStream : InputStream | TestMessageBodyReader.java:22:18:22:52 | new ObjectInputStream(...) |
|
||||
nodes
|
||||
| A.java:13:31:13:51 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
|
||||
| A.java:14:28:14:61 | new ObjectInputStream(...) : ObjectInputStream | semmle.label | new ObjectInputStream(...) : ObjectInputStream |
|
||||
| A.java:14:50:14:60 | inputStream : InputStream | semmle.label | inputStream : InputStream |
|
||||
| A.java:15:12:15:13 | in | semmle.label | in |
|
||||
| A.java:19:31:19:51 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
|
||||
| A.java:20:28:20:61 | new ObjectInputStream(...) : ObjectInputStream | semmle.label | new ObjectInputStream(...) : ObjectInputStream |
|
||||
| A.java:20:50:20:60 | inputStream : InputStream | semmle.label | inputStream : InputStream |
|
||||
| A.java:21:12:21:13 | in | semmle.label | in |
|
||||
| A.java:25:31:25:51 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
|
||||
| A.java:26:20:26:46 | new XMLDecoder(...) : XMLDecoder | semmle.label | new XMLDecoder(...) : XMLDecoder |
|
||||
| A.java:26:35:26:45 | inputStream : InputStream | semmle.label | inputStream : InputStream |
|
||||
| A.java:27:12:27:12 | d | semmle.label | d |
|
||||
| A.java:32:31:32:51 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
|
||||
| A.java:33:21:33:54 | new InputStreamReader(...) : InputStreamReader | semmle.label | new InputStreamReader(...) : InputStreamReader |
|
||||
| A.java:33:43:33:53 | inputStream : InputStream | semmle.label | inputStream : InputStream |
|
||||
| A.java:34:23:34:28 | reader | semmle.label | reader |
|
||||
| A.java:39:19:39:50 | new Input(...) : Input | semmle.label | new Input(...) : Input |
|
||||
| A.java:39:29:39:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
|
||||
| A.java:40:28:40:32 | input | semmle.label | input |
|
||||
| A.java:41:34:41:38 | input | semmle.label | input |
|
||||
| A.java:42:40:42:44 | input | semmle.label | input |
|
||||
| A.java:60:25:60:45 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
|
||||
| A.java:61:26:61:30 | input | semmle.label | input |
|
||||
| A.java:62:30:62:34 | input | semmle.label | input |
|
||||
| A.java:63:28:63:55 | new InputStreamReader(...) | semmle.label | new InputStreamReader(...) |
|
||||
| A.java:63:50:63:54 | input : InputStream | semmle.label | input : InputStream |
|
||||
| A.java:64:24:64:28 | input | semmle.label | input |
|
||||
| A.java:65:24:65:51 | new InputStreamReader(...) | semmle.label | new InputStreamReader(...) |
|
||||
| A.java:65:46:65:50 | input : InputStream | semmle.label | input : InputStream |
|
||||
| A.java:70:25:70:45 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
|
||||
| A.java:71:26:71:30 | input | semmle.label | input |
|
||||
| A.java:72:30:72:34 | input | semmle.label | input |
|
||||
| A.java:73:28:73:55 | new InputStreamReader(...) | semmle.label | new InputStreamReader(...) |
|
||||
| A.java:73:50:73:54 | input : InputStream | semmle.label | input : InputStream |
|
||||
| A.java:74:24:74:28 | input | semmle.label | input |
|
||||
| A.java:75:24:75:51 | new InputStreamReader(...) | semmle.label | new InputStreamReader(...) |
|
||||
| A.java:75:46:75:50 | input : InputStream | semmle.label | input : InputStream |
|
||||
| A.java:90:25:90:45 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
|
||||
| A.java:91:26:91:30 | input | semmle.label | input |
|
||||
| A.java:92:30:92:34 | input | semmle.label | input |
|
||||
| A.java:93:28:93:55 | new InputStreamReader(...) | semmle.label | new InputStreamReader(...) |
|
||||
| A.java:93:50:93:54 | input : InputStream | semmle.label | input : InputStream |
|
||||
| A.java:94:24:94:28 | input | semmle.label | input |
|
||||
| A.java:95:24:95:51 | new InputStreamReader(...) | semmle.label | new InputStreamReader(...) |
|
||||
| A.java:95:46:95:50 | input : InputStream | semmle.label | input : InputStream |
|
||||
| B.java:7:31:7:51 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
|
||||
| B.java:8:29:8:39 | inputStream | semmle.label | inputStream |
|
||||
| B.java:12:31:12:51 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
|
||||
| B.java:14:5:14:15 | inputStream : InputStream | semmle.label | inputStream : InputStream |
|
||||
| B.java:14:22:14:26 | bytes [post update] : byte[] | semmle.label | bytes [post update] : byte[] |
|
||||
| B.java:15:23:15:27 | bytes | semmle.label | bytes |
|
||||
| B.java:19:31:19:51 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
|
||||
| B.java:21:5:21:15 | inputStream : InputStream | semmle.label | inputStream : InputStream |
|
||||
| B.java:21:22:21:26 | bytes [post update] : byte[] | semmle.label | bytes [post update] : byte[] |
|
||||
| B.java:23:29:23:29 | s | semmle.label | s |
|
||||
| B.java:27:31:27:51 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
|
||||
| B.java:29:5:29:15 | inputStream : InputStream | semmle.label | inputStream : InputStream |
|
||||
| B.java:29:22:29:26 | bytes [post update] : byte[] | semmle.label | bytes [post update] : byte[] |
|
||||
| B.java:31:23:31:23 | s | semmle.label | s |
|
||||
| C.java:23:17:23:44 | getParameter(...) : String | semmle.label | getParameter(...) : String |
|
||||
| C.java:24:13:24:16 | data | semmle.label | data |
|
||||
| C.java:25:19:25:22 | data | semmle.label | data |
|
||||
| C.java:26:25:26:28 | data | semmle.label | data |
|
||||
| C.java:27:17:27:20 | data | semmle.label | data |
|
||||
| C.java:30:19:30:22 | data | semmle.label | data |
|
||||
| C.java:31:25:31:28 | data | semmle.label | data |
|
||||
| C.java:32:31:32:34 | data | semmle.label | data |
|
||||
| C.java:33:23:33:26 | data | semmle.label | data |
|
||||
| C.java:38:17:38:44 | getParameter(...) : String | semmle.label | getParameter(...) : String |
|
||||
| C.java:43:25:43:28 | data | semmle.label | data |
|
||||
| C.java:46:3:46:4 | jr | semmle.label | jr |
|
||||
| C.java:51:17:51:44 | getParameter(...) : String | semmle.label | getParameter(...) : String |
|
||||
| C.java:53:3:53:3 | r | semmle.label | r |
|
||||
| C.java:54:3:54:3 | r | semmle.label | r |
|
||||
| C.java:55:3:55:3 | r | semmle.label | r |
|
||||
| C.java:60:18:60:45 | getParameter(...) : String | semmle.label | getParameter(...) : String |
|
||||
| C.java:61:30:61:60 | new ByteArrayInputStream(...) : ByteArrayInputStream | semmle.label | new ByteArrayInputStream(...) : ByteArrayInputStream |
|
||||
| C.java:61:55:61:59 | bytes : byte[] | semmle.label | bytes : byte[] |
|
||||
| C.java:63:3:63:14 | hessianInput | semmle.label | hessianInput |
|
||||
| C.java:64:3:64:14 | hessianInput | semmle.label | hessianInput |
|
||||
| C.java:69:18:69:45 | getParameter(...) : String | semmle.label | getParameter(...) : String |
|
||||
| C.java:70:30:70:60 | new ByteArrayInputStream(...) : ByteArrayInputStream | semmle.label | new ByteArrayInputStream(...) : ByteArrayInputStream |
|
||||
| C.java:70:55:70:59 | bytes : byte[] | semmle.label | bytes : byte[] |
|
||||
| C.java:72:3:72:14 | hessianInput | semmle.label | hessianInput |
|
||||
| C.java:73:3:73:14 | hessianInput | semmle.label | hessianInput |
|
||||
| C.java:79:26:79:71 | new StringReader(...) | semmle.label | new StringReader(...) |
|
||||
| C.java:79:43:79:70 | getParameter(...) : String | semmle.label | getParameter(...) : String |
|
||||
| C.java:84:27:84:54 | getParameter(...) : String | semmle.label | getParameter(...) : String |
|
||||
| C.java:85:29:85:68 | new ByteArrayInputStream(...) : ByteArrayInputStream | semmle.label | new ByteArrayInputStream(...) : ByteArrayInputStream |
|
||||
| C.java:85:54:85:67 | serializedData : byte[] | semmle.label | serializedData : byte[] |
|
||||
| C.java:87:3:87:13 | burlapInput | semmle.label | burlapInput |
|
||||
| C.java:91:3:91:14 | burlapInput1 | semmle.label | burlapInput1 |
|
||||
| TestMessageBodyReader.java:20:55:20:78 | entityStream : InputStream | semmle.label | entityStream : InputStream |
|
||||
| TestMessageBodyReader.java:22:18:22:52 | new ObjectInputStream(...) | semmle.label | new ObjectInputStream(...) |
|
||||
| TestMessageBodyReader.java:22:40:22:51 | entityStream : InputStream | semmle.label | entityStream : InputStream |
|
||||
#select
|
||||
| A.java:15:12:15:26 | readObject(...) | A.java:13:31:13:51 | getInputStream(...) : InputStream | A.java:15:12:15:13 | in | Unsafe deserialization of $@. | A.java:13:31:13:51 | getInputStream(...) | user input |
|
||||
| A.java:21:12:21:28 | readUnshared(...) | A.java:19:31:19:51 | getInputStream(...) : InputStream | A.java:21:12:21:13 | in | Unsafe deserialization of $@. | A.java:19:31:19:51 | getInputStream(...) | user input |
|
||||
| A.java:27:12:27:25 | readObject(...) | A.java:25:31:25:51 | getInputStream(...) : InputStream | A.java:27:12:27:12 | d | Unsafe deserialization of $@. | A.java:25:31:25:51 | getInputStream(...) | user input |
|
||||
| A.java:34:12:34:29 | fromXML(...) | A.java:32:31:32:51 | getInputStream(...) : InputStream | A.java:34:23:34:28 | reader | Unsafe deserialization of $@. | A.java:32:31:32:51 | getInputStream(...) | user input |
|
||||
| A.java:40:12:40:42 | readObject(...) | A.java:39:29:39:49 | getInputStream(...) : InputStream | A.java:40:28:40:32 | input | Unsafe deserialization of $@. | A.java:39:29:39:49 | getInputStream(...) | user input |
|
||||
| A.java:41:12:41:48 | readObjectOrNull(...) | A.java:39:29:39:49 | getInputStream(...) : InputStream | A.java:41:34:41:38 | input | Unsafe deserialization of $@. | A.java:39:29:39:49 | getInputStream(...) | user input |
|
||||
| A.java:42:16:42:45 | readClassAndObject(...) | A.java:39:29:39:49 | getInputStream(...) : InputStream | A.java:42:40:42:44 | input | Unsafe deserialization of $@. | A.java:39:29:39:49 | getInputStream(...) | user input |
|
||||
| A.java:61:16:61:31 | load(...) | A.java:60:25:60:45 | getInputStream(...) : InputStream | A.java:61:26:61:30 | input | Unsafe deserialization of $@. | A.java:60:25:60:45 | getInputStream(...) | user input |
|
||||
| A.java:62:17:62:35 | loadAll(...) | A.java:60:25:60:45 | getInputStream(...) : InputStream | A.java:62:30:62:34 | input | Unsafe deserialization of $@. | A.java:60:25:60:45 | getInputStream(...) | user input |
|
||||
| A.java:63:17:63:56 | parse(...) | A.java:60:25:60:45 | getInputStream(...) : InputStream | A.java:63:28:63:55 | new InputStreamReader(...) | Unsafe deserialization of $@. | A.java:60:25:60:45 | getInputStream(...) | user input |
|
||||
| A.java:64:12:64:38 | loadAs(...) | A.java:60:25:60:45 | getInputStream(...) : InputStream | A.java:64:24:64:28 | input | Unsafe deserialization of $@. | A.java:60:25:60:45 | getInputStream(...) | user input |
|
||||
| A.java:65:12:65:61 | loadAs(...) | A.java:60:25:60:45 | getInputStream(...) : InputStream | A.java:65:24:65:51 | new InputStreamReader(...) | Unsafe deserialization of $@. | A.java:60:25:60:45 | getInputStream(...) | user input |
|
||||
| A.java:71:16:71:31 | load(...) | A.java:70:25:70:45 | getInputStream(...) : InputStream | A.java:71:26:71:30 | input | Unsafe deserialization of $@. | A.java:70:25:70:45 | getInputStream(...) | user input |
|
||||
| A.java:72:17:72:35 | loadAll(...) | A.java:70:25:70:45 | getInputStream(...) : InputStream | A.java:72:30:72:34 | input | Unsafe deserialization of $@. | A.java:70:25:70:45 | getInputStream(...) | user input |
|
||||
| A.java:73:17:73:56 | parse(...) | A.java:70:25:70:45 | getInputStream(...) : InputStream | A.java:73:28:73:55 | new InputStreamReader(...) | Unsafe deserialization of $@. | A.java:70:25:70:45 | getInputStream(...) | user input |
|
||||
| A.java:74:12:74:38 | loadAs(...) | A.java:70:25:70:45 | getInputStream(...) : InputStream | A.java:74:24:74:28 | input | Unsafe deserialization of $@. | A.java:70:25:70:45 | getInputStream(...) | user input |
|
||||
| A.java:75:12:75:61 | loadAs(...) | A.java:70:25:70:45 | getInputStream(...) : InputStream | A.java:75:24:75:51 | new InputStreamReader(...) | Unsafe deserialization of $@. | A.java:70:25:70:45 | getInputStream(...) | user input |
|
||||
| A.java:91:16:91:31 | load(...) | A.java:90:25:90:45 | getInputStream(...) : InputStream | A.java:91:26:91:30 | input | Unsafe deserialization of $@. | A.java:90:25:90:45 | getInputStream(...) | user input |
|
||||
| A.java:92:17:92:35 | loadAll(...) | A.java:90:25:90:45 | getInputStream(...) : InputStream | A.java:92:30:92:34 | input | Unsafe deserialization of $@. | A.java:90:25:90:45 | getInputStream(...) | user input |
|
||||
| A.java:93:17:93:56 | parse(...) | A.java:90:25:90:45 | getInputStream(...) : InputStream | A.java:93:28:93:55 | new InputStreamReader(...) | Unsafe deserialization of $@. | A.java:90:25:90:45 | getInputStream(...) | user input |
|
||||
| A.java:94:12:94:38 | loadAs(...) | A.java:90:25:90:45 | getInputStream(...) : InputStream | A.java:94:24:94:28 | input | Unsafe deserialization of $@. | A.java:90:25:90:45 | getInputStream(...) | user input |
|
||||
| A.java:95:12:95:61 | loadAs(...) | A.java:90:25:90:45 | getInputStream(...) : InputStream | A.java:95:24:95:51 | new InputStreamReader(...) | Unsafe deserialization of $@. | A.java:90:25:90:45 | getInputStream(...) | user input |
|
||||
| B.java:8:12:8:46 | parseObject(...) | B.java:7:31:7:51 | getInputStream(...) : InputStream | B.java:8:29:8:39 | inputStream | Unsafe deserialization of $@. | B.java:7:31:7:51 | getInputStream(...) | user input |
|
||||
| B.java:15:12:15:28 | parse(...) | B.java:12:31:12:51 | getInputStream(...) : InputStream | B.java:15:23:15:27 | bytes | Unsafe deserialization of $@. | B.java:12:31:12:51 | getInputStream(...) | user input |
|
||||
| B.java:23:12:23:30 | parseObject(...) | B.java:19:31:19:51 | getInputStream(...) : InputStream | B.java:23:29:23:29 | s | Unsafe deserialization of $@. | B.java:19:31:19:51 | getInputStream(...) | user input |
|
||||
| B.java:31:12:31:24 | parse(...) | B.java:27:31:27:51 | getInputStream(...) : InputStream | B.java:31:23:31:23 | s | Unsafe deserialization of $@. | B.java:27:31:27:51 | getInputStream(...) | user input |
|
||||
| C.java:24:3:24:17 | load(...) | C.java:23:17:23:44 | getParameter(...) : String | C.java:24:13:24:16 | data | Unsafe deserialization of $@. | C.java:23:17:23:44 | getParameter(...) | user input |
|
||||
| C.java:25:3:25:23 | loadStream(...) | C.java:23:17:23:44 | getParameter(...) : String | C.java:25:19:25:22 | data | Unsafe deserialization of $@. | C.java:23:17:23:44 | getParameter(...) | user input |
|
||||
| C.java:26:3:26:43 | loadStreamOfType(...) | C.java:23:17:23:44 | getParameter(...) : String | C.java:26:25:26:28 | data | Unsafe deserialization of $@. | C.java:23:17:23:44 | getParameter(...) | user input |
|
||||
| C.java:27:3:27:35 | loadType(...) | C.java:23:17:23:44 | getParameter(...) : String | C.java:27:17:27:20 | data | Unsafe deserialization of $@. | C.java:23:17:23:44 | getParameter(...) | user input |
|
||||
| C.java:30:3:30:23 | load(...) | C.java:23:17:23:44 | getParameter(...) : String | C.java:30:19:30:22 | data | Unsafe deserialization of $@. | C.java:23:17:23:44 | getParameter(...) | user input |
|
||||
| C.java:31:3:31:29 | loadStream(...) | C.java:23:17:23:44 | getParameter(...) : String | C.java:31:25:31:28 | data | Unsafe deserialization of $@. | C.java:23:17:23:44 | getParameter(...) | user input |
|
||||
| C.java:32:3:32:49 | loadStreamOfType(...) | C.java:23:17:23:44 | getParameter(...) : String | C.java:32:31:32:34 | data | Unsafe deserialization of $@. | C.java:23:17:23:44 | getParameter(...) | user input |
|
||||
| C.java:33:3:33:41 | loadType(...) | C.java:23:17:23:44 | getParameter(...) : String | C.java:33:23:33:26 | data | Unsafe deserialization of $@. | C.java:23:17:23:44 | getParameter(...) | user input |
|
||||
| C.java:43:3:43:29 | jsonToJava(...) | C.java:38:17:38:44 | getParameter(...) : String | C.java:43:25:43:28 | data | Unsafe deserialization of $@. | C.java:38:17:38:44 | getParameter(...) | user input |
|
||||
| C.java:46:3:46:17 | readObject(...) | C.java:38:17:38:44 | getParameter(...) : String | C.java:46:3:46:4 | jr | Unsafe deserialization of $@. | C.java:38:17:38:44 | getParameter(...) | user input |
|
||||
| C.java:53:3:53:10 | read(...) | C.java:51:17:51:44 | getParameter(...) : String | C.java:53:3:53:3 | r | Unsafe deserialization of $@. | C.java:51:17:51:44 | getParameter(...) | user input |
|
||||
| C.java:54:3:54:22 | read(...) | C.java:51:17:51:44 | getParameter(...) : String | C.java:54:3:54:3 | r | Unsafe deserialization of $@. | C.java:51:17:51:44 | getParameter(...) | user input |
|
||||
| C.java:55:3:55:36 | read(...) | C.java:51:17:51:44 | getParameter(...) : String | C.java:55:3:55:3 | r | Unsafe deserialization of $@. | C.java:51:17:51:44 | getParameter(...) | user input |
|
||||
| C.java:63:3:63:27 | readObject(...) | C.java:60:18:60:45 | getParameter(...) : String | C.java:63:3:63:14 | hessianInput | Unsafe deserialization of $@. | C.java:60:18:60:45 | getParameter(...) | user input |
|
||||
| C.java:64:3:64:39 | readObject(...) | C.java:60:18:60:45 | getParameter(...) : String | C.java:64:3:64:14 | hessianInput | Unsafe deserialization of $@. | C.java:60:18:60:45 | getParameter(...) | user input |
|
||||
| C.java:72:3:72:27 | readObject(...) | C.java:69:18:69:45 | getParameter(...) : String | C.java:72:3:72:14 | hessianInput | Unsafe deserialization of $@. | C.java:69:18:69:45 | getParameter(...) | user input |
|
||||
| C.java:73:3:73:39 | readObject(...) | C.java:69:18:69:45 | getParameter(...) : String | C.java:73:3:73:14 | hessianInput | Unsafe deserialization of $@. | C.java:69:18:69:45 | getParameter(...) | user input |
|
||||
| C.java:79:3:79:72 | unmarshal(...) | C.java:79:43:79:70 | getParameter(...) : String | C.java:79:26:79:71 | new StringReader(...) | Unsafe deserialization of $@. | C.java:79:43:79:70 | getParameter(...) | user input |
|
||||
| C.java:87:3:87:26 | readObject(...) | C.java:84:27:84:54 | getParameter(...) : String | C.java:87:3:87:13 | burlapInput | Unsafe deserialization of $@. | C.java:84:27:84:54 | getParameter(...) | user input |
|
||||
| C.java:91:3:91:27 | readObject(...) | C.java:84:27:84:54 | getParameter(...) : String | C.java:91:3:91:14 | burlapInput1 | Unsafe deserialization of $@. | C.java:84:27:84:54 | getParameter(...) | user input |
|
||||
| TestMessageBodyReader.java:22:18:22:65 | readObject(...) | TestMessageBodyReader.java:20:55:20:78 | entityStream : InputStream | TestMessageBodyReader.java:22:18:22:52 | new ObjectInputStream(...) | Unsafe deserialization of $@. | TestMessageBodyReader.java:20:55:20:78 | entityStream | user input |
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import java
|
||||
import semmle.code.java.security.UnsafeDeserializationQuery
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
class UnsafeDeserializationTest extends InlineExpectationsTest {
|
||||
UnsafeDeserializationTest() { this = "UnsafeDeserializationTest" }
|
||||
|
||||
override string getARelevantTag() { result = "unsafeDeserialization" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
tag = "unsafeDeserialization" and
|
||||
exists(DataFlow::Node sink, UnsafeDeserializationConfig conf | conf.hasFlowTo(sink) |
|
||||
sink.getLocation() = location and
|
||||
element = sink.toString() and
|
||||
value = ""
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
Security/CWE/CWE-502/UnsafeDeserialization.ql
|
||||
@@ -1 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/snakeyaml-1.21:${testdir}/../../../stubs/xstream-1.4.10:${testdir}/../../../stubs/kryo-4.0.2:${testdir}/../../../stubs/jsr311-api-1.1.1:${testdir}/../../../stubs/fastjson-1.2.74:${testdir}/../../../stubs/springframework-5.3.8:${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/jyaml-1.3:${testdir}/../../../stubs/json-io-4.10.0:${testdir}/../../../stubs/yamlbeans-1.09:${testdir}/../../../stubs/hessian-4.0.38:${testdir}/../../../stubs/castor-1.4.1
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/snakeyaml-1.21:${testdir}/../../../stubs/xstream-1.4.10:${testdir}/../../../stubs/kryo-4.0.2:${testdir}/../../../stubs/jsr311-api-1.1.1:${testdir}/../../../stubs/fastjson-1.2.74:${testdir}/../../../stubs/springframework-5.3.8:${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/jyaml-1.3:${testdir}/../../../stubs/json-io-4.10.0:${testdir}/../../../stubs/yamlbeans-1.09:${testdir}/../../../stubs/hessian-4.0.38:${testdir}/../../../stubs/castor-1.4.1:${testdir}/../../../stubs/jackson-databind-2.10
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.fasterxml.jackson.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface JsonTypeInfo {
|
||||
JsonTypeInfo.Id use();
|
||||
|
||||
public static enum Id {
|
||||
CLASS("@class"),
|
||||
MINIMAL_CLASS("@c");
|
||||
|
||||
private Id(String defProp) { }
|
||||
|
||||
public String getDefaultPropertyName() { return null; }
|
||||
}
|
||||
}
|
||||
@@ -9,4 +9,8 @@ public class JsonFactory {
|
||||
public JsonGenerator createGenerator(Writer writer) {
|
||||
return new JsonGenerator();
|
||||
}
|
||||
|
||||
public JsonParser createParser(String content) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
package com.fasterxml.jackson.core;
|
||||
|
||||
public abstract class JsonParser {}
|
||||
@@ -0,0 +1,3 @@
|
||||
package com.fasterxml.jackson.core;
|
||||
|
||||
public interface TreeNode {}
|
||||
@@ -0,0 +1,3 @@
|
||||
package com.fasterxml.jackson.databind;
|
||||
|
||||
public class JavaType {}
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.fasterxml.jackson.databind;
|
||||
|
||||
import java.util.*;
|
||||
import com.fasterxml.jackson.core.TreeNode;
|
||||
|
||||
public abstract class JsonNode implements Iterable<JsonNode> {
|
||||
public JsonNode() {
|
||||
}
|
||||
public abstract class JsonNode implements TreeNode, Iterable<JsonNode> {
|
||||
public JsonNode() {}
|
||||
}
|
||||
|
||||
@@ -25,4 +25,8 @@ public class MappingIterator<T> implements Iterator<T>, Closeable {
|
||||
public void close() throws IOException {
|
||||
|
||||
}
|
||||
|
||||
public List<T> readAll() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
package com.fasterxml.jackson.databind;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.TreeNode;
|
||||
import com.fasterxml.jackson.databind.jsontype.PolymorphicTypeValidator;
|
||||
import java.lang.reflect.Type;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
@@ -38,4 +42,36 @@ public class ObjectMapper {
|
||||
public <T> T convertValue(Object fromValue, Class<T> toValueType) throws IllegalArgumentException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public ObjectMapper setPolymorphicTypeValidator(PolymorphicTypeValidator ptv) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public ObjectMapper enableDefaultTyping() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T> T readValue(String content, Class<T> valueType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T> T readValue(String content, JavaType valueType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T> MappingIterator<T> readValues(JsonParser p, Class<T> valueType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T> T treeToValue(TreeNode n, Class<T> valueType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public JsonNode readTree(String content) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public JavaType constructType(Type t) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.fasterxml.jackson.databind.cfg;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.jsontype.PolymorphicTypeValidator;
|
||||
|
||||
public abstract class MapperBuilder<M extends ObjectMapper, B extends MapperBuilder<M, B>> {
|
||||
public M build() { return null; }
|
||||
public B polymorphicTypeValidator(PolymorphicTypeValidator ptv) { return null; }
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.fasterxml.jackson.databind.json;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.cfg.MapperBuilder;
|
||||
|
||||
public class JsonMapper extends ObjectMapper {
|
||||
public static JsonMapper.Builder builder() { return null; }
|
||||
public static class Builder extends MapperBuilder<JsonMapper, JsonMapper.Builder> {}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.fasterxml.jackson.databind.jsontype;
|
||||
|
||||
public class BasicPolymorphicTypeValidator extends PolymorphicTypeValidator {
|
||||
public static BasicPolymorphicTypeValidator.Builder builder() { return null; }
|
||||
|
||||
public static class Builder {
|
||||
public BasicPolymorphicTypeValidator.Builder allowIfSubType(final String prefixForSubType) { return null; }
|
||||
public BasicPolymorphicTypeValidator build() { return null; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package com.fasterxml.jackson.databind.jsontype;
|
||||
|
||||
public abstract class PolymorphicTypeValidator {}
|
||||
Reference in New Issue
Block a user