Merge branch 'main' into atorralba/promote-ognl-injection

This commit is contained in:
Tony Torralba
2021-06-16 15:46:33 +02:00
committed by GitHub
1054 changed files with 29133 additions and 9060 deletions

View File

@@ -7,6 +7,7 @@
* Such operations could interfere with the EJB container's operation.
* @kind problem
* @problem.severity error
* @security-severity 4.9
* @precision low
* @id java/ejb/container-interference
* @tags reliability

View File

@@ -5,6 +5,7 @@
* for enterprise components.
* @kind problem
* @problem.severity error
* @security-severity 4.9
* @precision low
* @id java/ejb/file-io
* @tags reliability

View File

@@ -4,6 +4,7 @@
* Such use could compromise security and system stability.
* @kind problem
* @problem.severity error
* @security-severity 4.9
* @precision low
* @id java/ejb/native-code
* @tags reliability

View File

@@ -4,6 +4,7 @@
* as this could compromise security.
* @kind problem
* @problem.severity error
* @security-severity 4.9
* @precision low
* @id java/ejb/reflection
* @tags external/cwe/cwe-573

View File

@@ -5,6 +5,7 @@
* This functionality is reserved for the EJB container for security reasons.
* @kind problem
* @problem.severity error
* @security-severity 4.9
* @precision low
* @id java/ejb/security-configuration-access
* @tags external/cwe/cwe-573

View File

@@ -4,6 +4,7 @@
* the Java serialization protocol, since their use could compromise security.
* @kind problem
* @problem.severity error
* @security-severity 4.9
* @precision low
* @id java/ejb/substitution-in-serialization
* @tags external/cwe/cwe-573

View File

@@ -5,6 +5,7 @@
* compromise security or interfere with the EJB container's operation.
* @kind problem
* @problem.severity error
* @security-severity 4.9
* @precision low
* @id java/ejb/socket-or-stream-handler-factory
* @tags reliability

View File

@@ -5,6 +5,7 @@
* numeric errors such as overflows.
* @kind problem
* @problem.severity warning
* @security-severity 5.9
* @precision very-high
* @id java/implicit-cast-in-compound-assignment
* @tags reliability

View File

@@ -4,6 +4,7 @@
* guarantee an evenly distributed sequence of random numbers.
* @kind problem
* @problem.severity warning
* @security-severity 5.9
* @precision medium
* @id java/random-used-once
* @tags reliability

View File

@@ -4,6 +4,7 @@
* may cause a deadlock.
* @kind problem
* @problem.severity error
* @security-severity 6.9
* @precision medium
* @id java/unreleased-lock
* @tags reliability

View File

@@ -14,7 +14,7 @@ but not closed may cause a resource leak.
<p>Ensure that the resource is always closed to avoid a resource leak. Note that, because of exceptions,
it is safest to close a resource in a <code>finally</code> block. (However, this is unnecessary for
subclasses of <code>StringReader</code> and <code>ByteArrayInputStream</code>.)
subclasses of <code>CharArrayReader</code>, <code>StringReader</code> and <code>ByteArrayInputStream</code>.)
</p>
<p>For Java 7 or later, the recommended way to close resources that implement <code>java.lang.AutoCloseable</code>

View File

@@ -17,16 +17,16 @@ import CloseType
predicate readerType(RefType t) {
exists(RefType sup | sup = t.getASupertype*() |
sup.hasName("Reader") or
sup.hasName("InputStream") or
sup.hasQualifiedName("java.io", ["Reader", "InputStream"]) or
sup.hasQualifiedName("java.util.zip", "ZipFile")
)
}
predicate safeReaderType(RefType t) {
exists(RefType sup | sup = t.getASupertype*() |
sup.hasName("StringReader") or
sup.hasName("ByteArrayInputStream") or
sup.hasQualifiedName("java.io", ["CharArrayReader", "StringReader", "ByteArrayInputStream"])
or
// Note: It is unclear which specific class this is supposed to match
sup.hasName("StringInputStream")
)
}

View File

@@ -14,7 +14,7 @@ but not properly closed later may cause a resource leak.
<p>Ensure that the resource is always closed to avoid a resource leak. Note that, because of exceptions,
it is safest to close a resource properly in a <code>finally</code> block. (However, this is unnecessary for
subclasses of <code>StringWriter</code> and <code>ByteArrayOutputStream</code>.)</p>
subclasses of <code>CharArrayWriter</code>, <code>StringWriter</code> and <code>ByteArrayOutputStream</code>.)</p>
<p>For Java 7 or later, the recommended way to close resources that implement <code>java.lang.AutoCloseable</code>
is to declare them within a <code>try-with-resources</code> statement, so that they are closed implicitly.</p>

View File

@@ -17,15 +17,13 @@ import CloseType
predicate writerType(RefType t) {
exists(RefType sup | sup = t.getASupertype*() |
sup.hasName("Writer") or
sup.hasName("OutputStream")
sup.hasQualifiedName("java.io", ["Writer", "OutputStream"])
)
}
predicate safeWriterType(RefType t) {
exists(RefType sup | sup = t.getASupertype*() |
sup.hasName("StringWriter") or
sup.hasName("ByteArrayOutputStream")
sup.hasQualifiedName("java.io", ["CharArrayWriter", "StringWriter", "ByteArrayOutputStream"])
)
}

View File

@@ -5,6 +5,7 @@
* @kind path-problem
* @precision low
* @problem.severity error
* @security-severity 5.9
* @tags security external/cwe/cwe-20
*/

View File

@@ -3,6 +3,7 @@
* @description Accessing paths influenced by users can allow an attacker to access unexpected resources.
* @kind path-problem
* @problem.severity error
* @security-severity 6.4
* @precision high
* @id java/path-injection
* @tags security

View File

@@ -3,6 +3,7 @@
* @description Accessing paths influenced by users can allow an attacker to access unexpected resources.
* @kind path-problem
* @problem.severity recommendation
* @security-severity 6.4
* @precision medium
* @id java/path-injection-local
* @tags security

View File

@@ -6,6 +6,7 @@
* @kind path-problem
* @id java/zipslip
* @problem.severity error
* @security-severity 6.4
* @precision high
* @tags security
* external/cwe/cwe-022

View File

@@ -4,6 +4,7 @@
* malicious changes in the PATH environment variable.
* @kind problem
* @problem.severity warning
* @security-severity 5.9
* @precision medium
* @id java/relative-path-command
* @tags security

View File

@@ -4,6 +4,7 @@
* changes in the strings.
* @kind path-problem
* @problem.severity error
* @security-severity 5.9
* @precision high
* @id java/command-line-injection
* @tags security

View File

@@ -4,6 +4,7 @@
* changes in the strings.
* @kind path-problem
* @problem.severity recommendation
* @security-severity 5.9
* @precision medium
* @id java/command-line-injection-local
* @tags security

View File

@@ -4,6 +4,7 @@
* insertion of special characters in the strings.
* @kind problem
* @problem.severity error
* @security-severity 5.9
* @precision high
* @id java/concatenated-command-line
* @tags security

View File

@@ -4,6 +4,7 @@
* allows for a cross-site scripting vulnerability.
* @kind path-problem
* @problem.severity error
* @security-severity 2.9
* @precision high
* @id java/xss
* @tags security

View File

@@ -4,6 +4,7 @@
* allows for a cross-site scripting vulnerability.
* @kind path-problem
* @problem.severity recommendation
* @security-severity 2.9
* @precision medium
* @id java/xss-local
* @tags security

View File

@@ -4,6 +4,7 @@
* malicious code by the user.
* @kind path-problem
* @problem.severity error
* @security-severity 6.4
* @precision high
* @id java/sql-injection
* @tags security

View File

@@ -4,6 +4,7 @@
* malicious code by the user.
* @kind path-problem
* @problem.severity recommendation
* @security-severity 6.4
* @precision medium
* @id java/sql-injection-local
* @tags security

View File

@@ -4,6 +4,7 @@
* characters is vulnerable to insertion of malicious code.
* @kind problem
* @problem.severity error
* @security-severity 6.4
* @precision high
* @id java/concatenated-sql-query
* @tags security

View File

@@ -4,6 +4,7 @@
* malicious LDAP code by the user.
* @kind path-problem
* @problem.severity error
* @security-severity 5.9
* @precision high
* @id java/ldap-injection
* @tags security

View File

@@ -3,6 +3,7 @@
* @description User-controlled data may be evaluated as a Java EL expression, leading to arbitrary code execution.
* @kind path-problem
* @problem.severity error
* @security-severity 10.0
* @precision high
* @id java/insecure-bean-validation
* @tags security

View File

@@ -0,0 +1,38 @@
/**
* @name Expression language injection (JEXL)
* @description Evaluation of a user-controlled JEXL expression
* may lead to arbitrary code execution.
* @kind path-problem
* @problem.severity error
* @security-severity 10.0
* @precision high
* @id java/jexl-expression-injection
* @tags security
* external/cwe/cwe-094
*/
import java
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.security.JexlInjection
import DataFlow::PathGraph
/**
* A taint-tracking configuration for unsafe user input
* that is used to construct and evaluate a JEXL expression.
* It supports both JEXL 2 and 3.
*/
class JexlInjectionConfig extends TaintTracking::Configuration {
JexlInjectionConfig() { this = "JexlInjectionConfig" }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) { sink instanceof JexlEvaluationSink }
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
any(JexlInjectionAdditionalTaintStep c).step(node1, node2)
}
}
from DataFlow::PathNode source, DataFlow::PathNode sink, JexlInjectionConfig conf
where conf.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "JEXL injection from $@.", source.getNode(), "this user input"

View File

@@ -3,6 +3,7 @@
* @description Using a deprecated artifact repository may eventually give attackers access for a supply chain attack.
* @kind problem
* @problem.severity error
* @security-severity 6.5
* @precision very-high
* @id java/maven/dependency-upon-bintray
* @tags security

View File

@@ -5,6 +5,7 @@
* an HTTP header.
* @kind problem
* @problem.severity error
* @security-severity 3.6
* @precision high
* @id java/netty-http-response-splitting
* @tags security

View File

@@ -4,6 +4,7 @@
* makes code vulnerable to attack by header splitting.
* @kind path-problem
* @problem.severity error
* @security-severity 3.6
* @precision high
* @id java/http-response-splitting
* @tags security

View File

@@ -4,6 +4,7 @@
* makes code vulnerable to attack by header splitting.
* @kind path-problem
* @problem.severity recommendation
* @security-severity 3.6
* @precision medium
* @id java/http-response-splitting-local
* @tags security

View File

@@ -3,6 +3,7 @@
* @description Using unvalidated external input as the argument to a construction of an array can lead to index out of bound exceptions.
* @kind path-problem
* @problem.severity warning
* @security-severity 5.9
* @precision medium
* @id java/improper-validation-of-array-construction
* @tags security

View File

@@ -4,6 +4,7 @@
* a construction of an array can lead to index out of bound exceptions.
* @kind path-problem
* @problem.severity recommendation
* @security-severity 5.9
* @precision medium
* @id java/improper-validation-of-array-construction-code-specified
* @tags security

View File

@@ -4,6 +4,7 @@
* a construction of an array can lead to index out of bound exceptions.
* @kind path-problem
* @problem.severity recommendation
* @security-severity 5.9
* @precision medium
* @id java/improper-validation-of-array-construction-local
* @tags security

View File

@@ -3,6 +3,7 @@
* @description Using external input as an index to an array, without proper validation, can lead to index out of bound exceptions.
* @kind path-problem
* @problem.severity warning
* @security-severity 5.9
* @precision medium
* @id java/improper-validation-of-array-index
* @tags security

View File

@@ -4,6 +4,7 @@
* proper validation, can lead to index out of bound exceptions.
* @kind path-problem
* @problem.severity recommendation
* @security-severity 5.9
* @precision medium
* @id java/improper-validation-of-array-index-code-specified
* @tags security

View File

@@ -4,6 +4,7 @@
* proper validation, can lead to index out of bound exceptions.
* @kind path-problem
* @problem.severity recommendation
* @security-severity 5.9
* @precision medium
* @id java/improper-validation-of-array-index-local
* @tags security

View File

@@ -3,6 +3,7 @@
* @description Using external input in format strings can lead to exceptions or information leaks.
* @kind path-problem
* @problem.severity error
* @security-severity 6.9
* @precision high
* @id java/tainted-format-string
* @tags security

View File

@@ -3,6 +3,7 @@
* @description Using external input in format strings can lead to exceptions or information leaks.
* @kind path-problem
* @problem.severity recommendation
* @security-severity 6.9
* @precision medium
* @id java/tainted-format-string-local
* @tags security

View File

@@ -4,6 +4,7 @@
* overflows.
* @kind path-problem
* @problem.severity warning
* @security-severity 5.9
* @precision medium
* @id java/tainted-arithmetic
* @tags security

View File

@@ -4,6 +4,7 @@
* overflows.
* @kind path-problem
* @problem.severity recommendation
* @security-severity 5.9
* @precision medium
* @id java/tainted-arithmetic-local
* @tags security

View File

