Merge pull request #1305 from aschackmull/java/abstract-flowsources

Java: Introduce an abstract class RemoteFlowSource to ease customization.
This commit is contained in:
Max Schaefer
2019-05-10 11:42:15 +01:00
committed by GitHub
16 changed files with 118 additions and 50 deletions

View File

@@ -20,7 +20,7 @@ import DataFlow::PathGraph
class TaintedPathConfig extends TaintTracking::Configuration {
TaintedPathConfig() { this = "TaintedPathConfig" }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteUserInput }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) {
exists(Expr e | e = sink.asExpr() | e = any(PathCreation p).getInput() and not guarded(e))

View File

@@ -6,7 +6,7 @@ private class RemoteUserInputToArgumentToExecFlowConfig extends TaintTracking::C
this = "ExecCommon::RemoteUserInputToArgumentToExecFlowConfig"
}
override predicate isSource(DataFlow::Node src) { src instanceof RemoteUserInput }
override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof ArgumentToExec }

View File

@@ -18,7 +18,7 @@ import DataFlow2::PathGraph
class XSSConfig extends TaintTracking::Configuration2 {
XSSConfig() { this = "XSSConfig" }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteUserInput }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) { sink instanceof XssSink }

View File

@@ -49,7 +49,7 @@ class PersistenceQueryInjectionSink extends QueryInjectionSink {
private class QueryInjectionFlowConfig extends TaintTracking::Configuration {
QueryInjectionFlowConfig() { this = "SqlInjectionLib::QueryInjectionFlowConfig" }
override predicate isSource(DataFlow::Node src) { src instanceof RemoteUserInput }
override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) { sink instanceof QueryInjectionSink }

View File

@@ -18,7 +18,7 @@ class ResponseSplittingConfig extends TaintTracking::Configuration {
ResponseSplittingConfig() { this = "ResponseSplittingConfig" }
override predicate isSource(DataFlow::Node source) {
source instanceof RemoteUserInput and
source instanceof RemoteFlowSource and
not source instanceof WhitelistedSource
}

View File

@@ -30,7 +30,7 @@ class HeaderSplittingSink extends DataFlow::ExprNode {
}
}
class WhitelistedSource extends RemoteUserInput {
class WhitelistedSource extends DataFlow::ExprNode {
WhitelistedSource() {
this.asExpr().(MethodAccess).getMethod() instanceof HttpServletRequestGetHeaderMethod or
this.asExpr().(MethodAccess).getMethod() instanceof CookieGetNameMethod

View File

@@ -17,7 +17,7 @@ import DataFlow::PathGraph
class Conf extends TaintTracking::Configuration {
Conf() { this = "RemoteUserInputTocanThrowOutOfBoundsDueToEmptyArrayConfig" }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteUserInput }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) {
any(CheckableArrayAccess caa).canThrowOutOfBoundsDueToEmptyArray(sink.asExpr(), _)

View File

@@ -17,7 +17,7 @@ import DataFlow::PathGraph
class Conf extends TaintTracking::Configuration {
Conf() { this = "RemoteUserInputTocanThrowOutOfBoundsDueToEmptyArrayConfig" }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteUserInput }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) {
any(CheckableArrayAccess caa).canThrowOutOfBounds(sink.asExpr())

View File

@@ -17,7 +17,7 @@ import DataFlow::PathGraph
class ExternallyControlledFormatStringConfig extends TaintTracking::Configuration {
ExternallyControlledFormatStringConfig() { this = "ExternallyControlledFormatStringConfig" }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteUserInput }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) {
sink.asExpr() = any(StringFormat formatCall).getFormatArgument()

View File

@@ -32,7 +32,7 @@ predicate sink(ArithExpr exp, VarAccess tainted, string effect) {
class RemoteUserInputConfig extends TaintTracking::Configuration {
RemoteUserInputConfig() { this = "ArithmeticTainted.ql:RemoteUserInputConfig" }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteUserInput }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) { sink(_, sink.asExpr(), _) }

View File

@@ -18,7 +18,7 @@ import DataFlow::PathGraph
class UnsafeDeserializationConfig extends TaintTracking::Configuration {
UnsafeDeserializationConfig() { this = "UnsafeDeserializationConfig" }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteUserInput }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) { sink instanceof UnsafeDeserializationSink }
}

View File

@@ -18,7 +18,7 @@ import DataFlow::PathGraph
class UrlRedirectConfig extends TaintTracking::Configuration {
UrlRedirectConfig() { this = "UrlRedirectConfig" }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteUserInput }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) { sink instanceof UrlRedirectSink }
}

View File

@@ -40,7 +40,7 @@ class UnsafeXxeSink extends DataFlow::ExprNode {
class XxeConfig extends TaintTracking::Configuration {
XxeConfig() { this = "XXE.ql::XxeConfig" }
override predicate isSource(DataFlow::Node src) { src instanceof RemoteUserInput }
override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) { sink instanceof UnsafeXxeSink }
}

View File

