mirror of
https://github.com/github/codeql.git
synced 2026-03-04 22:56:47 +01:00
Merge pull request #13256 from atorralba/atorralba/java/stapler-models
Java: Model the Stapler framework
This commit is contained in:
@@ -41,6 +41,7 @@ abstract class RemoteFlowSource extends DataFlow::Node {
|
||||
*/
|
||||
private module FlowSources {
|
||||
private import semmle.code.java.frameworks.hudson.Hudson
|
||||
private import semmle.code.java.frameworks.stapler.Stapler
|
||||
}
|
||||
|
||||
private class ExternalRemoteFlowSource extends RemoteFlowSource {
|
||||
|
||||
@@ -23,6 +23,7 @@ private module Frameworks {
|
||||
private import semmle.code.java.frameworks.Properties
|
||||
private import semmle.code.java.frameworks.Protobuf
|
||||
private import semmle.code.java.frameworks.ratpack.RatpackExec
|
||||
private import semmle.code.java.frameworks.stapler.Stapler
|
||||
private import semmle.code.java.JDK
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,17 @@
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.FlowSources
|
||||
private import semmle.code.java.frameworks.stapler.Stapler
|
||||
private import semmle.code.java.security.XSS
|
||||
|
||||
/** A method declared in a subtype of `hudson.model.Descriptor` that returns an `HttpResponse`. */
|
||||
class HudsonWebMethod extends Method {
|
||||
HudsonWebMethod() {
|
||||
this.getReturnType().(RefType).getASourceSupertype*() instanceof HttpResponse and
|
||||
this.getDeclaringType().getASourceSupertype*().hasQualifiedName("hudson.model", "Descriptor")
|
||||
}
|
||||
}
|
||||
|
||||
private class FilePathRead extends LocalUserInput {
|
||||
FilePathRead() {
|
||||
this.asExpr()
|
||||
|
||||
124
java/ql/lib/semmle/code/java/frameworks/stapler/Stapler.qll
Normal file
124
java/ql/lib/semmle/code/java/frameworks/stapler/Stapler.qll
Normal file
@@ -0,0 +1,124 @@
|
||||
/** Provides classes and predicates related to the Stapler framework. */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.DataFlow
|
||||
private import semmle.code.java.dataflow.FlowSources
|
||||
private import semmle.code.java.dataflow.FlowSteps
|
||||
private import semmle.code.java.dataflow.TypeFlow
|
||||
private import semmle.code.java.frameworks.hudson.Hudson
|
||||
private import semmle.code.java.frameworks.JavaxAnnotations
|
||||
|
||||
/**
|
||||
* A callable annotated with a Stapler `DataBound` annotation,
|
||||
* or that has the `@stapler-constructor` Javadoc annotation.
|
||||
*/
|
||||
class DataBoundAnnotated extends Callable {
|
||||
DataBoundAnnotated() {
|
||||
exists(Annotation an |
|
||||
an.getType()
|
||||
.hasQualifiedName("org.kohsuke.stapler", ["DataBoundConstructor", "DataBoundSetter"])
|
||||
|
|
||||
this = an.getAnnotatedElement()
|
||||
)
|
||||
or
|
||||
exists(Javadoc doc | doc.getAChild().getText().matches("%@stapler-constructor%") |
|
||||
doc.getCommentedElement() = this
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** The interface `org.kohsuke.stapler.HttpResponse`. */
|
||||
class HttpResponse extends Interface {
|
||||
HttpResponse() { this.hasQualifiedName("org.kohsuke.stapler", "HttpResponse") }
|
||||
}
|
||||
|
||||
/**
|
||||
* A remote flow source for parameters annotated with an annotation
|
||||
* that is itself annotated with `InjectedParameter`.
|
||||
*
|
||||
* Such parameters are populated with user-provided data by Stapler.
|
||||
*/
|
||||
private class InjectedParameterSource extends RemoteFlowSource {
|
||||
InjectedParameterSource() {
|
||||
this.asParameter().getAnAnnotation().getType() instanceof InjectedParameterAnnotatedType
|
||||
}
|
||||
|
||||
override string getSourceType() { result = "Stapler injected parameter" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A dataflow step from the `HttpResponse` return value of a `HudsonWebMethod`
|
||||
* to the instance parameter of the `generateResponse` method of the appropriate subtype of `HttpResponse`.
|
||||
*
|
||||
* This models the rendering process of an `HttpResponse` by Stapler.
|
||||
*/
|
||||
private class HttpResponseGetDescriptionStep extends AdditionalValueStep {
|
||||
override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
|
||||
exists(ReturnStmt s, GenerateResponseMethod m |
|
||||
s.getEnclosingCallable() instanceof HudsonWebMethod and
|
||||
boundOrStaticType(s.getResult(), m.getDeclaringType().getADescendant())
|
||||
|
|
||||
n1.asExpr() = s.getResult() and
|
||||
n2.(DataFlow::InstanceParameterNode).getCallable() = m
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A dataflow step from the post-update node of an instance access in a `DataBoundAnnotated` method
|
||||
* to the instance parameter of a `PostConstruct` method of the same type.
|
||||
*
|
||||
* This models the construction process of a `DataBound` object in Stapler.
|
||||
*/
|
||||
private class PostConstructDataBoundAdditionalStep extends AdditionalValueStep {
|
||||
override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
|
||||
exists(PostConstructDataBoundMethod postConstruct, DataBoundAnnotated input |
|
||||
postConstruct.getDeclaringType() = input.getDeclaringType()
|
||||
|
|
||||
n1.(DataFlow::PostUpdateNode)
|
||||
.getPreUpdateNode()
|
||||
.(DataFlow::InstanceAccessNode)
|
||||
.getEnclosingCallable() = input and
|
||||
n2.(DataFlow::InstanceParameterNode).getCallable() = postConstruct
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** An annotation type annotated with the `InjectedParameter` annotation. */
|
||||
private class InjectedParameterAnnotatedType extends AnnotationType {
|
||||
InjectedParameterAnnotatedType() {
|
||||
this.getAnAnnotation().getType().hasQualifiedName("org.kohsuke.stapler", "InjectedParameter")
|
||||
}
|
||||
}
|
||||
|
||||
/** The `generateResponse` method of `org.kohsuke.stapler.HttpResponse` or its subtypes. */
|
||||
private class GenerateResponseMethod extends Method {
|
||||
GenerateResponseMethod() {
|
||||
this.getDeclaringType().getASourceSupertype*() instanceof HttpResponse and
|
||||
this.hasName("generateResponse")
|
||||
}
|
||||
}
|
||||
|
||||
/** Holds if `t` is the static type of `e`, or an upper bound of the runtime type of `e`. */
|
||||
private predicate boundOrStaticType(Expr e, RefType t) {
|
||||
exprTypeFlow(e, t, false)
|
||||
or
|
||||
t = e.getType()
|
||||
}
|
||||
|
||||
/**
|
||||
* A method called after the construction of a `DataBound` object.
|
||||
*
|
||||
* That is, either the `bindResolve` method of a subtype of `org.kohsuke.stapler.DataBoundResolvable`,
|
||||
* or a method annotated with `javax.annotation.PostConstruct`.
|
||||
*/
|
||||
private class PostConstructDataBoundMethod extends Method {
|
||||
PostConstructDataBoundMethod() {
|
||||
this.getDeclaringType()
|
||||
.getASourceSupertype*()
|
||||
.hasQualifiedName("org.kohsuke.stapler", "DataBoundResolvable") and
|
||||
this.hasName("bindResolve")
|
||||
or
|
||||
this.getAnAnnotation() instanceof PostConstructAnnotation
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user