@@ -4,6 +4,7 @@
* overflows.
* @kind path-problem
* @problem.severity warning
* @security-severity 5.9
* @precision medium
* @id java/uncontrolled-arithmetic
* @tags security

View File

@@ -4,6 +4,7 @@
* is then used in an arithmetic expression, this may result in an overflow.
* @kind path-problem
* @problem.severity recommendation
* @security-severity 5.9
* @precision medium
* @id java/extreme-value-arithmetic
* @tags security

View File

@@ -4,6 +4,7 @@
* to behave unexpectedly.
* @kind problem
* @problem.severity warning
* @security-severity 5.9
* @precision medium
* @id java/comparison-with-wider-type
* @tags reliability

View File

@@ -5,6 +5,7 @@
* that are useful to an attacker for developing a subsequent exploit.
* @kind problem
* @problem.severity error
* @security-severity 3.6
* @precision high
* @id java/stack-trace-exposure
* @tags security
@@ -15,7 +16,7 @@
import java
import semmle.code.java.dataflow.DataFlow
import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.security.XSS
import semmle.code.java.security.InformationLeak
/**
* One of the `printStackTrace()` overloads on `Throwable`.
@@ -83,14 +84,14 @@ predicate stackTraceExpr(Expr exception, MethodAccess stackTraceString) {
)
}
class StackTraceStringToXssSinkFlowConfig extends TaintTracking::Configuration {
StackTraceStringToXssSinkFlowConfig() {
this = "StackTraceExposure::StackTraceStringToXssSinkFlowConfig"
class StackTraceStringToHttpResponseSinkFlowConfig extends TaintTracking::Configuration {
StackTraceStringToHttpResponseSinkFlowConfig() {
this = "StackTraceExposure::StackTraceStringToHttpResponseSinkFlowConfig"
}
override predicate isSource(DataFlow::Node src) { stackTraceExpr(_, src.asExpr()) }
override predicate isSink(DataFlow::Node sink) { sink instanceof XssSink }
override predicate isSink(DataFlow::Node sink) { sink instanceof InformationLeakSink }
}
/**
@@ -105,8 +106,8 @@ predicate printsStackExternally(MethodAccess call, Expr stackTrace) {
/**
* A stringified stack trace flows to an external sink.
*/
predicate stringifiedStackFlowsExternally(XssSink externalExpr, Expr stackTrace) {
exists(MethodAccess stackTraceString, StackTraceStringToXssSinkFlowConfig conf |
predicate stringifiedStackFlowsExternally(DataFlow::Node externalExpr, Expr stackTrace) {
exists(MethodAccess stackTraceString, StackTraceStringToHttpResponseSinkFlowConfig conf |
stackTraceExpr(stackTrace, stackTraceString) and
conf.hasFlow(DataFlow::exprNode(stackTraceString), externalExpr)
)
@@ -123,21 +124,21 @@ class GetMessageFlowSource extends MethodAccess {
}
}
class GetMessageFlowSourceToXssSinkFlowConfig extends TaintTracking::Configuration {
GetMessageFlowSourceToXssSinkFlowConfig() {
this = "StackTraceExposure::GetMessageFlowSourceToXssSinkFlowConfig"
class GetMessageFlowSourceToHttpResponseSinkFlowConfig extends TaintTracking::Configuration {
GetMessageFlowSourceToHttpResponseSinkFlowConfig() {
this = "StackTraceExposure::GetMessageFlowSourceToHttpResponseSinkFlowConfig"
}
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof GetMessageFlowSource }
override predicate isSink(DataFlow::Node sink) { sink instanceof XssSink }
override predicate isSink(DataFlow::Node sink) { sink instanceof InformationLeakSink }
}
/**
* A call to `getMessage()` that then flows to a servlet response.
*/
predicate getMessageFlowsExternally(XssSink externalExpr, GetMessageFlowSource getMessage) {
any(GetMessageFlowSourceToXssSinkFlowConfig conf)
predicate getMessageFlowsExternally(DataFlow::Node externalExpr, GetMessageFlowSource getMessage) {
any(GetMessageFlowSourceToHttpResponseSinkFlowConfig conf)
.hasFlow(DataFlow::exprNode(getMessage), externalExpr)
}

View File

@@ -3,6 +3,7 @@
* @description Marking a certificate as valid for a host without checking the certificate hostname allows an attacker to perform a machine-in-the-middle attack.
* @kind path-problem
* @problem.severity error
* @security-severity 4.9
* @precision high
* @id java/unsafe-hostname-verification
* @tags security

View File

@@ -3,6 +3,7 @@
* @description Storing sensitive information in cleartext can expose it to an attacker.
* @kind problem
* @problem.severity recommendation
* @security-severity 5.9
* @precision medium
* @id java/cleartext-storage-in-class
* @tags security

View File

@@ -3,6 +3,7 @@
* @description Storing sensitive information in cleartext can expose it to an attacker.
* @kind problem
* @problem.severity error
* @security-severity 2.9
* @precision high
* @id java/cleartext-storage-in-cookie
* @tags security

View File

@@ -3,6 +3,7 @@
* @description Storing sensitive information in cleartext can expose it to an attacker.
* @kind problem
* @problem.severity warning
* @security-severity 6.4
* @precision medium
* @id java/cleartext-storage-in-properties
* @tags security

View File

@@ -3,6 +3,7 @@
* @description Non-HTTPS connections can be intercepted by third parties.
* @kind path-problem
* @problem.severity recommendation
* @security-severity 5.2
* @precision medium
* @id java/non-https-url
* @tags security

View File

@@ -3,6 +3,7 @@
* @description Non-SSL connections can be intercepted by third parties.
* @kind problem
* @problem.severity recommendation
* @security-severity 5.2
* @precision medium
* @id java/non-ssl-connection
* @tags security

View File

@@ -4,6 +4,7 @@
* third parties.
* @kind problem
* @problem.severity recommendation
* @security-severity 5.2
* @precision medium
* @id java/non-ssl-socket-factory
* @tags security

View File

@@ -3,6 +3,7 @@
* @description Using broken or weak cryptographic algorithms can allow an attacker to compromise security.
* @kind path-problem
* @problem.severity warning
* @security-severity 5.2
* @precision high
* @id java/weak-cryptographic-algorithm
* @tags security

View File

@@ -3,6 +3,7 @@
* @description Using broken or weak cryptographic algorithms can allow an attacker to compromise security.
* @kind path-problem
* @problem.severity warning
* @security-severity 5.2
* @precision medium
* @id java/potentially-weak-cryptographic-algorithm
* @tags security

View File

@@ -3,9 +3,11 @@
* @description Using a predictable seed in a pseudo-random number generator can lead to predictability of the numbers generated by it.
* @kind problem
* @problem.severity error
* @security-severity 5.9
* @precision high
* @id java/predictable-seed
* @tags security
* external/cwe/cwe-335
*/
import java

View File

@@ -3,6 +3,7 @@
* @description Using a vulnerable version of JHipster to generate random numbers makes it easier for attackers to take over accounts.
* @kind problem
* @problem.severity error
* @security-severity 5.9
* @precision very-high
* @id java/jhipster-prng
* @tags security

View File

@@ -4,6 +4,7 @@
* a Cross-Site Request Forgery (CSRF) attack.
* @kind problem
* @problem.severity error
* @security-severity 6.4
* @precision high
* @id java/spring-disabled-csrf-protection
* @tags security

View File

@@ -4,6 +4,7 @@
* if the state may be changed between the check and use.
* @kind problem
* @problem.severity warning
* @security-severity 5.9
* @precision medium
* @id java/toctou-race-condition
* @tags security

View File

@@ -3,6 +3,7 @@
* @description Opening a socket after authenticating via a different channel may allow an attacker to connect to the port first.
* @kind problem
* @problem.severity warning
* @security-severity 10.0
* @precision medium
* @id java/socket-auth-race-condition
* @tags security

View File

@@ -4,6 +4,7 @@
* execute arbitrary code.
* @kind path-problem
* @problem.severity error
* @security-severity 5.9
* @precision high
* @id java/unsafe-deserialization
* @tags security

View File

@@ -4,6 +4,7 @@
* may cause redirection to malicious web sites.
* @kind path-problem
* @problem.severity error
* @security-severity 2.7
* @precision high
* @id java/unvalidated-url-redirection
* @tags security

View File

@@ -4,6 +4,7 @@
* may cause redirection to malicious web sites.
* @kind path-problem
* @problem.severity recommendation
* @security-severity 2.7
* @precision medium
* @id java/unvalidated-url-redirection-local
* @tags security

View File

@@ -4,6 +4,7 @@
* references may lead to disclosure of confidential data or denial of service.
* @kind path-problem
* @problem.severity error
* @security-severity 5.9
* @precision high
* @id java/xxe
* @tags security

View File

@@ -4,6 +4,7 @@
* interception.
* @kind problem
* @problem.severity error
* @security-severity 2.9
* @precision high
* @id java/insecure-cookie
* @tags security

View File

@@ -4,6 +4,7 @@
* malicious code by the user.
* @kind path-problem
* @problem.severity error
* @security-severity 5.9
* @precision high
* @id java/xml/xpath-injection
* @tags security

View File

@@ -3,6 +3,7 @@
* @description Certain standard library routines are dangerous to call.
* @kind problem
* @problem.severity warning
* @security-severity 10.0
* @precision medium
* @id java/potentially-dangerous-function
* @tags reliability

View File

@@ -4,6 +4,7 @@
* can cause unexpected truncation.
* @kind path-problem
* @problem.severity error
* @security-severity 5.9
* @precision high
* @id java/tainted-numeric-cast
* @tags security

View File

@@ -4,6 +4,7 @@
* can cause unexpected truncation.
* @kind path-problem
* @problem.severity recommendation
* @security-severity 5.9
* @precision medium
* @id java/tainted-numeric-cast-local
* @tags security

View File

@@ -4,6 +4,7 @@
* the file may be modified or removed by external actors.
* @kind problem
* @problem.severity error
* @security-severity 5.9
* @precision high
* @id java/world-writable-file-read
* @tags security

View File

@@ -3,6 +3,7 @@
* @description Using a hard-coded credential in a call to a sensitive Java API may compromise security.
* @kind path-problem
* @problem.severity error
* @security-severity 5.9
* @precision medium
* @id java/hardcoded-credential-api-call
* @tags security

View File

@@ -3,6 +3,7 @@
* @description Comparing a parameter to a hard-coded credential may compromise security.
* @kind problem
* @problem.severity error
* @security-severity 5.9
* @precision low
* @id java/hardcoded-credential-comparison
* @tags security

View File

@@ -3,6 +3,7 @@
* @description Using a hard-coded credential in a sensitive call may compromise security.
* @kind path-problem
* @problem.severity error
* @security-severity 5.9
* @precision low
* @id java/hardcoded-credential-sensitive-call
* @tags security

View File

@@ -3,6 +3,7 @@
* @description Hard-coding a password string may compromise security.
* @kind problem
* @problem.severity error
* @security-severity 5.9
* @precision low
* @id java/hardcoded-password-field
* @tags security

View File

@@ -4,6 +4,7 @@
* passing through authentication systems.
* @kind path-problem
* @problem.severity error
* @security-severity 5.9
* @precision medium
* @id java/user-controlled-bypass
* @tags security

View File

@@ -4,6 +4,7 @@
* permissions being granted.
* @kind path-problem
* @problem.severity error
* @security-severity 5.9
* @precision high
* @id java/tainted-permissions-check
* @tags security

View File

@@ -3,6 +3,7 @@
* @description Non-HTTPS connections can be intercepted by third parties.
* @kind problem
* @problem.severity error
* @security-severity 5.9
* @precision very-high
* @id java/maven/non-https-url
* @tags security

View File

@@ -3,6 +3,7 @@
* @description Acquiring multiple locks in a different order may cause deadlock.
* @kind problem
* @problem.severity recommendation
* @security-severity 6.9
* @precision medium
* @id java/lock-order-inconsistency
* @tags security

View File

@@ -5,6 +5,7 @@
* looping.
* @kind problem
* @problem.severity warning
* @security-severity 3.6
* @precision medium
* @id java/unreachable-exit-in-loop
* @tags security

View File

@@ -1,19 +0,0 @@
/**
* @name Expression language injection (JEXL)
* @description Evaluation of a user-controlled JEXL expression
* may lead to arbitrary code execution.
* @kind path-problem
* @problem.severity error
* @precision high
* @id java/jexl-expression-injection
* @tags security
* external/cwe/cwe-094
*/
import java
import JexlInjectionLib
import DataFlow::PathGraph
from DataFlow::PathNode source, DataFlow::PathNode sink, JexlInjectionConfig conf
where conf.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "JEXL injection from $@.", source.getNode(), "this user input"

View File

@@ -1,277 +0,0 @@
import java
import FlowUtils
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.dataflow.TaintTracking
/**
* A taint-tracking configuration for unsafe user input
* that is used to construct and evaluate a JEXL expression.
* It supports both JEXL 2 and 3.
*/
class JexlInjectionConfig extends TaintTracking::Configuration {
JexlInjectionConfig() { this = "JexlInjectionConfig" }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) { sink instanceof JexlEvaluationSink }
override predicate isAdditionalTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
any(TaintPropagatingJexlMethodCall c).taintFlow(fromNode, toNode) or
hasGetterFlow(fromNode, toNode)
}
}
/**
* A sink for Expresssion Language injection vulnerabilities via Jexl,
* i.e. method calls that run evaluation of a JEXL expression.
*
* Creating a `Callable` from a tainted JEXL expression or script is considered as a sink
* although the tainted expression is not executed at this point.
* Here we assume that it will get executed at some point,
* maybe stored in an object field and then reached by a different flow.
*/
private class JexlEvaluationSink extends DataFlow::ExprNode {
JexlEvaluationSink() {
exists(MethodAccess ma, Method m, Expr taintFrom |
ma.getMethod() = m and taintFrom = this.asExpr()
|
m instanceof DirectJexlEvaluationMethod and ma.getQualifier() = taintFrom
or
m instanceof CreateJexlCallableMethod and ma.getQualifier() = taintFrom
or
m instanceof JexlEngineGetSetPropertyMethod and
taintFrom.getType() instanceof TypeString and
ma.getAnArgument() = taintFrom
)
}
}
/**
* Defines method calls that propagate tainted data via one of the methods
* from JEXL library.
*/
private class TaintPropagatingJexlMethodCall extends MethodAccess {
Expr taintFromExpr;
TaintPropagatingJexlMethodCall() {
exists(Method m, RefType taintType |
this.getMethod() = m and
taintType = taintFromExpr.getType()
|
isUnsafeEngine(this.getQualifier()) and
(
m instanceof CreateJexlScriptMethod and
taintFromExpr = this.getArgument(0) and
taintType instanceof TypeString
or
m instanceof CreateJexlExpressionMethod and
taintFromExpr = this.getAnArgument() and
taintType instanceof TypeString
or
m instanceof CreateJexlTemplateMethod and
(taintType instanceof TypeString or taintType instanceof Reader) and
taintFromExpr = this.getArgument([0, 1])
)
)
}
/**
* Holds if `fromNode` to `toNode` is a dataflow step that propagates
* tainted data.
*/
predicate taintFlow(DataFlow::Node fromNode, DataFlow::Node toNode) {
fromNode.asExpr() = taintFromExpr and toNode.asExpr() = this
}
}
/**
* Holds if `expr` is a JEXL engine that is not configured with a sandbox.
*/
private predicate isUnsafeEngine(Expr expr) {
not exists(SandboxedJexlFlowConfig config | config.hasFlowTo(DataFlow::exprNode(expr)))
}
/**
* A configuration for a tracking sandboxed JEXL engines.
*/
private class SandboxedJexlFlowConfig extends DataFlow2::Configuration {
SandboxedJexlFlowConfig() { this = "JexlInjection::SandboxedJexlFlowConfig" }
override predicate isSource(DataFlow::Node node) { node instanceof SandboxedJexlSource }
override predicate isSink(DataFlow::Node node) {
exists(MethodAccess ma, Method m | ma.getMethod() = m |
(
m instanceof CreateJexlScriptMethod or
m instanceof CreateJexlExpressionMethod or
m instanceof CreateJexlTemplateMethod
) and
ma.getQualifier() = node.asExpr()
)
}
override predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
createsJexlEngine(fromNode, toNode)
}
}
/**
* Defines a data flow source for JEXL engines configured with a sandbox.
*/
private class SandboxedJexlSource extends DataFlow::ExprNode {
SandboxedJexlSource() {
exists(MethodAccess ma, Method m | m = ma.getMethod() |
m.getDeclaringType() instanceof JexlBuilder and
m.hasName(["uberspect", "sandbox"]) and
m.getReturnType() instanceof JexlBuilder and
this.asExpr() = [ma, ma.getQualifier()]
)
or
exists(ConstructorCall cc |
cc.getConstructedType() instanceof JexlEngine and
cc.getArgument(0).getType() instanceof JexlUberspect and
cc = this.asExpr()
)
}
}
/**
* Holds if `fromNode` to `toNode` is a dataflow step that creates one of the JEXL engines.
*/
private predicate createsJexlEngine(DataFlow::Node fromNode, DataFlow::Node toNode) {
exists(MethodAccess ma, Method m | m = ma.getMethod() |
(m.getDeclaringType() instanceof JexlBuilder or m.getDeclaringType() instanceof JexlEngine) and
m.hasName(["create", "createJxltEngine"]) and
ma.getQualifier() = fromNode.asExpr() and
ma = toNode.asExpr()
)
or
exists(ConstructorCall cc |
cc.getConstructedType() instanceof UnifiedJexl and
cc.getArgument(0) = fromNode.asExpr() and
cc = toNode.asExpr()
)
}
/**
* A methods in the `JexlEngine` class that gets or sets a property with a JEXL expression.
*/
private class JexlEngineGetSetPropertyMethod extends Method {
JexlEngineGetSetPropertyMethod() {
getDeclaringType() instanceof JexlEngine and
hasName(["getProperty", "setProperty"])
}
}
/**
* A method that triggers direct evaluation of JEXL expressions.
*/
private class DirectJexlEvaluationMethod extends Method {
DirectJexlEvaluationMethod() {
getDeclaringType() instanceof JexlExpression and hasName("evaluate")
or
getDeclaringType() instanceof JexlScript and hasName("execute")
or
getDeclaringType() instanceof JxltEngineExpression and hasName(["evaluate", "prepare"])
or
getDeclaringType() instanceof JxltEngineTemplate and hasName("evaluate")
or
getDeclaringType() instanceof UnifiedJexlExpression and hasName(["evaluate", "prepare"])
or
getDeclaringType() instanceof UnifiedJexlTemplate and hasName("evaluate")
}
}
/**
* A method that creates a JEXL script.
*/
private class CreateJexlScriptMethod extends Method {
CreateJexlScriptMethod() { getDeclaringType() instanceof JexlEngine and hasName("createScript") }
}
/**
* A method that creates a `Callable` for a JEXL expression or script.
*/
private class CreateJexlCallableMethod extends Method {
CreateJexlCallableMethod() {
(getDeclaringType() instanceof JexlExpression or getDeclaringType() instanceof JexlScript) and
hasName("callable")
}
}
/**
* A method that creates a JEXL template.
*/
private class CreateJexlTemplateMethod extends Method {
CreateJexlTemplateMethod() {
(getDeclaringType() instanceof JxltEngine or getDeclaringType() instanceof UnifiedJexl) and
hasName("createTemplate")
}
}
/**
* A method that creates a JEXL expression.
*/
private class CreateJexlExpressionMethod extends Method {
CreateJexlExpressionMethod() {
(getDeclaringType() instanceof JexlEngine or getDeclaringType() instanceof JxltEngine) and
hasName("createExpression")
or
getDeclaringType() instanceof UnifiedJexl and hasName("parse")
}
}
private class JexlRefType extends RefType {
JexlRefType() { getPackage().hasName(["org.apache.commons.jexl2", "org.apache.commons.jexl3"]) }
}
private class JexlExpression extends JexlRefType {
JexlExpression() { hasName(["Expression", "JexlExpression"]) }
}
private class JexlScript extends JexlRefType {
JexlScript() { hasName(["Script", "JexlScript"]) }
}
private class JexlBuilder extends JexlRefType {
JexlBuilder() { hasName("JexlBuilder") }
}
private class JexlEngine extends JexlRefType {
JexlEngine() { hasName("JexlEngine") }
}
private class JxltEngine extends JexlRefType {
JxltEngine() { hasName("JxltEngine") }
}
private class UnifiedJexl extends JexlRefType {
UnifiedJexl() { hasName("UnifiedJEXL") }
}
private class JexlUberspect extends Interface {
JexlUberspect() {
hasQualifiedName("org.apache.commons.jexl2.introspection", "Uberspect") or
hasQualifiedName("org.apache.commons.jexl3.introspection", "JexlUberspect")
}
}
private class JxltEngineExpression extends NestedType {
JxltEngineExpression() { getEnclosingType() instanceof JxltEngine and hasName("Expression") }
}
private class JxltEngineTemplate extends NestedType {
JxltEngineTemplate() { getEnclosingType() instanceof JxltEngine and hasName("Template") }
}
private class UnifiedJexlExpression extends NestedType {
UnifiedJexlExpression() { getEnclosingType() instanceof UnifiedJexl and hasName("Expression") }
}
private class UnifiedJexlTemplate extends NestedType {
UnifiedJexlTemplate() { getEnclosingType() instanceof UnifiedJexl and hasName("Template") }
}
private class Reader extends RefType {
Reader() { hasQualifiedName("java.io", "Reader") }
}

View File

@@ -3,6 +3,8 @@
* @description Evaluation of a user-controlled malicious expression in Java Python
* interpreter may lead to remote code execution.
* @kind path-problem
* @problem.severity error
* @precision high
* @id java/jython-injection
* @tags security
* external/cwe/cwe-094

View File

@@ -0,0 +1,9 @@
public void bindRemoteObject(Registry registry, int port) throws Exception {
ObjectInputFilter filter = info -> {
if (info.serialClass().getCanonicalName().startsWith("com.safe.package.")) {
return ObjectInputFilter.Status.ALLOWED;
}
return ObjectInputFilter.Status.REJECTED;
};
registry.bind("safer", UnicastRemoteObject.exportObject(new RemoteObjectImpl(), port, filter));
}

View File

@@ -0,0 +1,14 @@
public class Server {
public void bindRemoteObject(Registry registry) throws Exception {
registry.bind("safe", new RemoteObjectImpl());
}
}
interface RemoteObject extends Remote {
void calculate(int a, double b) throws RemoteException;
void save(String s) throws RemoteException;
}
class RemoteObjectImpl implements RemoteObject {
// ...
}

View File

@@ -0,0 +1,13 @@
public class Server {
public void bindRemoteObject(Registry registry) throws Exception {
registry.bind("unsafe", new RemoteObjectImpl());
}
}
interface RemoteObject extends Remote {
void action(Object obj) throws RemoteException;
}
class RemoteObjectImpl implements RemoteObject {
// ...
}

View File

@@ -0,0 +1,81 @@
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
<qhelp>
<overview>
<p>
Java RMI uses the default Java serialization mechanism (in other words, <code>ObjectInputStream</code>)
to pass parameters in remote method invocations. This mechanism is known to be unsafe when deserializing
untrusted data. If a registered remote object has a method that accepts a complex object,
an attacker can take advantage of the unsafe deserialization mechanism.
In the worst case, it results in remote code execution.
</p>
</overview>
<recommendation>
<p>
Use only strings and primitive types for parameters of remotely invokable methods.
</p>
<p>
Set a filter for incoming serialized data by wrapping remote objects using either <code>UnicastRemoteObject.exportObject(Remote, int, ObjectInputFilter)</code>
or <code>UnicastRemoteObject.exportObject(Remote, int, RMIClientSocketFactory, RMIServerSocketFactory, ObjectInputFilter)</code> methods.
Those methods accept an <code>ObjectInputFilter</code> that decides which classes are allowed for deserialization.
The filter should allow deserializing only safe classes.
</p>
<p>
It is also possible to set a process-wide deserialization filter.
The filter can be set by with <code>ObjectInputFilter.Config.setSerialFilter(ObjectInputFilter)</code> method,
or by setting system or security property <code>jdk.serialFilter</code>.
Make sure that you use the latest Java versions that include JEP 290.
Please note that the query is not sensitive to this mitigation.
</p>
<p>
If switching to the latest Java versions is not possible,
consider using other implementations of remote procedure calls. For example, HTTP API with JSON.
Make sure that the underlying deserialization mechanism is properly configured
so that deserialization attacks are not possible.
</p>
</recommendation>
<example>
<p>
The following code registers a remote object
with a vulnerable method that accepts a complex object:
</p>
<sample src="RmiUnsafeRemoteObject.java" />
<p>
The next example registers a safe remote object
whose methods use only primitive types and strings:
</p>
<sample src="RmiSafeRemoteObject.java" />
<p>
The next example shows how to set a deserilization filter for a remote object:
</p>
<sample src="RmiRemoteObjectWithFilter.java" />
</example>
<references>
<li>
Oracle:
<a href="https://www.oracle.com/java/technologies/javase/remote-method-invocation-home.html">Remote Method Invocation (RMI)</a>.
</li>
<li>
ITNEXT:
<a href="https://itnext.io/java-rmi-for-pentesters-part-two-reconnaissance-attack-against-non-jmx-registries-187a6561314d">Java RMI for pentesters part two - reconnaissance &amp; attack against non-JMX registries</a>.
</li>
<li>
MOGWAI LABS:
<a href="https://mogwailabs.de/en/blog/2019/03/attacking-java-rmi-services-after-jep-290">Attacking Java RMI services after JEP 290</a>
</li>
<li>
OWASP:
<a href="https://www.owasp.org/index.php/Deserialization_of_untrusted_data">Deserialization of untrusted data</a>.
</li>
<li>
OpenJDK:
<a href="https://openjdk.java.net/jeps/290">JEP 290: Filter Incoming Serialization Data</a>
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,78 @@
/**
* @name Unsafe deserialization in a remotely callable method.
* @description If a registered remote object has a method that accepts a complex object,
* an attacker can take advantage of the unsafe deserialization mechanism
* which is used to pass parameters in RMI.
* In the worst case, it results in remote code execution.
* @kind path-problem
* @problem.severity error
* @precision high
* @id java/unsafe-deserialization-rmi
* @tags security
* external/cwe/cwe-502
*/
import java
import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.frameworks.Rmi
import DataFlow::PathGraph
/**
* A method that binds a name to a remote object.
*/
private class BindMethod extends Method {
BindMethod() {
(
getDeclaringType().hasQualifiedName("java.rmi", "Naming") or
getDeclaringType().hasQualifiedName("java.rmi.registry", "Registry")
) and
hasName(["bind", "rebind"])
}
}
/**
* Holds if `type` has an vulnerable remote method.
*/
private predicate hasVulnerableMethod(RefType type) {
exists(RemoteCallableMethod m, Type parameterType |
m.getDeclaringType() = type and parameterType = m.getAParamType()
|
not parameterType instanceof PrimitiveType and
not parameterType instanceof TypeString and
not parameterType.(RefType).hasQualifiedName("java.io", "ObjectInputStream")
)
}
/**
* A taint-tracking configuration for unsafe remote objects
* that are vulnerable to deserialization attacks.
*/
private class BindingUnsafeRemoteObjectConfig extends TaintTracking::Configuration {
BindingUnsafeRemoteObjectConfig() { this = "BindingUnsafeRemoteObjectConfig" }
override predicate isSource(DataFlow::Node source) {
exists(ConstructorCall cc | cc = source.asExpr() |
hasVulnerableMethod(cc.getConstructedType().getASupertype*())
)
}
override predicate isSink(DataFlow::Node sink) {
exists(MethodAccess ma | ma.getArgument(1) = sink.asExpr() |
ma.getMethod() instanceof BindMethod
)
}
override predicate isAdditionalTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
exists(MethodAccess ma, Method m | m = ma.getMethod() |
m.getDeclaringType().hasQualifiedName("java.rmi.server", "UnicastRemoteObject") and
m.hasName("exportObject") and
not m.getParameterType([2, 4]).(RefType).hasQualifiedName("java.io", "ObjectInputFilter") and
ma.getArgument(0) = fromNode.asExpr() and
ma = toNode.asExpr()
)
}
}
from DataFlow::PathNode source, DataFlow::PathNode sink, BindingUnsafeRemoteObjectConfig conf
where conf.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "Unsafe deserialization in a remote object."