@@ -19,7 +19,7 @@ import DataFlow::PathGraph
private class NumericCastFlowConfig extends TaintTracking::Configuration {
NumericCastFlowConfig() { this = "NumericCastTainted::RemoteUserInputToNumericNarrowingCastExpr" }
override predicate isSource(DataFlow::Node src) { src instanceof RemoteUserInput }
override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) {
sink.asExpr() = any(NumericNarrowingCastExpr cast).getExpr()

View File

@@ -21,8 +21,54 @@ import semmle.code.java.frameworks.Guice
import semmle.code.java.frameworks.struts.StrutsActions
import semmle.code.java.frameworks.Thrift
/** Class for `tainted` user input. */
abstract class UserInput extends DataFlow::Node { }
/** A data flow source of remote user input. */
abstract class RemoteFlowSource extends DataFlow::Node {
/** Gets a string that describes the type of this remote flow source. */
abstract string getSourceType();
}
private class RemoteTaintedMethodAccessSource extends RemoteFlowSource {
RemoteTaintedMethodAccessSource() {
this.asExpr().(MethodAccess).getMethod() instanceof RemoteTaintedMethod
}
override string getSourceType() { result = "network data source" }
}
private class RmiMethodParameterSource extends RemoteFlowSource {
RmiMethodParameterSource() {
exists(RemoteCallableMethod method |
method.getAParameter() = this.asParameter() and
(
getType() instanceof PrimitiveType or
getType() instanceof TypeString
)
)
}
override string getSourceType() { result = "RMI method parameter" }
}
private class JaxWsMethodParameterSource extends RemoteFlowSource {
JaxWsMethodParameterSource() {
exists(JaxWsEndpoint endpoint |
endpoint.getARemoteMethod().getAParameter() = this.asParameter()
)
}
override string getSourceType() { result = "Jax WS method parameter" }
}
private class JaxRsMethodParameterSource extends RemoteFlowSource {
JaxRsMethodParameterSource() {
exists(JaxRsResourceClass service |
service.getAnInjectableCallable().getAParameter() = this.asParameter() or
service.getAnInjectableField().getAnAccess() = this.asExpr()
)
}
override string getSourceType() { result = "Jax Rs method parameter" }
}
private predicate variableStep(Expr tracked, VarAccess sink) {
exists(VariableAssign def |
@@ -31,32 +77,9 @@ private predicate variableStep(Expr tracked, VarAccess sink) {
)
}
/** Input that may be controlled by a remote user. */
class RemoteUserInput extends UserInput {
RemoteUserInput() {
this.asExpr().(MethodAccess).getMethod() instanceof RemoteTaintedMethod
or
// Parameters to RMI methods.
exists(RemoteCallableMethod method |
method.getAParameter() = this.asParameter() and
(
getType() instanceof PrimitiveType or
getType() instanceof TypeString
)
)
or
// Parameters to Jax WS methods.
exists(JaxWsEndpoint endpoint |
endpoint.getARemoteMethod().getAParameter() = this.asParameter()
)
or
// Parameters to Jax Rs methods.
exists(JaxRsResourceClass service |
service.getAnInjectableCallable().getAParameter() = this.asParameter() or
service.getAnInjectableField().getAnAccess() = this.asExpr()
)
or
// Reverse DNS. Try not to trigger on `localhost`.
private class ReverseDnsSource extends RemoteFlowSource {
ReverseDnsSource() {
// Try not to trigger on `localhost`.
exists(MethodAccess m | m = this.asExpr() |
m.getMethod() instanceof ReverseDNSMethod and
not exists(MethodAccess l |
@@ -64,25 +87,70 @@ class RemoteUserInput extends UserInput {
l.getMethod().getName() = "getLocalHost"
)
)
or
//MessageBodyReader
}
override string getSourceType() { result = "reverse DNS lookup" }
}
private class MessageBodyReaderParameterSource extends RemoteFlowSource {
MessageBodyReaderParameterSource() {
exists(MessageBodyReaderRead m |
m.getParameter(4) = this.asParameter() or
m.getParameter(5) = this.asParameter()
)
or
}
override string getSourceType() { result = "MessageBodyReader parameter" }
}
private class SpringServletInputParameterSource extends RemoteFlowSource {
SpringServletInputParameterSource() {
this.asParameter().getAnAnnotation() instanceof SpringServletInputAnnotation
or
}
override string getSourceType() { result = "Spring servlet input parameter" }
}
private class GuiceRequestParameterSource extends RemoteFlowSource {
GuiceRequestParameterSource() {
exists(GuiceRequestParametersAnnotation a |
a = this.asParameter().getAnAnnotation() or
a = this.asExpr().(FieldRead).getField().getAnAnnotation()
)
or
exists(Struts2ActionSupportClass c | c.getASetterMethod().getField() = this.asExpr().(FieldRead).getField())
or
}
override string getSourceType() { result = "Guice request parameter" }
}
private class Struts2ActionSupportClassFieldReadSource extends RemoteFlowSource {
Struts2ActionSupportClassFieldReadSource() {
exists(Struts2ActionSupportClass c |
c.getASetterMethod().getField() = this.asExpr().(FieldRead).getField()
)
}
override string getSourceType() { result = "Struts2 ActionSupport field" }
}
private class ThriftIfaceParameterSource extends RemoteFlowSource {
ThriftIfaceParameterSource() {
exists(ThriftIface i | i.getAnImplementingMethod().getAParameter() = this.asParameter())
}
override string getSourceType() { result = "Thrift Iface parameter" }
}
/** Class for `tainted` user input. */
abstract class UserInput extends DataFlow::Node { }
/**
* DEPRECATED: Use `RemoteFlowSource` instead.
*
* Input that may be controlled by a remote user.
*/
class RemoteUserInput extends UserInput {
RemoteUserInput() { this instanceof RemoteFlowSource }
/**
* DEPRECATED: Use a configuration with a defined sink instead.
*