mirror of
https://github.com/github/codeql.git
synced 2025-12-21 11:16:30 +01:00
343 lines
11 KiB
Plaintext
343 lines
11 KiB
Plaintext
/**
|
|
* Provides classes representing various flow sources for taint tracking.
|
|
*/
|
|
|
|
import java
|
|
import semmle.code.java.dataflow.DataFlow
|
|
import semmle.code.java.dataflow.TaintTracking
|
|
import semmle.code.java.dataflow.DefUse
|
|
import semmle.code.java.frameworks.Jdbc
|
|
import semmle.code.java.frameworks.Networking
|
|
import semmle.code.java.frameworks.Properties
|
|
import semmle.code.java.frameworks.Rmi
|
|
import semmle.code.java.frameworks.Servlets
|
|
import semmle.code.java.frameworks.ApacheHttp
|
|
import semmle.code.java.frameworks.android.XmlParsing
|
|
import semmle.code.java.frameworks.android.WebView
|
|
import semmle.code.java.frameworks.JaxWS
|
|
import semmle.code.java.frameworks.javase.WebSocket
|
|
import semmle.code.java.frameworks.android.Android
|
|
import semmle.code.java.frameworks.android.ExternalStorage
|
|
import semmle.code.java.frameworks.android.OnActivityResultSource
|
|
import semmle.code.java.frameworks.android.Intent
|
|
import semmle.code.java.frameworks.play.Play
|
|
import semmle.code.java.frameworks.spring.SpringWeb
|
|
import semmle.code.java.frameworks.spring.SpringController
|
|
import semmle.code.java.frameworks.spring.SpringWebClient
|
|
import semmle.code.java.frameworks.Guice
|
|
import semmle.code.java.frameworks.struts.StrutsActions
|
|
import semmle.code.java.frameworks.Thrift
|
|
import semmle.code.java.frameworks.javaee.jsf.JSFRenderer
|
|
private import semmle.code.java.dataflow.ExternalFlow
|
|
private import semmle.code.java.dataflow.ExternalFlowConfiguration
|
|
|
|
/**
|
|
* A data flow source.
|
|
*/
|
|
abstract class SourceNode extends DataFlow::Node {
|
|
/**
|
|
* Gets a string that represents the source kind with respect to threat modeling.
|
|
*/
|
|
abstract string getThreatModel();
|
|
}
|
|
|
|
/**
|
|
* A class of data flow sources that respects the
|
|
* current threat model configuration.
|
|
*/
|
|
class ThreatModelFlowSource extends DataFlow::Node {
|
|
ThreatModelFlowSource() {
|
|
// Expansive threat model.
|
|
currentThreatModel("all") and
|
|
(this instanceof SourceNode or sourceNode(this, _))
|
|
or
|
|
exists(string kind |
|
|
// Specific threat model.
|
|
currentThreatModel(kind) and
|
|
(this.(SourceNode).getThreatModel() = kind or sourceNode(this, kind))
|
|
)
|
|
}
|
|
}
|
|
|
|
/** 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();
|
|
}
|
|
|
|
/**
|
|
* A module for importing frameworks that define flow sources.
|
|
*/
|
|
private module FlowSources {
|
|
private import semmle.code.java.frameworks.hudson.Hudson
|
|
private import semmle.code.java.frameworks.stapler.Stapler
|
|
}
|
|
|
|
private class ExternalRemoteFlowSource extends RemoteFlowSource {
|
|
ExternalRemoteFlowSource() { sourceNode(this, "remote") }
|
|
|
|
override string getSourceType() { result = "external" }
|
|
}
|
|
|
|
private class RmiMethodParameterSource extends RemoteFlowSource {
|
|
RmiMethodParameterSource() {
|
|
exists(RemoteCallableMethod method |
|
|
method.getAParameter() = this.asParameter() and
|
|
(
|
|
this.getType() instanceof PrimitiveType or
|
|
this.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 |
|
|
def.getSource() = tracked and
|
|
defUsePair(def, sink)
|
|
)
|
|
}
|
|
|
|
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 |
|
|
(variableStep(l, m.getQualifier()) or l = m.getQualifier()) and
|
|
l.getMethod().getName() = "getLocalHost"
|
|
)
|
|
)
|
|
}
|
|
|
|
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()
|
|
)
|
|
}
|
|
|
|
override string getSourceType() { result = "MessageBodyReader parameter" }
|
|
}
|
|
|
|
private class PlayParameterSource extends RemoteFlowSource {
|
|
PlayParameterSource() { this.asParameter() instanceof PlayActionMethodQueryParameter }
|
|
|
|
override string getSourceType() { result = "Play Query Parameters" }
|
|
}
|
|
|
|
private class SpringServletInputParameterSource extends RemoteFlowSource {
|
|
SpringServletInputParameterSource() {
|
|
this.asParameter() = any(SpringRequestMappingParameter srmp | srmp.isTaintedInput())
|
|
}
|
|
|
|
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()
|
|
)
|
|
}
|
|
|
|
override string getSourceType() { result = "Guice request parameter" }
|
|
}
|
|
|
|
private class Struts2ActionSupportClassFieldSource extends RemoteFlowSource {
|
|
Struts2ActionSupportClassFieldSource() {
|
|
this.(DataFlow::FieldValueNode).getField() =
|
|
any(Struts2ActionSupportClass c).getASetterMethod().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" }
|
|
}
|
|
|
|
private class AndroidExternalStorageSource extends RemoteFlowSource {
|
|
AndroidExternalStorageSource() { androidExternalStorageSource(this) }
|
|
|
|
override string getSourceType() { result = "Android external storage" }
|
|
}
|
|
|
|
/** Class for `tainted` user input. */
|
|
abstract class UserInput extends DataFlow::Node { }
|
|
|
|
/**
|
|
* Input that may be controlled by a remote user.
|
|
*/
|
|
private class RemoteUserInput extends UserInput instanceof RemoteFlowSource { }
|
|
|
|
/** A node with input that may be controlled by a local user. */
|
|
abstract class LocalUserInput extends UserInput { }
|
|
|
|
/**
|
|
* A node with input from the local environment, such as files, standard in,
|
|
* environment variables, and main method parameters.
|
|
*/
|
|
class EnvInput extends LocalUserInput {
|
|
EnvInput() {
|
|
// Parameters to a main method.
|
|
exists(MainMethod main | this.asParameter() = main.getParameter(0))
|
|
or
|
|
// Args4j arguments.
|
|
exists(Field f | this.asExpr() = f.getAnAccess() |
|
|
f.getAnAnnotation().getType().getQualifiedName() = "org.kohsuke.args4j.Argument"
|
|
)
|
|
or
|
|
// Results from various specific methods.
|
|
this.asExpr().(MethodAccess).getMethod() instanceof EnvReadMethod
|
|
or
|
|
// Access to `System.in`.
|
|
exists(Field f | this.asExpr() = f.getAnAccess() | f instanceof SystemIn)
|
|
or
|
|
// Access to files.
|
|
this.asExpr()
|
|
.(ConstructorCall)
|
|
.getConstructedType()
|
|
.hasQualifiedName("java.io", "FileInputStream")
|
|
}
|
|
}
|
|
|
|
/** A node with input from a database. */
|
|
class DatabaseInput extends LocalUserInput {
|
|
DatabaseInput() { this.asExpr().(MethodAccess).getMethod() instanceof ResultSetGetStringMethod }
|
|
}
|
|
|
|
/** A method that reads from the environment, such as `System.getProperty` or `System.getenv`. */
|
|
class EnvReadMethod extends Method {
|
|
EnvReadMethod() {
|
|
this instanceof MethodSystemGetenv or
|
|
this instanceof PropertiesGetPropertyMethod or
|
|
this instanceof PropertiesGetMethod or
|
|
this instanceof MethodSystemGetProperty
|
|
}
|
|
}
|
|
|
|
/** The type `java.net.InetAddress`. */
|
|
class TypeInetAddr extends RefType {
|
|
TypeInetAddr() { this.getQualifiedName() = "java.net.InetAddress" }
|
|
}
|
|
|
|
/** A reverse DNS method. */
|
|
class ReverseDnsMethod extends Method {
|
|
ReverseDnsMethod() {
|
|
this.getDeclaringType() instanceof TypeInetAddr and
|
|
(
|
|
this.getName() = "getHostName" or
|
|
this.getName() = "getCanonicalHostName"
|
|
)
|
|
}
|
|
}
|
|
|
|
/** DEPRECATED: Alias for ReverseDnsMethod */
|
|
deprecated class ReverseDNSMethod = ReverseDnsMethod;
|
|
|
|
/** Android `Intent` that may have come from a hostile application. */
|
|
class AndroidIntentInput extends DataFlow::Node {
|
|
Type receiverType;
|
|
|
|
AndroidIntentInput() {
|
|
exists(MethodAccess ma, AndroidGetIntentMethod m |
|
|
ma.getMethod().overrides*(m) and
|
|
this.asExpr() = ma and
|
|
receiverType = ma.getReceiverType()
|
|
)
|
|
or
|
|
exists(Method m, AndroidReceiveIntentMethod rI |
|
|
m.overrides*(rI) and
|
|
this.asParameter() = m.getParameter(1) and
|
|
receiverType = m.getDeclaringType()
|
|
)
|
|
or
|
|
exists(Method m, AndroidServiceIntentMethod sI |
|
|
m.overrides*(sI) and
|
|
this.asParameter() = m.getParameter(0) and
|
|
receiverType = m.getDeclaringType()
|
|
)
|
|
}
|
|
}
|
|
|
|
/** Exported Android `Intent` that may have come from a hostile application. */
|
|
class ExportedAndroidIntentInput extends RemoteFlowSource, AndroidIntentInput {
|
|
ExportedAndroidIntentInput() { receiverType.(ExportableAndroidComponent).isExported() }
|
|
|
|
override string getSourceType() { result = "Exported Android intent source" }
|
|
}
|
|
|
|
/** A parameter of an entry-point method declared in a `ContentProvider` class. */
|
|
class AndroidContentProviderInput extends DataFlow::Node {
|
|
AndroidContentProvider declaringType;
|
|
|
|
AndroidContentProviderInput() {
|
|
sourceNode(this, "contentprovider") and
|
|
this.getEnclosingCallable().getDeclaringType() = declaringType
|
|
}
|
|
}
|
|
|
|
/** A parameter of an entry-point method declared in an exported `ContentProvider` class. */
|
|
class ExportedAndroidContentProviderInput extends RemoteFlowSource, AndroidContentProviderInput {
|
|
ExportedAndroidContentProviderInput() { declaringType.isExported() }
|
|
|
|
override string getSourceType() { result = "Exported Android content provider source" }
|
|
}
|
|
|
|
/**
|
|
* The data Intent parameter in the `onActivityResult` method in an Activity or Fragment that
|
|
* calls `startActivityForResult` with an implicit Intent.
|
|
*/
|
|
class OnActivityResultIntentSource extends OnActivityResultIncomingIntent, RemoteFlowSource {
|
|
cached
|
|
OnActivityResultIntentSource() { this.isRemoteSource() }
|
|
|
|
override string getSourceType() { result = "Android onActivityResult incoming Intent" }
|
|
}
|
|
|
|
/**
|
|
* A parameter of a method annotated with the `android.webkit.JavascriptInterface` annotation.
|
|
*/
|
|
class AndroidJavascriptInterfaceMethodParameter extends RemoteFlowSource {
|
|
AndroidJavascriptInterfaceMethodParameter() {
|
|
exists(JavascriptInterfaceMethod m | this.asParameter() = m.getAParameter())
|
|
}
|
|
|
|
override string getSourceType() {
|
|
result = "Parameter of method with JavascriptInterface annotation"
|
|
}
|
|
}
|