View File

@@ -0,0 +1,38 @@
package com.example.demo;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DemoApplication {
@GetMapping("/string1")
public String string1(@RequestParam(value = "input", defaultValue = "test") String input,
@RequestParam(value = "pattern", defaultValue = ".*") String pattern) {
// BAD: Unsanitized user input is used to construct a regular expression
if (input.matches("^" + pattern + "=.*$"))
return "match!";
return "doesn't match!";
}
@GetMapping("/string2")
public String string2(@RequestParam(value = "input", defaultValue = "test") String input,
@RequestParam(value = "pattern", defaultValue = ".*") String pattern) {
// GOOD: User input is sanitized before constructing the regex
if (input.matches("^" + escapeSpecialRegexChars(pattern) + "=.*$"))
return "match!";
return "doesn't match!";
}
Pattern SPECIAL_REGEX_CHARS = Pattern.compile("[{}()\\[\\]><-=!.+*?^$\\\\|]");
String escapeSpecialRegexChars(String str) {
return SPECIAL_REGEX_CHARS.matcher(str).replaceAll("\\\\$0");
}
}

View File

@@ -0,0 +1,48 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
Constructing a regular expression with unsanitized user input is dangerous as a malicious user may
be able to modify the meaning of the expression. In particular, such a user may be able to provide
a regular expression fragment that takes exponential time in the worst case, and use that to
perform a Denial of Service attack.
</p>
</overview>
<recommendation>
<p>
Before embedding user input into a regular expression, use a sanitization function
to escape meta-characters that have special meaning.
</p>
</recommendation>
<example>
<p>
The following example shows a HTTP request parameter that is used to construct a regular expression:
</p>
<sample src="RegexInjection.java" />
<p>
In the first case the user-provided regex is not escaped.
If a malicious user provides a regex that has exponential worst case performance,
then this could lead to a Denial of Service.
</p>
<p>
In the second case, the user input is escaped using <code>escapeSpecialRegexChars</code> before being included
in the regular expression. This ensures that the user cannot insert characters which have a special
meaning in regular expressions.
</p>
</example>
<references>
<li>
OWASP:
<a href="https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS">Regular expression Denial of Service - ReDoS</a>.
</li>
<li>
Wikipedia: <a href="https://en.wikipedia.org/wiki/ReDoS">ReDoS</a>.
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,89 @@
/**
* @name Regular expression injection
* @description User input should not be used in regular expressions without first being sanitized,
* otherwise a malicious user may be able to provide a regex that could require
* exponential time on certain inputs.
* @kind path-problem
* @problem.severity error
* @precision high
* @id java/regex-injection
* @tags security
* external/cwe/cwe-730
* external/cwe/cwe-400
*/
import java
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.dataflow.TaintTracking
import DataFlow::PathGraph
/**
* A data flow sink for untrusted user input used to construct regular expressions.
*/
class RegexSink extends DataFlow::ExprNode {
RegexSink() {
exists(MethodAccess ma, Method m | m = ma.getMethod() |
(
m.getDeclaringType() instanceof TypeString and
(
ma.getArgument(0) = this.asExpr() and
m.hasName(["matches", "split", "replaceFirst", "replaceAll"])
)
or
m.getDeclaringType().hasQualifiedName("java.util.regex", "Pattern") and
(
ma.getArgument(0) = this.asExpr() and
m.hasName(["compile", "matches"])
)
or
m.getDeclaringType().hasQualifiedName("org.apache.commons.lang3", "RegExUtils") and
(
ma.getArgument(1) = this.asExpr() and
m.getParameterType(1) instanceof TypeString and
m.hasName([
"removeAll", "removeFirst", "removePattern", "replaceAll", "replaceFirst",
"replacePattern"
])
)
)
)
}
}
abstract class Sanitizer extends DataFlow::ExprNode { }
/**
* A call to a function whose name suggests that it escapes regular
* expression meta-characters.
*/
class RegExpSanitizationCall extends Sanitizer {
RegExpSanitizationCall() {
exists(string calleeName, string sanitize, string regexp |
calleeName = this.asExpr().(Call).getCallee().getName() and
sanitize = "(?:escape|saniti[sz]e)" and
regexp = "regexp?"
|
calleeName
.regexpMatch("(?i)(" + sanitize + ".*" + regexp + ".*)" + "|(" + regexp + ".*" + sanitize +
".*)")
)
}
}
/**
* A taint-tracking configuration for untrusted user input used to construct regular expressions.
*/
class RegexInjectionConfiguration extends TaintTracking::Configuration {
RegexInjectionConfiguration() { this = "RegexInjectionConfiguration" }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) { sink instanceof RegexSink }
override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
}
from DataFlow::PathNode source, DataFlow::PathNode sink, RegexInjectionConfiguration c
where c.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "$@ is user controlled.", source.getNode(),
"This regular expression pattern"

