mirror of
https://github.com/github/codeql.git
synced 2026-03-05 07:06:47 +01:00
Merge branch 'main' into starcke/automodel-pack
This commit is contained in:
@@ -33,6 +33,7 @@ class Member extends Element, Annotatable, Modifiable, @member {
|
||||
* Holds if this member has the specified name and is declared in the
|
||||
* specified package and type.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate hasQualifiedName(string package, string type, string name) {
|
||||
this.getDeclaringType().hasQualifiedName(package, type) and this.hasName(name)
|
||||
}
|
||||
|
||||
@@ -345,6 +345,29 @@ private predicate elementSpec(
|
||||
neutralModel(package, type, name, signature, _, _) and ext = "" and subtypes = false
|
||||
}
|
||||
|
||||
private string getNestedName(Type t) {
|
||||
not t instanceof RefType and result = t.toString()
|
||||
or
|
||||
not t.(Array).getElementType() instanceof NestedType and result = t.(RefType).nestedName()
|
||||
or
|
||||
result =
|
||||
t.(Array).getElementType().(NestedType).getEnclosingType().nestedName() + "$" + t.getName()
|
||||
}
|
||||
|
||||
private string getQualifiedName(Type t) {
|
||||
not t instanceof RefType and result = t.toString()
|
||||
or
|
||||
result = t.(RefType).getQualifiedName()
|
||||
or
|
||||
exists(Array a, Type c | a = t and c = a.getElementType() |
|
||||
not c instanceof RefType and result = t.toString()
|
||||
or
|
||||
exists(string pkgName | pkgName = c.(RefType).getPackage().getName() |
|
||||
if pkgName = "" then result = getNestedName(a) else result = pkgName + "." + getNestedName(a)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a parenthesized string containing all parameter types of this callable, separated by a comma.
|
||||
*
|
||||
@@ -354,31 +377,39 @@ private predicate elementSpec(
|
||||
cached
|
||||
string paramsString(Callable c) {
|
||||
result =
|
||||
"(" + concat(int i | | c.getParameterType(i).getErasure().toString(), "," order by i) + ")"
|
||||
"(" + concat(int i | | getNestedName(c.getParameterType(i).getErasure()), "," order by i) + ")"
|
||||
}
|
||||
|
||||
private string paramsStringQualified(Callable c) {
|
||||
result =
|
||||
"(" + concat(int i | | getQualifiedName(c.getParameterType(i).getErasure()), "," order by i) +
|
||||
")"
|
||||
}
|
||||
|
||||
private Element interpretElement0(
|
||||
string package, string type, boolean subtypes, string name, string signature
|
||||
) {
|
||||
elementSpec(package, type, subtypes, name, signature, _) and
|
||||
exists(RefType t | t.hasQualifiedName(package, type) |
|
||||
(
|
||||
exists(Member m |
|
||||
(
|
||||
result = m
|
||||
or
|
||||
subtypes = true and result.(SrcMethod).overridesOrInstantiates+(m)
|
||||
) and
|
||||
m.getDeclaringType() = t and
|
||||
m.hasName(name)
|
||||
m.hasQualifiedName(package, type, name)
|
||||
|
|
||||
signature = "" or
|
||||
m.(Callable).getSignature() = any(string nameprefix) + signature or
|
||||
paramsStringQualified(m) = signature or
|
||||
paramsString(m) = signature
|
||||
)
|
||||
or
|
||||
(if subtypes = true then result.(SrcRefType).getASourceSupertype*() = t else result = t) and
|
||||
name = "" and
|
||||
signature = ""
|
||||
exists(RefType t |
|
||||
t.hasQualifiedName(package, type) and
|
||||
(if subtypes = true then result.(SrcRefType).getASourceSupertype*() = t else result = t) and
|
||||
name = "" and
|
||||
signature = ""
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -175,8 +175,6 @@ class Provenance = Impl::Public::Provenance;
|
||||
|
||||
class SummarizedCallable = Impl::Public::SummarizedCallable;
|
||||
|
||||
class NeutralCallable = Impl::Public::NeutralCallable;
|
||||
|
||||
/**
|
||||
* An adapter class to add the flow summaries specified on `SyntheticCallable`
|
||||
* to `SummarizedCallable`.
|
||||
|
||||
@@ -257,11 +257,22 @@ private Guard boundFlowCond(SsaVariable v, Expr e, int delta, boolean upper, boo
|
||||
or
|
||||
// guard that tests whether `v2` is bounded by `e + delta + d1 - d2` and
|
||||
// exists a guard `guardEq` such that `v = v2 - d1 + d2`.
|
||||
exists(SsaVariable v2, Guard guardEq, boolean eqIsTrue, int d1, int d2 |
|
||||
guardEq = eqFlowCond(v, ssaRead(v2, d1), d2, true, eqIsTrue) and
|
||||
result = boundFlowCond(v2, e, delta + d1 - d2, upper, testIsTrue) and
|
||||
// guardEq needs to control guard
|
||||
guardEq.directlyControls(result.getBasicBlock(), eqIsTrue)
|
||||
exists(SsaVariable v2, int d |
|
||||
// equality needs to control guard
|
||||
result.getBasicBlock() = eqSsaCondDirectlyControls(v, v2, d) and
|
||||
result = boundFlowCond(v2, e, delta - d, upper, testIsTrue)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a basic block in which `v1` equals `v2 + delta`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private BasicBlock eqSsaCondDirectlyControls(SsaVariable v1, SsaVariable v2, int delta) {
|
||||
exists(Guard guardEq, int d1, int d2, boolean eqIsTrue |
|
||||
guardEq = eqFlowCond(v1, ssaRead(v2, d1), d2, true, eqIsTrue) and
|
||||
delta = d2 - d1 and
|
||||
guardEq.directlyControls(result, eqIsTrue)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,10 @@ import semmle.code.java.dataflow.DataFlow2
|
||||
import semmle.code.java.dataflow.internal.TaintTrackingUtil::StringBuilderVarModule
|
||||
|
||||
module TaintTracking {
|
||||
import semmle.code.java.dataflow.internal.tainttracking1.TaintTracking
|
||||
import semmle.code.java.dataflow.internal.tainttracking1.TaintTrackingParameter::Public
|
||||
private import semmle.code.java.dataflow.internal.DataFlowImplSpecific
|
||||
private import semmle.code.java.dataflow.internal.TaintTrackingImplSpecific
|
||||
private import codeql.dataflow.TaintTracking
|
||||
import TaintFlowMake<JavaDataFlow, JavaTaintTracking>
|
||||
import semmle.code.java.dataflow.internal.tainttracking1.TaintTrackingImpl
|
||||
}
|
||||
|
||||
@@ -2,16 +2,16 @@ private import java
|
||||
private import DataFlowPrivate
|
||||
private import DataFlowUtil
|
||||
private import semmle.code.java.dataflow.InstanceAccess
|
||||
private import semmle.code.java.dataflow.FlowSummary
|
||||
private import semmle.code.java.dataflow.internal.FlowSummaryImpl as Impl
|
||||
private import semmle.code.java.dispatch.VirtualDispatch as VirtualDispatch
|
||||
private import semmle.code.java.dataflow.TypeFlow
|
||||
private import semmle.code.java.dispatch.internal.Unification
|
||||
|
||||
private module DispatchImpl {
|
||||
private predicate hasHighConfidenceTarget(Call c) {
|
||||
exists(SummarizedCallable sc | sc.getACall() = c and not sc.applyGeneratedModel())
|
||||
exists(Impl::Public::SummarizedCallable sc | sc.getACall() = c and not sc.applyGeneratedModel())
|
||||
or
|
||||
exists(NeutralCallable nc | nc.getACall() = c and nc.hasManualModel())
|
||||
exists(Impl::Public::NeutralSummaryCallable nc | nc.getACall() = c and nc.hasManualModel())
|
||||
or
|
||||
exists(Callable srcTgt |
|
||||
srcTgt = VirtualDispatch::viableCallable(c) and
|
||||
|
||||
@@ -296,11 +296,21 @@ module Public {
|
||||
predicate hasProvenance(Provenance provenance) { provenance = "manual" }
|
||||
}
|
||||
|
||||
/** A callable where there is no flow via the callable. */
|
||||
class NeutralCallable extends SummarizedCallableBase {
|
||||
/**
|
||||
* A callable where there is no flow via the callable.
|
||||
*/
|
||||
class NeutralSummaryCallable extends NeutralCallable {
|
||||
NeutralSummaryCallable() { this.getKind() = "summary" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A callable that has a neutral model.
|
||||
*/
|
||||
class NeutralCallable extends NeutralCallableBase {
|
||||
private string kind;
|
||||
private Provenance provenance;
|
||||
|
||||
NeutralCallable() { neutralSummaryElement(this, provenance) }
|
||||
NeutralCallable() { neutralElement(this, kind, provenance) }
|
||||
|
||||
/**
|
||||
* Holds if the neutral is auto generated.
|
||||
@@ -316,6 +326,11 @@ module Public {
|
||||
* Holds if the neutral has provenance `p`.
|
||||
*/
|
||||
predicate hasProvenance(Provenance p) { p = provenance }
|
||||
|
||||
/**
|
||||
* Gets the kind of the neutral.
|
||||
*/
|
||||
string getKind() { result = kind }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1318,6 +1333,11 @@ module Private {
|
||||
/** Gets the string representation of this callable used by `neutral/1`. */
|
||||
abstract string getCallableCsv();
|
||||
|
||||
/**
|
||||
* Gets the kind of the neutral.
|
||||
*/
|
||||
string getKind() { result = super.getKind() }
|
||||
|
||||
string toString() { result = super.toString() }
|
||||
}
|
||||
|
||||
@@ -1358,12 +1378,13 @@ module Private {
|
||||
|
||||
/**
|
||||
* Holds if a neutral model `csv` exists (semi-colon separated format). Used for testing purposes.
|
||||
* The syntax is: "namespace;type;name;signature;provenance"",
|
||||
* The syntax is: "namespace;type;name;signature;kind;provenance"",
|
||||
*/
|
||||
query predicate neutral(string csv) {
|
||||
exists(RelevantNeutralCallable c |
|
||||
csv =
|
||||
c.getCallableCsv() // Callable information
|
||||
+ c.getKind() + ";" // kind
|
||||
+ renderProvenanceNeutral(c) // provenance
|
||||
)
|
||||
}
|
||||
|
||||
@@ -14,6 +14,16 @@ private import semmle.code.java.dataflow.internal.AccessPathSyntax as AccessPath
|
||||
|
||||
class SummarizedCallableBase = FlowSummary::SummarizedCallableBase;
|
||||
|
||||
/**
|
||||
* A class of callables that are candidates for neutral modeling.
|
||||
*/
|
||||
class NeutralCallableBase extends Callable {
|
||||
NeutralCallableBase() { this.isSourceDeclaration() }
|
||||
|
||||
/** Gets a call that targets this neutral. */
|
||||
Call getACall() { result.getCallee().getSourceDeclaration() = this }
|
||||
}
|
||||
|
||||
/**
|
||||
* A module for importing frameworks that define synthetic globals.
|
||||
*/
|
||||
@@ -156,13 +166,13 @@ predicate summaryElement(
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a neutral summary model exists for `c` with provenance `provenance`,
|
||||
* which means that there is no flow through `c`.
|
||||
* Holds if a neutral model exists for `c` of kind `kind`
|
||||
* and with provenance `provenance`.
|
||||
*/
|
||||
predicate neutralSummaryElement(SummarizedCallableBase c, string provenance) {
|
||||
predicate neutralElement(NeutralCallableBase c, string kind, string provenance) {
|
||||
exists(string namespace, string type, string name, string signature |
|
||||
neutralModel(namespace, type, name, signature, "summary", provenance) and
|
||||
c.asCallable() = interpretElement(namespace, type, false, name, signature, "")
|
||||
neutralModel(namespace, type, name, signature, kind, provenance) and
|
||||
c = interpretElement(namespace, type, false, name, signature, "")
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Provides Java-specific definitions for use in the taint tracking library.
|
||||
*/
|
||||
|
||||
private import codeql.dataflow.TaintTracking
|
||||
private import DataFlowImplSpecific
|
||||
|
||||
module JavaTaintTracking implements InputSig<JavaDataFlow> {
|
||||
import TaintTrackingUtil
|
||||
}
|
||||
@@ -177,7 +177,7 @@ private RefType getElementType(RefType container) {
|
||||
* of `c` at sinks and inputs to additional taint steps.
|
||||
*/
|
||||
bindingset[node]
|
||||
predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::Content c) {
|
||||
predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||
exists(RefType container |
|
||||
(node.asExpr() instanceof Argument or node instanceof ArgumentNode) and
|
||||
getElementType*(node.getType()) = container
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
/**
|
||||
* Provides classes for performing local (intra-procedural) and
|
||||
* global (inter-procedural) taint-tracking analyses.
|
||||
*/
|
||||
|
||||
import TaintTrackingParameter::Public
|
||||
private import TaintTrackingParameter::Private
|
||||
|
||||
private module AddTaintDefaults<DataFlowInternal::FullStateConfigSig Config> implements
|
||||
DataFlowInternal::FullStateConfigSig
|
||||
{
|
||||
import Config
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
Config::isBarrier(node) or defaultTaintSanitizer(node)
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
Config::isAdditionalFlowStep(node1, node2) or
|
||||
defaultAdditionalTaintStep(node1, node2)
|
||||
}
|
||||
|
||||
predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||
Config::allowImplicitRead(node, c)
|
||||
or
|
||||
(
|
||||
Config::isSink(node) or
|
||||
Config::isSink(node, _) or
|
||||
Config::isAdditionalFlowStep(node, _) or
|
||||
Config::isAdditionalFlowStep(node, _, _, _)
|
||||
) and
|
||||
defaultImplicitTaintRead(node, c)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a global taint tracking computation.
|
||||
*/
|
||||
module Global<DataFlow::ConfigSig Config> implements DataFlow::GlobalFlowSig {
|
||||
private module Config0 implements DataFlowInternal::FullStateConfigSig {
|
||||
import DataFlowInternal::DefaultState<Config>
|
||||
import Config
|
||||
}
|
||||
|
||||
private module C implements DataFlowInternal::FullStateConfigSig {
|
||||
import AddTaintDefaults<Config0>
|
||||
}
|
||||
|
||||
import DataFlowInternal::Impl<C>
|
||||
}
|
||||
|
||||
/** DEPRECATED: Use `Global` instead. */
|
||||
deprecated module Make<DataFlow::ConfigSig Config> implements DataFlow::GlobalFlowSig {
|
||||
import Global<Config>
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a global taint tracking computation using flow state.
|
||||
*/
|
||||
module GlobalWithState<DataFlow::StateConfigSig Config> implements DataFlow::GlobalFlowSig {
|
||||
private module Config0 implements DataFlowInternal::FullStateConfigSig {
|
||||
import Config
|
||||
}
|
||||
|
||||
private module C implements DataFlowInternal::FullStateConfigSig {
|
||||
import AddTaintDefaults<Config0>
|
||||
}
|
||||
|
||||
import DataFlowInternal::Impl<C>
|
||||
}
|
||||
|
||||
/** DEPRECATED: Use `GlobalWithState` instead. */
|
||||
deprecated module MakeWithState<DataFlow::StateConfigSig Config> implements DataFlow::GlobalFlowSig {
|
||||
import GlobalWithState<Config>
|
||||
}
|
||||
@@ -4,6 +4,8 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
private import semmle.code.java.frameworks.Networking
|
||||
private import semmle.code.java.frameworks.Rmi
|
||||
private import semmle.code.java.security.XSS
|
||||
|
||||
/**
|
||||
@@ -23,16 +25,112 @@ string getAJaxRsPackage(string subpackage) { result = getAJaxRsPackage() + "." +
|
||||
*/
|
||||
class JaxWsEndpoint extends Class {
|
||||
JaxWsEndpoint() {
|
||||
exists(AnnotationType a | a = this.getAnAnnotation().getType() |
|
||||
exists(AnnotationType a | a = this.getAnAncestor().getAnAnnotation().getType() |
|
||||
a.hasName(["WebService", "WebServiceProvider", "WebServiceClient"])
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets a method annotated with `@WebMethod` or `@WebEndpoint`. */
|
||||
Callable getARemoteMethod() {
|
||||
/**
|
||||
* Gets a method of this class that is not an excluded `@WebMethod`,
|
||||
* and the parameters and return value of which are either of an acceptable type,
|
||||
* or are annotated with `@XmlJavaTypeAdapter`.
|
||||
*/
|
||||
Method getARemoteMethod() {
|
||||
result = this.getACallable() and
|
||||
exists(AnnotationType a | a = result.getAnAnnotation().getType() |
|
||||
a.hasName(["WebMethod", "WebEndpoint"])
|
||||
result.isPublic() and
|
||||
not result instanceof InitializerMethod and
|
||||
not exists(Annotation a | a = result.getAnAnnotation() |
|
||||
a.getType().hasQualifiedName(["javax", "jakarta"] + ".jws", "WebMethod") and
|
||||
a.getValue("exclude").(BooleanLiteral).getBooleanValue() = true
|
||||
) and
|
||||
forex(ParamOrReturn paramOrRet | paramOrRet = result.getAParameter() or paramOrRet = result |
|
||||
exists(Type t | t = paramOrRet.getType() |
|
||||
t instanceof JaxAcceptableType
|
||||
or
|
||||
t.(Annotatable).getAnAnnotation().getType() instanceof XmlJavaTypeAdapter
|
||||
or
|
||||
t instanceof VoidType
|
||||
)
|
||||
or
|
||||
paramOrRet.getInheritedAnnotation().getType() instanceof XmlJavaTypeAdapter
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** The annotation type `@XmlJavaTypeAdapter`. */
|
||||
class XmlJavaTypeAdapter extends AnnotationType {
|
||||
XmlJavaTypeAdapter() {
|
||||
this.hasQualifiedName(["javax", "jakarta"] + ".xml.bind.annotation.adapters",
|
||||
"XmlJavaTypeAdapter")
|
||||
}
|
||||
}
|
||||
|
||||
private class ParamOrReturn extends Annotatable {
|
||||
ParamOrReturn() { this instanceof Parameter or this instanceof Method }
|
||||
|
||||
Type getType() {
|
||||
result = this.(Parameter).getType()
|
||||
or
|
||||
result = this.(Method).getReturnType()
|
||||
}
|
||||
|
||||
Annotation getInheritedAnnotation() {
|
||||
result = this.getAnAnnotation()
|
||||
or
|
||||
result = this.(Method).getAnOverride*().getAnAnnotation()
|
||||
or
|
||||
result =
|
||||
this.(Parameter)
|
||||
.getCallable()
|
||||
.(Method)
|
||||
.getAnOverride*()
|
||||
.getParameter(this.(Parameter).getPosition())
|
||||
.getAnAnnotation()
|
||||
}
|
||||
}
|
||||
|
||||
// JAX-RPC 1.1, section 5
|
||||
private class JaxAcceptableType extends Type {
|
||||
JaxAcceptableType() {
|
||||
// JAX-RPC 1.1, section 5.1.1
|
||||
this instanceof PrimitiveType
|
||||
or
|
||||
// JAX-RPC 1.1, section 5.1.2
|
||||
this.(Array).getElementType() instanceof JaxAcceptableType
|
||||
or
|
||||
// JAX-RPC 1.1, section 5.1.3
|
||||
this instanceof JaxAcceptableStandardClass
|
||||
or
|
||||
// JAX-RPC 1.1, section 5.1.4
|
||||
this instanceof JaxValueType
|
||||
}
|
||||
}
|
||||
|
||||
private class JaxAcceptableStandardClass extends RefType {
|
||||
JaxAcceptableStandardClass() {
|
||||
this instanceof TypeString or
|
||||
this.hasQualifiedName("java.util", "Date") or
|
||||
this.hasQualifiedName("java.util", "Calendar") or
|
||||
this.hasQualifiedName("java.math", "BigInteger") or
|
||||
this.hasQualifiedName("java.math", "BigDecimal") or
|
||||
this.hasQualifiedName("javax.xml.namespace", "QName") or
|
||||
this instanceof TypeUri
|
||||
}
|
||||
}
|
||||
|
||||
// JAX-RPC 1.1, section 5.4
|
||||
private class JaxValueType extends RefType {
|
||||
JaxValueType() {
|
||||
not this instanceof Wildcard and
|
||||
// Mutually exclusive with other `JaxAcceptableType`s
|
||||
not this instanceof Array and
|
||||
not this instanceof JaxAcceptableStandardClass and
|
||||
not this.getPackage().getName().matches("java.%") and
|
||||
// Must not implement (directly or indirectly) the java.rmi.Remote interface.
|
||||
not this.getAnAncestor() instanceof TypeRemote and
|
||||
// The Java type of a public field must be a supported JAX-RPC type as specified in the section 5.1.
|
||||
forall(Field f | this.getAMember() = f and f.isPublic() |
|
||||
f.getType() instanceof JaxAcceptableType
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -397,3 +397,8 @@ class GetServletResourceAsStreamMethod extends Method {
|
||||
this.hasName("getResourceAsStream")
|
||||
}
|
||||
}
|
||||
|
||||
/** The interface `javax.servlet.http.HttpSession` */
|
||||
class HttpServletSession extends RefType {
|
||||
HttpServletSession() { this.hasQualifiedName("javax.servlet.http", "HttpSession") }
|
||||
}
|
||||
|
||||
22
java/ql/lib/semmle/code/java/frameworks/mdht/MdhtXml.qll
Normal file
22
java/ql/lib/semmle/code/java/frameworks/mdht/MdhtXml.qll
Normal file
@@ -0,0 +1,22 @@
|
||||
/** Provides definitions related to XML parsing in Model-Driven Health Tools. */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.security.XmlParsers
|
||||
|
||||
/** A call to `CDAUtil.load` or `CDAUtil.loadAs`. */
|
||||
private class CdaUtilLoad extends XmlParserCall {
|
||||
CdaUtilLoad() {
|
||||
this.getMethod()
|
||||
.hasQualifiedName("org.openhealthtools.mdht.uml.cda.util", "CDAUtil", ["load", "loadAs"])
|
||||
}
|
||||
|
||||
override Expr getSink() {
|
||||
result = this.getAnArgument() and
|
||||
exists(RefType t | result.getType().(RefType).getASourceSupertype*() = t |
|
||||
t instanceof TypeInputStream or
|
||||
t instanceof InputSource
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSafe() { none() }
|
||||
}
|
||||
40
java/ql/lib/semmle/code/java/frameworks/owasp/Esapi.qll
Normal file
40
java/ql/lib/semmle/code/java/frameworks/owasp/Esapi.qll
Normal file
@@ -0,0 +1,40 @@
|
||||
/** Classes and predicates for reasoning about the `owasp.easpi` package. */
|
||||
|
||||
import java
|
||||
|
||||
/**
|
||||
* The `org.owasp.esapi.Validator` interface.
|
||||
*/
|
||||
class EsapiValidator extends RefType {
|
||||
EsapiValidator() { this.hasQualifiedName("org.owasp.esapi", "Validator") }
|
||||
}
|
||||
|
||||
/**
|
||||
* The methods of `org.owasp.esapi.Validator` which validate data.
|
||||
*/
|
||||
class EsapiIsValidMethod extends Method {
|
||||
EsapiIsValidMethod() {
|
||||
this.getDeclaringType() instanceof EsapiValidator and
|
||||
this.hasName([
|
||||
"isValidCreditCard", "isValidDate", "isValidDirectoryPath", "isValidDouble",
|
||||
"isValidFileContent", "isValidFileName", "isValidInput", "isValidInteger",
|
||||
"isValidListItem", "isValidNumber", "isValidPrintable", "isValidRedirectLocation",
|
||||
"isValidSafeHTML", "isValidURI"
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The methods of `org.owasp.esapi.Validator` which return validated data.
|
||||
*/
|
||||
class EsapiGetValidMethod extends Method {
|
||||
EsapiGetValidMethod() {
|
||||
this.getDeclaringType() instanceof EsapiValidator and
|
||||
this.hasName([
|
||||
"getValidCreditCard", "getValidDate", "getValidDirectoryPath", "getValidDouble",
|
||||
"getValidFileContent", "getValidFileName", "getValidInput", "getValidInteger",
|
||||
"getValidListItem", "getValidNumber", "getValidPrintable", "getValidRedirectLocation",
|
||||
"getValidSafeHTML", "getValidURI"
|
||||
])
|
||||
}
|
||||
}
|
||||
@@ -148,6 +148,8 @@ private module RegexFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
node.getEnclosingCallable().getDeclaringType() instanceof NonSecurityTestClass
|
||||
}
|
||||
|
||||
int fieldFlowBranchLimit() { result = 1 }
|
||||
}
|
||||
|
||||
private module RegexFlow = DataFlow::Global<RegexFlowConfig>;
|
||||
|
||||
@@ -42,6 +42,8 @@ private class DefaultCommandInjectionSanitizer extends CommandInjectionSanitizer
|
||||
or
|
||||
this.getType() instanceof BoxedType
|
||||
or
|
||||
this.getType() instanceof NumberType
|
||||
or
|
||||
isSafeCommandArgument(this.asExpr())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,7 +270,7 @@ string getInsecureAlgorithmRegex() {
|
||||
string getASecureAlgorithmName() {
|
||||
result =
|
||||
[
|
||||
"RSA", "SHA256", "SHA512", "CCM", "GCM", "AES(?)",
|
||||
"RSA", "SHA-?256", "SHA-?512", "CCM", "GCM", "AES(?)",
|
||||
"Blowfish", "ECIES"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
/** Provides classes and predicates to reason about trust boundary violations */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.DataFlow
|
||||
private import semmle.code.java.controlflow.Guards
|
||||
private import semmle.code.java.dataflow.ExternalFlow
|
||||
private import semmle.code.java.dataflow.FlowSources
|
||||
private import semmle.code.java.frameworks.owasp.Esapi
|
||||
|
||||
/**
|
||||
* A source of data that crosses a trust boundary.
|
||||
*/
|
||||
abstract class TrustBoundaryViolationSource extends DataFlow::Node { }
|
||||
|
||||
private class RemoteSource extends TrustBoundaryViolationSource instanceof RemoteFlowSource { }
|
||||
|
||||
/**
|
||||
* A sink for data that crosses a trust boundary.
|
||||
*/
|
||||
class TrustBoundaryViolationSink extends DataFlow::Node {
|
||||
TrustBoundaryViolationSink() { sinkNode(this, "trust-boundary-violation") }
|
||||
}
|
||||
|
||||
/**
|
||||
* A sanitizer for data that crosses a trust boundary.
|
||||
*/
|
||||
abstract class TrustBoundaryValidationSanitizer extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A node validated by an OWASP ESAPI validation method.
|
||||
*/
|
||||
private class EsapiValidatedInputSanitizer extends TrustBoundaryValidationSanitizer {
|
||||
EsapiValidatedInputSanitizer() {
|
||||
this = DataFlow::BarrierGuard<esapiIsValidData/3>::getABarrierNode() or
|
||||
this.asExpr().(MethodAccess).getMethod() instanceof EsapiGetValidMethod
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `g` is a guard that checks that `e` is valid data according to an OWASP ESAPI validation method.
|
||||
*/
|
||||
private predicate esapiIsValidData(Guard g, Expr e, boolean branch) {
|
||||
branch = true and
|
||||
exists(MethodAccess ma | ma.getMethod() instanceof EsapiIsValidMethod |
|
||||
g = ma and
|
||||
e = ma.getArgument(1)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Taint tracking for data that crosses a trust boundary.
|
||||
*/
|
||||
module TrustBoundaryConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof TrustBoundaryViolationSource }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
node instanceof TrustBoundaryValidationSanitizer or
|
||||
node.getType() instanceof HttpServletSession or
|
||||
node.getType() instanceof NumberType or
|
||||
node.getType() instanceof PrimitiveType or
|
||||
node.getType() instanceof BoxedType
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof TrustBoundaryViolationSink }
|
||||
}
|
||||
|
||||
/**
|
||||
* Taint-tracking flow for values which cross a trust boundary.
|
||||
*/
|
||||
module TrustBoundaryFlow = TaintTracking::Global<TrustBoundaryConfig>;
|
||||
@@ -9,6 +9,7 @@ private module Frameworks {
|
||||
private import semmle.code.java.frameworks.apache.CommonsXml
|
||||
private import semmle.code.java.frameworks.javaee.Xml
|
||||
private import semmle.code.java.frameworks.javase.Beans
|
||||
private import semmle.code.java.frameworks.mdht.MdhtXml
|
||||
private import semmle.code.java.frameworks.rundeck.RundeckXml
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user