View File

@@ -73,10 +73,10 @@ class BlockStmt extends Stmt, @block {
/** Gets the last statement in this block. */
Stmt getLastStmt() { result = getStmt(getNumStmt() - 1) }
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
override string pp() { result = "{ ... }" }
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string toString() { result = "{ ... }" }
override string getHalsteadID() { result = "BlockStmt" }
override string getAPrimaryQlClass() { result = "BlockStmt" }
@@ -130,14 +130,14 @@ class IfStmt extends ConditionalStmt, @ifstmt {
/** Gets the `else` branch of this `if` statement. */
Stmt getElse() { result.isNthChildOf(this, 2) }
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
override string pp() {
result = "if (...) " + this.getThen().pp() + " else " + this.getElse().pp()
or
not exists(this.getElse()) and result = "if (...) " + this.getThen().pp()
}
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string toString() { result = "if (...)" }
override string getHalsteadID() { result = "IfStmt" }
override string getAPrimaryQlClass() { result = "IfStmt" }
@@ -201,10 +201,10 @@ class ForStmt extends ConditionalStmt, @forstmt {
getCondition().getAChildExpr*() = result.getAnAccess()
}
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
override string pp() { result = "for (...;...;...) " + this.getStmt().pp() }
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string toString() { result = "for (...;...;...)" }
override string getHalsteadID() { result = "ForStmt" }
override string getAPrimaryQlClass() { result = "ForStmt" }
@@ -221,10 +221,10 @@ class EnhancedForStmt extends Stmt, @enhancedforstmt {
/** Gets the body of this enhanced `for` loop. */
Stmt getStmt() { result.getParent() = this }
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
override string pp() { result = "for (...) " + this.getStmt().pp() }
override string pp() { result = "for (... : ...) " + this.getStmt().pp() }
override string toString() { result = "for (... : ...)" }
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string getHalsteadID() { result = "EnhancedForStmt" }
override string getAPrimaryQlClass() { result = "EnhancedForStmt" }
@@ -244,10 +244,10 @@ class WhileStmt extends ConditionalStmt, @whilestmt {
*/
deprecated override Stmt getTrueSuccessor() { result = getStmt() }
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
override string pp() { result = "while (...) " + this.getStmt().pp() }
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string toString() { result = "while (...)" }
override string getHalsteadID() { result = "WhileStmt" }
override string getAPrimaryQlClass() { result = "WhileStmt" }
@@ -267,10 +267,10 @@ class DoStmt extends ConditionalStmt, @dostmt {
*/
deprecated override Stmt getTrueSuccessor() { result = getStmt() }
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
override string pp() { result = "do " + this.getStmt().pp() + " while (...)" }
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string toString() { result = "do ... while (...)" }
override string getHalsteadID() { result = "DoStmt" }
override string getAPrimaryQlClass() { result = "DoStmt" }
@@ -356,10 +356,10 @@ class TryStmt extends Stmt, @trystmt {
result = getAResourceExpr().getVariable()
}
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
override string pp() { result = "try " + this.getBlock().pp() + " catch (...)" }
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string toString() { result = "try ..." }
override string getHalsteadID() { result = "TryStmt" }
override string getAPrimaryQlClass() { result = "TryStmt" }
@@ -387,10 +387,10 @@ class CatchClause extends Stmt, @catchclause {
)
}
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
override string pp() { result = "catch (...) " + this.getBlock().pp() }
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string toString() { result = "catch (...)" }
override string getHalsteadID() { result = "CatchClause" }
override string getAPrimaryQlClass() { result = "CatchClause" }
@@ -422,10 +422,10 @@ class SwitchStmt extends Stmt, @switchstmt {
/** Gets the expression of this `switch` statement. */
Expr getExpr() { result.getParent() = this }
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
override string pp() { result = "switch (...)" }
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string toString() { result = "switch (...)" }
override string getHalsteadID() { result = "SwitchStmt" }
override string getAPrimaryQlClass() { result = "SwitchStmt" }
@@ -485,10 +485,10 @@ class ConstCase extends SwitchCase {
*/
Expr getValue(int i) { result.getParent() = this and result.getIndex() = i and i >= 0 }
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
override string pp() { result = "case ..." }
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string toString() { result = "case ..." }
override string getHalsteadID() { result = "ConstCase" }
override string getAPrimaryQlClass() { result = "ConstCase" }
@@ -498,10 +498,10 @@ class ConstCase extends SwitchCase {
class DefaultCase extends SwitchCase {
DefaultCase() { not exists(Expr e | e.getParent() = this | e.getIndex() >= 0) }
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
override string pp() { result = "default" }
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string toString() { result = "default" }
override string getHalsteadID() { result = "DefaultCase" }
override string getAPrimaryQlClass() { result = "DefaultCase" }
@@ -515,10 +515,10 @@ class SynchronizedStmt extends Stmt, @synchronizedstmt {
/** Gets the block of this `synchronized` statement. */
Stmt getBlock() { result.getParent() = this }
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
override string pp() { result = "synchronized (...) " + this.getBlock().pp() }
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string toString() { result = "synchronized (...)" }
override string getHalsteadID() { result = "SynchronizedStmt" }
override string getAPrimaryQlClass() { result = "SynchronizedStmt" }
@@ -529,10 +529,10 @@ class ReturnStmt extends Stmt, @returnstmt {
/** Gets the expression returned by this `return` statement, if any. */
Expr getResult() { result.getParent() = this }
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
override string pp() { result = "return ..." }
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string toString() { result = "return ..." }
override string getHalsteadID() { result = "ReturnStmt" }
override string getAPrimaryQlClass() { result = "ReturnStmt" }
@@ -543,10 +543,10 @@ class ThrowStmt extends Stmt, @throwstmt {
/** Gets the expression thrown by this `throw` statement. */
Expr getExpr() { result.getParent() = this }
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
override string pp() { result = "throw ..." }
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string toString() { result = "throw ..." }
override string getHalsteadID() { result = "ThrowStmt" }
/** Gets the type of the expression thrown by this `throw` statement. */
@@ -638,12 +638,12 @@ class BreakStmt extends Stmt, @breakstmt {
/** Holds if this `break` statement has an explicit label. */
predicate hasLabel() { exists(string s | s = this.getLabel()) }
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
override string pp() {
if this.hasLabel() then result = "break " + this.getLabel() else result = "break"
}
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string toString() { result = "break" }
override string getHalsteadID() { result = "BreakStmt" }
override string getAPrimaryQlClass() { result = "BreakStmt" }
@@ -660,6 +660,8 @@ class YieldStmt extends Stmt, @yieldstmt {
override string pp() { result = "yield ..." }
override string toString() { result = "yield ..." }
override string getHalsteadID() { result = "YieldStmt" }
override string getAPrimaryQlClass() { result = "YieldStmt" }
@@ -673,12 +675,12 @@ class ContinueStmt extends Stmt, @continuestmt {
/** Holds if this `continue` statement has an explicit label. */
predicate hasLabel() { exists(string s | s = this.getLabel()) }
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
override string pp() {
if this.hasLabel() then result = "continue " + this.getLabel() else result = "continue"
}
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string toString() { result = "continue" }
override string getHalsteadID() { result = "ContinueStmt" }
override string getAPrimaryQlClass() { result = "ContinueStmt" }
@@ -686,10 +688,10 @@ class ContinueStmt extends Stmt, @continuestmt {
/** The empty statement. */
class EmptyStmt extends Stmt, @emptystmt {
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
override string pp() { result = ";" }
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string toString() { result = ";" }
override string getHalsteadID() { result = "EmptyStmt" }
override string getAPrimaryQlClass() { result = "EmptyStmt" }
@@ -704,10 +706,10 @@ class ExprStmt extends Stmt, @exprstmt {
/** Gets the expression of this expression statement. */
Expr getExpr() { result.getParent() = this }
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
override string pp() { result = "...;" }
override string pp() { result = "<Expr>;" }
override string toString() { result = "<Expr>;" }
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string getHalsteadID() { result = "ExprStmt" }
/** Holds if this statement represents a field declaration with an initializer. */
@@ -733,13 +735,13 @@ class LabeledStmt extends Stmt, @labeledstmt {
/** Gets the label of this labeled statement. */
string getLabel() { namestrings(result, _, this) }
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
override string pp() { result = this.getLabel() + ": " + this.getStmt().pp() }
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string getHalsteadID() { result = this.getLabel() + ":" }
override string getAPrimaryQlClass() { result = "LabelStmt" }
override string toString() { result = "<Label>: ..." }
override string getAPrimaryQlClass() { result = "LabeledStmt" }
}
/** An `assert` statement. */
@@ -750,12 +752,12 @@ class AssertStmt extends Stmt, @assertstmt {
/** Gets the assertion message expression, if any. */
Expr getMessage() { exprs(result, _, _, this, _) and result.getIndex() = 1 }
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
override string pp() {
if exists(this.getMessage()) then result = "assert ... : ..." else result = "assert ..."
}
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string toString() { result = "assert ..." }
override string getHalsteadID() { result = "AssertStmt" }
override string getAPrimaryQlClass() { result = "AssertStmt" }
@@ -775,10 +777,10 @@ class LocalVariableDeclStmt extends Stmt, @localvariabledeclstmt {
/** Gets an index of a variable declared in this local variable declaration statement. */
int getAVariableIndex() { exists(getVariable(result)) }
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
override string pp() { result = "local variable declaration" }
override string pp() { result = "var ...;" }
override string toString() { result = "var ...;" }
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string getHalsteadID() { result = "LocalVariableDeclStmt" }
override string getAPrimaryQlClass() { result = "LocalVariableDeclStmt" }
@@ -789,10 +791,10 @@ class LocalClassDeclStmt extends Stmt, @localclassdeclstmt {
/** Gets the local class declared by this statement. */
LocalClass getLocalClass() { isLocalClass(result, this) }
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
override string pp() { result = "local class declaration: " + this.getLocalClass().toString() }
override string pp() { result = "class " + this.getLocalClass().toString() }
override string toString() { result = "class ..." }
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string getHalsteadID() { result = "LocalClassDeclStmt" }
override string getAPrimaryQlClass() { result = "LocalClassDeclStmt" }
@@ -829,13 +831,10 @@ class ThisConstructorInvocationStmt extends Stmt, ConstructorCall, @constructori
/** Gets the immediately enclosing statement of this constructor invocation. */
override Stmt getEnclosingStmt() { result = this }
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
override string pp() { result = "this(...)" }
/** Gets a printable representation of this statement. */
override string toString() { result = pp() }
override string toString() { result = "this(...)" }
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string getHalsteadID() { result = "ConstructorInvocationStmt" }
override string getAPrimaryQlClass() { result = "ThisConstructorInvocationStmt" }
@@ -873,13 +872,10 @@ class SuperConstructorInvocationStmt extends Stmt, ConstructorCall, @superconstr
/** Gets the immediately enclosing statement of this constructor invocation. */
override Stmt getEnclosingStmt() { result = this }
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
override string pp() { result = "super(...)" }
/** Gets a printable representation of this statement. */
override string toString() { result = pp() }
override string toString() { result = "super(...)" }
/** This statement's Halstead ID (used to compute Halstead metrics). */
override string getHalsteadID() { result = "SuperConstructorInvocationStmt" }
override string getAPrimaryQlClass() { result = "SuperConstructorInvocationStmt" }

View File

@@ -67,6 +67,8 @@
import java
private import semmle.code.java.dataflow.DataFlow::DataFlow
private import internal.DataFlowPrivate
private import internal.FlowSummaryImpl::Private::External
private import internal.FlowSummaryImplSpecific
private import FlowSummary
/**
@@ -74,20 +76,30 @@ private import FlowSummary
* ensuring that they are visible to the taint tracking / data flow library.
*/
private module Frameworks {
private import internal.ContainerFlow
private import semmle.code.java.frameworks.ApacheHttp
private import semmle.code.java.frameworks.apache.Lang
private import semmle.code.java.frameworks.guava.Guava
private import semmle.code.java.frameworks.jackson.JacksonSerializability
private import semmle.code.java.security.ResponseSplitting
private import semmle.code.java.security.InformationLeak
private import semmle.code.java.security.XSS
private import semmle.code.java.security.LdapInjection
private import semmle.code.java.security.XPath
private import semmle.code.java.security.JexlInjection
private import semmle.code.java.security.OgnlInjection
}
private predicate sourceModelCsv(string row) {
row =
[
// org.springframework.security.web.savedrequest.SavedRequest
"org.springframework.security.web.savedrequest;SavedRequest;true;getRedirectUrl;;;ReturnValue;remote",
"org.springframework.security.web.savedrequest;SavedRequest;true;getCookies;;;ReturnValue;remote",
"org.springframework.security.web.savedrequest;SavedRequest;true;getHeaderValues;;;ReturnValue;remote",
"org.springframework.security.web.savedrequest;SavedRequest;true;getHeaderNames;;;ReturnValue;remote",
"org.springframework.security.web.savedrequest;SavedRequest;true;getParameterValues;;;ReturnValue;remote",
"org.springframework.security.web.savedrequest;SavedRequest;true;getParameterMap;;;ReturnValue;remote",
// ServletRequestGetParameterMethod
"javax.servlet;ServletRequest;false;getParameter;(String);;ReturnValue;remote",
"javax.servlet;ServletRequest;false;getParameterValues;(String);;ReturnValue;remote",
@@ -351,7 +363,8 @@ private predicate summaryModel(string row) {
any(SummaryModelCsv s).row(row)
}
private predicate sourceModel(
/** Holds if a source model exists for the given parameters. */
predicate sourceModel(
string namespace, string type, boolean subtypes, string name, string signature, string ext,
string output, string kind
) {
@@ -369,7 +382,8 @@ private predicate sourceModel(
)
}
private predicate sinkModel(
/** Holds if a sink model exists for the given parameters. */
predicate sinkModel(
string namespace, string type, boolean subtypes, string name, string signature, string ext,
string input, string kind
) {
@@ -387,7 +401,8 @@ private predicate sinkModel(
)
}
private predicate summaryModel(
/** Holds if a summary model exists for the given parameters. */
predicate summaryModel(
string namespace, string type, boolean subtypes, string name, string signature, string ext,
string input, string output, string kind
) {
@@ -474,7 +489,7 @@ module CsvValidation {
not namespace.regexpMatch("[a-zA-Z0-9_\\.]+") and
msg = "Dubious namespace \"" + namespace + "\" in " + pred + " model."
or
not type.regexpMatch("[a-zA-Z0-9_\\$]+") and
not type.regexpMatch("[a-zA-Z0-9_\\$<>]+") and
msg = "Dubious type \"" + type + "\" in " + pred + " model."
or
not name.regexpMatch("[a-zA-Z0-9_]*") and
@@ -492,10 +507,15 @@ module CsvValidation {
or
summaryModel(_, _, _, _, _, _, input, _, _) and pred = "summary"
|
specSplit(input, part, _) and
not part.regexpMatch("|ReturnValue|ArrayElement|Element|MapKey|MapValue") and
not (part = "Argument" and pred = "sink") and
not parseArg(part, _) and
(
invalidSpecComponent(input, part) and
not part = "" and
not (part = "Argument" and pred = "sink") and
not parseArg(part, _)
or
specSplit(input, part, _) and
parseParam(part, _)
) and
msg = "Unrecognized input specification \"" + part + "\" in " + pred + " model."
)
or
@@ -504,11 +524,9 @@ module CsvValidation {
or
summaryModel(_, _, _, _, _, _, _, output, _) and pred = "summary"
|
specSplit(output, part, _) and
not part.regexpMatch("|ReturnValue|ArrayElement|Element|MapKey|MapValue") and
invalidSpecComponent(output, part) and
not part = "" and
not (part = ["Argument", "Parameter"] and pred = "source") and
not parseArg(part, _) and
not parseParam(part, _) and
msg = "Unrecognized output specification \"" + part + "\" in " + pred + " model."
)
or
@@ -555,7 +573,7 @@ private RefType interpretType(string namespace, string type, boolean subtypes) {
private string paramsStringPart(Callable c, int i) {
i = -1 and result = "("
or
exists(int n, string p | c.getParameterType(n).toString() = p |
exists(int n, string p | c.getParameterType(n).getErasure().toString() = p |
i = 2 * n and result = p
or
i = 2 * n - 1 and result = "," and n != 0
@@ -589,7 +607,8 @@ private Element interpretElement0(
)
}
private Element interpretElement(
/** Gets the source/sink/summary element corresponding to the supplied parameters. */
Element interpretElement(
string namespace, string type, boolean subtypes, string name, string signature, string ext
) {
elementSpec(namespace, type, subtypes, name, signature, ext) and
@@ -600,269 +619,25 @@ private Element interpretElement(
)
}
private predicate sourceElement(Element e, string output, string kind) {
exists(
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
sourceModel(namespace, type, subtypes, name, signature, ext, output, kind) and
e = interpretElement(namespace, type, subtypes, name, signature, ext)
)
}
cached
private module Cached {
/**
* Holds if `node` is specified as a source with the given kind in a CSV flow
* model.
*/
cached
predicate sourceNode(Node node, string kind) {
exists(InterpretNode n | isSourceNode(n, kind) and n.asNode() = node)
}
private predicate sinkElement(Element e, string input, string kind) {
exists(
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
sinkModel(namespace, type, subtypes, name, signature, ext, input, kind) and
e = interpretElement(namespace, type, subtypes, name, signature, ext)
)
}
private predicate summaryElement(Element e, string input, string output, string kind) {
exists(
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind) and
e = interpretElement(namespace, type, subtypes, name, signature, ext)
)
}
private string inOutSpec() {
sourceModel(_, _, _, _, _, _, result, _) or
sinkModel(_, _, _, _, _, _, result, _) or
summaryModel(_, _, _, _, _, _, result, _, _) or
summaryModel(_, _, _, _, _, _, _, result, _)
}
private predicate specSplit(string s, string c, int n) {
inOutSpec() = s and s.splitAt(" of ", n) = c
}
private predicate len(string s, int len) { len = 1 + max(int n | specSplit(s, _, n)) }
private string getLast(string s) {
exists(int len |
len(s, len) and
specSplit(s, result, len - 1)
)
}
private predicate parseParam(string c, int n) {
specSplit(_, c, _) and
(
c.regexpCapture("Parameter\\[([-0-9]+)\\]", 1).toInt() = n
or
exists(int n1, int n2 |
c.regexpCapture("Parameter\\[([-0-9]+)\\.\\.([0-9]+)\\]", 1).toInt() = n1 and
c.regexpCapture("Parameter\\[([-0-9]+)\\.\\.([0-9]+)\\]", 2).toInt() = n2 and
n = [n1 .. n2]
)
)
}
private predicate parseArg(string c, int n) {
specSplit(_, c, _) and
(
c.regexpCapture("Argument\\[([-0-9]+)\\]", 1).toInt() = n
or
exists(int n1, int n2 |
c.regexpCapture("Argument\\[([-0-9]+)\\.\\.([0-9]+)\\]", 1).toInt() = n1 and
c.regexpCapture("Argument\\[([-0-9]+)\\.\\.([0-9]+)\\]", 2).toInt() = n2 and
n = [n1 .. n2]
)
)
}
private predicate inputNeedsReference(string c) {
c = "Argument" or
parseArg(c, _)
}
private predicate outputNeedsReference(string c) {
c = "Argument" or
parseArg(c, _) or
c = "ReturnValue"
}
private predicate sourceElementRef(Top ref, string output, string kind) {
exists(Element e |
sourceElement(e, output, kind) and
if outputNeedsReference(getLast(output))
then ref.(Call).getCallee().getSourceDeclaration() = e
else ref = e
)
}
private predicate sinkElementRef(Top ref, string input, string kind) {
exists(Element e |
sinkElement(e, input, kind) and
if inputNeedsReference(getLast(input))
then ref.(Call).getCallee().getSourceDeclaration() = e
else ref = e
)
}
private predicate summaryElementRef(Top ref, string input, string output, string kind) {
exists(Element e |
summaryElement(e, input, output, kind) and
if inputNeedsReference(getLast(input))
then ref.(Call).getCallee().getSourceDeclaration() = e
else ref = e
)
}
private SummaryComponent interpretComponent(string c) {
specSplit(_, c, _) and
(
exists(int pos | parseArg(c, pos) and result = SummaryComponent::argument(pos))
or
exists(int pos | parseParam(c, pos) and result = SummaryComponent::parameter(pos))
or
c = "ReturnValue" and result = SummaryComponent::return()
or
c = "ArrayElement" and result = SummaryComponent::content(any(ArrayContent c0))
or
c = "Element" and result = SummaryComponent::content(any(CollectionContent c0))
or
c = "MapKey" and result = SummaryComponent::content(any(MapKeyContent c0))
or
c = "MapValue" and result = SummaryComponent::content(any(MapValueContent c0))
)
}
private predicate interpretSpec(string spec, int idx, SummaryComponentStack stack) {
exists(string c |
summaryElement(_, spec, _, _) or
summaryElement(_, _, spec, _)
|
len(spec, idx + 1) and
specSplit(spec, c, idx) and
stack = SummaryComponentStack::singleton(interpretComponent(c))
)
or
exists(SummaryComponent head, SummaryComponentStack tail |
interpretSpec(spec, idx, head, tail) and
stack = SummaryComponentStack::push(head, tail)
)
}
private predicate interpretSpec(
string output, int idx, SummaryComponent head, SummaryComponentStack tail
) {
exists(string c |
interpretSpec(output, idx + 1, tail) and
specSplit(output, c, idx) and
head = interpretComponent(c)
)
}
private class MkStack extends RequiredSummaryComponentStack {
MkStack() { interpretSpec(_, _, _, this) }
override predicate required(SummaryComponent c) { interpretSpec(_, _, c, this) }
}
private class SummarizedCallableExternal extends SummarizedCallable {
SummarizedCallableExternal() { summaryElement(this, _, _, _) }
override predicate propagatesFlow(
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
) {
exists(string inSpec, string outSpec, string kind |
summaryElement(this, inSpec, outSpec, kind) and
interpretSpec(inSpec, 0, input) and
interpretSpec(outSpec, 0, output)
|
kind = "value" and preservesValue = true
or
kind = "taint" and preservesValue = false
)
/**
* Holds if `node` is specified as a sink with the given kind in a CSV flow
* model.
*/
cached
predicate sinkNode(Node node, string kind) {
exists(InterpretNode n | isSinkNode(n, kind) and n.asNode() = node)
}
}
private newtype TAstOrNode =
TAst(Top t) or
TNode(Node n)
private predicate interpretOutput(string output, int idx, Top ref, TAstOrNode node) {
(
sourceElementRef(ref, output, _) or
summaryElementRef(ref, _, output, _)
) and
len(output, idx) and
node = TAst(ref)
or
exists(Top mid, string c, Node n |
interpretOutput(output, idx + 1, ref, TAst(mid)) and
specSplit(output, c, idx) and
node = TNode(n)
|
exists(int pos | n.(PostUpdateNode).getPreUpdateNode().(ArgumentNode).argumentOf(mid, pos) |
c = "Argument" or parseArg(c, pos)
)
or
exists(int pos | n.(ParameterNode).isParameterOf(mid, pos) |
c = "Parameter" or parseParam(c, pos)
)
or
(c = "Parameter" or c = "") and
n.asParameter() = mid
or
c = "ReturnValue" and
n.asExpr().(Call) = mid
or
c = "" and
n.asExpr().(FieldRead).getField() = mid
)
}
private predicate interpretInput(string input, int idx, Top ref, TAstOrNode node) {
(
sinkElementRef(ref, input, _) or
summaryElementRef(ref, input, _, _)
) and
len(input, idx) and
node = TAst(ref)
or
exists(Top mid, string c, Node n |
interpretInput(input, idx + 1, ref, TAst(mid)) and
specSplit(input, c, idx) and
node = TNode(n)
|
exists(int pos | n.(ArgumentNode).argumentOf(mid, pos) | c = "Argument" or parseArg(c, pos))
or
exists(ReturnStmt ret |
c = "ReturnValue" and
n.asExpr() = ret.getResult() and
mid = ret.getEnclosingCallable()
)
or
exists(FieldWrite fw |
c = "" and
fw.getField() = mid and
n.asExpr() = fw.getRHS()
)
)
}
/**
* Holds if `node` is specified as a source with the given kind in a CSV flow
* model.
*/
predicate sourceNode(Node node, string kind) {
exists(Top ref, string output |
sourceElementRef(ref, output, kind) and
interpretOutput(output, 0, ref, TNode(node))
)
}
/**
* Holds if `node` is specified as a sink with the given kind in a CSV flow
* model.
*/
predicate sinkNode(Node node, string kind) {
exists(Top ref, string input |
sinkElementRef(ref, input, kind) and
interpretInput(input, 0, ref, TNode(node))
)
}
import Cached

View File

@@ -1,6 +1,9 @@
import java
import semmle.code.java.Collections
import semmle.code.java.Maps
private import semmle.code.java.dataflow.SSA
private import DataFlowUtil
private import semmle.code.java.dataflow.ExternalFlow
private class EntryType extends RefType {
EntryType() {
@@ -88,6 +91,286 @@ class ContainerType extends RefType {
}
}
private class ContainerFlowSummaries extends SummaryModelCsv {
override predicate row(string row) {
row =
[
"java.util;Map<>$Entry;true;getValue;;;MapValue of Argument[-1];ReturnValue;value",
"java.util;Map<>$Entry;true;setValue;;;MapValue of Argument[-1];ReturnValue;value",
"java.util;Map<>$Entry;true;setValue;;;Argument[0];MapValue of Argument[-1];value",
"java.lang;Iterable;true;iterator;();;Element of Argument[-1];Element of ReturnValue;value",
"java.lang;Iterable;true;spliterator;();;Element of Argument[-1];Element of ReturnValue;value",
"java.util;Iterator;true;next;;;Element of Argument[-1];ReturnValue;value",
"java.util;ListIterator;true;previous;;;Element of Argument[-1];ReturnValue;value",
"java.util;ListIterator;true;add;(Object);;Argument[0];Element of Argument[-1];value",
"java.util;ListIterator;true;set;(Object);;Argument[0];Element of Argument[-1];value",
"java.util;Enumeration;true;asIterator;;;Element of Argument[-1];Element of ReturnValue;value",
"java.util;Enumeration;true;nextElement;;;Element of Argument[-1];ReturnValue;value",
"java.util;Map;true;computeIfAbsent;;;MapValue of Argument[-1];ReturnValue;value",
"java.util;Map;true;computeIfAbsent;;;ReturnValue of Argument[1];ReturnValue;value",
"java.util;Map;true;computeIfAbsent;;;ReturnValue of Argument[1];MapValue of Argument[-1];value",
"java.util;Map;true;entrySet;;;MapValue of Argument[-1];MapValue of Element of ReturnValue;value",
"java.util;Map;true;entrySet;;;MapKey of Argument[-1];MapKey of Element of ReturnValue;value",
"java.util;Map;true;get;;;MapValue of Argument[-1];ReturnValue;value",
"java.util;Map;true;getOrDefault;;;MapValue of Argument[-1];ReturnValue;value",
"java.util;Map;true;getOrDefault;;;Argument[1];ReturnValue;value",
"java.util;Map;true;put;;;MapValue of Argument[-1];ReturnValue;value",
"java.util;Map;true;put;;;Argument[0];MapKey of Argument[-1];value",
"java.util;Map;true;put;;;Argument[1];MapValue of Argument[-1];value",
"java.util;Map;true;putIfAbsent;;;MapValue of Argument[-1];ReturnValue;value",
"java.util;Map;true;putIfAbsent;;;Argument[0];MapKey of Argument[-1];value",
"java.util;Map;true;putIfAbsent;;;Argument[1];MapValue of Argument[-1];value",
"java.util;Map;true;remove;(Object);;MapValue of Argument[-1];ReturnValue;value",
"java.util;Map;true;replace;(Object,Object);;MapValue of Argument[-1];ReturnValue;value",
"java.util;Map;true;replace;(Object,Object);;Argument[0];MapKey of Argument[-1];value",
"java.util;Map;true;replace;(Object,Object);;Argument[1];MapValue of Argument[-1];value",
"java.util;Map;true;replace;(Object,Object,Object);;Argument[0];MapKey of Argument[-1];value",
"java.util;Map;true;replace;(Object,Object,Object);;Argument[2];MapValue of Argument[-1];value",
"java.util;Map;true;keySet;();;MapKey of Argument[-1];Element of ReturnValue;value",
"java.util;Map;true;values;();;MapValue of Argument[-1];Element of ReturnValue;value",
"java.util;Map;true;merge;(Object,Object,BiFunction);;Argument[1];MapValue of Argument[-1];value",
"java.util;Map;true;putAll;(Map);;MapKey of Argument[0];MapKey of Argument[-1];value",
"java.util;Map;true;putAll;(Map);;MapValue of Argument[0];MapValue of Argument[-1];value",
"java.util;Collection;true;parallelStream;();;Element of Argument[-1];Element of ReturnValue;value",
"java.util;Collection;true;stream;();;Element of Argument[-1];Element of ReturnValue;value",
"java.util;Collection;true;toArray;;;Element of Argument[-1];ArrayElement of ReturnValue;value",
"java.util;Collection;true;toArray;;;Element of Argument[-1];ArrayElement of Argument[0];value",
"java.util;Collection;true;add;;;Argument[0];Element of Argument[-1];value",
"java.util;Collection;true;addAll;;;Element of Argument[0];Element of Argument[-1];value",
"java.util;List;true;get;(int);;Element of Argument[-1];ReturnValue;value",
"java.util;List;true;listIterator;;;Element of Argument[-1];Element of ReturnValue;value",
"java.util;List;true;remove;(int);;Element of Argument[-1];ReturnValue;value",
"java.util;List;true;set;(int,Object);;Element of Argument[-1];ReturnValue;value",
"java.util;List;true;set;(int,Object);;Argument[1];Element of Argument[-1];value",
"java.util;List;true;subList;;;Element of Argument[-1];Element of ReturnValue;value",
"java.util;List;true;add;(int,Object);;Argument[1];Element of Argument[-1];value",
"java.util;List;true;addAll;(int,Collection);;Element of Argument[1];Element of Argument[-1];value",
"java.util;Vector;true;elementAt;(int);;Element of Argument[-1];ReturnValue;value",
"java.util;Vector;true;elements;();;Element of Argument[-1];Element of ReturnValue;value",
"java.util;Vector;true;firstElement;();;Element of Argument[-1];ReturnValue;value",
"java.util;Vector;true;lastElement;();;Element of Argument[-1];ReturnValue;value",
"java.util;Vector;true;addElement;(Object);;Argument[0];Element of Argument[-1];value",
"java.util;Vector;true;insertElementAt;(Object,int);;Argument[0];Element of Argument[-1];value",
"java.util;Vector;true;setElementAt;(Object,int);;Argument[0];Element of Argument[-1];value",
"java.util;Vector;true;copyInto;(Object[]);;Element of Argument[-1];ArrayElement of Argument[0];value",
"java.util;Stack;true;peek;();;Element of Argument[-1];ReturnValue;value",
"java.util;Stack;true;pop;();;Element of Argument[-1];ReturnValue;value",
"java.util;Stack;true;push;(Object);;Argument[0];Element of Argument[-1];value",
"java.util;Queue;true;element;();;Element of Argument[-1];ReturnValue;value",
"java.util;Queue;true;peek;();;Element of Argument[-1];ReturnValue;value",
"java.util;Queue;true;poll;();;Element of Argument[-1];ReturnValue;value",
"java.util;Queue;true;remove;();;Element of Argument[-1];ReturnValue;value",
"java.util;Queue;true;offer;(Object);;Argument[0];Element of Argument[-1];value",
"java.util;Deque;true;descendingIterator;();;Element of Argument[-1];Element of ReturnValue;value",
"java.util;Deque;true;getFirst;();;Element of Argument[-1];ReturnValue;value",
"java.util;Deque;true;getLast;();;Element of Argument[-1];ReturnValue;value",
"java.util;Deque;true;peekFirst;();;Element of Argument[-1];ReturnValue;value",
"java.util;Deque;true;peekLast;();;Element of Argument[-1];ReturnValue;value",
"java.util;Deque;true;pollFirst;();;Element of Argument[-1];ReturnValue;value",
"java.util;Deque;true;pollLast;();;Element of Argument[-1];ReturnValue;value",
"java.util;Deque;true;pop;();;Element of Argument[-1];ReturnValue;value",
"java.util;Deque;true;removeFirst;();;Element of Argument[-1];ReturnValue;value",
"java.util;Deque;true;removeLast;();;Element of Argument[-1];ReturnValue;value",
"java.util;Deque;true;push;(Object);;Argument[0];Element of Argument[-1];value",
"java.util;Deque;true;offerLast;(Object);;Argument[0];Element of Argument[-1];value",
"java.util;Deque;true;offerFirst;(Object);;Argument[0];Element of Argument[-1];value",
"java.util;Deque;true;addLast;(Object);;Argument[0];Element of Argument[-1];value",
"java.util;Deque;true;addFirst;(Object);;Argument[0];Element of Argument[-1];value",
"java.util.concurrent;BlockingDeque;true;pollFirst;(long,TimeUnit);;Element of Argument[-1];ReturnValue;value",
"java.util.concurrent;BlockingDeque;true;pollLast;(long,TimeUnit);;Element of Argument[-1];ReturnValue;value",
"java.util.concurrent;BlockingDeque;true;takeFirst;();;Element of Argument[-1];ReturnValue;value",
"java.util.concurrent;BlockingDeque;true;takeLast;();;Element of Argument[-1];ReturnValue;value",
"java.util.concurrent;BlockingQueue;true;poll;(long,TimeUnit);;Element of Argument[-1];ReturnValue;value",
"java.util.concurrent;BlockingQueue;true;take;();;Element of Argument[-1];ReturnValue;value",
"java.util.concurrent;BlockingQueue;true;offer;(Object,long,TimeUnit);;Argument[0];Element of Argument[-1];value",
"java.util.concurrent;BlockingQueue;true;put;(Object);;Argument[0];Element of Argument[-1];value",
"java.util.concurrent;BlockingDeque;true;offerLast;(Object,long,TimeUnit);;Argument[0];Element of Argument[-1];value",
"java.util.concurrent;BlockingDeque;true;offerFirst;(Object,long,TimeUnit);;Argument[0];Element of Argument[-1];value",
"java.util.concurrent;BlockingDeque;true;putLast;(Object);;Argument[0];Element of Argument[-1];value",
"java.util.concurrent;BlockingDeque;true;putFirst;(Object);;Argument[0];Element of Argument[-1];value",
"java.util.concurrent;BlockingQueue;true;drainTo;(Collection,int);;Element of Argument[-1];Element of Argument[0];value",
"java.util.concurrent;BlockingQueue;true;drainTo;(Collection);;Element of Argument[-1];Element of Argument[0];value",
"java.util.concurrent;ConcurrentHashMap;true;elements;();;MapValue of Argument[-1];Element of ReturnValue;value",
"java.util;Dictionary;true;elements;();;MapValue of Argument[-1];Element of ReturnValue;value",
"java.util;Dictionary;true;get;(Object);;MapValue of Argument[-1];ReturnValue;value",
"java.util;Dictionary;true;put;(Object,Object);;MapValue of Argument[-1];ReturnValue;value",
"java.util;Dictionary;true;put;(Object,Object);;Argument[0];MapKey of Argument[-1];value",
"java.util;Dictionary;true;put;(Object,Object);;Argument[1];MapValue of Argument[-1];value",
"java.util;Dictionary;true;remove;(Object);;MapValue of Argument[-1];ReturnValue;value",
"java.util;NavigableMap;true;ceilingEntry;(Object);;MapKey of Argument[-1];MapKey of ReturnValue;value",
"java.util;NavigableMap;true;ceilingEntry;(Object);;MapValue of Argument[-1];MapValue of ReturnValue;value",
"java.util;NavigableMap;true;descendingMap;();;MapKey of Argument[-1];MapKey of ReturnValue;value",
"java.util;NavigableMap;true;descendingMap;();;MapValue of Argument[-1];MapValue of ReturnValue;value",
"java.util;NavigableMap;true;firstEntry;();;MapKey of Argument[-1];MapKey of ReturnValue;value",
"java.util;NavigableMap;true;firstEntry;();;MapValue of Argument[-1];MapValue of ReturnValue;value",
"java.util;NavigableMap;true;floorEntry;(Object);;MapKey of Argument[-1];MapKey of ReturnValue;value",
"java.util;NavigableMap;true;floorEntry;(Object);;MapValue of Argument[-1];MapValue of ReturnValue;value",
"java.util;NavigableMap;true;headMap;(Object,boolean);;MapKey of Argument[-1];MapKey of ReturnValue;value",
"java.util;NavigableMap;true;headMap;(Object,boolean);;MapValue of Argument[-1];MapValue of ReturnValue;value",
"java.util;NavigableMap;true;higherEntry;(Object);;MapKey of Argument[-1];MapKey of ReturnValue;value",
"java.util;NavigableMap;true;higherEntry;(Object);;MapValue of Argument[-1];MapValue of ReturnValue;value",
"java.util;NavigableMap;true;lastEntry;();;MapKey of Argument[-1];MapKey of ReturnValue;value",
"java.util;NavigableMap;true;lastEntry;();;MapValue of Argument[-1];MapValue of ReturnValue;value",
"java.util;NavigableMap;true;lowerEntry;(Object);;MapKey of Argument[-1];MapKey of ReturnValue;value",
"java.util;NavigableMap;true;lowerEntry;(Object);;MapValue of Argument[-1];MapValue of ReturnValue;value",
"java.util;NavigableMap;true;pollFirstEntry;();;MapKey of Argument[-1];MapKey of ReturnValue;value",
"java.util;NavigableMap;true;pollFirstEntry;();;MapValue of Argument[-1];MapValue of ReturnValue;value",
"java.util;NavigableMap;true;pollLastEntry;();;MapKey of Argument[-1];MapKey of ReturnValue;value",
"java.util;NavigableMap;true;pollLastEntry;();;MapValue of Argument[-1];MapValue of ReturnValue;value",
"java.util;NavigableMap;true;subMap;(Object,boolean,Object,boolean);;MapKey of Argument[-1];MapKey of ReturnValue;value",
"java.util;NavigableMap;true;subMap;(Object,boolean,Object,boolean);;MapValue of Argument[-1];MapValue of ReturnValue;value",
"java.util;NavigableMap;true;tailMap;(Object,boolean);;MapKey of Argument[-1];MapKey of ReturnValue;value",
"java.util;NavigableMap;true;tailMap;(Object,boolean);;MapValue of Argument[-1];MapValue of ReturnValue;value",
"java.util;NavigableSet;true;ceiling;(Object);;Element of Argument[-1];ReturnValue;value",
"java.util;NavigableSet;true;descendingIterator;();;Element of Argument[-1];Element of ReturnValue;value",
"java.util;NavigableSet;true;descendingSet;();;Element of Argument[-1];Element of ReturnValue;value",
"java.util;NavigableSet;true;floor;(Object);;Element of Argument[-1];ReturnValue;value",
"java.util;NavigableSet;true;headSet;(Object,boolean);;Element of Argument[-1];Element of ReturnValue;value",
"java.util;NavigableSet;true;higher;(Object);;Element of Argument[-1];ReturnValue;value",
"java.util;NavigableSet;true;lower;(Object);;Element of Argument[-1];ReturnValue;value",
"java.util;NavigableSet;true;pollFirst;();;Element of Argument[-1];ReturnValue;value",
"java.util;NavigableSet;true;pollLast;();;Element of Argument[-1];ReturnValue;value",
"java.util;NavigableSet;true;subSet;(Object,boolean,Object,boolean);;Element of Argument[-1];Element of ReturnValue;value",
"java.util;NavigableSet;true;tailSet;(Object,boolean);;Element of Argument[-1];Element of ReturnValue;value",
"java.util;Scanner;true;next;(Pattern);;Argument[-1];ReturnValue;taint",
"java.util;Scanner;true;next;(String);;Argument[-1];ReturnValue;taint",
"java.util;SortedMap;true;headMap;(Object);;MapKey of Argument[-1];MapKey of ReturnValue;value",
"java.util;SortedMap;true;headMap;(Object);;MapValue of Argument[-1];MapValue of ReturnValue;value",
"java.util;SortedMap;true;subMap;(Object,Object);;MapKey of Argument[-1];MapKey of ReturnValue;value",
"java.util;SortedMap;true;subMap;(Object,Object);;MapValue of Argument[-1];MapValue of ReturnValue;value",
"java.util;SortedMap;true;tailMap;(Object);;MapKey of Argument[-1];MapKey of ReturnValue;value",
"java.util;SortedMap;true;tailMap;(Object);;MapValue of Argument[-1];MapValue of ReturnValue;value",
"java.util;SortedSet;true;first;();;Element of Argument[-1];ReturnValue;value",
"java.util;SortedSet;true;headSet;(Object);;Element of Argument[-1];Element of ReturnValue;value",
"java.util;SortedSet;true;last;();;Element of Argument[-1];ReturnValue;value",
"java.util;SortedSet;true;subSet;(Object,Object);;Element of Argument[-1];Element of ReturnValue;value",
"java.util;SortedSet;true;tailSet;(Object);;Element of Argument[-1];Element of ReturnValue;value",
"java.util.concurrent;TransferQueue;true;tryTransfer;(Object,long,TimeUnit);;Argument[0];Element of Argument[-1];value",
"java.util.concurrent;TransferQueue;true;transfer;(Object);;Argument[0];Element of Argument[-1];value",
"java.util.concurrent;TransferQueue;true;tryTransfer;(Object);;Argument[0];Element of Argument[-1];value",
"java.util;List;false;copyOf;(Collection);;Element of Argument[0];Element of ReturnValue;value",
"java.util;List;false;of;(Object[]);;ArrayElement of Argument[0];Element of ReturnValue;value",
"java.util;List;false;of;(Object);;Argument[0];Element of ReturnValue;value",
"java.util;List;false;of;(Object,Object);;Argument[0..1];Element of ReturnValue;value",
"java.util;List;false;of;(Object,Object,Object);;Argument[0..2];Element of ReturnValue;value",
"java.util;List;false;of;(Object,Object,Object,Object);;Argument[0..3];Element of ReturnValue;value",
"java.util;List;false;of;(Object,Object,Object,Object,Object);;Argument[0..4];Element of ReturnValue;value",
"java.util;List;false;of;(Object,Object,Object,Object,Object,Object);;Argument[0..5];Element of ReturnValue;value",
"java.util;List;false;of;(Object,Object,Object,Object,Object,Object,Object);;Argument[0..6];Element of ReturnValue;value",
"java.util;List;false;of;(Object,Object,Object,Object,Object,Object,Object,Object);;Argument[0..7];Element of ReturnValue;value",
"java.util;List;false;of;(Object,Object,Object,Object,Object,Object,Object,Object,Object);;Argument[0..8];Element of ReturnValue;value",
"java.util;List;false;of;(Object,Object,Object,Object,Object,Object,Object,Object,Object,Object);;Argument[0..9];Element of ReturnValue;value",
"java.util;Map;false;copyOf;(Map);;MapKey of Argument[0];MapKey of ReturnValue;value",
"java.util;Map;false;copyOf;(Map);;MapValue of Argument[0];MapValue of ReturnValue;value",
"java.util;Map;false;entry;(Object,Object);;Argument[0];MapKey of ReturnValue;value",
"java.util;Map;false;entry;(Object,Object);;Argument[1];MapValue of ReturnValue;value",
"java.util;Map;false;of;;;Argument[0];MapKey of ReturnValue;value",
"java.util;Map;false;of;;;Argument[1];MapValue of ReturnValue;value",
"java.util;Map;false;of;;;Argument[2];MapKey of ReturnValue;value",
"java.util;Map;false;of;;;Argument[3];MapValue of ReturnValue;value",
"java.util;Map;false;of;;;Argument[4];MapKey of ReturnValue;value",
"java.util;Map;false;of;;;Argument[5];MapValue of ReturnValue;value",
"java.util;Map;false;of;;;Argument[6];MapKey of ReturnValue;value",
"java.util;Map;false;of;;;Argument[7];MapValue of ReturnValue;value",
"java.util;Map;false;of;;;Argument[8];MapKey of ReturnValue;value",
"java.util;Map;false;of;;;Argument[9];MapValue of ReturnValue;value",
"java.util;Map;false;of;;;Argument[10];MapKey of ReturnValue;value",
"java.util;Map;false;of;;;Argument[11];MapValue of ReturnValue;value",
"java.util;Map;false;of;;;Argument[12];MapKey of ReturnValue;value",
"java.util;Map;false;of;;;Argument[13];MapValue of ReturnValue;value",
"java.util;Map;false;of;;;Argument[14];MapKey of ReturnValue;value",
"java.util;Map;false;of;;;Argument[15];MapValue of ReturnValue;value",
"java.util;Map;false;of;;;Argument[16];MapKey of ReturnValue;value",
"java.util;Map;false;of;;;Argument[17];MapValue of ReturnValue;value",
"java.util;Map;false;of;;;Argument[18];MapKey of ReturnValue;value",
"java.util;Map;false;of;;;Argument[19];MapValue of ReturnValue;value",
"java.util;Map;false;ofEntries;;;MapKey of ArrayElement of Argument[0];MapKey of ReturnValue;value",
"java.util;Map;false;ofEntries;;;MapValue of ArrayElement of Argument[0];MapValue of ReturnValue;value",
"java.util;Set;false;copyOf;(Collection);;Element of Argument[0];Element of ReturnValue;value",
"java.util;Set;false;of;(Object[]);;ArrayElement of Argument[0];Element of ReturnValue;value",
"java.util;Set;false;of;(Object);;Argument[0];Element of ReturnValue;value",
"java.util;Set;false;of;(Object,Object);;Argument[0..1];Element of ReturnValue;value",
"java.util;Set;false;of;(Object,Object,Object);;Argument[0..2];Element of ReturnValue;value",
"java.util;Set;false;of;(Object,Object,Object,Object);;Argument[0..3];Element of ReturnValue;value",
"java.util;Set;false;of;(Object,Object,Object,Object,Object);;Argument[0..4];Element of ReturnValue;value",
"java.util;Set;false;of;(Object,Object,Object,Object,Object,Object);;Argument[0..5];Element of ReturnValue;value",
"java.util;Set;false;of;(Object,Object,Object,Object,Object,Object,Object);;Argument[0..6];Element of ReturnValue;value",
"java.util;Set;false;of;(Object,Object,Object,Object,Object,Object,Object,Object);;Argument[0..7];Element of ReturnValue;value",
"java.util;Set;false;of;(Object,Object,Object,Object,Object,Object,Object,Object,Object);;Argument[0..8];Element of ReturnValue;value",
"java.util;Set;false;of;(Object,Object,Object,Object,Object,Object,Object,Object,Object,Object);;Argument[0..9];Element of ReturnValue;value",
"java.util;Arrays;false;stream;;;ArrayElement of Argument[0];Element of ReturnValue;value",
"java.util;Arrays;false;spliterator;;;ArrayElement of Argument[0];Element of ReturnValue;value",
"java.util;Arrays;false;copyOfRange;;;ArrayElement of Argument[0];ArrayElement of ReturnValue;value",
"java.util;Arrays;false;copyOf;;;ArrayElement of Argument[0];ArrayElement of ReturnValue;value",
"java.util;Collections;false;list;(Enumeration);;Element of Argument[0];Element of ReturnValue;value",
"java.util;Collections;false;enumeration;(Collection);;Element of Argument[0];Element of ReturnValue;value",
"java.util;Collections;false;nCopies;(int,Object);;Argument[1];Element of ReturnValue;value",
"java.util;Collections;false;singletonMap;(Object,Object);;Argument[0];MapKey of ReturnValue;value",
"java.util;Collections;false;singletonMap;(Object,Object);;Argument[1];MapValue of ReturnValue;value",
"java.util;Collections;false;singletonList;(Object);;Argument[0];Element of ReturnValue;value",
"java.util;Collections;false;singleton;(Object);;Argument[0];Element of ReturnValue;value",
"java.util;Collections;false;checkedNavigableMap;(NavigableMap,Class,Class);;MapKey of Argument[0];MapKey of ReturnValue;value",
"java.util;Collections;false;checkedNavigableMap;(NavigableMap,Class,Class);;MapValue of Argument[0];MapValue of ReturnValue;value",
"java.util;Collections;false;checkedSortedMap;(SortedMap,Class,Class);;MapKey of Argument[0];MapKey of ReturnValue;value",
"java.util;Collections;false;checkedSortedMap;(SortedMap,Class,Class);;MapValue of Argument[0];MapValue of ReturnValue;value",
"java.util;Collections;false;checkedMap;(Map,Class,Class);;MapKey of Argument[0];MapKey of ReturnValue;value",
"java.util;Collections;false;checkedMap;(Map,Class,Class);;MapValue of Argument[0];MapValue of ReturnValue;value",
"java.util;Collections;false;checkedList;(List,Class);;Element of Argument[0];Element of ReturnValue;value",
"java.util;Collections;false;checkedNavigableSet;(NavigableSet,Class);;Element of Argument[0];Element of ReturnValue;value",
"java.util;Collections;false;checkedSortedSet;(SortedSet,Class);;Element of Argument[0];Element of ReturnValue;value",
"java.util;Collections;false;checkedSet;(Set,Class);;Element of Argument[0];Element of ReturnValue;value",
"java.util;Collections;false;checkedCollection;(Collection,Class);;Element of Argument[0];Element of ReturnValue;value",
"java.util;Collections;false;synchronizedNavigableMap;(NavigableMap);;MapKey of Argument[0];MapKey of ReturnValue;value",
"java.util;Collections;false;synchronizedNavigableMap;(NavigableMap);;MapValue of Argument[0];MapValue of ReturnValue;value",
"java.util;Collections;false;synchronizedSortedMap;(SortedMap);;MapKey of Argument[0];MapKey of ReturnValue;value",
"java.util;Collections;false;synchronizedSortedMap;(SortedMap);;MapValue of Argument[0];MapValue of ReturnValue;value",
"java.util;Collections;false;synchronizedMap;(Map);;MapKey of Argument[0];MapKey of ReturnValue;value",
"java.util;Collections;false;synchronizedMap;(Map);;MapValue of Argument[0];MapValue of ReturnValue;value",
"java.util;Collections;false;synchronizedList;(List);;Element of Argument[0];Element of ReturnValue;value",
"java.util;Collections;false;synchronizedNavigableSet;(NavigableSet);;Element of Argument[0];Element of ReturnValue;value",
"java.util;Collections;false;synchronizedSortedSet;(SortedSet);;Element of Argument[0];Element of ReturnValue;value",
"java.util;Collections;false;synchronizedSet;(Set);;Element of Argument[0];Element of ReturnValue;value",
"java.util;Collections;false;synchronizedCollection;(Collection);;Element of Argument[0];Element of ReturnValue;value",
"java.util;Collections;false;unmodifiableNavigableMap;(NavigableMap);;MapKey of Argument[0];MapKey of ReturnValue;value",
"java.util;Collections;false;unmodifiableNavigableMap;(NavigableMap);;MapValue of Argument[0];MapValue of ReturnValue;value",
"java.util;Collections;false;unmodifiableSortedMap;(SortedMap);;MapKey of Argument[0];MapKey of ReturnValue;value",
"java.util;Collections;false;unmodifiableSortedMap;(SortedMap);;MapValue of Argument[0];MapValue of ReturnValue;value",
"java.util;Collections;false;unmodifiableMap;(Map);;MapKey of Argument[0];MapKey of ReturnValue;value",
"java.util;Collections;false;unmodifiableMap;(Map);;MapValue of Argument[0];MapValue of ReturnValue;value",
"java.util;Collections;false;unmodifiableList;(List);;Element of Argument[0];Element of ReturnValue;value",
"java.util;Collections;false;unmodifiableNavigableSet;(NavigableSet);;Element of Argument[0];Element of ReturnValue;value",
"java.util;Collections;false;unmodifiableSortedSet;(SortedSet);;Element of Argument[0];Element of ReturnValue;value",
"java.util;Collections;false;unmodifiableSet;(Set);;Element of Argument[0];Element of ReturnValue;value",
"java.util;Collections;false;unmodifiableCollection;(Collection);;Element of Argument[0];Element of ReturnValue;value",
"java.util;Collections;false;max;;;Element of Argument[0];ReturnValue;value",
"java.util;Collections;false;min;;;Element of Argument[0];ReturnValue;value",
"java.util;Arrays;false;fill;(Object[],int,int,Object);;Argument[3];ArrayElement of Argument[0];value",
"java.util;Arrays;false;fill;(Object[],Object);;Argument[1];ArrayElement of Argument[0];value",
"java.util;Arrays;false;fill;(float[],int,int,float);;Argument[3];ArrayElement of Argument[0];value",
"java.util;Arrays;false;fill;(float[],float);;Argument[1];ArrayElement of Argument[0];value",
"java.util;Arrays;false;fill;(double[],int,int,double);;Argument[3];ArrayElement of Argument[0];value",
"java.util;Arrays;false;fill;(double[],double);;Argument[1];ArrayElement of Argument[0];value",
"java.util;Arrays;false;fill;(boolean[],int,int,boolean);;Argument[3];ArrayElement of Argument[0];value",
"java.util;Arrays;false;fill;(boolean[],boolean);;Argument[1];ArrayElement of Argument[0];value",
"java.util;Arrays;false;fill;(byte[],int,int,byte);;Argument[3];ArrayElement of Argument[0];value",
"java.util;Arrays;false;fill;(byte[],byte);;Argument[1];ArrayElement of Argument[0];value",
"java.util;Arrays;false;fill;(char[],int,int,char);;Argument[3];ArrayElement of Argument[0];value",
"java.util;Arrays;false;fill;(char[],char);;Argument[1];ArrayElement of Argument[0];value",
"java.util;Arrays;false;fill;(short[],int,int,short);;Argument[3];ArrayElement of Argument[0];value",
"java.util;Arrays;false;fill;(short[],short);;Argument[1];ArrayElement of Argument[0];value",
"java.util;Arrays;false;fill;(int[],int,int,int);;Argument[3];ArrayElement of Argument[0];value",
"java.util;Arrays;false;fill;(int[],int);;Argument[1];ArrayElement of Argument[0];value",
"java.util;Arrays;false;fill;(long[],int,int,long);;Argument[3];ArrayElement of Argument[0];value",
"java.util;Arrays;false;fill;(long[],long);;Argument[1];ArrayElement of Argument[0];value",
"java.util;Collections;false;replaceAll;(List,Object,Object);;Argument[2];Element of Argument[0];value",
"java.util;Collections;false;copy;(List,List);;Element of Argument[1];Element of Argument[0];value",
"java.util;Collections;false;fill;(List,Object);;Argument[1];Element of Argument[0];value",
"java.util;Arrays;false;asList;;;ArrayElement of Argument[0];Element of ReturnValue;value",
"java.util;Collections;false;addAll;(Collection,Object[]);;ArrayElement of Argument[1];Element of Argument[0];value"
]
}
}
private predicate taintPreservingQualifierToMethod(Method m) {
// java.util.Map.Entry
m.getDeclaringType() instanceof EntryType and
@@ -426,3 +709,58 @@ predicate containerStep(Expr n1, Expr n2) {
containerReturnValueStep(n1, n2) or
containerUpdateStep(n1, n2)
}
/**
* Holds if the step from `node1` to `node2` stores a value in an array.
* This covers array assignments and initializers as well as implicit array
* creations for varargs.
*/
predicate arrayStoreStep(Node node1, Node node2) {
exists(Argument arg |
node1.asExpr() = arg and
arg.isVararg() and
node2.(ImplicitVarargsArray).getCall() = arg.getCall()
)
or
node2.asExpr().(ArrayInit).getAnInit() = node1.asExpr()
or
exists(Assignment assign | assign.getSource() = node1.asExpr() |
node2.(PostUpdateNode).getPreUpdateNode().asExpr() = assign.getDest().(ArrayAccess).getArray()
)
}
private predicate enhancedForStmtStep(Node node1, Node node2, Type containerType) {
exists(EnhancedForStmt for, Expr e, SsaExplicitUpdate v |
for.getExpr() = e and
node1.asExpr() = e and
containerType = e.getType() and
v.getDefiningExpr() = for.getVariable() and
v.getAFirstUse() = node2.asExpr()
)
}
/**
* Holds if the step from `node1` to `node2` reads a value from an array.
* This covers ordinary array reads as well as array iteration through enhanced
* `for` statements.
*/
predicate arrayReadStep(Node node1, Node node2, Type elemType) {
exists(ArrayAccess aa |
aa.getArray() = node1.asExpr() and
aa.getType() = elemType and
node2.asExpr() = aa
)
or
exists(Array arr |
enhancedForStmtStep(node1, node2, arr) and
arr.getComponentType() = elemType
)
}
/**
* Holds if the step from `node1` to `node2` reads a value from a collection.
* This only covers iteration through enhanced `for` statements.
*/
predicate collectionReadStep(Node node1, Node node2) {
enhancedForStmtStep(node1, node2, any(Type t | not t instanceof Array))
}

View File

@@ -106,7 +106,7 @@ private module DispatchImpl {
mayBenefitFromCallContext(ma, c, i) and
c = viableCallable(ctx) and
contextArgHasType(ctx, i, t, exact) and
ma.getMethod() = def
ma.getMethod().getSourceDeclaration() = def
|
exact = true and result = VirtualDispatch::exactMethodImpl(def, t.getSourceDeclaration())
or

Some files were not shown because too many files have changed in this diff Show More