mirror of
https://github.com/github/codeql.git
synced 2026-04-30 11:15:13 +02:00
Merge remote-tracking branch 'upstream-public/main' into yo-h/java16
This commit is contained in:
2
java/change-notes/2021-03-05-commons-lang-randomutils.md
Normal file
2
java/change-notes/2021-03-05-commons-lang-randomutils.md
Normal file
@@ -0,0 +1,2 @@
|
||||
lgtm,codescanning
|
||||
* Added models for the Apache Commons Lang `RandomUtils` class. This may lead to extra results from queries that check for proper use of random-number generators or those which check the range of possible random values that could be returned, including `java/improper-validation-of-array-index-code-specified` and `java/uncontrolled-arithmetic`.
|
||||
2
java/change-notes/2021-03-05-commons-object-utils.md
Normal file
2
java/change-notes/2021-03-05-commons-object-utils.md
Normal file
@@ -0,0 +1,2 @@
|
||||
lgtm,codescanning
|
||||
* Added models for `ObjectUtils` methods in the Apache Commons Lang library. This may lead to more results from any dataflow query where traversal of `ObjectUtils` methods means we can now complete a path from a source of tainted data to a corresponding sink.
|
||||
@@ -0,0 +1,2 @@
|
||||
lgtm,codescanning
|
||||
* The legacy code duplication library has been removed.
|
||||
@@ -0,0 +1,2 @@
|
||||
lgtm,codescanning
|
||||
* Legacy filter queries have been removed.
|
||||
@@ -11,15 +11,15 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.security.Random
|
||||
|
||||
from MethodAccess ma, Method abs, Method nextIntOrLong, MethodAccess nma
|
||||
from MethodAccess ma, Method abs, Method nextIntOrLong, RandomDataSource nma
|
||||
where
|
||||
ma.getMethod() = abs and
|
||||
abs.hasName("abs") and
|
||||
abs.getDeclaringType().hasQualifiedName("java.lang", "Math") and
|
||||
ma.getAnArgument() = nma and
|
||||
nma.getMethod() = nextIntOrLong and
|
||||
(nextIntOrLong.hasName("nextInt") or nextIntOrLong.hasName("nextLong")) and
|
||||
nextIntOrLong.getDeclaringType().hasQualifiedName("java.util", "Random") and
|
||||
nextIntOrLong.hasNoParameters()
|
||||
nextIntOrLong.hasName(["nextInt", "nextLong"]) and
|
||||
not nma.resultMayBeBounded()
|
||||
select ma, "Incorrect computation of abs of signed integral random value."
|
||||
|
||||
@@ -12,10 +12,8 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.security.Random
|
||||
|
||||
from MethodAccess ma, Method random
|
||||
where
|
||||
random.getDeclaringType().hasQualifiedName("java.util", "Random") and
|
||||
ma.getMethod() = random and
|
||||
ma.getQualifier() instanceof ClassInstanceExpr
|
||||
from RandomDataSource ma
|
||||
where ma.getQualifier() instanceof ClassInstanceExpr
|
||||
select ma, "Random object created and used only once."
|
||||
|
||||
@@ -13,12 +13,7 @@
|
||||
import java
|
||||
|
||||
class NewStringBufferOrBuilder extends ClassInstanceExpr {
|
||||
NewStringBufferOrBuilder() {
|
||||
exists(Class c | c = this.getConstructedType() |
|
||||
c.hasQualifiedName("java.lang", "StringBuilder") or
|
||||
c.hasQualifiedName("java.lang", "StringBuffer")
|
||||
)
|
||||
}
|
||||
NewStringBufferOrBuilder() { getConstructedType() instanceof StringBuildingType }
|
||||
|
||||
string getName() { result = this.getConstructedType().getName() }
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* @kind treemap
|
||||
* @treemap.warnOn highValues
|
||||
* @metricType externalDependency
|
||||
* @precision medium
|
||||
* @id java/external-dependencies
|
||||
*/
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* @treemap.warnOn highValues
|
||||
* @metricType file
|
||||
* @metricAggregate avg sum max
|
||||
* @precision very-high
|
||||
* @id java/lines-of-code-in-files
|
||||
* @tags maintainability
|
||||
* complexity
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* @treemap.warnOn lowValues
|
||||
* @metricType file
|
||||
* @metricAggregate avg sum max
|
||||
* @precision very-high
|
||||
* @id java/lines-of-comments-in-files
|
||||
* @tags maintainability
|
||||
* documentation
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* @treemap.warnOn highValues
|
||||
* @metricType file
|
||||
* @metricAggregate avg sum max
|
||||
* @precision high
|
||||
* @id java/lines-of-commented-out-code-in-files
|
||||
* @tags maintainability
|
||||
* documentation
|
||||
|
||||
@@ -7,21 +7,13 @@
|
||||
* @treemap.warnOn highValues
|
||||
* @metricType file
|
||||
* @metricAggregate avg sum max
|
||||
* @precision high
|
||||
* @id java/duplicated-lines-in-files
|
||||
* @tags testability
|
||||
* modularity
|
||||
*/
|
||||
|
||||
import external.CodeDuplication
|
||||
import java
|
||||
|
||||
from File f, int n
|
||||
where
|
||||
n =
|
||||
count(int line |
|
||||
exists(DuplicateBlock d | d.sourceFile() = f |
|
||||
line in [d.sourceStartLine() .. d.sourceEndLine()] and
|
||||
not whitelistedLineForDuplication(f, line)
|
||||
)
|
||||
)
|
||||
where none()
|
||||
select f, n order by n desc
|
||||
|
||||
@@ -11,15 +11,8 @@
|
||||
* @tags testability
|
||||
*/
|
||||
|
||||
import external.CodeDuplication
|
||||
import java
|
||||
|
||||
from File f, int n
|
||||
where
|
||||
n =
|
||||
count(int line |
|
||||
exists(SimilarBlock d | d.sourceFile() = f |
|
||||
line in [d.sourceStartLine() .. d.sourceEndLine()] and
|
||||
not whitelistedLineForDuplication(f, line)
|
||||
)
|
||||
)
|
||||
where none()
|
||||
select f, n order by n desc
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* @treemap.warnOn lowValues
|
||||
* @metricType file
|
||||
* @metricAggregate avg sum max
|
||||
* @precision medium
|
||||
* @id java/tests-in-files
|
||||
* @tags maintainability
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import semmle.code.java.dataflow.DefUse
|
||||
import semmle.code.java.security.Random
|
||||
private import BoundingChecks
|
||||
|
||||
/**
|
||||
@@ -124,33 +125,16 @@ abstract class BoundedFlowSource extends DataFlow::Node {
|
||||
}
|
||||
|
||||
/**
|
||||
* Input that is constructed using a `Random` value.
|
||||
* Input that is constructed using a random value.
|
||||
*/
|
||||
class RandomValueFlowSource extends BoundedFlowSource {
|
||||
RandomValueFlowSource() {
|
||||
exists(RefType random, MethodAccess nextAccess |
|
||||
random.hasQualifiedName("java.util", "Random")
|
||||
|
|
||||
nextAccess.getCallee().getDeclaringType().getAnAncestor() = random and
|
||||
nextAccess.getCallee().getName().matches("next%") and
|
||||
nextAccess = this.asExpr()
|
||||
)
|
||||
}
|
||||
RandomDataSource nextAccess;
|
||||
|
||||
override int lowerBound() {
|
||||
// If this call is to `nextInt()`, the lower bound is zero.
|
||||
this.asExpr().(MethodAccess).getCallee().hasName("nextInt") and
|
||||
this.asExpr().(MethodAccess).getNumArgument() = 1 and
|
||||
result = 0
|
||||
}
|
||||
RandomValueFlowSource() { this.asExpr() = nextAccess }
|
||||
|
||||
override int upperBound() {
|
||||
// If this call specified an argument to `nextInt()`, and that argument is a compile time constant,
|
||||
// it forms the upper bound.
|
||||
this.asExpr().(MethodAccess).getCallee().hasName("nextInt") and
|
||||
this.asExpr().(MethodAccess).getNumArgument() = 1 and
|
||||
result = this.asExpr().(MethodAccess).getArgument(0).(CompileTimeConstantExpr).getIntValue()
|
||||
}
|
||||
override int lowerBound() { result = nextAccess.getLowerBound() }
|
||||
|
||||
override int upperBound() { result = nextAccess.getUpperBound() }
|
||||
|
||||
override string getDescription() { result = "Random value" }
|
||||
}
|
||||
|
||||
@@ -13,34 +13,14 @@
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.security.Random
|
||||
import semmle.code.java.security.SecurityTests
|
||||
import ArithmeticCommon
|
||||
import DataFlow::PathGraph
|
||||
|
||||
class TaintSource extends DataFlow::ExprNode {
|
||||
TaintSource() {
|
||||
// Either this is an access to a random number generating method of the right kind, ...
|
||||
exists(Method def |
|
||||
def = this.getExpr().(MethodAccess).getMethod() and
|
||||
(
|
||||
// Some random-number methods are omitted:
|
||||
// `nextDouble` and `nextFloat` are between 0 and 1,
|
||||
// `nextGaussian` is extremely unlikely to hit max values.
|
||||
def.getName() = "nextInt" or
|
||||
def.getName() = "nextLong"
|
||||
) and
|
||||
def.getNumberOfParameters() = 0 and
|
||||
def.getDeclaringType().hasQualifiedName("java.util", "Random")
|
||||
)
|
||||
or
|
||||
// ... or this is the array parameter of `nextBytes`, which is filled with random bytes.
|
||||
exists(MethodAccess m, Method def |
|
||||
m.getAnArgument() = this.getExpr() and
|
||||
m.getMethod() = def and
|
||||
def.getName() = "nextBytes" and
|
||||
def.getNumberOfParameters() = 1 and
|
||||
def.getDeclaringType().hasQualifiedName("java.util", "Random")
|
||||
)
|
||||
exists(RandomDataSource m | not m.resultMayBeBounded() | m.getOutput() = this.getExpr())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -44,8 +44,7 @@ predicate objectToString(MethodAccess ma) {
|
||||
class StringContainer extends RefType {
|
||||
StringContainer() {
|
||||
this instanceof TypeString or
|
||||
this.hasQualifiedName("java.lang", "StringBuilder") or
|
||||
this.hasQualifiedName("java.lang", "StringBuffer") or
|
||||
this instanceof StringBuildingType or
|
||||
this.hasQualifiedName("java.util", "StringTokenizer") or
|
||||
this.(Array).getComponentType() instanceof StringContainer
|
||||
}
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
/**
|
||||
* @name openStream called on URLs created from remote source
|
||||
* @description Calling openStream on URLs created from remote source
|
||||
* can lead to local file disclosure.
|
||||
* can lead to local file disclosure.
|
||||
* @kind path-problem
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @id java/openstream-called-on-tainted-url
|
||||
* @tags security
|
||||
* external/cwe/cwe-036
|
||||
*/
|
||||
|
||||
import java
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
|
||||
<p>If unsanitized user input is written to a log entry, a malicious user may be able to forge new log entries.</p>
|
||||
|
||||
<p>Forgery can occur if a user provides some input creating the appearance of multiple
|
||||
log entries. This can include unescaped new-line characters, or HTML or other markup.</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>
|
||||
User input should be suitably sanitized before it is logged.
|
||||
</p>
|
||||
<p>
|
||||
If the log entries are plain text then line breaks should be removed from user input, using for example
|
||||
<code>String replace(char oldChar, char newChar)</code> or similar. Care should also be taken that user input is clearly marked
|
||||
in log entries, and that a malicious user cannot cause confusion in other ways.
|
||||
</p>
|
||||
<p>
|
||||
For log entries that will be displayed in HTML, user input should be HTML encoded before being logged, to prevent forgery and
|
||||
other forms of HTML injection.
|
||||
</p>
|
||||
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>In the example, a username, provided by the user, is logged using <code>logger.warn</code> (from <code>org.slf4j.Logger</code>).
|
||||
In the first case (<code>/bad</code> endpoint), the username is logged without any sanitization.
|
||||
If a malicious user provides <code>Guest'%0AUser:'Admin</code> as a username parameter,
|
||||
the log entry will be split into two separate lines, where the first line will be <code>User:'Guest'</code> and the second one will be <code>User:'Admin'</code>.
|
||||
</p>
|
||||
<sample src="LogInjectionBad.java" />
|
||||
|
||||
<p> In the second case (<code>/good</code> endpoint), <code>matches()</code> is used to ensure the user input only has alphanumeric characters.
|
||||
If a malicious user provides `Guest'%0AUser:'Admin` as a username parameter,
|
||||
the log entry will not be split into two separate lines, resulting in a single line <code>User:'Guest'User:'Admin'</code>.</p>
|
||||
|
||||
<sample src="LogInjectionGood.java" />
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>OWASP: <a href="https://owasp.org/www-community/attacks/Log_Injection">Log Injection</a>.</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* @name Log Injection
|
||||
* @description Building log entries from user-controlled data is vulnerable to
|
||||
* insertion of forged log entries by a malicious user.
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @id java/log-injection
|
||||
* @tags security
|
||||
* external/cwe/cwe-117
|
||||
*/
|
||||
|
||||
import java
|
||||
import DataFlow::PathGraph
|
||||
import experimental.semmle.code.java.Logging
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for tracking untrusted user input used in log entries.
|
||||
*/
|
||||
private class LogInjectionConfiguration extends TaintTracking::Configuration {
|
||||
LogInjectionConfiguration() { this = "Log Injection" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
sink.asExpr() = any(LoggingCall c).getALogArgument()
|
||||
}
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
node.getType() instanceof BoxedType or node.getType() instanceof PrimitiveType
|
||||
}
|
||||
}
|
||||
|
||||
from LogInjectionConfiguration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where cfg.hasFlowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "$@ flows to log entry.", source.getNode(),
|
||||
"User-provided value"
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.example.restservice;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
public class LogInjection {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(LogInjection.class);
|
||||
|
||||
// /bad?username=Guest'%0AUser:'Admin
|
||||
@GetMapping("/bad")
|
||||
public String bad(@RequestParam(value = "username", defaultValue = "name") String username) {
|
||||
log.warn("User:'{}'", username);
|
||||
// The logging call above would result in multiple log entries as shown below:
|
||||
// User:'Guest'
|
||||
// User:'Admin'
|
||||
return username;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.example.restservice;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
public class LogInjection {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(LogInjection.class);
|
||||
|
||||
// /good?username=Guest'%0AUser:'Admin
|
||||
@GetMapping("/good")
|
||||
public String good(@RequestParam(value = "username", defaultValue = "name") String username) {
|
||||
// The regex check here, allows only alphanumeric characters to pass.
|
||||
// Hence, does not result in log injection
|
||||
if (username.matches("\w*")) {
|
||||
log.warn("User:'{}'", username);
|
||||
|
||||
return username;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,12 @@
|
||||
/**
|
||||
* @name Unsafe certificate trust
|
||||
* @description Unsafe implementation of the interface X509TrustManager and SSLSocket/SSLEngine ignores all SSL certificate validation errors when establishing an HTTPS connection, thereby making the app vulnerable to man-in-the-middle attacks.
|
||||
* @description Unsafe implementation of the interface X509TrustManager and
|
||||
* SSLSocket/SSLEngine ignores all SSL certificate validation
|
||||
* errors when establishing an HTTPS connection, thereby making
|
||||
* the app vulnerable to man-in-the-middle attacks.
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @id java/unsafe-cert-trust
|
||||
* @tags security
|
||||
* external/cwe-273
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
/**
|
||||
* @name JxBrowser with disabled certificate validation
|
||||
* @description Insecure configuration of JxBrowser disables certificate validation making the app vulnerable to man-in-the-middle attacks.
|
||||
* @description Insecure configuration of JxBrowser disables certificate
|
||||
* validation making the app vulnerable to man-in-the-middle
|
||||
* attacks.
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @id java/jxbrowser/disabled-certificate-validation
|
||||
* @tags security
|
||||
* external/cwe/cwe-295
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
/**
|
||||
* @id java/insecure-smtp-ssl
|
||||
* @name Insecure JavaMail SSL Configuration
|
||||
* @description Java application configured to use authenticated mail session over SSL does not validate the SSL certificate to properly ensure that it is actually associated with that host.
|
||||
* @description Java application configured to use authenticated mail session
|
||||
* over SSL does not validate the SSL certificate to properly
|
||||
* ensure that it is actually associated with that host.
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @id java/insecure-smtp-ssl
|
||||
* @tags security
|
||||
* external/cwe-297
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
public class InsecureLdapEndpoint {
|
||||
public Hashtable<String, String> createConnectionEnv() {
|
||||
Hashtable<String, String> env = new Hashtable<String, String>();
|
||||
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
|
||||
env.put(Context.PROVIDER_URL, "ldaps://ad.your-server.com:636");
|
||||
|
||||
env.put(Context.SECURITY_AUTHENTICATION, "simple");
|
||||
env.put(Context.SECURITY_PRINCIPAL, "username");
|
||||
env.put(Context.SECURITY_CREDENTIALS, "secpassword");
|
||||
|
||||
// BAD - Test configuration with disabled SSL endpoint check.
|
||||
{
|
||||
System.setProperty("com.sun.jndi.ldap.object.disableEndpointIdentification", "true");
|
||||
}
|
||||
|
||||
return env;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>Java versions 8u181 or greater have enabled LDAPS endpoint identification by default. Nowadays
|
||||
infrastructure services like LDAP are commonly deployed behind load balancers therefore the LDAP
|
||||
server name can be different from the FQDN of the LDAPS endpoint. If a service certificate does not
|
||||
properly contain a matching DNS name as part of the certificate, Java will reject it by default.</p>
|
||||
<p>Instead of addressing the issue properly by having a compliant certificate deployed, frequently
|
||||
developers simply disable the LDAPS endpoint check.</p>
|
||||
<p>Failing to validate the certificate makes the SSL session susceptible to a man-in-the-middle attack.
|
||||
This query checks whether the LDAPS endpoint check is disabled in system properties.</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>Replace any non-conforming LDAP server certificates to include a DNS name in the subjectAltName field
|
||||
of the certificate that matches the FQDN of the service.</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>The following two examples show two ways of configuring LDAPS endpoint. In the 'BAD' case,
|
||||
endpoint check is disabled. In the 'GOOD' case, endpoint check is left enabled through the
|
||||
default Java configuration.</p>
|
||||
<sample src="InsecureLdapEndpoint.java" />
|
||||
<sample src="InsecureLdapEndpoint2.java" />
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>
|
||||
Oracle Java 8 Update 181 (8u181):
|
||||
<a href="https://www.java.com/en/download/help/release_changes.html">Endpoint identification enabled on LDAPS connections</a>
|
||||
</li>
|
||||
<li>
|
||||
IBM:
|
||||
<a href="https://www.ibm.com/support/pages/how-do-i-fix-ldap-ssl-error-%E2%80%9Cjavasecuritycertcertificateexception-no-subject-alternative-names-present%E2%80%9D-websphere-application-server">Fix this LDAP SSL error</a>
|
||||
</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -0,0 +1,110 @@
|
||||
/**
|
||||
* @name Insecure LDAPS Endpoint Configuration
|
||||
* @description Java application configured to disable LDAPS endpoint
|
||||
* identification does not validate the SSL certificate to
|
||||
* properly ensure that it is actually associated with that host.
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @id java/insecure-ldaps-endpoint
|
||||
* @tags security
|
||||
* external/cwe-297
|
||||
*/
|
||||
|
||||
import java
|
||||
|
||||
/** The method to set a system property. */
|
||||
class SetSystemPropertyMethod extends Method {
|
||||
SetSystemPropertyMethod() {
|
||||
this.hasName("setProperty") and
|
||||
this.getDeclaringType().hasQualifiedName("java.lang", "System")
|
||||
}
|
||||
}
|
||||
|
||||
/** The class `java.util.Hashtable`. */
|
||||
class TypeHashtable extends Class {
|
||||
TypeHashtable() { this.getSourceDeclaration().hasQualifiedName("java.util", "Hashtable") }
|
||||
}
|
||||
|
||||
/**
|
||||
* The method to set Java properties either through `setProperty` declared in the class `Properties`
|
||||
* or `put` declared in its parent class `HashTable`.
|
||||
*/
|
||||
class SetPropertyMethod extends Method {
|
||||
SetPropertyMethod() {
|
||||
this.getDeclaringType().getAnAncestor() instanceof TypeHashtable and
|
||||
this.hasName(["put", "setProperty"])
|
||||
}
|
||||
}
|
||||
|
||||
/** The `setProperties` method declared in `java.lang.System`. */
|
||||
class SetSystemPropertiesMethod extends Method {
|
||||
SetSystemPropertiesMethod() {
|
||||
this.hasName("setProperties") and
|
||||
this.getDeclaringType().hasQualifiedName("java.lang", "System")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `Expr` expr is evaluated to the string literal
|
||||
* `com.sun.jndi.ldap.object.disableEndpointIdentification`.
|
||||
*/
|
||||
predicate isPropertyDisableLdapEndpointId(Expr expr) {
|
||||
expr.(CompileTimeConstantExpr).getStringValue() =
|
||||
"com.sun.jndi.ldap.object.disableEndpointIdentification"
|
||||
or
|
||||
exists(Field f |
|
||||
expr = f.getAnAccess() and
|
||||
f.getAnAssignedValue().(StringLiteral).getValue() =
|
||||
"com.sun.jndi.ldap.object.disableEndpointIdentification"
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if an expression is evaluated to the boolean value true. */
|
||||
predicate isBooleanTrue(Expr expr) {
|
||||
expr.(CompileTimeConstantExpr).getStringValue() = "true" // "true"
|
||||
or
|
||||
expr.(BooleanLiteral).getBooleanValue() = true // true
|
||||
or
|
||||
exists(MethodAccess ma |
|
||||
expr = ma and
|
||||
ma.getMethod().hasName("toString") and
|
||||
ma.getQualifier().(FieldAccess).getField().hasName("TRUE") and
|
||||
ma.getQualifier()
|
||||
.(FieldAccess)
|
||||
.getField()
|
||||
.getDeclaringType()
|
||||
.hasQualifiedName("java.lang", "Boolean") // Boolean.TRUE.toString()
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `ma` is in a test class or method. */
|
||||
predicate isTestMethod(MethodAccess ma) {
|
||||
ma.getEnclosingCallable() instanceof TestMethod or
|
||||
ma.getEnclosingCallable().getDeclaringType() instanceof TestClass or
|
||||
ma.getEnclosingCallable().getDeclaringType().getPackage().getName().matches("%test%") or
|
||||
ma.getEnclosingCallable().getDeclaringType().getName().toLowerCase().matches("%test%")
|
||||
}
|
||||
|
||||
/** Holds if `MethodAccess` ma disables SSL endpoint check. */
|
||||
predicate isInsecureSSLEndpoint(MethodAccess ma) {
|
||||
(
|
||||
ma.getMethod() instanceof SetSystemPropertyMethod and
|
||||
isPropertyDisableLdapEndpointId(ma.getArgument(0)) and
|
||||
isBooleanTrue(ma.getArgument(1)) //com.sun.jndi.ldap.object.disableEndpointIdentification=true
|
||||
or
|
||||
ma.getMethod() instanceof SetSystemPropertiesMethod and
|
||||
exists(MethodAccess ma2 |
|
||||
ma2.getMethod() instanceof SetPropertyMethod and
|
||||
isPropertyDisableLdapEndpointId(ma2.getArgument(0)) and
|
||||
isBooleanTrue(ma2.getArgument(1)) and //com.sun.jndi.ldap.object.disableEndpointIdentification=true
|
||||
ma2.getQualifier().(VarAccess).getVariable().getAnAccess() = ma.getArgument(0) // systemProps.setProperties(properties)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
from MethodAccess ma
|
||||
where
|
||||
isInsecureSSLEndpoint(ma) and
|
||||
not isTestMethod(ma)
|
||||
select ma, "LDAPS configuration allows insecure endpoint identification"
|
||||
@@ -0,0 +1,17 @@
|
||||
public class InsecureLdapEndpoint2 {
|
||||
public Hashtable<String, String> createConnectionEnv() {
|
||||
Hashtable<String, String> env = new Hashtable<String, String>();
|
||||
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
|
||||
env.put(Context.PROVIDER_URL, "ldaps://ad.your-server.com:636");
|
||||
|
||||
env.put(Context.SECURITY_AUTHENTICATION, "simple");
|
||||
env.put(Context.SECURITY_PRINCIPAL, "username");
|
||||
env.put(Context.SECURITY_CREDENTIALS, "secpassword");
|
||||
|
||||
// GOOD - No configuration to disable SSL endpoint check since it is enabled by default.
|
||||
{
|
||||
}
|
||||
|
||||
return env;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,11 @@
|
||||
/**
|
||||
* @name Cleartext storage of sensitive information using `SharedPreferences` on Android
|
||||
* @description Cleartext Storage of Sensitive Information using SharedPreferences on Android allows access for users with root privileges or unexpected exposure from chained vulnerabilities.
|
||||
* @description Cleartext Storage of Sensitive Information using
|
||||
* SharedPreferences on Android allows access for users with root
|
||||
* privileges or unexpected exposure from chained vulnerabilities.
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @id java/android/cleartext-storage-shared-prefs
|
||||
* @tags security
|
||||
* external/cwe/cwe-312
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
* @name Weak encryption: Insufficient key size
|
||||
* @description Finds uses of encryption algorithms with too small a key size
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @id java/insufficient-key-size
|
||||
* @tags security
|
||||
* external/cwe/cwe-326
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
public class CorsFilter implements Filter {
|
||||
public void init(FilterConfig filterConfig) throws ServletException {}
|
||||
|
||||
public void doFilter(ServletRequest req, ServletResponse res,
|
||||
FilterChain chain) throws IOException, ServletException {
|
||||
HttpServletRequest request = (HttpServletRequest) req;
|
||||
HttpServletResponse response = (HttpServletResponse) res;
|
||||
String url = request.getHeader("Origin");
|
||||
|
||||
if (!StringUtils.isEmpty(url)) {
|
||||
String val = response.getHeader("Access-Control-Allow-Origin");
|
||||
|
||||
if (StringUtils.isEmpty(val)) {
|
||||
response.addHeader("Access-Control-Allow-Origin", url); // BAD -> User controlled CORS header being set here.
|
||||
response.addHeader("Access-Control-Allow-Credentials", "true");
|
||||
}
|
||||
}
|
||||
|
||||
if (!StringUtils.isEmpty(url)) {
|
||||
List<String> checkorigins = Arrays.asList("www.example.com", "www.sub.example.com");
|
||||
|
||||
if (checkorigins.contains(url)) { // GOOD -> Origin is validated here.
|
||||
response.addHeader("Access-Control-Allow-Origin", url);
|
||||
response.addHeader("Access-Control-Allow-Credentials", "true");
|
||||
}
|
||||
}
|
||||
|
||||
chain.doFilter(req, res);
|
||||
}
|
||||
|
||||
public void destroy() {}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>
|
||||
|
||||
A server can send the
|
||||
<code>Access-Control-Allow-Credentials</code> CORS header to control
|
||||
when a browser may send user credentials in Cross-Origin HTTP
|
||||
requests.
|
||||
|
||||
</p>
|
||||
<p>
|
||||
|
||||
When the <code>Access-Control-Allow-Credentials</code> header
|
||||
is <code>true</code>, the <code>Access-Control-Allow-Origin</code>
|
||||
header must have a value different from <code>*</code> in order
|
||||
for browsers to accept the header. Therefore, to allow multiple origins
|
||||
for cross-origin requests with credentials, the server must
|
||||
dynamically compute the value of the
|
||||
<code>Access-Control-Allow-Origin</code> header. Computing this
|
||||
header value from information in the request to the server can
|
||||
therefore potentially allow an attacker to control the origins that
|
||||
the browser sends credentials to.
|
||||
|
||||
</p>
|
||||
|
||||
|
||||
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>
|
||||
|
||||
When the <code>Access-Control-Allow-Credentials</code> header
|
||||
value is <code>true</code>, a dynamic computation of the
|
||||
<code>Access-Control-Allow-Origin</code> header must involve
|
||||
sanitization if it relies on user-controlled input.
|
||||
|
||||
|
||||
</p>
|
||||
<p>
|
||||
|
||||
Since the <code>null</code> origin is easy to obtain for an
|
||||
attacker, it is never safe to use <code>null</code> as the value of
|
||||
the <code>Access-Control-Allow-Origin</code> header when the
|
||||
<code>Access-Control-Allow-Credentials</code> header value is
|
||||
<code>true</code>.A null origin can be set by an attacker using a sandboxed iframe.
|
||||
A more detailed explanation is available in the portswigger blogpost referenced below.
|
||||
|
||||
</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>
|
||||
|
||||
In the example below, the server allows the browser to send
|
||||
user credentials in a cross-origin request. The request header
|
||||
<code>origins</code> controls the allowed origins for such a
|
||||
Cross-Origin request.
|
||||
|
||||
</p>
|
||||
|
||||
<sample src="UnvalidatedCors.java"/>
|
||||
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>Mozilla Developer Network: <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin">CORS, Access-Control-Allow-Origin</a>.</li>
|
||||
<li>Mozilla Developer Network: <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials">CORS, Access-Control-Allow-Credentials</a>.</li>
|
||||
<li>PortSwigger: <a href="http://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html">Exploiting CORS Misconfigurations for Bitcoins and Bounties</a></li>
|
||||
<li>W3C: <a href="https://w3c.github.io/webappsec-cors-for-developers/#resources">CORS for developers, Advice for Resource Owners</a></li>
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* @name CORS is derived from untrusted input
|
||||
* @description CORS header is derived from untrusted input, allowing a remote user to control which origins are trusted.
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @id java/unvalidated-cors-origin-set
|
||||
* @tags security
|
||||
* external/cwe/cwe-346
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.frameworks.Servlets
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.dataflow.TaintTracking2
|
||||
import DataFlow::PathGraph
|
||||
|
||||
/**
|
||||
* Holds if `header` sets `Access-Control-Allow-Credentials` to `true`. This ensures fair chances of exploitability.
|
||||
*/
|
||||
private predicate setsAllowCredentials(MethodAccess header) {
|
||||
(
|
||||
header.getMethod() instanceof ResponseSetHeaderMethod or
|
||||
header.getMethod() instanceof ResponseAddHeaderMethod
|
||||
) and
|
||||
header.getArgument(0).(CompileTimeConstantExpr).getStringValue().toLowerCase() =
|
||||
"access-control-allow-credentials" and
|
||||
header.getArgument(1).(CompileTimeConstantExpr).getStringValue().toLowerCase() = "true"
|
||||
}
|
||||
|
||||
private class CorsProbableCheckAccess extends MethodAccess {
|
||||
CorsProbableCheckAccess() {
|
||||
getMethod().hasName("contains") and
|
||||
getMethod().getDeclaringType().getASourceSupertype*() instanceof CollectionType
|
||||
or
|
||||
getMethod().hasName("containsKey") and
|
||||
getMethod().getDeclaringType().getASourceSupertype*() instanceof MapType
|
||||
or
|
||||
getMethod().hasName("equals") and
|
||||
getQualifier().getType() instanceof TypeString
|
||||
}
|
||||
}
|
||||
|
||||
private Expr getAccessControlAllowOriginHeaderName() {
|
||||
result.(CompileTimeConstantExpr).getStringValue().toLowerCase() = "access-control-allow-origin"
|
||||
}
|
||||
|
||||
/**
|
||||
* This taintflow2 configuration checks if there is a flow from source node towards CorsProbableCheckAccess methods.
|
||||
*/
|
||||
class CorsSourceReachesCheckConfig extends TaintTracking2::Configuration {
|
||||
CorsSourceReachesCheckConfig() { this = "CorsOriginConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { any(CorsOriginConfig c).hasFlow(source, _) }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
sink.asExpr() = any(CorsProbableCheckAccess check).getAnArgument()
|
||||
}
|
||||
}
|
||||
|
||||
private class CorsOriginConfig extends TaintTracking::Configuration {
|
||||
CorsOriginConfig() { this = "CorsOriginConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodAccess corsHeader, MethodAccess allowCredentialsHeader |
|
||||
(
|
||||
corsHeader.getMethod() instanceof ResponseSetHeaderMethod or
|
||||
corsHeader.getMethod() instanceof ResponseAddHeaderMethod
|
||||
) and
|
||||
getAccessControlAllowOriginHeaderName() = corsHeader.getArgument(0) and
|
||||
setsAllowCredentials(allowCredentialsHeader) and
|
||||
corsHeader.getEnclosingCallable() = allowCredentialsHeader.getEnclosingCallable() and
|
||||
sink.asExpr() = corsHeader.getArgument(1)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
from
|
||||
DataFlow::PathNode source, DataFlow::PathNode sink, CorsOriginConfig conf,
|
||||
CorsSourceReachesCheckConfig sanconf
|
||||
where conf.hasFlowPath(source, sink) and not sanconf.hasFlow(source.getNode(), _)
|
||||
select sink.getNode(), source, sink, "CORS header is being set using user controlled value $@.",
|
||||
source.getNode(), "user-provided value"
|
||||
@@ -2,6 +2,8 @@
|
||||
* @name Main Method in Enterprise Java Bean
|
||||
* @description Java EE applications with a main method.
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @id java/main-method-in-enterprise-bean
|
||||
* @tags security
|
||||
* external/cwe-489
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
* @name Main Method in Java EE Web Components
|
||||
* @description Java EE web applications with a main method.
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @id java/main-method-in-web-components
|
||||
* @tags security
|
||||
* external/cwe-489
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
@Configuration
|
||||
public class Server {
|
||||
|
||||
@Bean(name = "/account")
|
||||
HttpInvokerServiceExporter accountService() {
|
||||
HttpInvokerServiceExporter exporter = new HttpInvokerServiceExporter();
|
||||
exporter.setService(new AccountServiceImpl());
|
||||
exporter.setServiceInterface(AccountService.class);
|
||||
return exporter;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class AccountServiceImpl implements AccountService {
|
||||
|
||||
@Override
|
||||
public String echo(String data) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
interface AccountService {
|
||||
String echo(String data);
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
<bean name="/account" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
|
||||
<property name="service" ref="accountService"/>
|
||||
<property name="serviceInterface" value="AccountService"/>
|
||||
</bean>
|
||||
@@ -0,0 +1,8 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<include src="UnsafeSpringExporterQuery.inc.qhelp" />
|
||||
<include src="UnsafeSpringExporterInConfigurationClassExample.inc.qhelp" />
|
||||
<include src="UnsafeSpringExporterReferences.inc.qhelp" />
|
||||
</qhelp>
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* @name Unsafe deserialization with Spring's remote service exporters.
|
||||
* @description A Spring bean, which is based on RemoteInvocationSerializingExporter,
|
||||
* initializes an endpoint that uses ObjectInputStream to deserialize
|
||||
* incoming data. In the worst case, that may lead to remote code execution.
|
||||
* @kind problem
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @id java/unsafe-deserialization-spring-exporter-in-configuration-class
|
||||
* @tags security
|
||||
* external/cwe/cwe-502
|
||||
*/
|
||||
|
||||
import java
|
||||
import UnsafeSpringExporterLib
|
||||
|
||||
/**
|
||||
* Holds if `type` is a Spring configuration that declares beans.
|
||||
*/
|
||||
private predicate isConfiguration(RefType type) {
|
||||
type.hasAnnotation("org.springframework.context.annotation", "Configuration") or
|
||||
isConfigurationAnnotation(type.getAnAnnotation())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `annotation` is a Java annotations that declares a Spring configuration.
|
||||
*/
|
||||
private predicate isConfigurationAnnotation(Annotation annotation) {
|
||||
isConfiguration(annotation.getType()) or
|
||||
isConfigurationAnnotation(annotation.getType().getAnAnnotation())
|
||||
}
|
||||
|
||||
/**
|
||||
* A method that initializes a unsafe bean based on `RemoteInvocationSerializingExporter`.
|
||||
*/
|
||||
private class UnsafeBeanInitMethod extends Method {
|
||||
string identifier;
|
||||
|
||||
UnsafeBeanInitMethod() {
|
||||
isRemoteInvocationSerializingExporter(this.getReturnType()) and
|
||||
isConfiguration(this.getDeclaringType()) and
|
||||
exists(Annotation a | this.getAnAnnotation() = a |
|
||||
a.getType().hasQualifiedName("org.springframework.context.annotation", "Bean") and
|
||||
if a.getValue("name") instanceof StringLiteral
|
||||
then identifier = a.getValue("name").(StringLiteral).getRepresentedString()
|
||||
else identifier = this.getName()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this bean's name if given by the `Bean` annotation, or this method's identifier otherwise.
|
||||
*/
|
||||
string getBeanIdentifier() { result = identifier }
|
||||
}
|
||||
|
||||
from UnsafeBeanInitMethod method
|
||||
select method,
|
||||
"Unsafe deserialization in a Spring exporter bean '" + method.getBeanIdentifier() + "'"
|
||||
@@ -0,0 +1,14 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<example>
|
||||
<p>
|
||||
The following example shows how a vulnerable HTTP endpoint can be defined
|
||||
using <code>HttpInvokerServiceExporter</code> and Spring annotations:
|
||||
</p>
|
||||
<sample src="SpringExporterUnsafeDeserialization.java" />
|
||||
</example>
|
||||
|
||||
</qhelp>
|
||||
@@ -0,0 +1,8 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<include src="UnsafeSpringExporterQuery.inc.qhelp" />
|
||||
<include src="UnsafeSpringExporterInXMLConfigurationExample.inc.qhelp" />
|
||||
<include src="UnsafeSpringExporterReferences.inc.qhelp" />
|
||||
</qhelp>
|
||||
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @name Unsafe deserialization with Spring's remote service exporters.
|
||||
* @description A Spring bean, which is based on RemoteInvocationSerializingExporter,
|
||||
* initializes an endpoint that uses ObjectInputStream to deserialize
|
||||
* incoming data. In the worst case, that may lead to remote code execution.
|
||||
* @kind problem
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @id java/unsafe-deserialization-spring-exporter-in-xml-configuration
|
||||
* @tags security
|
||||
* external/cwe/cwe-502
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.frameworks.spring.SpringBean
|
||||
import UnsafeSpringExporterLib
|
||||
|
||||
from SpringBean bean
|
||||
where isRemoteInvocationSerializingExporter(bean.getClass())
|
||||
select bean, "Unsafe deserialization in a Spring exporter bean '" + bean.getBeanIdentifier() + "'"
|
||||
@@ -0,0 +1,13 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<example>
|
||||
<p>
|
||||
The following examples shows how a vulnerable HTTP endpoint can be defined in a Spring XML config:
|
||||
</p>
|
||||
<sample src="SpringExporterUnsafeDeserialization.xml" />
|
||||
</example>
|
||||
|
||||
</qhelp>
|
||||
@@ -0,0 +1,9 @@
|
||||
import java
|
||||
|
||||
/**
|
||||
* Holds if `type` is `RemoteInvocationSerializingExporter`.
|
||||
*/
|
||||
predicate isRemoteInvocationSerializingExporter(RefType type) {
|
||||
type.getASupertype*()
|
||||
.hasQualifiedName("org.springframework.remoting.rmi", "RemoteInvocationSerializingExporter")
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>
|
||||
The Spring Framework provides an abstract base class <code>RemoteInvocationSerializingExporter</code>
|
||||
for creating remote service exporters.
|
||||
A Spring exporter, which is based on this class, deserializes incoming data using <code>ObjectInputStream</code>.
|
||||
Deserializing untrusted data is easily exploitable and in many cases allows an attacker
|
||||
to execute arbitrary code.
|
||||
</p>
|
||||
<p>
|
||||
The Spring Framework also provides <code>HttpInvokerServiceExporter</code>
|
||||
and <code>SimpleHttpInvokerServiceExporter</code> classes
|
||||
that extend <code>RemoteInvocationSerializingExporter</code>.
|
||||
</p>
|
||||
<p>
|
||||
These classes export specified beans as HTTP endpoints that deserialize data from an HTTP request
|
||||
using unsafe <code>ObjectInputStream</code>. If a remote attacker can reach such endpoints,
|
||||
it results in remote code execution in the worst case.
|
||||
</p>
|
||||
<p>
|
||||
CVE-2016-1000027 has been assigned to this issue in the Spring Framework.
|
||||
It is regarded as a design limitation, and can be mitigated but not fixed outright.
|
||||
</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>
|
||||
Avoid using <code>HttpInvokerServiceExporter</code>, <code>SimpleHttpInvokerServiceExporter</code>
|
||||
and any other exporter that is based on <code>RemoteInvocationSerializingExporter</code>.
|
||||
Instead, use other message formats for API endpoints (for example, JSON),
|
||||
but make sure that the underlying deserialization mechanism is properly configured
|
||||
so that deserialization attacks are not possible. If the vulnerable exporters can not be replaced,
|
||||
consider using global deserialization filters introduced in JEP 290.
|
||||
</p>
|
||||
</recommendation>
|
||||
|
||||
</qhelp>
|
||||
@@ -0,0 +1,37 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<references>
|
||||
<li>
|
||||
OWASP:
|
||||
<a href="https://www.owasp.org/index.php/Deserialization_of_untrusted_data">Deserialization of untrusted data</a>.
|
||||
</li>
|
||||
<li>
|
||||
Spring Framework API documentation:
|
||||
<a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/remoting/rmi/RemoteInvocationSerializingExporter.html">RemoteInvocationSerializingExporter class</a>
|
||||
</li>
|
||||
<li>
|
||||
Spring Framework API documentation:
|
||||
<a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/remoting/httpinvoker/HttpInvokerServiceExporter.html">HttpInvokerServiceExporter class</a>
|
||||
</li>
|
||||
<li>
|
||||
National Vulnerability Database:
|
||||
<a href="https://nvd.nist.gov/vuln/detail/CVE-2016-1000027">CVE-2016-1000027</a>
|
||||
</li>
|
||||
<li>
|
||||
Tenable Research Advisory:
|
||||
<a href="https://www.tenable.com/security/research/tra-2016-20">[R2] Pivotal Spring Framework HttpInvokerServiceExporter readRemoteInvocation Method Untrusted Java Deserialization</a>
|
||||
</li>
|
||||
<li>
|
||||
Spring Framework bug tracker:
|
||||
<a href="https://github.com/spring-projects/spring-framework/issues/24434">Sonatype vulnerability CVE-2016-1000027 in Spring-web project</a>
|
||||
</li>
|
||||
<li>
|
||||
OpenJDK:
|
||||
<a href="https://openjdk.java.net/jeps/290">JEP 290: Filter Incoming Serialization Data</a>
|
||||
</li>
|
||||
</references>
|
||||
|
||||
</qhelp>
|
||||
@@ -1,7 +1,12 @@
|
||||
/**
|
||||
* @name Insecure basic authentication
|
||||
* @description Basic authentication only obfuscates username/password in Base64 encoding, which can be easily recognized and reversed. Transmission of sensitive information not over HTTPS is vulnerable to packet sniffing.
|
||||
* @description Basic authentication only obfuscates username/password in
|
||||
* Base64 encoding, which can be easily recognized and reversed.
|
||||
* Transmission of sensitive information not over HTTPS is
|
||||
* vulnerable to packet sniffing.
|
||||
* @kind path-problem
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @id java/insecure-basic-auth
|
||||
* @tags security
|
||||
* external/cwe-522
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
* @name Insecure LDAP authentication
|
||||
* @description LDAP authentication with credentials sent in cleartext.
|
||||
* @kind path-problem
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @id java/insecure-ldap-auth
|
||||
* @tags security
|
||||
* external/cwe-522
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
/**
|
||||
* @id java/sensitiveinfo-in-logfile
|
||||
* @name Insertion of sensitive information into log files
|
||||
* @description Writing sensitive information to log files can give valuable guidance to an attacker or expose sensitive user information.
|
||||
* @description Writing sensitive information to log files can give valuable
|
||||
* guidance to an attacker or expose sensitive user information.
|
||||
* @kind path-problem
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @id java/sensitiveinfo-in-logfile
|
||||
* @tags security
|
||||
* external/cwe-532
|
||||
*/
|
||||
@@ -10,6 +13,7 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.security.SensitiveActions
|
||||
import experimental.semmle.code.java.Logging
|
||||
import DataFlow
|
||||
import PathGraph
|
||||
|
||||
@@ -27,38 +31,14 @@ class CredentialExpr extends Expr {
|
||||
}
|
||||
}
|
||||
|
||||
/** Class of popular logging utilities * */
|
||||
class LoggerType extends RefType {
|
||||
LoggerType() {
|
||||
this.hasQualifiedName("org.apache.log4j", "Category") or //Log4J
|
||||
this.hasQualifiedName("org.apache.logging.log4j", "Logger") or //Log4J 2
|
||||
this.hasQualifiedName("org.slf4j", "Logger") or //SLF4j and Gradle Logging
|
||||
this.hasQualifiedName("org.jboss.logging", "BasicLogger") or //JBoss Logging
|
||||
this.hasQualifiedName("org.jboss.logging", "Logger") or //JBoss Logging (`org.jboss.logging.Logger` in some implementations like JBoss Application Server 4.0.4 did not implement `BasicLogger`)
|
||||
this.hasQualifiedName("org.apache.commons.logging", "Log") or //Apache Commons Logging
|
||||
this.hasQualifiedName("org.scijava.log", "Logger") //SciJava Logging
|
||||
}
|
||||
}
|
||||
|
||||
predicate isSensitiveLoggingSink(DataFlow::Node sink) {
|
||||
exists(MethodAccess ma |
|
||||
ma.getMethod().getDeclaringType() instanceof LoggerType and
|
||||
(
|
||||
ma.getMethod().hasName("debug") or
|
||||
ma.getMethod().hasName("trace") or
|
||||
ma.getMethod().hasName("debugf") or
|
||||
ma.getMethod().hasName("debugv")
|
||||
) and //Check low priority log levels which are more likely to be real issues to reduce false positives
|
||||
sink.asExpr() = ma.getAnArgument()
|
||||
)
|
||||
}
|
||||
|
||||
class LoggerConfiguration extends DataFlow::Configuration {
|
||||
LoggerConfiguration() { this = "Logger Configuration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source.asExpr() instanceof CredentialExpr }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { isSensitiveLoggingSink(sink) }
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(LoggingCall c | sink.asExpr() = c.getALogArgument())
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
TaintTracking::localTaintStep(node1, node2)
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
/**
|
||||
* @name Directories and files exposure
|
||||
* @description A directory listing provides an attacker with the complete index of all the resources located inside of the complete web directory, which could yield files containing sensitive information like source code and credentials to the attacker.
|
||||
* @description A directory listing provides an attacker with the complete
|
||||
* index of all the resources located inside of the complete web
|
||||
* directory, which could yield files containing sensitive
|
||||
* information like source code and credentials to the attacker.
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @id java/server-directory-listing
|
||||
* @tags security
|
||||
* external/cwe-548
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
* @name Password in configuration file
|
||||
* @description Finds passwords in configuration files.
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @id java/password-in-configuration
|
||||
* @tags security
|
||||
* external/cwe/cwe-555
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
* @name Sensitive GET Query
|
||||
* @description Use of GET request method with sensitive query strings.
|
||||
* @kind path-problem
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @id java/sensitive-query-with-get
|
||||
* @tags security
|
||||
* external/cwe-598
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
/**
|
||||
* @name Uncaught Servlet Exception
|
||||
* @description Uncaught exceptions in a servlet could leave a system in an unexpected state, possibly resulting in denial-of-service attacks or the exposure of sensitive information disclosed in stack traces.
|
||||
* @description Uncaught exceptions in a servlet could leave a system in an
|
||||
* unexpected state, possibly resulting in denial-of-service
|
||||
* attacks or the exposure of sensitive information disclosed in
|
||||
* stack traces.
|
||||
* @kind path-problem
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @id java/uncaught-servlet-exception
|
||||
* @tags security
|
||||
* external/cwe-600
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.xquery.XQConnection;
|
||||
import javax.xml.xquery.XQDataSource;
|
||||
import javax.xml.xquery.XQException;
|
||||
import javax.xml.xquery.XQItemType;
|
||||
import javax.xml.xquery.XQPreparedExpression;
|
||||
import javax.xml.xquery.XQResultSequence;
|
||||
import net.sf.saxon.xqj.SaxonXQDataSource;
|
||||
|
||||
public void bad(HttpServletRequest request) throws XQException {
|
||||
String name = request.getParameter("name");
|
||||
XQDataSource ds = new SaxonXQDataSource();
|
||||
XQConnection conn = ds.getConnection();
|
||||
String query = "for $user in doc(\"users.xml\")/Users/User[name='" + name + "'] return $user/password";
|
||||
XQPreparedExpression xqpe = conn.prepareExpression(query);
|
||||
XQResultSequence result = xqpe.executeQuery();
|
||||
while (result.next()){
|
||||
System.out.println(result.getItemAsString(null));
|
||||
}
|
||||
}
|
||||
|
||||
public void bad1(HttpServletRequest request) throws XQException {
|
||||
String name = request.getParameter("name");
|
||||
XQDataSource xqds = new SaxonXQDataSource();
|
||||
String query = "for $user in doc(\"users.xml\")/Users/User[name='" + name + "'] return $user/password";
|
||||
XQConnection conn = xqds.getConnection();
|
||||
XQExpression expr = conn.createExpression();
|
||||
XQResultSequence result = expr.executeQuery(query);
|
||||
while (result.next()){
|
||||
System.out.println(result.getItemAsString(null));
|
||||
}
|
||||
}
|
||||
|
||||
public void bad2(HttpServletRequest request) throws XQException {
|
||||
String name = request.getParameter("name");
|
||||
XQDataSource xqds = new SaxonXQDataSource();
|
||||
XQConnection conn = xqds.getConnection();
|
||||
XQExpression expr = conn.createExpression();
|
||||
//bad code
|
||||
expr.executeCommand(name);
|
||||
}
|
||||
|
||||
public void good(HttpServletRequest request) throws XQException {
|
||||
String name = request.getParameter("name");
|
||||
XQDataSource ds = new SaxonXQDataSource();
|
||||
XQConnection conn = ds.getConnection();
|
||||
String query = "declare variable $name as xs:string external;"
|
||||
+ " for $user in doc(\"users.xml\")/Users/User[name=$name] return $user/password";
|
||||
XQPreparedExpression xqpe = conn.prepareExpression(query);
|
||||
xqpe.bindString(new QName("name"), name, conn.createAtomicType(XQItemType.XQBASETYPE_STRING));
|
||||
XQResultSequence result = xqpe.executeQuery();
|
||||
while (result.next()){
|
||||
System.out.println(result.getItemAsString(null));
|
||||
}
|
||||
}
|
||||
|
||||
public void good1(HttpServletRequest request) throws XQException {
|
||||
String name = request.getParameter("name");
|
||||
String query = "declare variable $name as xs:string external;"
|
||||
+ " for $user in doc(\"users.xml\")/Users/User[name=$name] return $user/password";
|
||||
XQDataSource xqds = new SaxonXQDataSource();
|
||||
XQConnection conn = xqds.getConnection();
|
||||
XQExpression expr = conn.createExpression();
|
||||
expr.bindString(new QName("name"), name, conn.createAtomicType(XQItemType.XQBASETYPE_STRING));
|
||||
XQResultSequence result = expr.executeQuery(query);
|
||||
while (result.next()){
|
||||
System.out.println(result.getItemAsString(null));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>The software uses external input to dynamically construct an XQuery expression which is then used to retrieve data from an XML database.
|
||||
However, the input is not neutralized, or is incorrectly neutralized, which allows an attacker to control the structure of the query.</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
|
||||
<p>Use parameterized queries. This will help ensure the program retains control of the query structure.</p>
|
||||
|
||||
</recommendation>
|
||||
<example>
|
||||
|
||||
<p>The following example compares building a query by string concatenation (bad) vs. using <code>bindString</code> to parameterize the query (good).</p>
|
||||
|
||||
<sample src="XQueryInjection.java" />
|
||||
|
||||
</example>
|
||||
<references>
|
||||
|
||||
<li>Balisage:
|
||||
<a href="https://www.balisage.net/Proceedings/vol7/html/Vlist02/BalisageVol7-Vlist02.html">XQuery Injection</a>.</li>
|
||||
|
||||
|
||||
|
||||
<!-- LocalWords: CWE
|
||||
-->
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* @name XQuery query built from user-controlled sources
|
||||
* @description Building an XQuery query from user-controlled sources is vulnerable to insertion of
|
||||
* malicious XQuery code by the user.
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @id java/xquery-injection
|
||||
* @tags security
|
||||
* external/cwe/cwe-652
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import XQueryInjectionLib
|
||||
import DataFlow::PathGraph
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration tracing flow from remote sources, through an XQuery parser, to its eventual execution.
|
||||
*/
|
||||
class XQueryInjectionConfig extends TaintTracking::Configuration {
|
||||
XQueryInjectionConfig() { this = "XQueryInjectionConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
sink.asExpr() = any(XQueryPreparedExecuteCall xpec).getPreparedExpression() or
|
||||
sink.asExpr() = any(XQueryExecuteCall xec).getExecuteQueryArgument() or
|
||||
sink.asExpr() = any(XQueryExecuteCommandCall xecc).getExecuteCommandArgument()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if taint from the input `pred` to a `prepareExpression` call flows to the returned prepared expression `succ`.
|
||||
*/
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(XQueryParserCall parser | pred.asExpr() = parser.getInput() and succ.asExpr() = parser)
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, XQueryInjectionConfig conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "XQuery query might include code from $@.", source.getNode(),
|
||||
"this user input"
|
||||
@@ -0,0 +1,68 @@
|
||||
import java
|
||||
|
||||
/** A call to `XQConnection.prepareExpression`. */
|
||||
class XQueryParserCall extends MethodAccess {
|
||||
XQueryParserCall() {
|
||||
exists(Method m |
|
||||
this.getMethod() = m and
|
||||
m.getDeclaringType()
|
||||
.getASourceSupertype*()
|
||||
.hasQualifiedName("javax.xml.xquery", "XQConnection") and
|
||||
m.hasName("prepareExpression")
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first parameter of the `prepareExpression` method, which provides
|
||||
* the string, stream or reader to be compiled into a prepared expression.
|
||||
*/
|
||||
Expr getInput() { result = this.getArgument(0) }
|
||||
}
|
||||
|
||||
/** A call to `XQPreparedExpression.executeQuery`. */
|
||||
class XQueryPreparedExecuteCall extends MethodAccess {
|
||||
XQueryPreparedExecuteCall() {
|
||||
exists(Method m |
|
||||
this.getMethod() = m and
|
||||
m.hasName("executeQuery") and
|
||||
m.getDeclaringType()
|
||||
.getASourceSupertype*()
|
||||
.hasQualifiedName("javax.xml.xquery", "XQPreparedExpression")
|
||||
)
|
||||
}
|
||||
|
||||
/** Return this prepared expression. */
|
||||
Expr getPreparedExpression() { result = this.getQualifier() }
|
||||
}
|
||||
|
||||
/** A call to `XQExpression.executeQuery`. */
|
||||
class XQueryExecuteCall extends MethodAccess {
|
||||
XQueryExecuteCall() {
|
||||
exists(Method m |
|
||||
this.getMethod() = m and
|
||||
m.hasName("executeQuery") and
|
||||
m.getDeclaringType()
|
||||
.getASourceSupertype*()
|
||||
.hasQualifiedName("javax.xml.xquery", "XQExpression")
|
||||
)
|
||||
}
|
||||
|
||||
/** Return this execute query argument. */
|
||||
Expr getExecuteQueryArgument() { result = this.getArgument(0) }
|
||||
}
|
||||
|
||||
/** A call to `XQExpression.executeCommand`. */
|
||||
class XQueryExecuteCommandCall extends MethodAccess {
|
||||
XQueryExecuteCommandCall() {
|
||||
exists(Method m |
|
||||
this.getMethod() = m and
|
||||
m.hasName("executeCommand") and
|
||||
m.getDeclaringType()
|
||||
.getASourceSupertype*()
|
||||
.hasQualifiedName("javax.xml.xquery", "XQExpression")
|
||||
)
|
||||
}
|
||||
|
||||
/** Return this execute command argument. */
|
||||
Expr getExecuteCommandArgument() { result = this.getArgument(0) }
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
/**
|
||||
* @name Unsafe resource fetching in Android webview
|
||||
* @id java/android/unsafe-android-webview-fetch
|
||||
* @description JavaScript rendered inside WebViews can access any protected application file and web resource from any origin
|
||||
* @description JavaScript rendered inside WebViews can access any protected
|
||||
* application file and web resource from any origin
|
||||
* @kind path-problem
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @id java/android/unsafe-android-webview-fetch
|
||||
* @tags security
|
||||
* external/cwe/cwe-749
|
||||
* external/cwe/cwe-079
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
/**
|
||||
* @name Local Android DoS Caused By NumberFormatException
|
||||
* @id java/android/nfe-local-android-dos
|
||||
* @description NumberFormatException thrown but not caught by an Android application that allows external inputs can crash the application, constituting a local Denial of Service (DoS) attack.
|
||||
* @description NumberFormatException thrown but not caught by an Android
|
||||
* application that allows external inputs can crash the
|
||||
* application, constituting a local Denial of Service (DoS)
|
||||
* attack.
|
||||
* @kind path-problem
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @id java/android/nfe-local-android-dos
|
||||
* @tags security
|
||||
* external/cwe/cwe-755
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
public class HashWithoutSalt {
|
||||
// BAD - Hash without a salt.
|
||||
public void getSHA256Hash(String password) throws NoSuchAlgorithmException {
|
||||
MessageDigest md = MessageDigest.getInstance("SHA-256");
|
||||
byte[] messageDigest = md.digest(password.getBytes());
|
||||
}
|
||||
|
||||
// GOOD - Hash with a salt.
|
||||
public void getSHA256Hash(String password, byte[] salt) throws NoSuchAlgorithmException {
|
||||
MessageDigest md = MessageDigest.getInstance("SHA-256");
|
||||
md.update(salt);
|
||||
byte[] messageDigest = md.digest(password.getBytes());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>In cryptography, a salt is some random data used as an additional input to a one-way function that hashes a password or pass-phrase. It makes dictionary attacks more difficult.</p>
|
||||
|
||||
<p>Without a salt, it is much easier for attackers to pre-compute the hash value using dictionary attack techniques such as rainbow tables to crack passwords.</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>Use a long random salt of at least 32 bytes then use the combination of password and salt to hash a password or password phrase.</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>The following example shows two ways of hashing. In the 'BAD' case, no salt is provided. In the 'GOOD' case, a salt is provided.</p>
|
||||
<sample src="HashWithoutSalt.java" />
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>
|
||||
DZone:
|
||||
<a href="https://dzone.com/articles/a-look-at-java-cryptography">A Look at Java Cryptography</a>
|
||||
</li>
|
||||
<li>
|
||||
CWE:
|
||||
<a href="https://cwe.mitre.org/data/definitions/759.html">CWE-759: Use of a One-Way Hash without a Salt</a>
|
||||
</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
190
java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql
Normal file
190
java/ql/src/experimental/Security/CWE/CWE-759/HashWithoutSalt.ql
Normal file
@@ -0,0 +1,190 @@
|
||||
/**
|
||||
* @name Use of a hash function without a salt
|
||||
* @description Hashed passwords without a salt are vulnerable to dictionary attacks.
|
||||
* @kind path-problem
|
||||
* @problem.severity warning
|
||||
* @precision low
|
||||
* @id java/hash-without-salt
|
||||
* @tags security
|
||||
* external/cwe-759
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import DataFlow::PathGraph
|
||||
|
||||
/**
|
||||
* Gets a regular expression for matching common names of variables
|
||||
* that indicate the value being held is a password.
|
||||
*/
|
||||
string getPasswordRegex() { result = "(?i).*pass(wd|word|code|phrase).*" }
|
||||
|
||||
/** Finds variables that hold password information judging by their names. */
|
||||
class PasswordVarExpr extends VarAccess {
|
||||
PasswordVarExpr() {
|
||||
exists(string name | name = this.getVariable().getName().toLowerCase() |
|
||||
name.regexpMatch(getPasswordRegex()) and not name.matches("%hash%") // Exclude variable names such as `passwordHash` since their values were already hashed
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Holds if `Expr` e is a direct or indirect operand of `ae`. */
|
||||
predicate hasAddExprAncestor(AddExpr ae, Expr e) { ae.getAnOperand+() = e }
|
||||
|
||||
/** The Java class `java.security.MessageDigest`. */
|
||||
class MessageDigest extends RefType {
|
||||
MessageDigest() { this.hasQualifiedName("java.security", "MessageDigest") }
|
||||
}
|
||||
|
||||
/** The method call `MessageDigest.getInstance(...)` */
|
||||
class MDConstructor extends StaticMethodAccess {
|
||||
MDConstructor() {
|
||||
exists(Method m | m = this.getMethod() |
|
||||
m.getDeclaringType() instanceof MessageDigest and
|
||||
m.hasName("getInstance")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** The method `digest()` declared in `java.security.MessageDigest`. */
|
||||
class MDDigestMethod extends Method {
|
||||
MDDigestMethod() {
|
||||
this.getDeclaringType() instanceof MessageDigest and
|
||||
this.hasName("digest")
|
||||
}
|
||||
}
|
||||
|
||||
/** The method `update()` declared in `java.security.MessageDigest`. */
|
||||
class MDUpdateMethod extends Method {
|
||||
MDUpdateMethod() {
|
||||
this.getDeclaringType() instanceof MessageDigest and
|
||||
this.hasName("update")
|
||||
}
|
||||
}
|
||||
|
||||
/** The hashing method that could taint the input. */
|
||||
class MDHashMethodAccess extends MethodAccess {
|
||||
MDHashMethodAccess() {
|
||||
(
|
||||
this.getMethod() instanceof MDDigestMethod or
|
||||
this.getMethod() instanceof MDUpdateMethod
|
||||
) and
|
||||
this.getNumArgument() != 0
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `MethodAccess` ma is a method access of `MDHashMethodAccess` or
|
||||
* invokes a method access of `MDHashMethodAccess` directly or indirectly.
|
||||
*/
|
||||
predicate isHashAccess(MethodAccess ma) {
|
||||
ma instanceof MDHashMethodAccess
|
||||
or
|
||||
exists(MethodAccess mca |
|
||||
ma.getMethod().calls(mca.getMethod()) and
|
||||
isHashAccess(mca) and
|
||||
DataFlow::localExprFlow(ma.getMethod().getAParameter().getAnAccess(), mca.getAnArgument())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there is a second method access that satisfies `isHashAccess` whose qualifier or argument
|
||||
* is the same as the method call `ma` that satisfies `isHashAccess`.
|
||||
*/
|
||||
predicate hasAnotherHashCall(MethodAccess ma) {
|
||||
isHashAccess(ma) and
|
||||
exists(MethodAccess ma2, VarAccess va |
|
||||
ma2 != ma and
|
||||
isHashAccess(ma2) and
|
||||
not va.getVariable().getType() instanceof PrimitiveType and
|
||||
(
|
||||
ma.getQualifier() = va and
|
||||
ma2.getQualifier() = va.getVariable().getAnAccess()
|
||||
or
|
||||
ma.getQualifier() = va and
|
||||
ma2.getAnArgument() = va.getVariable().getAnAccess()
|
||||
or
|
||||
ma.getAnArgument() = va and
|
||||
ma2.getQualifier() = va.getVariable().getAnAccess()
|
||||
or
|
||||
ma.getAnArgument() = va and
|
||||
ma2.getAnArgument() = va.getVariable().getAnAccess()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `MethodAccess` ma is part of a call graph that satisfies `isHashAccess`
|
||||
* but is not at the top of the call hierarchy.
|
||||
*/
|
||||
predicate hasHashAncestor(MethodAccess ma) {
|
||||
exists(MethodAccess mpa |
|
||||
mpa.getMethod().calls(ma.getMethod()) and
|
||||
isHashAccess(mpa) and
|
||||
DataFlow::localExprFlow(mpa.getMethod().getAParameter().getAnAccess(), ma.getAnArgument())
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `MethodAccess` ma is a hashing call without a sibling node making another hashing call. */
|
||||
predicate isSingleHashMethodCall(MethodAccess ma) {
|
||||
isHashAccess(ma) and not hasAnotherHashCall(ma)
|
||||
}
|
||||
|
||||
/** Holds if `MethodAccess` ma is a single hashing call that is not invoked by a wrapper method. */
|
||||
predicate isSink(MethodAccess ma) { isSingleHashMethodCall(ma) and not hasHashAncestor(ma) }
|
||||
|
||||
/** Sink of hashing calls. */
|
||||
class HashWithoutSaltSink extends DataFlow::ExprNode {
|
||||
HashWithoutSaltSink() {
|
||||
exists(MethodAccess ma |
|
||||
this.asExpr() = ma.getAnArgument() and
|
||||
isSink(ma)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Taint configuration tracking flow from an expression whose name suggests it holds password data
|
||||
* to a method call that generates a hash without a salt.
|
||||
*/
|
||||
class HashWithoutSaltConfiguration extends TaintTracking::Configuration {
|
||||
HashWithoutSaltConfiguration() { this = "HashWithoutSaltConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source.asExpr() instanceof PasswordVarExpr }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof HashWithoutSaltSink }
|
||||
|
||||
/**
|
||||
* Holds if a password is concatenated with a salt then hashed together through the call `System.arraycopy(password.getBytes(), ...)`, for example,
|
||||
* `System.arraycopy(password.getBytes(), 0, allBytes, 0, password.getBytes().length);`
|
||||
* `System.arraycopy(salt, 0, allBytes, password.getBytes().length, salt.length);`
|
||||
* `byte[] messageDigest = md.digest(allBytes);`
|
||||
* Or the password is concatenated with a salt as a string.
|
||||
*/
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
exists(MethodAccess ma |
|
||||
ma.getMethod().getDeclaringType().hasQualifiedName("java.lang", "System") and
|
||||
ma.getMethod().hasName("arraycopy") and
|
||||
ma.getArgument(0) = node.asExpr()
|
||||
) // System.arraycopy(password.getBytes(), ...)
|
||||
or
|
||||
exists(AddExpr e | hasAddExprAncestor(e, node.asExpr())) // password+salt
|
||||
or
|
||||
exists(ConditionalExpr ce | ce.getAChildExpr() = node.asExpr()) // useSalt?password+":"+salt:password
|
||||
or
|
||||
exists(MethodAccess ma |
|
||||
ma.getMethod().getDeclaringType().hasQualifiedName("java.lang", "StringBuilder") and
|
||||
ma.getMethod().hasName("append") and
|
||||
ma.getArgument(0) = node.asExpr() // stringBuilder.append(password).append(salt)
|
||||
)
|
||||
or
|
||||
exists(MethodAccess ma |
|
||||
ma.getQualifier().(VarAccess).getVariable().getType() instanceof Interface and
|
||||
ma.getAnArgument() = node.asExpr() // Method access of interface type variables requires runtime determination thus not handled
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, HashWithoutSaltConfiguration cc
|
||||
where cc.hasFlowPath(source, sink)
|
||||
select sink, source, sink, "$@ is hashed without a salt.", source, "The password"
|
||||
@@ -1,8 +1,12 @@
|
||||
/**
|
||||
* @name Broadcasting sensitive data to all Android applications
|
||||
* @id java/sensitive-broadcast
|
||||
* @description An Android application uses implicit intents to broadcast sensitive data to all applications without specifying any receiver permission.
|
||||
* @description An Android application uses implicit intents to broadcast
|
||||
* sensitive data to all applications without specifying any
|
||||
* receiver permission.
|
||||
* @kind path-problem
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @id java/sensitive-broadcast
|
||||
* @tags security
|
||||
* external/cwe-927
|
||||
*/
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
/**
|
||||
* @id java/incorrect-url-verification
|
||||
* @name Incorrect URL verification
|
||||
* @description Apps that rely on URL parsing to verify that a given URL is pointing to a trusted server are susceptible to wrong ways of URL parsing and verification.
|
||||
* @description Apps that rely on URL parsing to verify that a given URL is
|
||||
* pointing to a trusted server are susceptible to wrong ways of
|
||||
* URL parsing and verification.
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @id java/incorrect-url-verification
|
||||
* @tags security
|
||||
* external/cwe-939
|
||||
*/
|
||||
|
||||
35
java/ql/src/experimental/semmle/code/java/Logging.qll
Normal file
35
java/ql/src/experimental/semmle/code/java/Logging.qll
Normal file
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Provides classes and predicates for working with loggers.
|
||||
*/
|
||||
|
||||
import java
|
||||
|
||||
/** Models a call to a logging method. */
|
||||
class LoggingCall extends MethodAccess {
|
||||
LoggingCall() {
|
||||
exists(RefType t, Method m |
|
||||
t.hasQualifiedName("org.apache.log4j", "Category") or // Log4j 1
|
||||
t.hasQualifiedName("org.apache.logging.log4j", ["Logger", "LogBuilder"]) or // Log4j 2
|
||||
t.hasQualifiedName("org.apache.commons.logging", "Log") or
|
||||
// JBoss Logging (`org.jboss.logging.Logger` in some implementations like JBoss Application Server 4.0.4 did not implement `BasicLogger`)
|
||||
t.hasQualifiedName("org.jboss.logging", ["BasicLogger", "Logger"]) or
|
||||
t.hasQualifiedName("org.slf4j.spi", "LoggingEventBuilder") or
|
||||
t.hasQualifiedName("org.slf4j", "Logger") or
|
||||
t.hasQualifiedName("org.scijava.log", "Logger") or
|
||||
t.hasQualifiedName("com.google.common.flogger", "LoggingApi") or
|
||||
t.hasQualifiedName("java.lang", "System$Logger") or
|
||||
t.hasQualifiedName("java.util.logging", "Logger") or
|
||||
t.hasQualifiedName("android.util", "Log")
|
||||
|
|
||||
(
|
||||
m.getDeclaringType().getASourceSupertype*() = t or
|
||||
m.getDeclaringType().extendsOrImplements*(t)
|
||||
) and
|
||||
m.getReturnType() instanceof VoidType and
|
||||
this = m.getAReference()
|
||||
)
|
||||
}
|
||||
|
||||
/** Returns an argument which would be logged by this call. */
|
||||
Argument getALogArgument() { result = this.getArgument(_) }
|
||||
}
|
||||
268
java/ql/src/external/CodeDuplication.qll
vendored
268
java/ql/src/external/CodeDuplication.qll
vendored
@@ -1,268 +0,0 @@
|
||||
import java
|
||||
|
||||
private string relativePath(File file) { result = file.getRelativePath().replaceAll("\\", "/") }
|
||||
|
||||
cached
|
||||
private predicate tokenLocation(File file, int sl, int sc, int ec, int el, Copy copy, int index) {
|
||||
file = copy.sourceFile() and
|
||||
tokens(copy, index, sl, sc, ec, el)
|
||||
}
|
||||
|
||||
class Copy extends @duplication_or_similarity {
|
||||
private int lastToken() { result = max(int i | tokens(this, i, _, _, _, _) | i) }
|
||||
|
||||
int tokenStartingAt(Location loc) {
|
||||
tokenLocation(loc.getFile(), loc.getStartLine(), loc.getStartColumn(), _, _, this, result)
|
||||
}
|
||||
|
||||
int tokenEndingAt(Location loc) {
|
||||
tokenLocation(loc.getFile(), _, _, loc.getEndLine(), loc.getEndColumn(), this, result)
|
||||
}
|
||||
|
||||
int sourceStartLine() { tokens(this, 0, result, _, _, _) }
|
||||
|
||||
int sourceStartColumn() { tokens(this, 0, _, result, _, _) }
|
||||
|
||||
int sourceEndLine() { tokens(this, lastToken(), _, _, result, _) }
|
||||
|
||||
int sourceEndColumn() { tokens(this, lastToken(), _, _, _, result) }
|
||||
|
||||
int sourceLines() { result = this.sourceEndLine() + 1 - this.sourceStartLine() }
|
||||
|
||||
int getEquivalenceClass() { duplicateCode(this, _, result) or similarCode(this, _, result) }
|
||||
|
||||
File sourceFile() {
|
||||
exists(string name | duplicateCode(this, name, _) or similarCode(this, name, _) |
|
||||
name.replaceAll("\\", "/") = relativePath(result)
|
||||
)
|
||||
}
|
||||
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
sourceFile().getAbsolutePath() = filepath and
|
||||
startline = sourceStartLine() and
|
||||
startcolumn = sourceStartColumn() and
|
||||
endline = sourceEndLine() and
|
||||
endcolumn = sourceEndColumn()
|
||||
}
|
||||
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class DuplicateBlock extends Copy, @duplication {
|
||||
override string toString() { result = "Duplicate code: " + sourceLines() + " duplicated lines." }
|
||||
}
|
||||
|
||||
class SimilarBlock extends Copy, @similarity {
|
||||
override string toString() {
|
||||
result = "Similar code: " + sourceLines() + " almost duplicated lines."
|
||||
}
|
||||
}
|
||||
|
||||
Method sourceMethod() { hasLocation(result, _) and numlines(result, _, _, _) }
|
||||
|
||||
int numberOfSourceMethods(Class c) {
|
||||
result = count(Method m | m = sourceMethod() and m.getDeclaringType() = c)
|
||||
}
|
||||
|
||||
private predicate blockCoversStatement(int equivClass, int first, int last, Stmt stmt) {
|
||||
exists(DuplicateBlock b, Location loc |
|
||||
stmt.getLocation() = loc and
|
||||
first = b.tokenStartingAt(loc) and
|
||||
last = b.tokenEndingAt(loc) and
|
||||
b.getEquivalenceClass() = equivClass
|
||||
)
|
||||
}
|
||||
|
||||
private Stmt statementInMethod(Method m) {
|
||||
result.getEnclosingCallable() = m and
|
||||
not result instanceof BlockStmt
|
||||
}
|
||||
|
||||
private predicate duplicateStatement(Method m1, Method m2, Stmt s1, Stmt s2) {
|
||||
exists(int equivClass, int first, int last |
|
||||
s1 = statementInMethod(m1) and
|
||||
s2 = statementInMethod(m2) and
|
||||
blockCoversStatement(equivClass, first, last, s1) and
|
||||
blockCoversStatement(equivClass, first, last, s2) and
|
||||
s1 != s2 and
|
||||
m1 != m2
|
||||
)
|
||||
}
|
||||
|
||||
predicate duplicateStatements(Method m1, Method m2, int duplicate, int total) {
|
||||
duplicate = strictcount(Stmt s | duplicateStatement(m1, m2, s, _)) and
|
||||
total = strictcount(statementInMethod(m1))
|
||||
}
|
||||
|
||||
/**
|
||||
* Pairs of methods that are identical.
|
||||
*/
|
||||
predicate duplicateMethod(Method m, Method other) {
|
||||
exists(int total | duplicateStatements(m, other, total, total))
|
||||
}
|
||||
|
||||
predicate similarLines(File f, int line) {
|
||||
exists(SimilarBlock b | b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()])
|
||||
}
|
||||
|
||||
private predicate similarLinesPerEquivalenceClass(int equivClass, int lines, File f) {
|
||||
lines =
|
||||
strictsum(SimilarBlock b, int toSum |
|
||||
(b.sourceFile() = f and b.getEquivalenceClass() = equivClass) and
|
||||
toSum = b.sourceLines()
|
||||
|
|
||||
toSum
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noopt]
|
||||
private predicate similarLinesCovered(File f, int coveredLines, File otherFile) {
|
||||
exists(int numLines | numLines = f.getTotalNumberOfLines() |
|
||||
exists(int coveredApprox |
|
||||
coveredApprox =
|
||||
strictsum(int num |
|
||||
exists(int equivClass |
|
||||
similarLinesPerEquivalenceClass(equivClass, num, f) and
|
||||
similarLinesPerEquivalenceClass(equivClass, num, otherFile) and
|
||||
f != otherFile
|
||||
)
|
||||
) and
|
||||
exists(int n, int product | product = coveredApprox * 100 and n = product / numLines | n > 75)
|
||||
) and
|
||||
exists(int notCovered |
|
||||
notCovered = count(int j | j in [1 .. numLines] and not similarLines(f, j)) and
|
||||
coveredLines = numLines - notCovered
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
predicate duplicateLines(File f, int line) {
|
||||
exists(DuplicateBlock b |
|
||||
b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()]
|
||||
)
|
||||
}
|
||||
|
||||
private predicate duplicateLinesPerEquivalenceClass(int equivClass, int lines, File f) {
|
||||
lines =
|
||||
strictsum(DuplicateBlock b, int toSum |
|
||||
(b.sourceFile() = f and b.getEquivalenceClass() = equivClass) and
|
||||
toSum = b.sourceLines()
|
||||
|
|
||||
toSum
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noopt]
|
||||
private predicate duplicateLinesCovered(File f, int coveredLines, File otherFile) {
|
||||
exists(int numLines | numLines = f.getTotalNumberOfLines() |
|
||||
exists(int coveredApprox |
|
||||
coveredApprox =
|
||||
strictsum(int num |
|
||||
exists(int equivClass |
|
||||
duplicateLinesPerEquivalenceClass(equivClass, num, f) and
|
||||
duplicateLinesPerEquivalenceClass(equivClass, num, otherFile) and
|
||||
f != otherFile
|
||||
)
|
||||
) and
|
||||
exists(int n, int product | product = coveredApprox * 100 and n = product / numLines | n > 75)
|
||||
) and
|
||||
exists(int notCovered |
|
||||
notCovered = count(int j | j in [1 .. numLines] and not duplicateLines(f, j)) and
|
||||
coveredLines = numLines - notCovered
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
predicate similarFiles(File f, File other, int percent) {
|
||||
exists(int covered, int total |
|
||||
similarLinesCovered(f, covered, other) and
|
||||
total = f.getTotalNumberOfLines() and
|
||||
covered * 100 / total = percent and
|
||||
percent > 80
|
||||
) and
|
||||
not duplicateFiles(f, other, _)
|
||||
}
|
||||
|
||||
predicate duplicateFiles(File f, File other, int percent) {
|
||||
exists(int covered, int total |
|
||||
duplicateLinesCovered(f, covered, other) and
|
||||
total = f.getTotalNumberOfLines() and
|
||||
covered * 100 / total = percent and
|
||||
percent > 70
|
||||
)
|
||||
}
|
||||
|
||||
predicate duplicateAnonymousClass(AnonymousClass c, AnonymousClass other) {
|
||||
exists(int numDup |
|
||||
numDup =
|
||||
strictcount(Method m1 |
|
||||
exists(Method m2 |
|
||||
duplicateMethod(m1, m2) and
|
||||
m1 = sourceMethod() and
|
||||
m1.getDeclaringType() = c and
|
||||
m2.getDeclaringType() = other and
|
||||
c != other
|
||||
)
|
||||
) and
|
||||
numDup = numberOfSourceMethods(c) and
|
||||
numDup = numberOfSourceMethods(other) and
|
||||
forall(Type t | c.getASupertype() = t | t = other.getASupertype())
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noopt]
|
||||
predicate mostlyDuplicateClassBase(Class c, Class other, int numDup, int total) {
|
||||
numDup =
|
||||
strictcount(Method m1 |
|
||||
exists(Method m2 |
|
||||
duplicateMethod(m1, m2) and
|
||||
m1 = sourceMethod() and
|
||||
m1.getDeclaringType() = c and
|
||||
m2.getDeclaringType() = other and
|
||||
other instanceof Class and
|
||||
c != other
|
||||
)
|
||||
) and
|
||||
total = numberOfSourceMethods(c) and
|
||||
exists(int n, int product | product = 100 * numDup and n = product / total | n > 80)
|
||||
}
|
||||
|
||||
predicate mostlyDuplicateClass(Class c, Class other, string message) {
|
||||
exists(int numDup, int total |
|
||||
mostlyDuplicateClassBase(c, other, numDup, total) and
|
||||
not c instanceof AnonymousClass and
|
||||
not other instanceof AnonymousClass and
|
||||
(
|
||||
total != numDup and
|
||||
exists(string s1, string s2, string s3, string name |
|
||||
s1 = " out of " and
|
||||
s2 = " methods in " and
|
||||
s3 = " are duplicated in $@." and
|
||||
name = c.getName()
|
||||
|
|
||||
message = numDup + s1 + total + s2 + name + s3
|
||||
)
|
||||
or
|
||||
total = numDup and
|
||||
exists(string s1, string s2, string name |
|
||||
s1 = "All methods in " and s2 = " are identical in $@." and name = c.getName()
|
||||
|
|
||||
message = s1 + name + s2
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
predicate fileLevelDuplication(File f, File other) {
|
||||
similarFiles(f, other, _) or duplicateFiles(f, other, _)
|
||||
}
|
||||
|
||||
predicate classLevelDuplication(Class c, Class other) {
|
||||
duplicateAnonymousClass(c, other) or mostlyDuplicateClass(c, other, _)
|
||||
}
|
||||
|
||||
predicate whitelistedLineForDuplication(File f, int line) {
|
||||
exists(Import i | i.getFile() = f and i.getLocation().getStartLine() = line)
|
||||
}
|
||||
55
java/ql/src/external/DefectFilter.qll
vendored
55
java/ql/src/external/DefectFilter.qll
vendored
@@ -1,55 +0,0 @@
|
||||
/** Provides a class for working with defect query results stored in dashboard databases. */
|
||||
|
||||
import java
|
||||
|
||||
/**
|
||||
* Holds if `id` in the opaque identifier of a result reported by query `queryPath`,
|
||||
* such that `message` is the associated message and the location of the result spans
|
||||
* column `startcolumn` of line `startline` to column `endcolumn` of line `endline`
|
||||
* in file `filepath`.
|
||||
*
|
||||
* For more information, see [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
*/
|
||||
external predicate defectResults(
|
||||
int id, string queryPath, string file, int startline, int startcol, int endline, int endcol,
|
||||
string message
|
||||
);
|
||||
|
||||
/**
|
||||
* A defect query result stored in a dashboard database.
|
||||
*/
|
||||
class DefectResult extends int {
|
||||
DefectResult() { defectResults(this, _, _, _, _, _, _, _) }
|
||||
|
||||
/** Gets the path of the query that reported the result. */
|
||||
string getQueryPath() { defectResults(this, result, _, _, _, _, _, _) }
|
||||
|
||||
/** Gets the file in which this query result was reported. */
|
||||
File getFile() {
|
||||
exists(string path | defectResults(this, _, path, _, _, _, _, _) |
|
||||
result.getAbsolutePath() = path
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the line on which the location of this query result starts. */
|
||||
int getStartLine() { defectResults(this, _, _, result, _, _, _, _) }
|
||||
|
||||
/** Gets the column on which the location of this query result starts. */
|
||||
int getStartColumn() { defectResults(this, _, _, _, result, _, _, _) }
|
||||
|
||||
/** Gets the line on which the location of this query result ends. */
|
||||
int getEndLine() { defectResults(this, _, _, _, _, result, _, _) }
|
||||
|
||||
/** Gets the column on which the location of this query result ends. */
|
||||
int getEndColumn() { defectResults(this, _, _, _, _, _, result, _) }
|
||||
|
||||
/** Gets the message associated with this query result. */
|
||||
string getMessage() { defectResults(this, _, _, _, _, _, _, result) }
|
||||
|
||||
/** Gets the URL corresponding to the location of this query result. */
|
||||
string getURL() {
|
||||
result =
|
||||
"file://" + getFile().getAbsolutePath() + ":" + getStartLine() + ":" + getStartColumn() + ":" +
|
||||
getEndLine() + ":" + getEndColumn()
|
||||
}
|
||||
}
|
||||
5
java/ql/src/external/DuplicateAnonymous.ql
vendored
5
java/ql/src/external/DuplicateAnonymous.ql
vendored
@@ -15,11 +15,8 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import CodeDuplication
|
||||
|
||||
from AnonymousClass c, AnonymousClass other
|
||||
where
|
||||
duplicateAnonymousClass(c, other) and
|
||||
not fileLevelDuplication(c.getCompilationUnit(), other.getCompilationUnit())
|
||||
where none()
|
||||
select c, "Anonymous class is identical to $@.", other,
|
||||
"another anonymous class in " + other.getFile().getStem()
|
||||
|
||||
12
java/ql/src/external/DuplicateBlock.ql
vendored
12
java/ql/src/external/DuplicateBlock.ql
vendored
@@ -8,16 +8,10 @@
|
||||
* @id java/duplicate-block
|
||||
*/
|
||||
|
||||
import CodeDuplication
|
||||
import java
|
||||
|
||||
from DuplicateBlock d, DuplicateBlock other, int lines, File otherFile, int otherLine
|
||||
where
|
||||
lines = d.sourceLines() and
|
||||
lines > 10 and
|
||||
other.getEquivalenceClass() = d.getEquivalenceClass() and
|
||||
other != d and
|
||||
otherFile = other.sourceFile() and
|
||||
otherLine = other.sourceStartLine()
|
||||
from BlockStmt d, int lines, File otherFile, int otherLine
|
||||
where none()
|
||||
select d,
|
||||
"Duplicate code: " + lines + " lines are duplicated at " + otherFile.getStem() + ":" + otherLine +
|
||||
"."
|
||||
|
||||
13
java/ql/src/external/DuplicateMethod.ql
vendored
13
java/ql/src/external/DuplicateMethod.ql
vendored
@@ -16,19 +16,8 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import CodeDuplication
|
||||
|
||||
predicate relevant(Method m) {
|
||||
m.getNumberOfLinesOfCode() > 5 and not m.getName().matches("get%")
|
||||
or
|
||||
m.getNumberOfLinesOfCode() > 10
|
||||
}
|
||||
|
||||
from Method m, Method other
|
||||
where
|
||||
duplicateMethod(m, other) and
|
||||
relevant(m) and
|
||||
not fileLevelDuplication(m.getCompilationUnit(), other.getCompilationUnit()) and
|
||||
not classLevelDuplication(m.getDeclaringType(), other.getDeclaringType())
|
||||
where none()
|
||||
select m, "Method " + m.getName() + " is duplicated in $@.", other,
|
||||
other.getDeclaringType().getQualifiedName()
|
||||
|
||||
44
java/ql/src/external/MetricFilter.qll
vendored
44
java/ql/src/external/MetricFilter.qll
vendored
@@ -1,44 +0,0 @@
|
||||
import java
|
||||
|
||||
external predicate metricResults(
|
||||
int id, string queryPath, string file, int startline, int startcol, int endline, int endcol,
|
||||
float value
|
||||
);
|
||||
|
||||
class MetricResult extends int {
|
||||
MetricResult() { metricResults(this, _, _, _, _, _, _, _) }
|
||||
|
||||
string getQueryPath() { metricResults(this, result, _, _, _, _, _, _) }
|
||||
|
||||
File getFile() {
|
||||
exists(string path |
|
||||
metricResults(this, _, path, _, _, _, _, _) and result.getAbsolutePath() = path
|
||||
)
|
||||
}
|
||||
|
||||
int getStartLine() { metricResults(this, _, _, result, _, _, _, _) }
|
||||
|
||||
int getStartColumn() { metricResults(this, _, _, _, result, _, _, _) }
|
||||
|
||||
int getEndLine() { metricResults(this, _, _, _, _, result, _, _) }
|
||||
|
||||
int getEndColumn() { metricResults(this, _, _, _, _, _, result, _) }
|
||||
|
||||
predicate hasMatchingLocation() { exists(this.getMatchingLocation()) }
|
||||
|
||||
Location getMatchingLocation() {
|
||||
result.getFile() = this.getFile() and
|
||||
result.getStartLine() = this.getStartLine() and
|
||||
result.getEndLine() = this.getEndLine() and
|
||||
result.getStartColumn() = this.getStartColumn() and
|
||||
result.getEndColumn() = this.getEndColumn()
|
||||
}
|
||||
|
||||
float getValue() { metricResults(this, _, _, _, _, _, _, result) }
|
||||
|
||||
string getURL() {
|
||||
result =
|
||||
"file://" + getFile().getAbsolutePath() + ":" + getStartLine() + ":" + getStartColumn() + ":" +
|
||||
getEndLine() + ":" + getEndColumn()
|
||||
}
|
||||
}
|
||||
5
java/ql/src/external/MostlyDuplicateClass.ql
vendored
5
java/ql/src/external/MostlyDuplicateClass.ql
vendored
@@ -16,10 +16,7 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import CodeDuplication
|
||||
|
||||
from Class c, string message, Class link
|
||||
where
|
||||
mostlyDuplicateClass(c, link, message) and
|
||||
not fileLevelDuplication(c.getCompilationUnit(), _)
|
||||
where none()
|
||||
select c, message, link, link.getQualifiedName()
|
||||
|
||||
3
java/ql/src/external/MostlyDuplicateFile.ql
vendored
3
java/ql/src/external/MostlyDuplicateFile.ql
vendored
@@ -16,9 +16,8 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import CodeDuplication
|
||||
|
||||
from File f, File other, int percent
|
||||
where duplicateFiles(f, other, percent)
|
||||
where none()
|
||||
select f, percent + "% of the lines in " + f.getStem() + " are copies of lines in $@.", other,
|
||||
other.getStem()
|
||||
|
||||
13
java/ql/src/external/MostlyDuplicateMethod.ql
vendored
13
java/ql/src/external/MostlyDuplicateMethod.ql
vendored
@@ -16,17 +16,8 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import CodeDuplication
|
||||
|
||||
from Method m, int covered, int total, Method other, int percent
|
||||
where
|
||||
duplicateStatements(m, other, covered, total) and
|
||||
covered != total and
|
||||
m.getMetrics().getNumberOfLinesOfCode() > 5 and
|
||||
covered * 100 / total = percent and
|
||||
percent > 80 and
|
||||
not duplicateMethod(m, other) and
|
||||
not classLevelDuplication(m.getDeclaringType(), other.getDeclaringType()) and
|
||||
not fileLevelDuplication(m.getCompilationUnit(), other.getCompilationUnit())
|
||||
from Method m, Method other, int percent
|
||||
where none()
|
||||
select m, percent + "% of the statements in " + m.getName() + " are duplicated in $@.", other,
|
||||
other.getDeclaringType().getName() + "." + other.getStringSignature()
|
||||
|
||||
3
java/ql/src/external/MostlySimilarFile.ql
vendored
3
java/ql/src/external/MostlySimilarFile.ql
vendored
@@ -16,9 +16,8 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import CodeDuplication
|
||||
|
||||
from File f, File other, int percent
|
||||
where similarFiles(f, other, percent)
|
||||
where none()
|
||||
select f, percent + "% of the lines in " + f.getStem() + " are similar to lines in $@.", other,
|
||||
other.getStem()
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
/**
|
||||
* @name Filter: only keep results from source
|
||||
* @description Shows how to filter for only certain files
|
||||
* @kind problem
|
||||
* @id java/source-filter
|
||||
*/
|
||||
|
||||
import java
|
||||
import external.DefectFilter
|
||||
|
||||
from DefectResult res, CompilationUnit cu
|
||||
where
|
||||
cu = res.getFile() and
|
||||
cu.fromSource()
|
||||
select res, res.getMessage()
|
||||
@@ -1,13 +0,0 @@
|
||||
/**
|
||||
* @name Filter: non-generated files
|
||||
* @description Only keep results that aren't in generated files
|
||||
* @kind problem
|
||||
* @id java/not-generated-file-filter
|
||||
*/
|
||||
|
||||
import java
|
||||
import external.DefectFilter
|
||||
|
||||
from DefectResult res
|
||||
where not res.getFile() instanceof GeneratedFile
|
||||
select res, res.getMessage()
|
||||
@@ -1,13 +0,0 @@
|
||||
/**
|
||||
* @name Metric Filter: non-generated files
|
||||
* @description Only keep metric results that aren't in generated files
|
||||
* @kind treemap
|
||||
* @id java/not-generated-file-metric-filter
|
||||
*/
|
||||
|
||||
import java
|
||||
import external.MetricFilter
|
||||
|
||||
from MetricResult res
|
||||
where not res.getFile() instanceof GeneratedFile
|
||||
select res, res.getValue()
|
||||
@@ -1,52 +0,0 @@
|
||||
/**
|
||||
* @name Filter: Suppression comments
|
||||
* @description Recognise comments containing `NOSEMMLE` as suppression comments
|
||||
* when they appear on a line containing an alert or the
|
||||
* immediately preceding line. As further customisations,
|
||||
* `NOSEMMLE(some text)` will only suppress alerts where the
|
||||
* message contains "some text", and `NOSEMMLE/some regex/` will
|
||||
* only suppress alerts where the message contains a match of the
|
||||
* regex. No special way of escaping `)` or `/` in the suppression
|
||||
* comment argument is provided.
|
||||
* @kind problem
|
||||
* @id java/nosemmle-suppression-comment-filter
|
||||
*/
|
||||
|
||||
import java
|
||||
import external.DefectFilter
|
||||
|
||||
class SuppressionComment extends Javadoc {
|
||||
SuppressionComment() { this.getAChild*().getText().matches("%NOSEMMLE%") }
|
||||
|
||||
private string getASuppressionDirective() {
|
||||
result = this.getAChild*().getText().regexpFind("\\bNOSEMMLE\\b(\\([^)]+?\\)|/[^/]+?/|)", _, 0)
|
||||
}
|
||||
|
||||
private string getAnActualSubstringArg() {
|
||||
result = this.getASuppressionDirective().regexpCapture("NOSEMMLE\\((.*)\\)", 1)
|
||||
}
|
||||
|
||||
private string getAnActualRegexArg() {
|
||||
result = ".*" + this.getASuppressionDirective().regexpCapture("NOSEMMLE/(.*)/", 1) + ".*"
|
||||
}
|
||||
|
||||
private string getASuppressionRegex() {
|
||||
result = getAnActualRegexArg()
|
||||
or
|
||||
exists(string substring | substring = getAnActualSubstringArg() |
|
||||
result = "\\Q" + substring.replaceAll("\\E", "\\E\\\\E\\Q") + "\\E"
|
||||
)
|
||||
or
|
||||
result = ".*" and getASuppressionDirective() = "NOSEMMLE"
|
||||
}
|
||||
|
||||
predicate suppresses(DefectResult res) {
|
||||
this.getFile() = res.getFile() and
|
||||
res.getEndLine() - this.getLocation().getEndLine() in [0 .. 2] and
|
||||
res.getMessage().regexpMatch(this.getASuppressionRegex())
|
||||
}
|
||||
}
|
||||
|
||||
from DefectResult res
|
||||
where not exists(SuppressionComment s | s.suppresses(res))
|
||||
select res, res.getMessage()
|
||||
14
java/ql/src/meta/frameworks/Coverage.ql
Normal file
14
java/ql/src/meta/frameworks/Coverage.ql
Normal file
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* @name Framework coverage
|
||||
* @description The number of API endpoints covered by CSV models sorted by
|
||||
* package and source-, sink-, and summary-kind.
|
||||
* @kind table
|
||||
* @id java/meta/framework-coverage
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.ExternalFlow
|
||||
|
||||
from string package, int pkgs, string kind, string part, int n
|
||||
where modelCoverage(package, pkgs, kind, part, n)
|
||||
select package, pkgs, kind, part, n
|
||||
@@ -653,11 +653,23 @@ class LongLiteral extends Literal, @longliteral {
|
||||
|
||||
/** A floating point literal. For example, `4.2f`. */
|
||||
class FloatingPointLiteral extends Literal, @floatingpointliteral {
|
||||
/**
|
||||
* Gets the value of this literal as CodeQL 64-bit `float`. The value will
|
||||
* be parsed as Java 32-bit `float` and then converted to a CodeQL `float`.
|
||||
*/
|
||||
float getFloatValue() { result = getValue().toFloat() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "FloatingPointLiteral" }
|
||||
}
|
||||
|
||||
/** A double literal. For example, `4.2`. */
|
||||
class DoubleLiteral extends Literal, @doubleliteral {
|
||||
/**
|
||||
* Gets the value of this literal as CodeQL 64-bit `float`. The result will
|
||||
* have the same effective value as the Java `double` literal.
|
||||
*/
|
||||
float getDoubleValue() { result = getValue().toFloat() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "DoubleLiteral" }
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,11 @@ class TypeStringBuilder extends Class {
|
||||
TypeStringBuilder() { this.hasQualifiedName("java.lang", "StringBuilder") }
|
||||
}
|
||||
|
||||
/** Class `java.lang.StringBuffer` or `java.lang.StringBuilder`. */
|
||||
class StringBuildingType extends Class {
|
||||
StringBuildingType() { this instanceof TypeStringBuffer or this instanceof TypeStringBuilder }
|
||||
}
|
||||
|
||||
/** The class `java.lang.System`. */
|
||||
class TypeSystem extends Class {
|
||||
TypeSystem() { this.hasQualifiedName("java.lang", "System") }
|
||||
|
||||
@@ -144,7 +144,7 @@ class OpensDirective extends Directive, @opens {
|
||||
|
||||
/**
|
||||
* Gets a module specified in the `to` clause of this
|
||||
* `exports` directive, if any.
|
||||
* `opens` directive, if any.
|
||||
*/
|
||||
Module getATargetModule() { opensTo(this, result) }
|
||||
|
||||
|
||||
@@ -210,10 +210,7 @@ private predicate printMethod(Method m, int i) {
|
||||
(t.hasQualifiedName("java.io", "PrintWriter") or t.hasQualifiedName("java.io", "PrintStream")) and
|
||||
(m.hasName("print") or m.hasName("println"))
|
||||
or
|
||||
(
|
||||
t.hasQualifiedName("java.lang", "StringBuilder") or
|
||||
t.hasQualifiedName("java.lang", "StringBuffer")
|
||||
) and
|
||||
t instanceof StringBuildingType and
|
||||
(m.hasName("append") or m.hasName("insert"))
|
||||
or
|
||||
t instanceof TypeString and m.hasName("valueOf")
|
||||
|
||||
@@ -32,26 +32,30 @@
|
||||
* 7. The `input` column specifies how data enters the element selected by the
|
||||
* first 6 columns, and the `output` column specifies how data leaves the
|
||||
* element selected by the first 6 columns. An `input` can be either "",
|
||||
* "Argument", "Argument[n]", "ReturnValue":
|
||||
* "Argument[n]", "Argument[n1..n2]", "ReturnValue":
|
||||
* - "": Selects a write to the selected element in case this is a field.
|
||||
* - "Argument": Selects any argument in a call to the selected element.
|
||||
* - "Argument[n]": Similar to "Argument" but restricted to a specific numbered
|
||||
* argument (zero-indexed, and `-1` specifies the qualifier).
|
||||
* - "Argument[n]": Selects an argument in a call to the selected element.
|
||||
* The arguments are zero-indexed, and `-1` specifies the qualifier.
|
||||
* - "Argument[n1..n2]": Similar to "Argument[n]" but select any argument in
|
||||
* the given range. The range is inclusive at both ends.
|
||||
* - "ReturnValue": Selects a value being returned by the selected element.
|
||||
* This requires that the selected element is a method with a body.
|
||||
*
|
||||
* An `output` can be either "", "Argument", "Argument[n]", "Parameter",
|
||||
* "Parameter[n]", or "ReturnValue":
|
||||
* An `output` can be either "", "Argument[n]", "Argument[n1..n2]", "Parameter",
|
||||
* "Parameter[n]", "Parameter[n1..n2]", or "ReturnValue":
|
||||
* - "": Selects a read of a selected field, or a selected parameter.
|
||||
* - "Argument": Selects the post-update value of an argument in a call to the
|
||||
* - "Argument[n]": Selects the post-update value of an argument in a call to the
|
||||
* selected element. That is, the value of the argument after the call returns.
|
||||
* - "Argument[n]": Similar to "Argument" but restricted to a specific numbered
|
||||
* argument (zero-indexed, and `-1` specifies the qualifier).
|
||||
* The arguments are zero-indexed, and `-1` specifies the qualifier.
|
||||
* - "Argument[n1..n2]": Similar to "Argument[n]" but select any argument in
|
||||
* the given range. The range is inclusive at both ends.
|
||||
* - "Parameter": Selects the value of a parameter of the selected element.
|
||||
* "Parameter" is also allowed in case the selected element is already a
|
||||
* parameter itself.
|
||||
* - "Parameter[n]": Similar to "Parameter" but restricted to a specific
|
||||
* numbered parameter (zero-indexed, and `-1` specifies the value of `this`).
|
||||
* - "Parameter[n1..n2]": Similar to "Parameter[n]" but selects any parameter
|
||||
* in the given range. The range is inclusive at both ends.
|
||||
* - "ReturnValue": Selects the return value of a call to the selected element.
|
||||
* 8. The `kind` column is a tag that can be referenced from QL to determine to
|
||||
* which classes the interpreted elements should be added. For example, for
|
||||
@@ -182,7 +186,91 @@ private predicate sourceModelCsv(string row) {
|
||||
|
||||
private predicate sinkModelCsv(string row) { none() }
|
||||
|
||||
private predicate summaryModelCsv(string row) { none() }
|
||||
private predicate summaryModelCsv(string row) {
|
||||
row =
|
||||
[
|
||||
// qualifier to arg
|
||||
"java.io;InputStream;true;read;(byte[]);;Argument[-1];Argument[0];taint",
|
||||
"java.io;InputStream;true;read;(byte[],int,int);;Argument[-1];Argument[0];taint",
|
||||
"java.io;ByteArrayOutputStream;false;writeTo;;;Argument[-1];Argument[0];taint",
|
||||
"java.io;Reader;true;read;;;Argument[-1];Argument[0];taint",
|
||||
// qualifier to return
|
||||
"java.io;ByteArrayOutputStream;false;toByteArray;;;Argument[-1];ReturnValue;taint",
|
||||
"java.io;ByteArrayOutputStream;false;toString;;;Argument[-1];ReturnValue;taint",
|
||||
"java.util;StringTokenizer;false;nextElement;();;Argument[-1];ReturnValue;taint",
|
||||
"java.util;StringTokenizer;false;nextToken;;;Argument[-1];ReturnValue;taint",
|
||||
"javax.xml.transform.sax;SAXSource;false;getInputSource;;;Argument[-1];ReturnValue;taint",
|
||||
"javax.xml.transform.stream;StreamSource;false;getInputStream;;;Argument[-1];ReturnValue;taint",
|
||||
"java.nio;ByteBuffer;false;get;;;Argument[-1];ReturnValue;taint",
|
||||
"java.net;URI;false;toURL;;;Argument[-1];ReturnValue;taint",
|
||||
"java.io;File;false;toURI;;;Argument[-1];ReturnValue;taint",
|
||||
"java.io;File;false;toPath;;;Argument[-1];ReturnValue;taint",
|
||||
"java.nio.file;Path;false;toFile;;;Argument[-1];ReturnValue;taint",
|
||||
"java.io;Reader;true;readLine;;;Argument[-1];ReturnValue;taint",
|
||||
"java.io;Reader;true;read;();;Argument[-1];ReturnValue;taint",
|
||||
// arg to return
|
||||
"java.util;Base64$Encoder;false;encode;(byte[]);;Argument[0];ReturnValue;taint",
|
||||
"java.util;Base64$Encoder;false;encode;(ByteBuffer);;Argument[0];ReturnValue;taint",
|
||||
"java.util;Base64$Encoder;false;encodeToString;(byte[]);;Argument[0];ReturnValue;taint",
|
||||
"java.util;Base64$Encoder;false;wrap;(OutputStream);;Argument[0];ReturnValue;taint",
|
||||
"java.util;Base64$Decoder;false;decode;(byte[]);;Argument[0];ReturnValue;taint",
|
||||
"java.util;Base64$Decoder;false;decode;(ByteBuffer);;Argument[0];ReturnValue;taint",
|
||||
"java.util;Base64$Decoder;false;decode;(String);;Argument[0];ReturnValue;taint",
|
||||
"java.util;Base64$Decoder;false;wrap;(InputStream);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.codec;Encoder;true;encode;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.codec;Decoder;true;decode;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.io;IOUtils;false;buffer;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.io;IOUtils;false;readLines;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.io;IOUtils;false;readFully;(InputStream,int);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.io;IOUtils;false;toBufferedInputStream;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.io;IOUtils;false;toBufferedReader;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.io;IOUtils;false;toByteArray;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.io;IOUtils;false;toCharArray;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.io;IOUtils;false;toInputStream;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.io;IOUtils;false;toString;;;Argument[0];ReturnValue;taint",
|
||||
"java.net;URLDecoder;false;decode;;;Argument[0];ReturnValue;taint",
|
||||
"java.net;URI;false;create;;;Argument[0];ReturnValue;taint",
|
||||
"javax.xml.transform.sax;SAXSource;false;sourceToInputSource;;;Argument[0];ReturnValue;taint",
|
||||
// arg to arg
|
||||
"java.lang;System;false;arraycopy;;;Argument[0];Argument[2];taint",
|
||||
"org.apache.commons.io;IOUtils;false;copy;;;Argument[0];Argument[1];taint",
|
||||
"org.apache.commons.io;IOUtils;false;copyLarge;;;Argument[0];Argument[1];taint",
|
||||
"org.apache.commons.io;IOUtils;false;read;;;Argument[0];Argument[1];taint",
|
||||
"org.apache.commons.io;IOUtils;false;readFully;(InputStream,byte[]);;Argument[0];Argument[1];taint",
|
||||
"org.apache.commons.io;IOUtils;false;readFully;(InputStream,byte[],int,int);;Argument[0];Argument[1];taint",
|
||||
"org.apache.commons.io;IOUtils;false;readFully;(InputStream,ByteBuffer);;Argument[0];Argument[1];taint",
|
||||
"org.apache.commons.io;IOUtils;false;readFully;(ReadableByteChannel,ByteBuffer);;Argument[0];Argument[1];taint",
|
||||
"org.apache.commons.io;IOUtils;false;readFully;(Reader,char[]);;Argument[0];Argument[1];taint",
|
||||
"org.apache.commons.io;IOUtils;false;readFully;(Reader,char[],int,int);;Argument[0];Argument[1];taint",
|
||||
"org.apache.commons.io;IOUtils;false;write;;;Argument[0];Argument[1];taint",
|
||||
"org.apache.commons.io;IOUtils;false;writeChunked;;;Argument[0];Argument[1];taint",
|
||||
"org.apache.commons.io;IOUtils;false;writeLines;;;Argument[0];Argument[2];taint",
|
||||
"org.apache.commons.io;IOUtils;false;writeLines;;;Argument[1];Argument[2];taint",
|
||||
// constructor flow
|
||||
"java.io;File;false;File;;;Argument[0];Argument[-1];taint",
|
||||
"java.io;File;false;File;;;Argument[1];Argument[-1];taint",
|
||||
"java.net;URI;false;URI;(String);;Argument[0];Argument[-1];taint",
|
||||
"javax.xml.transform.stream;StreamSource;false;StreamSource;;;Argument[0];Argument[-1];taint",
|
||||
"javax.xml.transform.sax;SAXSource;false;SAXSource;(InputSource);;Argument[0];Argument[-1];taint",
|
||||
"javax.xml.transform.sax;SAXSource;false;SAXSource;(XMLReader,InputSource);;Argument[1];Argument[-1];taint",
|
||||
"org.xml.sax;InputSource;false;InputSource;;;Argument[0];Argument[-1];taint",
|
||||
"javax.servlet.http;Cookie;false;Cookie;;;Argument[0];Argument[-1];taint",
|
||||
"javax.servlet.http;Cookie;false;Cookie;;;Argument[1];Argument[-1];taint",
|
||||
"java.util.zip;ZipInputStream;false;ZipInputStream;;;Argument[0];Argument[-1];taint",
|
||||
"java.util.zip;GZIPInputStream;false;GZIPInputStream;;;Argument[0];Argument[-1];taint",
|
||||
"java.util;StringTokenizer;false;StringTokenizer;;;Argument[0];Argument[-1];taint",
|
||||
"java.beans;XMLDecoder;false;XMLDecoder;;;Argument[0];Argument[-1];taint",
|
||||
"com.esotericsoftware.kryo.io;Input;false;Input;;;Argument[0];Argument[-1];taint",
|
||||
"java.io;BufferedInputStream;false;BufferedInputStream;;;Argument[0];Argument[-1];taint",
|
||||
"java.io;DataInputStream;false;DataInputStream;;;Argument[0];Argument[-1];taint",
|
||||
"java.io;ByteArrayInputStream;false;ByteArrayInputStream;;;Argument[0];Argument[-1];taint",
|
||||
"java.io;ObjectInputStream;false;ObjectInputStream;;;Argument[0];Argument[-1];taint",
|
||||
"java.io;StringReader;false;StringReader;;;Argument[0];Argument[-1];taint",
|
||||
"java.io;CharArrayReader;false;CharArrayReader;;;Argument[0];Argument[-1];taint",
|
||||
"java.io;BufferedReader;false;BufferedReader;;;Argument[0];Argument[-1];taint",
|
||||
"java.io;InputStreamReader;false;InputStreamReader;;;Argument[0];Argument[-1];taint"
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* A unit class for adding additional source model rows.
|
||||
@@ -284,6 +372,60 @@ private predicate summaryModel(
|
||||
)
|
||||
}
|
||||
|
||||
private predicate relevantPackage(string package) {
|
||||
sourceModel(package, _, _, _, _, _, _, _) or
|
||||
sinkModel(package, _, _, _, _, _, _, _) or
|
||||
summaryModel(package, _, _, _, _, _, _, _, _)
|
||||
}
|
||||
|
||||
private predicate packageLink(string shortpkg, string longpkg) {
|
||||
relevantPackage(shortpkg) and
|
||||
relevantPackage(longpkg) and
|
||||
longpkg.prefix(longpkg.indexOf(".")) = shortpkg
|
||||
}
|
||||
|
||||
private predicate canonicalPackage(string package) {
|
||||
relevantPackage(package) and not packageLink(_, package)
|
||||
}
|
||||
|
||||
private predicate canonicalPkgLink(string package, string subpkg) {
|
||||
canonicalPackage(package) and
|
||||
(subpkg = package or packageLink(package, subpkg))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if CSV framework coverage of `package` is `n` api endpoints of the
|
||||
* kind `(kind, part)`.
|
||||
*/
|
||||
predicate modelCoverage(string package, int pkgs, string kind, string part, int n) {
|
||||
pkgs = strictcount(string subpkg | canonicalPkgLink(package, subpkg)) and
|
||||
(
|
||||
part = "source" and
|
||||
n =
|
||||
strictcount(string subpkg, string type, boolean subtypes, string name, string signature,
|
||||
string ext, string output |
|
||||
canonicalPkgLink(package, subpkg) and
|
||||
sourceModel(subpkg, type, subtypes, name, signature, ext, output, kind)
|
||||
)
|
||||
or
|
||||
part = "sink" and
|
||||
n =
|
||||
strictcount(string subpkg, string type, boolean subtypes, string name, string signature,
|
||||
string ext, string input |
|
||||
canonicalPkgLink(package, subpkg) and
|
||||
sinkModel(subpkg, type, subtypes, name, signature, ext, input, kind)
|
||||
)
|
||||
or
|
||||
part = "summary" and
|
||||
n =
|
||||
strictcount(string subpkg, string type, boolean subtypes, string name, string signature,
|
||||
string ext, string input, string output |
|
||||
canonicalPkgLink(package, subpkg) and
|
||||
summaryModel(subpkg, type, subtypes, name, signature, ext, input, output, kind)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/** Provides a query predicate to check the CSV data for validation errors. */
|
||||
module CsvValidation {
|
||||
/** Holds if some row in a CSV-based flow model appears to contain typos. */
|
||||
@@ -470,11 +612,29 @@ private string getLast(string s) {
|
||||
}
|
||||
|
||||
private predicate parseParam(string c, int n) {
|
||||
specSplit(_, c, _) and c.regexpCapture("Parameter\\[([-0-9]+)\\]", 1).toInt() = 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
|
||||
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) {
|
||||
|
||||
@@ -152,8 +152,7 @@ private class NumberTaintPreservingCallable extends TaintPreservingCallable {
|
||||
|
||||
/** Holds for the types `StringBuilder`, `StringBuffer`, and `StringWriter`. */
|
||||
private predicate stringBuilderType(RefType t) {
|
||||
t.hasQualifiedName("java.lang", "StringBuilder") or
|
||||
t.hasQualifiedName("java.lang", "StringBuffer") or
|
||||
t instanceof StringBuildingType or
|
||||
t.hasQualifiedName("java.io", "StringWriter")
|
||||
}
|
||||
|
||||
|
||||
@@ -68,6 +68,7 @@ private import SSA
|
||||
private import RangeUtils
|
||||
private import semmle.code.java.dataflow.internal.rangeanalysis.SsaReadPositionCommon
|
||||
private import semmle.code.java.controlflow.internal.GuardsLogic
|
||||
private import semmle.code.java.security.Random
|
||||
private import SignAnalysis
|
||||
private import ModulusAnalysis
|
||||
private import semmle.code.java.Reflection
|
||||
@@ -486,14 +487,17 @@ private predicate boundFlowStep(Expr e2, Expr e1, int delta, boolean upper) {
|
||||
or
|
||||
e2.(AssignOrExpr).getSource() = e1 and positive(e2) and delta = 0 and upper = false
|
||||
or
|
||||
exists(MethodAccess ma, Method m |
|
||||
e2 = ma and
|
||||
ma.getMethod() = m and
|
||||
m.hasName("nextInt") and
|
||||
m.getDeclaringType().hasQualifiedName("java.util", "Random") and
|
||||
e1 = ma.getAnArgument() and
|
||||
delta = -1 and
|
||||
upper = true
|
||||
exists(RandomDataSource rds |
|
||||
e2 = rds.getOutput() and
|
||||
(
|
||||
e1 = rds.getUpperBoundExpr() and
|
||||
delta = -1 and
|
||||
upper = true
|
||||
or
|
||||
e1 = rds.getLowerBoundExpr() and
|
||||
delta = 0 and
|
||||
upper = false
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(MethodAccess ma, Method m |
|
||||
|
||||
@@ -41,6 +41,12 @@ private module DispatchImpl {
|
||||
)
|
||||
}
|
||||
|
||||
private RefType getPreciseType(Expr e) {
|
||||
result = e.(FunctionalExpr).getConstructedType()
|
||||
or
|
||||
not e instanceof FunctionalExpr and result = e.getType()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `i`th argument of `ctx` has type `t` and `ctx` is a
|
||||
* relevant call context.
|
||||
@@ -55,7 +61,7 @@ private module DispatchImpl {
|
||||
ctx.getArgument(i) = arg
|
||||
|
|
||||
src = variableTrack(arg) and
|
||||
srctype = src.getType() and
|
||||
srctype = getPreciseType(src) and
|
||||
if src instanceof ClassInstanceExpr then exact = true else exact = false
|
||||
)
|
||||
or
|
||||
@@ -67,11 +73,9 @@ private module DispatchImpl {
|
||||
if ctx instanceof ClassInstanceExpr then exact = true else exact = false
|
||||
)
|
||||
|
|
||||
exists(TypeVariable v | v = srctype |
|
||||
t = v.getUpperBoundType+() and not t instanceof TypeVariable
|
||||
)
|
||||
t = srctype.(BoundedType).getAnUltimateUpperBoundType()
|
||||
or
|
||||
t = srctype and not srctype instanceof TypeVariable
|
||||
t = srctype and not srctype instanceof BoundedType
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -444,8 +444,8 @@ private module Stage1 {
|
||||
// read
|
||||
exists(Node mid, Content c |
|
||||
read(node, c, mid) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, toReturn, config)
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
@@ -471,18 +471,18 @@ private module Stage1 {
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
fwdFlow(node, unbind(config)) and
|
||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||
read(node, c, mid) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, _, config)
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowStore(Content c, Node node, boolean toReturn, Configuration config) {
|
||||
exists(Node mid, TypedContent tc |
|
||||
revFlow(mid, toReturn, config) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
store(node, tc, mid, _) and
|
||||
c = tc.getContent()
|
||||
)
|
||||
@@ -552,8 +552,8 @@ private module Stage1 {
|
||||
Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
exists(Content c |
|
||||
revFlowIsReadAndStored(c, config) and
|
||||
revFlow(node2, unbind(config)) and
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlow(node2, pragma[only_bind_into](config)) and
|
||||
store(node1, tc, node2, contentType) and
|
||||
c = tc.getContent() and
|
||||
exists(ap1)
|
||||
@@ -562,8 +562,8 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(Node n1, Content c, Node n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, config) and
|
||||
revFlow(n2, unbind(config)) and
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2)
|
||||
}
|
||||
|
||||
@@ -626,9 +626,6 @@ private module Stage1 {
|
||||
/* End: Stage 1 logic. */
|
||||
}
|
||||
|
||||
bindingset[result, b]
|
||||
private boolean unbindBool(boolean b) { result != b.booleanNot() }
|
||||
|
||||
pragma[noinline]
|
||||
private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
|
||||
Stage1::revFlow(node2, config) and
|
||||
@@ -864,16 +861,16 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -1045,9 +1042,9 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -1059,9 +1056,9 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -1114,9 +1111,10 @@ private module Stage2 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1182,9 +1180,10 @@ private module Stage2 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ unbindBool(ap2), _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1240,8 +1239,8 @@ private predicate flowOutOfCallNodeCand2(
|
||||
DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, config) and
|
||||
Stage2::revFlow(node1, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node1, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1250,8 +1249,8 @@ private predicate flowIntoCallNodeCand2(
|
||||
Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, config) and
|
||||
Stage2::revFlow(node1, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node1, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
private module LocalFlowBigStep {
|
||||
@@ -1306,8 +1305,8 @@ private module LocalFlowBigStep {
|
||||
pragma[noinline]
|
||||
private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) {
|
||||
additionalLocalFlowStepNodeCand1(node1, node2, config) and
|
||||
Stage2::revFlow(node1, _, _, false, config) and
|
||||
Stage2::revFlow(node2, _, _, false, unbind(config))
|
||||
Stage2::revFlow(node1, _, _, false, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node2, _, _, false, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1324,7 +1323,7 @@ private module LocalFlowBigStep {
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, config) and
|
||||
localFlowEntry(node1, pragma[only_bind_into](config)) and
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
@@ -1337,22 +1336,22 @@ private module LocalFlowBigStep {
|
||||
node1 != node2 and
|
||||
cc.relevantFor(getNodeEnclosingCallable(node1)) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, pragma[only_bind_into](config), cc) and
|
||||
localFlowStepNodeCand1(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
localFlowStepPlus(node1, mid, _, _, pragma[only_bind_into](config), cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2) and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1459,6 +1458,13 @@ private module Stage3 {
|
||||
PrevStage::revFlow(node, _, _, apa, config)
|
||||
}
|
||||
|
||||
bindingset[result, apa]
|
||||
private ApApprox unbindApa(ApApprox apa) {
|
||||
exists(ApApprox apa0 |
|
||||
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable with access path `ap` from a source in the
|
||||
* configuration `config`.
|
||||
@@ -1470,7 +1476,7 @@ private module Stage3 {
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
fwdFlow0(node, cc, argAp, ap, config) and
|
||||
flowCand(node, unbindBool(getApprox(ap)), config) and
|
||||
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||
filter(node, ap)
|
||||
}
|
||||
|
||||
@@ -1494,16 +1500,16 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -1548,7 +1554,7 @@ private module Stage3 {
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||
PrevStage::storeStepCand(node1, unbindBool(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
typecheckStore(ap1, contentType)
|
||||
)
|
||||
}
|
||||
@@ -1627,7 +1633,7 @@ private module Stage3 {
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindBool(getApprox(ap)), config)
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1675,9 +1681,9 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -1689,9 +1695,9 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -1744,9 +1750,10 @@ private module Stage3 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1812,9 +1819,10 @@ private module Stage3 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2125,8 +2133,11 @@ private module Stage4 {
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc, getNodeEnclosingCallable(node))
|
||||
exists(Cc cc0 |
|
||||
cc = pragma[only_bind_into](cc0) and
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
|
||||
)
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2141,8 +2152,8 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, config) and
|
||||
PrevStage::revFlow(node1, _, _, _, unbind(config))
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -2151,8 +2162,8 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, config) and
|
||||
PrevStage::revFlow(node1, _, _, _, unbind(config))
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
bindingset[node, ap]
|
||||
@@ -2167,6 +2178,13 @@ private module Stage4 {
|
||||
PrevStage::revFlow(node, _, _, apa, config)
|
||||
}
|
||||
|
||||
bindingset[result, apa]
|
||||
private ApApprox unbindApa(ApApprox apa) {
|
||||
exists(ApApprox apa0 |
|
||||
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable with access path `ap` from a source in the
|
||||
* configuration `config`.
|
||||
@@ -2178,7 +2196,7 @@ private module Stage4 {
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
fwdFlow0(node, cc, argAp, ap, config) and
|
||||
flowCand(node, getApprox(ap), config) and
|
||||
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||
filter(node, ap)
|
||||
}
|
||||
|
||||
@@ -2202,16 +2220,16 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -2256,7 +2274,7 @@ private module Stage4 {
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
typecheckStore(ap1, contentType)
|
||||
)
|
||||
}
|
||||
@@ -2335,7 +2353,7 @@ private module Stage4 {
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2383,9 +2401,9 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -2397,9 +2415,9 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -2452,9 +2470,10 @@ private module Stage4 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2520,9 +2539,10 @@ private module Stage4 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2574,7 +2594,9 @@ private module Stage4 {
|
||||
}
|
||||
|
||||
bindingset[conf, result]
|
||||
private Configuration unbind(Configuration conf) { result >= conf and result <= conf }
|
||||
private Configuration unbindConf(Configuration conf) {
|
||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||
}
|
||||
|
||||
private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration config) {
|
||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
||||
@@ -2744,13 +2766,13 @@ private newtype TPathNode =
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
pathStep(mid, node, cc, sc, ap) and
|
||||
config = mid.getConfiguration() and
|
||||
Stage4::revFlow(node, _, _, ap.getApprox(), unbind(config))
|
||||
pragma[only_bind_into](config) = mid.getConfiguration() and
|
||||
Stage4::revFlow(node, _, _, ap.getApprox(), pragma[only_bind_into](config))
|
||||
)
|
||||
} or
|
||||
TPathNodeSink(Node node, Configuration config) {
|
||||
config.isSink(node) and
|
||||
Stage4::revFlow(node, unbind(config)) and
|
||||
pragma[only_bind_into](config).isSink(node) and
|
||||
Stage4::revFlow(node, pragma[only_bind_into](config)) and
|
||||
(
|
||||
// A sink that is also a source ...
|
||||
config.isSource(node)
|
||||
@@ -2758,7 +2780,7 @@ private newtype TPathNode =
|
||||
// ... or a sink that can be reached from a source
|
||||
exists(PathNodeMid mid |
|
||||
pathStep(mid, node, _, _, TAccessPathNil(_)) and
|
||||
config = unbind(mid.getConfiguration())
|
||||
pragma[only_bind_into](config) = mid.getConfiguration()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -3055,7 +3077,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
||||
|
||||
private PathNodeMid getSuccMid() {
|
||||
pathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx(), result.getAp()) and
|
||||
result.getConfiguration() = unbind(this.getConfiguration())
|
||||
result.getConfiguration() = unbindConf(this.getConfiguration())
|
||||
}
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
@@ -3067,7 +3089,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
||||
mid = getSuccMid() and
|
||||
mid.getNode() = sink.getNode() and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
sink.getConfiguration() = unbind(mid.getConfiguration()) and
|
||||
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
|
||||
result = sink
|
||||
)
|
||||
}
|
||||
@@ -3298,7 +3320,7 @@ private predicate pathThroughCallable0(
|
||||
) {
|
||||
exists(CallContext innercc, SummaryCtx sc |
|
||||
pathIntoCallable(mid, _, cc, innercc, sc, call) and
|
||||
paramFlowsThrough(kind, innercc, sc, ap, apa, unbind(mid.getConfiguration()))
|
||||
paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3310,7 +3332,7 @@ pragma[noinline]
|
||||
private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) {
|
||||
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
|
||||
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
|
||||
out = getAnOutNodeFlow(kind, call, apa, unbind(mid.getConfiguration()))
|
||||
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3433,8 +3455,8 @@ private module FlowExploration {
|
||||
private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) {
|
||||
exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config |
|
||||
callableStep(c1, c2, config) and
|
||||
ce1 = TCallable(c1, config) and
|
||||
ce2 = TCallable(c2, unbind(config))
|
||||
ce1 = TCallable(c1, pragma[only_bind_into](config)) and
|
||||
ce2 = TCallable(c2, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
exists(Node n, Configuration config |
|
||||
|
||||
@@ -444,8 +444,8 @@ private module Stage1 {
|
||||
// read
|
||||
exists(Node mid, Content c |
|
||||
read(node, c, mid) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, toReturn, config)
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
@@ -471,18 +471,18 @@ private module Stage1 {
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
fwdFlow(node, unbind(config)) and
|
||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||
read(node, c, mid) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, _, config)
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowStore(Content c, Node node, boolean toReturn, Configuration config) {
|
||||
exists(Node mid, TypedContent tc |
|
||||
revFlow(mid, toReturn, config) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
store(node, tc, mid, _) and
|
||||
c = tc.getContent()
|
||||
)
|
||||
@@ -552,8 +552,8 @@ private module Stage1 {
|
||||
Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
exists(Content c |
|
||||
revFlowIsReadAndStored(c, config) and
|
||||
revFlow(node2, unbind(config)) and
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlow(node2, pragma[only_bind_into](config)) and
|
||||
store(node1, tc, node2, contentType) and
|
||||
c = tc.getContent() and
|
||||
exists(ap1)
|
||||
@@ -562,8 +562,8 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(Node n1, Content c, Node n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, config) and
|
||||
revFlow(n2, unbind(config)) and
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2)
|
||||
}
|
||||
|
||||
@@ -626,9 +626,6 @@ private module Stage1 {
|
||||
/* End: Stage 1 logic. */
|
||||
}
|
||||
|
||||
bindingset[result, b]
|
||||
private boolean unbindBool(boolean b) { result != b.booleanNot() }
|
||||
|
||||
pragma[noinline]
|
||||
private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
|
||||
Stage1::revFlow(node2, config) and
|
||||
@@ -864,16 +861,16 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -1045,9 +1042,9 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -1059,9 +1056,9 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -1114,9 +1111,10 @@ private module Stage2 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1182,9 +1180,10 @@ private module Stage2 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ unbindBool(ap2), _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1240,8 +1239,8 @@ private predicate flowOutOfCallNodeCand2(
|
||||
DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, config) and
|
||||
Stage2::revFlow(node1, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node1, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1250,8 +1249,8 @@ private predicate flowIntoCallNodeCand2(
|
||||
Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, config) and
|
||||
Stage2::revFlow(node1, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node1, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
private module LocalFlowBigStep {
|
||||
@@ -1306,8 +1305,8 @@ private module LocalFlowBigStep {
|
||||
pragma[noinline]
|
||||
private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) {
|
||||
additionalLocalFlowStepNodeCand1(node1, node2, config) and
|
||||
Stage2::revFlow(node1, _, _, false, config) and
|
||||
Stage2::revFlow(node2, _, _, false, unbind(config))
|
||||
Stage2::revFlow(node1, _, _, false, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node2, _, _, false, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1324,7 +1323,7 @@ private module LocalFlowBigStep {
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, config) and
|
||||
localFlowEntry(node1, pragma[only_bind_into](config)) and
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
@@ -1337,22 +1336,22 @@ private module LocalFlowBigStep {
|
||||
node1 != node2 and
|
||||
cc.relevantFor(getNodeEnclosingCallable(node1)) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, pragma[only_bind_into](config), cc) and
|
||||
localFlowStepNodeCand1(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
localFlowStepPlus(node1, mid, _, _, pragma[only_bind_into](config), cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2) and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1459,6 +1458,13 @@ private module Stage3 {
|
||||
PrevStage::revFlow(node, _, _, apa, config)
|
||||
}
|
||||
|
||||
bindingset[result, apa]
|
||||
private ApApprox unbindApa(ApApprox apa) {
|
||||
exists(ApApprox apa0 |
|
||||
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable with access path `ap` from a source in the
|
||||
* configuration `config`.
|
||||
@@ -1470,7 +1476,7 @@ private module Stage3 {
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
fwdFlow0(node, cc, argAp, ap, config) and
|
||||
flowCand(node, unbindBool(getApprox(ap)), config) and
|
||||
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||
filter(node, ap)
|
||||
}
|
||||
|
||||
@@ -1494,16 +1500,16 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -1548,7 +1554,7 @@ private module Stage3 {
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||
PrevStage::storeStepCand(node1, unbindBool(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
typecheckStore(ap1, contentType)
|
||||
)
|
||||
}
|
||||
@@ -1627,7 +1633,7 @@ private module Stage3 {
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindBool(getApprox(ap)), config)
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1675,9 +1681,9 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -1689,9 +1695,9 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -1744,9 +1750,10 @@ private module Stage3 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1812,9 +1819,10 @@ private module Stage3 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2125,8 +2133,11 @@ private module Stage4 {
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc, getNodeEnclosingCallable(node))
|
||||
exists(Cc cc0 |
|
||||
cc = pragma[only_bind_into](cc0) and
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
|
||||
)
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2141,8 +2152,8 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, config) and
|
||||
PrevStage::revFlow(node1, _, _, _, unbind(config))
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -2151,8 +2162,8 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, config) and
|
||||
PrevStage::revFlow(node1, _, _, _, unbind(config))
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
bindingset[node, ap]
|
||||
@@ -2167,6 +2178,13 @@ private module Stage4 {
|
||||
PrevStage::revFlow(node, _, _, apa, config)
|
||||
}
|
||||
|
||||
bindingset[result, apa]
|
||||
private ApApprox unbindApa(ApApprox apa) {
|
||||
exists(ApApprox apa0 |
|
||||
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable with access path `ap` from a source in the
|
||||
* configuration `config`.
|
||||
@@ -2178,7 +2196,7 @@ private module Stage4 {
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
fwdFlow0(node, cc, argAp, ap, config) and
|
||||
flowCand(node, getApprox(ap), config) and
|
||||
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||
filter(node, ap)
|
||||
}
|
||||
|
||||
@@ -2202,16 +2220,16 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -2256,7 +2274,7 @@ private module Stage4 {
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
typecheckStore(ap1, contentType)
|
||||
)
|
||||
}
|
||||
@@ -2335,7 +2353,7 @@ private module Stage4 {
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2383,9 +2401,9 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -2397,9 +2415,9 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -2452,9 +2470,10 @@ private module Stage4 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2520,9 +2539,10 @@ private module Stage4 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2574,7 +2594,9 @@ private module Stage4 {
|
||||
}
|
||||
|
||||
bindingset[conf, result]
|
||||
private Configuration unbind(Configuration conf) { result >= conf and result <= conf }
|
||||
private Configuration unbindConf(Configuration conf) {
|
||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||
}
|
||||
|
||||
private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration config) {
|
||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
||||
@@ -2744,13 +2766,13 @@ private newtype TPathNode =
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
pathStep(mid, node, cc, sc, ap) and
|
||||
config = mid.getConfiguration() and
|
||||
Stage4::revFlow(node, _, _, ap.getApprox(), unbind(config))
|
||||
pragma[only_bind_into](config) = mid.getConfiguration() and
|
||||
Stage4::revFlow(node, _, _, ap.getApprox(), pragma[only_bind_into](config))
|
||||
)
|
||||
} or
|
||||
TPathNodeSink(Node node, Configuration config) {
|
||||
config.isSink(node) and
|
||||
Stage4::revFlow(node, unbind(config)) and
|
||||
pragma[only_bind_into](config).isSink(node) and
|
||||
Stage4::revFlow(node, pragma[only_bind_into](config)) and
|
||||
(
|
||||
// A sink that is also a source ...
|
||||
config.isSource(node)
|
||||
@@ -2758,7 +2780,7 @@ private newtype TPathNode =
|
||||
// ... or a sink that can be reached from a source
|
||||
exists(PathNodeMid mid |
|
||||
pathStep(mid, node, _, _, TAccessPathNil(_)) and
|
||||
config = unbind(mid.getConfiguration())
|
||||
pragma[only_bind_into](config) = mid.getConfiguration()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -3055,7 +3077,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
||||
|
||||
private PathNodeMid getSuccMid() {
|
||||
pathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx(), result.getAp()) and
|
||||
result.getConfiguration() = unbind(this.getConfiguration())
|
||||
result.getConfiguration() = unbindConf(this.getConfiguration())
|
||||
}
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
@@ -3067,7 +3089,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
||||
mid = getSuccMid() and
|
||||
mid.getNode() = sink.getNode() and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
sink.getConfiguration() = unbind(mid.getConfiguration()) and
|
||||
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
|
||||
result = sink
|
||||
)
|
||||
}
|
||||
@@ -3298,7 +3320,7 @@ private predicate pathThroughCallable0(
|
||||
) {
|
||||
exists(CallContext innercc, SummaryCtx sc |
|
||||
pathIntoCallable(mid, _, cc, innercc, sc, call) and
|
||||
paramFlowsThrough(kind, innercc, sc, ap, apa, unbind(mid.getConfiguration()))
|
||||
paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3310,7 +3332,7 @@ pragma[noinline]
|
||||
private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) {
|
||||
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
|
||||
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
|
||||
out = getAnOutNodeFlow(kind, call, apa, unbind(mid.getConfiguration()))
|
||||
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3433,8 +3455,8 @@ private module FlowExploration {
|
||||
private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) {
|
||||
exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config |
|
||||
callableStep(c1, c2, config) and
|
||||
ce1 = TCallable(c1, config) and
|
||||
ce2 = TCallable(c2, unbind(config))
|
||||
ce1 = TCallable(c1, pragma[only_bind_into](config)) and
|
||||
ce2 = TCallable(c2, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
exists(Node n, Configuration config |
|
||||
|
||||
@@ -444,8 +444,8 @@ private module Stage1 {
|
||||
// read
|
||||
exists(Node mid, Content c |
|
||||
read(node, c, mid) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, toReturn, config)
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
@@ -471,18 +471,18 @@ private module Stage1 {
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
fwdFlow(node, unbind(config)) and
|
||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||
read(node, c, mid) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, _, config)
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowStore(Content c, Node node, boolean toReturn, Configuration config) {
|
||||
exists(Node mid, TypedContent tc |
|
||||
revFlow(mid, toReturn, config) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
store(node, tc, mid, _) and
|
||||
c = tc.getContent()
|
||||
)
|
||||
@@ -552,8 +552,8 @@ private module Stage1 {
|
||||
Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
exists(Content c |
|
||||
revFlowIsReadAndStored(c, config) and
|
||||
revFlow(node2, unbind(config)) and
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlow(node2, pragma[only_bind_into](config)) and
|
||||
store(node1, tc, node2, contentType) and
|
||||
c = tc.getContent() and
|
||||
exists(ap1)
|
||||
@@ -562,8 +562,8 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(Node n1, Content c, Node n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, config) and
|
||||
revFlow(n2, unbind(config)) and
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2)
|
||||
}
|
||||
|
||||
@@ -626,9 +626,6 @@ private module Stage1 {
|
||||
/* End: Stage 1 logic. */
|
||||
}
|
||||
|
||||
bindingset[result, b]
|
||||
private boolean unbindBool(boolean b) { result != b.booleanNot() }
|
||||
|
||||
pragma[noinline]
|
||||
private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
|
||||
Stage1::revFlow(node2, config) and
|
||||
@@ -864,16 +861,16 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -1045,9 +1042,9 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -1059,9 +1056,9 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -1114,9 +1111,10 @@ private module Stage2 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1182,9 +1180,10 @@ private module Stage2 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ unbindBool(ap2), _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1240,8 +1239,8 @@ private predicate flowOutOfCallNodeCand2(
|
||||
DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, config) and
|
||||
Stage2::revFlow(node1, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node1, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1250,8 +1249,8 @@ private predicate flowIntoCallNodeCand2(
|
||||
Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, config) and
|
||||
Stage2::revFlow(node1, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node1, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
private module LocalFlowBigStep {
|
||||
@@ -1306,8 +1305,8 @@ private module LocalFlowBigStep {
|
||||
pragma[noinline]
|
||||
private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) {
|
||||
additionalLocalFlowStepNodeCand1(node1, node2, config) and
|
||||
Stage2::revFlow(node1, _, _, false, config) and
|
||||
Stage2::revFlow(node2, _, _, false, unbind(config))
|
||||
Stage2::revFlow(node1, _, _, false, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node2, _, _, false, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1324,7 +1323,7 @@ private module LocalFlowBigStep {
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, config) and
|
||||
localFlowEntry(node1, pragma[only_bind_into](config)) and
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
@@ -1337,22 +1336,22 @@ private module LocalFlowBigStep {
|
||||
node1 != node2 and
|
||||
cc.relevantFor(getNodeEnclosingCallable(node1)) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, pragma[only_bind_into](config), cc) and
|
||||
localFlowStepNodeCand1(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
localFlowStepPlus(node1, mid, _, _, pragma[only_bind_into](config), cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2) and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1459,6 +1458,13 @@ private module Stage3 {
|
||||
PrevStage::revFlow(node, _, _, apa, config)
|
||||
}
|
||||
|
||||
bindingset[result, apa]
|
||||
private ApApprox unbindApa(ApApprox apa) {
|
||||
exists(ApApprox apa0 |
|
||||
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable with access path `ap` from a source in the
|
||||
* configuration `config`.
|
||||
@@ -1470,7 +1476,7 @@ private module Stage3 {
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
fwdFlow0(node, cc, argAp, ap, config) and
|
||||
flowCand(node, unbindBool(getApprox(ap)), config) and
|
||||
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||
filter(node, ap)
|
||||
}
|
||||
|
||||
@@ -1494,16 +1500,16 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -1548,7 +1554,7 @@ private module Stage3 {
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||
PrevStage::storeStepCand(node1, unbindBool(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
typecheckStore(ap1, contentType)
|
||||
)
|
||||
}
|
||||
@@ -1627,7 +1633,7 @@ private module Stage3 {
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindBool(getApprox(ap)), config)
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1675,9 +1681,9 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -1689,9 +1695,9 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -1744,9 +1750,10 @@ private module Stage3 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1812,9 +1819,10 @@ private module Stage3 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2125,8 +2133,11 @@ private module Stage4 {
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc, getNodeEnclosingCallable(node))
|
||||
exists(Cc cc0 |
|
||||
cc = pragma[only_bind_into](cc0) and
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
|
||||
)
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2141,8 +2152,8 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, config) and
|
||||
PrevStage::revFlow(node1, _, _, _, unbind(config))
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -2151,8 +2162,8 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, config) and
|
||||
PrevStage::revFlow(node1, _, _, _, unbind(config))
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
bindingset[node, ap]
|
||||
@@ -2167,6 +2178,13 @@ private module Stage4 {
|
||||
PrevStage::revFlow(node, _, _, apa, config)
|
||||
}
|
||||
|
||||
bindingset[result, apa]
|
||||
private ApApprox unbindApa(ApApprox apa) {
|
||||
exists(ApApprox apa0 |
|
||||
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable with access path `ap` from a source in the
|
||||
* configuration `config`.
|
||||
@@ -2178,7 +2196,7 @@ private module Stage4 {
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
fwdFlow0(node, cc, argAp, ap, config) and
|
||||
flowCand(node, getApprox(ap), config) and
|
||||
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||
filter(node, ap)
|
||||
}
|
||||
|
||||
@@ -2202,16 +2220,16 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -2256,7 +2274,7 @@ private module Stage4 {
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
typecheckStore(ap1, contentType)
|
||||
)
|
||||
}
|
||||
@@ -2335,7 +2353,7 @@ private module Stage4 {
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2383,9 +2401,9 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -2397,9 +2415,9 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -2452,9 +2470,10 @@ private module Stage4 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2520,9 +2539,10 @@ private module Stage4 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2574,7 +2594,9 @@ private module Stage4 {
|
||||
}
|
||||
|
||||
bindingset[conf, result]
|
||||
private Configuration unbind(Configuration conf) { result >= conf and result <= conf }
|
||||
private Configuration unbindConf(Configuration conf) {
|
||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||
}
|
||||
|
||||
private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration config) {
|
||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
||||
@@ -2744,13 +2766,13 @@ private newtype TPathNode =
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
pathStep(mid, node, cc, sc, ap) and
|
||||
config = mid.getConfiguration() and
|
||||
Stage4::revFlow(node, _, _, ap.getApprox(), unbind(config))
|
||||
pragma[only_bind_into](config) = mid.getConfiguration() and
|
||||
Stage4::revFlow(node, _, _, ap.getApprox(), pragma[only_bind_into](config))
|
||||
)
|
||||
} or
|
||||
TPathNodeSink(Node node, Configuration config) {
|
||||
config.isSink(node) and
|
||||
Stage4::revFlow(node, unbind(config)) and
|
||||
pragma[only_bind_into](config).isSink(node) and
|
||||
Stage4::revFlow(node, pragma[only_bind_into](config)) and
|
||||
(
|
||||
// A sink that is also a source ...
|
||||
config.isSource(node)
|
||||
@@ -2758,7 +2780,7 @@ private newtype TPathNode =
|
||||
// ... or a sink that can be reached from a source
|
||||
exists(PathNodeMid mid |
|
||||
pathStep(mid, node, _, _, TAccessPathNil(_)) and
|
||||
config = unbind(mid.getConfiguration())
|
||||
pragma[only_bind_into](config) = mid.getConfiguration()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -3055,7 +3077,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
||||
|
||||
private PathNodeMid getSuccMid() {
|
||||
pathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx(), result.getAp()) and
|
||||
result.getConfiguration() = unbind(this.getConfiguration())
|
||||
result.getConfiguration() = unbindConf(this.getConfiguration())
|
||||
}
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
@@ -3067,7 +3089,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
||||
mid = getSuccMid() and
|
||||
mid.getNode() = sink.getNode() and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
sink.getConfiguration() = unbind(mid.getConfiguration()) and
|
||||
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
|
||||
result = sink
|
||||
)
|
||||
}
|
||||
@@ -3298,7 +3320,7 @@ private predicate pathThroughCallable0(
|
||||
) {
|
||||
exists(CallContext innercc, SummaryCtx sc |
|
||||
pathIntoCallable(mid, _, cc, innercc, sc, call) and
|
||||
paramFlowsThrough(kind, innercc, sc, ap, apa, unbind(mid.getConfiguration()))
|
||||
paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3310,7 +3332,7 @@ pragma[noinline]
|
||||
private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) {
|
||||
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
|
||||
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
|
||||
out = getAnOutNodeFlow(kind, call, apa, unbind(mid.getConfiguration()))
|
||||
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3433,8 +3455,8 @@ private module FlowExploration {
|
||||
private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) {
|
||||
exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config |
|
||||
callableStep(c1, c2, config) and
|
||||
ce1 = TCallable(c1, config) and
|
||||
ce2 = TCallable(c2, unbind(config))
|
||||
ce1 = TCallable(c1, pragma[only_bind_into](config)) and
|
||||
ce2 = TCallable(c2, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
exists(Node n, Configuration config |
|
||||
|
||||
@@ -444,8 +444,8 @@ private module Stage1 {
|
||||
// read
|
||||
exists(Node mid, Content c |
|
||||
read(node, c, mid) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, toReturn, config)
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
@@ -471,18 +471,18 @@ private module Stage1 {
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
fwdFlow(node, unbind(config)) and
|
||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||
read(node, c, mid) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, _, config)
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowStore(Content c, Node node, boolean toReturn, Configuration config) {
|
||||
exists(Node mid, TypedContent tc |
|
||||
revFlow(mid, toReturn, config) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
store(node, tc, mid, _) and
|
||||
c = tc.getContent()
|
||||
)
|
||||
@@ -552,8 +552,8 @@ private module Stage1 {
|
||||
Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
exists(Content c |
|
||||
revFlowIsReadAndStored(c, config) and
|
||||
revFlow(node2, unbind(config)) and
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlow(node2, pragma[only_bind_into](config)) and
|
||||
store(node1, tc, node2, contentType) and
|
||||
c = tc.getContent() and
|
||||
exists(ap1)
|
||||
@@ -562,8 +562,8 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(Node n1, Content c, Node n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, config) and
|
||||
revFlow(n2, unbind(config)) and
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2)
|
||||
}
|
||||
|
||||
@@ -626,9 +626,6 @@ private module Stage1 {
|
||||
/* End: Stage 1 logic. */
|
||||
}
|
||||
|
||||
bindingset[result, b]
|
||||
private boolean unbindBool(boolean b) { result != b.booleanNot() }
|
||||
|
||||
pragma[noinline]
|
||||
private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
|
||||
Stage1::revFlow(node2, config) and
|
||||
@@ -864,16 +861,16 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -1045,9 +1042,9 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -1059,9 +1056,9 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -1114,9 +1111,10 @@ private module Stage2 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1182,9 +1180,10 @@ private module Stage2 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ unbindBool(ap2), _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1240,8 +1239,8 @@ private predicate flowOutOfCallNodeCand2(
|
||||
DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, config) and
|
||||
Stage2::revFlow(node1, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node1, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1250,8 +1249,8 @@ private predicate flowIntoCallNodeCand2(
|
||||
Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, config) and
|
||||
Stage2::revFlow(node1, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node1, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
private module LocalFlowBigStep {
|
||||
@@ -1306,8 +1305,8 @@ private module LocalFlowBigStep {
|
||||
pragma[noinline]
|
||||
private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) {
|
||||
additionalLocalFlowStepNodeCand1(node1, node2, config) and
|
||||
Stage2::revFlow(node1, _, _, false, config) and
|
||||
Stage2::revFlow(node2, _, _, false, unbind(config))
|
||||
Stage2::revFlow(node1, _, _, false, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node2, _, _, false, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1324,7 +1323,7 @@ private module LocalFlowBigStep {
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, config) and
|
||||
localFlowEntry(node1, pragma[only_bind_into](config)) and
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
@@ -1337,22 +1336,22 @@ private module LocalFlowBigStep {
|
||||
node1 != node2 and
|
||||
cc.relevantFor(getNodeEnclosingCallable(node1)) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, pragma[only_bind_into](config), cc) and
|
||||
localFlowStepNodeCand1(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
localFlowStepPlus(node1, mid, _, _, pragma[only_bind_into](config), cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2) and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1459,6 +1458,13 @@ private module Stage3 {
|
||||
PrevStage::revFlow(node, _, _, apa, config)
|
||||
}
|
||||
|
||||
bindingset[result, apa]
|
||||
private ApApprox unbindApa(ApApprox apa) {
|
||||
exists(ApApprox apa0 |
|
||||
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable with access path `ap` from a source in the
|
||||
* configuration `config`.
|
||||
@@ -1470,7 +1476,7 @@ private module Stage3 {
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
fwdFlow0(node, cc, argAp, ap, config) and
|
||||
flowCand(node, unbindBool(getApprox(ap)), config) and
|
||||
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||
filter(node, ap)
|
||||
}
|
||||
|
||||
@@ -1494,16 +1500,16 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -1548,7 +1554,7 @@ private module Stage3 {
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||
PrevStage::storeStepCand(node1, unbindBool(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
typecheckStore(ap1, contentType)
|
||||
)
|
||||
}
|
||||
@@ -1627,7 +1633,7 @@ private module Stage3 {
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindBool(getApprox(ap)), config)
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1675,9 +1681,9 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -1689,9 +1695,9 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -1744,9 +1750,10 @@ private module Stage3 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1812,9 +1819,10 @@ private module Stage3 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2125,8 +2133,11 @@ private module Stage4 {
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc, getNodeEnclosingCallable(node))
|
||||
exists(Cc cc0 |
|
||||
cc = pragma[only_bind_into](cc0) and
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
|
||||
)
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2141,8 +2152,8 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, config) and
|
||||
PrevStage::revFlow(node1, _, _, _, unbind(config))
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -2151,8 +2162,8 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, config) and
|
||||
PrevStage::revFlow(node1, _, _, _, unbind(config))
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
bindingset[node, ap]
|
||||
@@ -2167,6 +2178,13 @@ private module Stage4 {
|
||||
PrevStage::revFlow(node, _, _, apa, config)
|
||||
}
|
||||
|
||||
bindingset[result, apa]
|
||||
private ApApprox unbindApa(ApApprox apa) {
|
||||
exists(ApApprox apa0 |
|
||||
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable with access path `ap` from a source in the
|
||||
* configuration `config`.
|
||||
@@ -2178,7 +2196,7 @@ private module Stage4 {
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
fwdFlow0(node, cc, argAp, ap, config) and
|
||||
flowCand(node, getApprox(ap), config) and
|
||||
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||
filter(node, ap)
|
||||
}
|
||||
|
||||
@@ -2202,16 +2220,16 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -2256,7 +2274,7 @@ private module Stage4 {
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
typecheckStore(ap1, contentType)
|
||||
)
|
||||
}
|
||||
@@ -2335,7 +2353,7 @@ private module Stage4 {
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2383,9 +2401,9 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -2397,9 +2415,9 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -2452,9 +2470,10 @@ private module Stage4 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2520,9 +2539,10 @@ private module Stage4 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2574,7 +2594,9 @@ private module Stage4 {
|
||||
}
|
||||
|
||||
bindingset[conf, result]
|
||||
private Configuration unbind(Configuration conf) { result >= conf and result <= conf }
|
||||
private Configuration unbindConf(Configuration conf) {
|
||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||
}
|
||||
|
||||
private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration config) {
|
||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
||||
@@ -2744,13 +2766,13 @@ private newtype TPathNode =
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
pathStep(mid, node, cc, sc, ap) and
|
||||
config = mid.getConfiguration() and
|
||||
Stage4::revFlow(node, _, _, ap.getApprox(), unbind(config))
|
||||
pragma[only_bind_into](config) = mid.getConfiguration() and
|
||||
Stage4::revFlow(node, _, _, ap.getApprox(), pragma[only_bind_into](config))
|
||||
)
|
||||
} or
|
||||
TPathNodeSink(Node node, Configuration config) {
|
||||
config.isSink(node) and
|
||||
Stage4::revFlow(node, unbind(config)) and
|
||||
pragma[only_bind_into](config).isSink(node) and
|
||||
Stage4::revFlow(node, pragma[only_bind_into](config)) and
|
||||
(
|
||||
// A sink that is also a source ...
|
||||
config.isSource(node)
|
||||
@@ -2758,7 +2780,7 @@ private newtype TPathNode =
|
||||
// ... or a sink that can be reached from a source
|
||||
exists(PathNodeMid mid |
|
||||
pathStep(mid, node, _, _, TAccessPathNil(_)) and
|
||||
config = unbind(mid.getConfiguration())
|
||||
pragma[only_bind_into](config) = mid.getConfiguration()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -3055,7 +3077,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
||||
|
||||
private PathNodeMid getSuccMid() {
|
||||
pathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx(), result.getAp()) and
|
||||
result.getConfiguration() = unbind(this.getConfiguration())
|
||||
result.getConfiguration() = unbindConf(this.getConfiguration())
|
||||
}
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
@@ -3067,7 +3089,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
||||
mid = getSuccMid() and
|
||||
mid.getNode() = sink.getNode() and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
sink.getConfiguration() = unbind(mid.getConfiguration()) and
|
||||
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
|
||||
result = sink
|
||||
)
|
||||
}
|
||||
@@ -3298,7 +3320,7 @@ private predicate pathThroughCallable0(
|
||||
) {
|
||||
exists(CallContext innercc, SummaryCtx sc |
|
||||
pathIntoCallable(mid, _, cc, innercc, sc, call) and
|
||||
paramFlowsThrough(kind, innercc, sc, ap, apa, unbind(mid.getConfiguration()))
|
||||
paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3310,7 +3332,7 @@ pragma[noinline]
|
||||
private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) {
|
||||
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
|
||||
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
|
||||
out = getAnOutNodeFlow(kind, call, apa, unbind(mid.getConfiguration()))
|
||||
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3433,8 +3455,8 @@ private module FlowExploration {
|
||||
private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) {
|
||||
exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config |
|
||||
callableStep(c1, c2, config) and
|
||||
ce1 = TCallable(c1, config) and
|
||||
ce2 = TCallable(c2, unbind(config))
|
||||
ce1 = TCallable(c1, pragma[only_bind_into](config)) and
|
||||
ce2 = TCallable(c2, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
exists(Node n, Configuration config |
|
||||
|
||||
@@ -444,8 +444,8 @@ private module Stage1 {
|
||||
// read
|
||||
exists(Node mid, Content c |
|
||||
read(node, c, mid) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, toReturn, config)
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
@@ -471,18 +471,18 @@ private module Stage1 {
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
fwdFlow(node, unbind(config)) and
|
||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||
read(node, c, mid) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, _, config)
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowStore(Content c, Node node, boolean toReturn, Configuration config) {
|
||||
exists(Node mid, TypedContent tc |
|
||||
revFlow(mid, toReturn, config) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
store(node, tc, mid, _) and
|
||||
c = tc.getContent()
|
||||
)
|
||||
@@ -552,8 +552,8 @@ private module Stage1 {
|
||||
Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
exists(Content c |
|
||||
revFlowIsReadAndStored(c, config) and
|
||||
revFlow(node2, unbind(config)) and
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlow(node2, pragma[only_bind_into](config)) and
|
||||
store(node1, tc, node2, contentType) and
|
||||
c = tc.getContent() and
|
||||
exists(ap1)
|
||||
@@ -562,8 +562,8 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(Node n1, Content c, Node n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, config) and
|
||||
revFlow(n2, unbind(config)) and
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2)
|
||||
}
|
||||
|
||||
@@ -626,9 +626,6 @@ private module Stage1 {
|
||||
/* End: Stage 1 logic. */
|
||||
}
|
||||
|
||||
bindingset[result, b]
|
||||
private boolean unbindBool(boolean b) { result != b.booleanNot() }
|
||||
|
||||
pragma[noinline]
|
||||
private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
|
||||
Stage1::revFlow(node2, config) and
|
||||
@@ -864,16 +861,16 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -1045,9 +1042,9 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -1059,9 +1056,9 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -1114,9 +1111,10 @@ private module Stage2 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1182,9 +1180,10 @@ private module Stage2 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ unbindBool(ap2), _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1240,8 +1239,8 @@ private predicate flowOutOfCallNodeCand2(
|
||||
DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, config) and
|
||||
Stage2::revFlow(node1, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node1, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1250,8 +1249,8 @@ private predicate flowIntoCallNodeCand2(
|
||||
Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, config) and
|
||||
Stage2::revFlow(node1, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node1, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
private module LocalFlowBigStep {
|
||||
@@ -1306,8 +1305,8 @@ private module LocalFlowBigStep {
|
||||
pragma[noinline]
|
||||
private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) {
|
||||
additionalLocalFlowStepNodeCand1(node1, node2, config) and
|
||||
Stage2::revFlow(node1, _, _, false, config) and
|
||||
Stage2::revFlow(node2, _, _, false, unbind(config))
|
||||
Stage2::revFlow(node1, _, _, false, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node2, _, _, false, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1324,7 +1323,7 @@ private module LocalFlowBigStep {
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, config) and
|
||||
localFlowEntry(node1, pragma[only_bind_into](config)) and
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
@@ -1337,22 +1336,22 @@ private module LocalFlowBigStep {
|
||||
node1 != node2 and
|
||||
cc.relevantFor(getNodeEnclosingCallable(node1)) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, pragma[only_bind_into](config), cc) and
|
||||
localFlowStepNodeCand1(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
localFlowStepPlus(node1, mid, _, _, pragma[only_bind_into](config), cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2) and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1459,6 +1458,13 @@ private module Stage3 {
|
||||
PrevStage::revFlow(node, _, _, apa, config)
|
||||
}
|
||||
|
||||
bindingset[result, apa]
|
||||
private ApApprox unbindApa(ApApprox apa) {
|
||||
exists(ApApprox apa0 |
|
||||
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable with access path `ap` from a source in the
|
||||
* configuration `config`.
|
||||
@@ -1470,7 +1476,7 @@ private module Stage3 {
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
fwdFlow0(node, cc, argAp, ap, config) and
|
||||
flowCand(node, unbindBool(getApprox(ap)), config) and
|
||||
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||
filter(node, ap)
|
||||
}
|
||||
|
||||
@@ -1494,16 +1500,16 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -1548,7 +1554,7 @@ private module Stage3 {
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||
PrevStage::storeStepCand(node1, unbindBool(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
typecheckStore(ap1, contentType)
|
||||
)
|
||||
}
|
||||
@@ -1627,7 +1633,7 @@ private module Stage3 {
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindBool(getApprox(ap)), config)
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1675,9 +1681,9 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -1689,9 +1695,9 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -1744,9 +1750,10 @@ private module Stage3 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1812,9 +1819,10 @@ private module Stage3 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2125,8 +2133,11 @@ private module Stage4 {
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc, getNodeEnclosingCallable(node))
|
||||
exists(Cc cc0 |
|
||||
cc = pragma[only_bind_into](cc0) and
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
|
||||
)
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2141,8 +2152,8 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, config) and
|
||||
PrevStage::revFlow(node1, _, _, _, unbind(config))
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -2151,8 +2162,8 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, config) and
|
||||
PrevStage::revFlow(node1, _, _, _, unbind(config))
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
bindingset[node, ap]
|
||||
@@ -2167,6 +2178,13 @@ private module Stage4 {
|
||||
PrevStage::revFlow(node, _, _, apa, config)
|
||||
}
|
||||
|
||||
bindingset[result, apa]
|
||||
private ApApprox unbindApa(ApApprox apa) {
|
||||
exists(ApApprox apa0 |
|
||||
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable with access path `ap` from a source in the
|
||||
* configuration `config`.
|
||||
@@ -2178,7 +2196,7 @@ private module Stage4 {
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
fwdFlow0(node, cc, argAp, ap, config) and
|
||||
flowCand(node, getApprox(ap), config) and
|
||||
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||
filter(node, ap)
|
||||
}
|
||||
|
||||
@@ -2202,16 +2220,16 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -2256,7 +2274,7 @@ private module Stage4 {
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
typecheckStore(ap1, contentType)
|
||||
)
|
||||
}
|
||||
@@ -2335,7 +2353,7 @@ private module Stage4 {
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2383,9 +2401,9 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -2397,9 +2415,9 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -2452,9 +2470,10 @@ private module Stage4 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2520,9 +2539,10 @@ private module Stage4 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2574,7 +2594,9 @@ private module Stage4 {
|
||||
}
|
||||
|
||||
bindingset[conf, result]
|
||||
private Configuration unbind(Configuration conf) { result >= conf and result <= conf }
|
||||
private Configuration unbindConf(Configuration conf) {
|
||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||
}
|
||||
|
||||
private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration config) {
|
||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
||||
@@ -2744,13 +2766,13 @@ private newtype TPathNode =
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
pathStep(mid, node, cc, sc, ap) and
|
||||
config = mid.getConfiguration() and
|
||||
Stage4::revFlow(node, _, _, ap.getApprox(), unbind(config))
|
||||
pragma[only_bind_into](config) = mid.getConfiguration() and
|
||||
Stage4::revFlow(node, _, _, ap.getApprox(), pragma[only_bind_into](config))
|
||||
)
|
||||
} or
|
||||
TPathNodeSink(Node node, Configuration config) {
|
||||
config.isSink(node) and
|
||||
Stage4::revFlow(node, unbind(config)) and
|
||||
pragma[only_bind_into](config).isSink(node) and
|
||||
Stage4::revFlow(node, pragma[only_bind_into](config)) and
|
||||
(
|
||||
// A sink that is also a source ...
|
||||
config.isSource(node)
|
||||
@@ -2758,7 +2780,7 @@ private newtype TPathNode =
|
||||
// ... or a sink that can be reached from a source
|
||||
exists(PathNodeMid mid |
|
||||
pathStep(mid, node, _, _, TAccessPathNil(_)) and
|
||||
config = unbind(mid.getConfiguration())
|
||||
pragma[only_bind_into](config) = mid.getConfiguration()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -3055,7 +3077,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
||||
|
||||
private PathNodeMid getSuccMid() {
|
||||
pathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx(), result.getAp()) and
|
||||
result.getConfiguration() = unbind(this.getConfiguration())
|
||||
result.getConfiguration() = unbindConf(this.getConfiguration())
|
||||
}
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
@@ -3067,7 +3089,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
||||
mid = getSuccMid() and
|
||||
mid.getNode() = sink.getNode() and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
sink.getConfiguration() = unbind(mid.getConfiguration()) and
|
||||
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
|
||||
result = sink
|
||||
)
|
||||
}
|
||||
@@ -3298,7 +3320,7 @@ private predicate pathThroughCallable0(
|
||||
) {
|
||||
exists(CallContext innercc, SummaryCtx sc |
|
||||
pathIntoCallable(mid, _, cc, innercc, sc, call) and
|
||||
paramFlowsThrough(kind, innercc, sc, ap, apa, unbind(mid.getConfiguration()))
|
||||
paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3310,7 +3332,7 @@ pragma[noinline]
|
||||
private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) {
|
||||
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
|
||||
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
|
||||
out = getAnOutNodeFlow(kind, call, apa, unbind(mid.getConfiguration()))
|
||||
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3433,8 +3455,8 @@ private module FlowExploration {
|
||||
private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) {
|
||||
exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config |
|
||||
callableStep(c1, c2, config) and
|
||||
ce1 = TCallable(c1, config) and
|
||||
ce2 = TCallable(c2, unbind(config))
|
||||
ce1 = TCallable(c1, pragma[only_bind_into](config)) and
|
||||
ce2 = TCallable(c2, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
exists(Node n, Configuration config |
|
||||
|
||||
@@ -26,15 +26,243 @@ predicate accessPathCostLimits(int apLimit, int tupleLimit) {
|
||||
tupleLimit = 1000
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a simple data-flow analysis for resolving lambda calls. The analysis
|
||||
* currently excludes read-steps, store-steps, and flow-through.
|
||||
*
|
||||
* The analysis uses non-linear recursion: When computing a flow path in or out
|
||||
* of a call, we use the results of the analysis recursively to resolve lamba
|
||||
* calls. For this reason, we cannot reuse the code from `DataFlowImpl.qll` directly.
|
||||
*/
|
||||
private module LambdaFlow {
|
||||
private predicate viableParamNonLambda(DataFlowCall call, int i, ParameterNode p) {
|
||||
p.isParameterOf(viableCallable(call), i)
|
||||
}
|
||||
|
||||
private predicate viableParamLambda(DataFlowCall call, int i, ParameterNode p) {
|
||||
p.isParameterOf(viableCallableLambda(call, _), i)
|
||||
}
|
||||
|
||||
private predicate viableParamArgNonLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) {
|
||||
exists(int i |
|
||||
viableParamNonLambda(call, i, p) and
|
||||
arg.argumentOf(call, i)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate viableParamArgLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) {
|
||||
exists(int i |
|
||||
viableParamLambda(call, i, p) and
|
||||
arg.argumentOf(call, i)
|
||||
)
|
||||
}
|
||||
|
||||
private newtype TReturnPositionSimple =
|
||||
TReturnPositionSimple0(DataFlowCallable c, ReturnKind kind) {
|
||||
exists(ReturnNode ret |
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
kind = ret.getKind()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private TReturnPositionSimple getReturnPositionSimple(ReturnNode ret, ReturnKind kind) {
|
||||
result = TReturnPositionSimple0(getNodeEnclosingCallable(ret), kind)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private TReturnPositionSimple viableReturnPosNonLambda(DataFlowCall call, ReturnKind kind) {
|
||||
result = TReturnPositionSimple0(viableCallable(call), kind)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private TReturnPositionSimple viableReturnPosLambda(
|
||||
DataFlowCall call, DataFlowCallOption lastCall, ReturnKind kind
|
||||
) {
|
||||
result = TReturnPositionSimple0(viableCallableLambda(call, lastCall), kind)
|
||||
}
|
||||
|
||||
private predicate viableReturnPosOutNonLambda(
|
||||
DataFlowCall call, TReturnPositionSimple pos, OutNode out
|
||||
) {
|
||||
exists(ReturnKind kind |
|
||||
pos = viableReturnPosNonLambda(call, kind) and
|
||||
out = getAnOutNode(call, kind)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate viableReturnPosOutLambda(
|
||||
DataFlowCall call, DataFlowCallOption lastCall, TReturnPositionSimple pos, OutNode out
|
||||
) {
|
||||
exists(ReturnKind kind |
|
||||
pos = viableReturnPosLambda(call, lastCall, kind) and
|
||||
out = getAnOutNode(call, kind)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow (inter-procedurally) from `node` (of type `t`) to
|
||||
* the lambda call `lambdaCall`.
|
||||
*
|
||||
* The parameter `toReturn` indicates whether the path from `node` to
|
||||
* `lambdaCall` goes through a return, and `toJump` whether the path goes
|
||||
* through a jump step.
|
||||
*
|
||||
* The call context `lastCall` records the last call on the path from `node`
|
||||
* to `lambdaCall`, if any. That is, `lastCall` is able to target the enclosing
|
||||
* callable of `lambdaCall`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revLambdaFlow(
|
||||
DataFlowCall lambdaCall, LambdaCallKind kind, Node node, DataFlowType t, boolean toReturn,
|
||||
boolean toJump, DataFlowCallOption lastCall
|
||||
) {
|
||||
revLambdaFlow0(lambdaCall, kind, node, t, toReturn, toJump, lastCall) and
|
||||
if node instanceof CastNode or node instanceof ArgumentNode or node instanceof ReturnNode
|
||||
then compatibleTypes(t, getNodeType(node))
|
||||
else any()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate revLambdaFlow0(
|
||||
DataFlowCall lambdaCall, LambdaCallKind kind, Node node, DataFlowType t, boolean toReturn,
|
||||
boolean toJump, DataFlowCallOption lastCall
|
||||
) {
|
||||
lambdaCall(lambdaCall, kind, node) and
|
||||
t = getNodeType(node) and
|
||||
toReturn = false and
|
||||
toJump = false and
|
||||
lastCall = TDataFlowCallNone()
|
||||
or
|
||||
// local flow
|
||||
exists(Node mid, DataFlowType t0 |
|
||||
revLambdaFlow(lambdaCall, kind, mid, t0, toReturn, toJump, lastCall)
|
||||
|
|
||||
simpleLocalFlowStep(node, mid) and
|
||||
t = t0
|
||||
or
|
||||
exists(boolean preservesValue |
|
||||
additionalLambdaFlowStep(node, mid, preservesValue) and
|
||||
getNodeEnclosingCallable(node) = getNodeEnclosingCallable(mid)
|
||||
|
|
||||
preservesValue = false and
|
||||
t = getNodeType(node)
|
||||
or
|
||||
preservesValue = true and
|
||||
t = t0
|
||||
)
|
||||
)
|
||||
or
|
||||
// jump step
|
||||
exists(Node mid, DataFlowType t0 |
|
||||
revLambdaFlow(lambdaCall, kind, mid, t0, _, _, _) and
|
||||
toReturn = false and
|
||||
toJump = true and
|
||||
lastCall = TDataFlowCallNone()
|
||||
|
|
||||
jumpStep(node, mid) and
|
||||
t = t0
|
||||
or
|
||||
exists(boolean preservesValue |
|
||||
additionalLambdaFlowStep(node, mid, preservesValue) and
|
||||
getNodeEnclosingCallable(node) != getNodeEnclosingCallable(mid)
|
||||
|
|
||||
preservesValue = false and
|
||||
t = getNodeType(node)
|
||||
or
|
||||
preservesValue = true and
|
||||
t = t0
|
||||
)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
exists(ParameterNode p, DataFlowCallOption lastCall0, DataFlowCall call |
|
||||
revLambdaFlowIn(lambdaCall, kind, p, t, toJump, lastCall0) and
|
||||
(
|
||||
if lastCall0 = TDataFlowCallNone() and toJump = false
|
||||
then lastCall = TDataFlowCallSome(call)
|
||||
else lastCall = lastCall0
|
||||
) and
|
||||
toReturn = false
|
||||
|
|
||||
viableParamArgNonLambda(call, p, node)
|
||||
or
|
||||
viableParamArgLambda(call, p, node) // non-linear recursion
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(TReturnPositionSimple pos |
|
||||
revLambdaFlowOut(lambdaCall, kind, pos, t, toJump, lastCall) and
|
||||
getReturnPositionSimple(node, node.(ReturnNode).getKind()) = pos and
|
||||
toReturn = true
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate revLambdaFlowOutLambdaCall(
|
||||
DataFlowCall lambdaCall, LambdaCallKind kind, OutNode out, DataFlowType t, boolean toJump,
|
||||
DataFlowCall call, DataFlowCallOption lastCall
|
||||
) {
|
||||
revLambdaFlow(lambdaCall, kind, out, t, _, toJump, lastCall) and
|
||||
exists(ReturnKindExt rk |
|
||||
out = rk.getAnOutNode(call) and
|
||||
lambdaCall(call, _, _)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate revLambdaFlowOut(
|
||||
DataFlowCall lambdaCall, LambdaCallKind kind, TReturnPositionSimple pos, DataFlowType t,
|
||||
boolean toJump, DataFlowCallOption lastCall
|
||||
) {
|
||||
exists(DataFlowCall call, OutNode out |
|
||||
revLambdaFlow(lambdaCall, kind, out, t, _, toJump, lastCall) and
|
||||
viableReturnPosOutNonLambda(call, pos, out)
|
||||
or
|
||||
// non-linear recursion
|
||||
revLambdaFlowOutLambdaCall(lambdaCall, kind, out, t, toJump, call, lastCall) and
|
||||
viableReturnPosOutLambda(call, _, pos, out)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate revLambdaFlowIn(
|
||||
DataFlowCall lambdaCall, LambdaCallKind kind, ParameterNode p, DataFlowType t, boolean toJump,
|
||||
DataFlowCallOption lastCall
|
||||
) {
|
||||
revLambdaFlow(lambdaCall, kind, p, t, false, toJump, lastCall)
|
||||
}
|
||||
}
|
||||
|
||||
private DataFlowCallable viableCallableExt(DataFlowCall call) {
|
||||
result = viableCallable(call)
|
||||
or
|
||||
result = viableCallableLambda(call, _)
|
||||
}
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
/**
|
||||
* Gets a viable target for the lambda call `call`.
|
||||
*
|
||||
* `lastCall` records the call required to reach `call` in order for the result
|
||||
* to be a viable target, if any.
|
||||
*/
|
||||
cached
|
||||
DataFlowCallable viableCallableLambda(DataFlowCall call, DataFlowCallOption lastCall) {
|
||||
exists(Node creation, LambdaCallKind kind |
|
||||
LambdaFlow::revLambdaFlow(call, kind, creation, _, _, _, lastCall) and
|
||||
lambdaCreation(creation, kind, result)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `p` is the `i`th parameter of a viable dispatch target of `call`.
|
||||
* The instance parameter is considered to have index `-1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate viableParam(DataFlowCall call, int i, ParameterNode p) {
|
||||
p.isParameterOf(viableCallable(call), i)
|
||||
p.isParameterOf(viableCallableExt(call), i)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,7 +280,7 @@ private module Cached {
|
||||
|
||||
pragma[nomagic]
|
||||
private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) {
|
||||
viableCallable(call) = result.getCallable() and
|
||||
viableCallableExt(call) = result.getCallable() and
|
||||
kind = result.getKind()
|
||||
}
|
||||
|
||||
@@ -317,6 +545,35 @@ private module Cached {
|
||||
|
||||
cached
|
||||
private module DispatchWithCallContext {
|
||||
/**
|
||||
* Holds if the set of viable implementations that can be called by `call`
|
||||
* might be improved by knowing the call context.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate mayBenefitFromCallContextExt(DataFlowCall call, DataFlowCallable callable) {
|
||||
mayBenefitFromCallContext(call, callable)
|
||||
or
|
||||
callable = call.getEnclosingCallable() and
|
||||
exists(viableCallableLambda(call, TDataFlowCallSome(_)))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||
* restricted to those `call`s for which a context might make a difference.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private DataFlowCallable viableImplInCallContextExt(DataFlowCall call, DataFlowCall ctx) {
|
||||
result = viableImplInCallContext(call, ctx)
|
||||
or
|
||||
result = viableCallableLambda(call, TDataFlowCallSome(ctx))
|
||||
or
|
||||
exists(DataFlowCallable enclosing |
|
||||
mayBenefitFromCallContextExt(call, enclosing) and
|
||||
enclosing = viableCallableExt(ctx) and
|
||||
result = viableCallableLambda(call, TDataFlowCallNone())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the call context `ctx` reduces the set of viable run-time
|
||||
* dispatch targets of call `call` in `c`.
|
||||
@@ -324,10 +581,10 @@ private module Cached {
|
||||
cached
|
||||
predicate reducedViableImplInCallContext(DataFlowCall call, DataFlowCallable c, DataFlowCall ctx) {
|
||||
exists(int tgts, int ctxtgts |
|
||||
mayBenefitFromCallContext(call, c) and
|
||||
c = viableCallable(ctx) and
|
||||
ctxtgts = count(viableImplInCallContext(call, ctx)) and
|
||||
tgts = strictcount(viableCallable(call)) and
|
||||
mayBenefitFromCallContextExt(call, c) and
|
||||
c = viableCallableExt(ctx) and
|
||||
ctxtgts = count(viableImplInCallContextExt(call, ctx)) and
|
||||
tgts = strictcount(viableCallableExt(call)) and
|
||||
ctxtgts < tgts
|
||||
)
|
||||
}
|
||||
@@ -339,7 +596,7 @@ private module Cached {
|
||||
*/
|
||||
cached
|
||||
DataFlowCallable prunedViableImplInCallContext(DataFlowCall call, DataFlowCall ctx) {
|
||||
result = viableImplInCallContext(call, ctx) and
|
||||
result = viableImplInCallContextExt(call, ctx) and
|
||||
reducedViableImplInCallContext(call, _, ctx)
|
||||
}
|
||||
|
||||
@@ -351,10 +608,10 @@ private module Cached {
|
||||
cached
|
||||
predicate reducedViableImplInReturn(DataFlowCallable c, DataFlowCall call) {
|
||||
exists(int tgts, int ctxtgts |
|
||||
mayBenefitFromCallContext(call, _) and
|
||||
c = viableCallable(call) and
|
||||
ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContext(call, ctx)) and
|
||||
tgts = strictcount(DataFlowCall ctx | viableCallable(ctx) = call.getEnclosingCallable()) and
|
||||
mayBenefitFromCallContextExt(call, _) and
|
||||
c = viableCallableExt(call) and
|
||||
ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContextExt(call, ctx)) and
|
||||
tgts = strictcount(DataFlowCall ctx | viableCallableExt(ctx) = call.getEnclosingCallable()) and
|
||||
ctxtgts < tgts
|
||||
)
|
||||
}
|
||||
@@ -367,7 +624,7 @@ private module Cached {
|
||||
*/
|
||||
cached
|
||||
DataFlowCallable prunedViableImplInCallContextReverse(DataFlowCall call, DataFlowCall ctx) {
|
||||
result = viableImplInCallContext(call, ctx) and
|
||||
result = viableImplInCallContextExt(call, ctx) and
|
||||
reducedViableImplInReturn(result, call)
|
||||
}
|
||||
}
|
||||
@@ -481,6 +738,11 @@ private module Cached {
|
||||
TBooleanNone() or
|
||||
TBooleanSome(boolean b) { b = true or b = false }
|
||||
|
||||
cached
|
||||
newtype TDataFlowCallOption =
|
||||
TDataFlowCallNone() or
|
||||
TDataFlowCallSome(DataFlowCall call)
|
||||
|
||||
cached
|
||||
newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) }
|
||||
|
||||
@@ -777,7 +1039,7 @@ ReturnPosition getReturnPosition(ReturnNodeExt ret) {
|
||||
|
||||
bindingset[cc, callable]
|
||||
predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall call) {
|
||||
cc instanceof CallContextAny and callable = viableCallable(call)
|
||||
cc instanceof CallContextAny and callable = viableCallableExt(call)
|
||||
or
|
||||
exists(DataFlowCallable c0, DataFlowCall call0 |
|
||||
call0.getEnclosingCallable() = callable and
|
||||
@@ -791,14 +1053,14 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) {
|
||||
exists(DataFlowCall ctx | cc = TSpecificCall(ctx) |
|
||||
if reducedViableImplInCallContext(call, _, ctx)
|
||||
then result = prunedViableImplInCallContext(call, ctx)
|
||||
else result = viableCallable(call)
|
||||
else result = viableCallableExt(call)
|
||||
)
|
||||
or
|
||||
result = viableCallable(call) and cc instanceof CallContextSomeCall
|
||||
result = viableCallableExt(call) and cc instanceof CallContextSomeCall
|
||||
or
|
||||
result = viableCallable(call) and cc instanceof CallContextAny
|
||||
result = viableCallableExt(call) and cc instanceof CallContextAny
|
||||
or
|
||||
result = viableCallable(call) and cc instanceof CallContextReturn
|
||||
result = viableCallableExt(call) and cc instanceof CallContextReturn
|
||||
}
|
||||
|
||||
predicate read = readStep/3;
|
||||
@@ -812,6 +1074,19 @@ class BooleanOption extends TBooleanOption {
|
||||
}
|
||||
}
|
||||
|
||||
/** An optional `DataFlowCall`. */
|
||||
class DataFlowCallOption extends TDataFlowCallOption {
|
||||
string toString() {
|
||||
this = TDataFlowCallNone() and
|
||||
result = "(none)"
|
||||
or
|
||||
exists(DataFlowCall call |
|
||||
this = TDataFlowCallSome(call) and
|
||||
result = call.toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Content tagged with the type of a containing object. */
|
||||
class TypedContent extends MkTypedContent {
|
||||
private Content c;
|
||||
|
||||
@@ -338,3 +338,14 @@ predicate isImmutableOrUnobservable(Node n) {
|
||||
|
||||
/** Holds if `n` should be hidden from path explanations. */
|
||||
predicate nodeIsHidden(Node n) { none() }
|
||||
|
||||
class LambdaCallKind = Unit;
|
||||
|
||||
/** Holds if `creation` is an expression that creates a lambda of kind `kind` for `c`. */
|
||||
predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c) { none() }
|
||||
|
||||
/** Holds if `call` is a lambda call of kind `kind` where `receiver` is the lambda expression. */
|
||||
predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) { none() }
|
||||
|
||||
/** Extra data-flow steps needed for lamba flow analysis. */
|
||||
predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) { none() }
|
||||
|
||||
@@ -11,6 +11,7 @@ private import semmle.code.java.frameworks.spring.SpringController
|
||||
private import semmle.code.java.frameworks.spring.SpringHttp
|
||||
private import semmle.code.java.frameworks.Networking
|
||||
private import semmle.code.java.dataflow.ExternalFlow
|
||||
private import semmle.code.java.dataflow.internal.DataFlowPrivate
|
||||
import semmle.code.java.dataflow.FlowSteps
|
||||
|
||||
/**
|
||||
@@ -41,12 +42,19 @@ predicate localTaintStep(DataFlow::Node src, DataFlow::Node sink) {
|
||||
* different objects.
|
||||
*/
|
||||
predicate localAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) {
|
||||
localAdditionalBasicTaintStep(src, sink)
|
||||
or
|
||||
composedValueAndTaintModelStep(src, sink)
|
||||
}
|
||||
|
||||
private predicate localAdditionalBasicTaintStep(DataFlow::Node src, DataFlow::Node sink) {
|
||||
localAdditionalTaintExprStep(src.asExpr(), sink.asExpr())
|
||||
or
|
||||
localAdditionalTaintUpdateStep(src.asExpr(),
|
||||
sink.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr())
|
||||
or
|
||||
summaryStep(src, sink, "taint")
|
||||
summaryStep(src, sink, "taint") and
|
||||
not summaryStep(src, sink, "value")
|
||||
or
|
||||
exists(Argument arg |
|
||||
src.asExpr() = arg and
|
||||
@@ -55,6 +63,26 @@ predicate localAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an additional step from `src` to `sink` through a call can be inferred from the
|
||||
* combination of a value-preserving step providing an alias between an input and the output
|
||||
* and a taint step from `src` to one the aliased nodes. For example, if we know that `f(a, b)` returns
|
||||
* the exact value of `a` and also propagates taint from `b` to `a`, then we also know that
|
||||
* the return value is tainted after `f` completes.
|
||||
*/
|
||||
private predicate composedValueAndTaintModelStep(ArgumentNode src, DataFlow::Node sink) {
|
||||
exists(Call call, ArgumentNode valueSource, DataFlow::PostUpdateNode valueSourcePost |
|
||||
src.argumentOf(call, _) and
|
||||
valueSource.argumentOf(call, _) and
|
||||
src != valueSource and
|
||||
valueSourcePost.getPreUpdateNode() = valueSource and
|
||||
// in-x -value-> out-y and in-z -taint-> in-x ==> in-z -taint-> out-y
|
||||
localAdditionalBasicTaintStep(src, valueSourcePost) and
|
||||
DataFlow::localFlowStep(valueSource, DataFlow::exprNode(call)) and
|
||||
sink = DataFlow::exprNode(call)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the additional step from `src` to `sink` should be included in all
|
||||
* global taint flow configurations.
|
||||
@@ -165,60 +193,6 @@ private predicate inputStreamWrapper(Constructor c, int argi) {
|
||||
/** An object construction that preserves the data flow status of any of its arguments. */
|
||||
private predicate constructorStep(Expr tracked, ConstructorCall sink) {
|
||||
exists(int argi | sink.getArgument(argi) = tracked |
|
||||
exists(string s | sink.getConstructedType().getQualifiedName() = s |
|
||||
// some readers preserve the content of streams
|
||||
s = "java.io.InputStreamReader" and argi = 0
|
||||
or
|
||||
s = "java.io.BufferedReader" and argi = 0
|
||||
or
|
||||
s = "java.io.CharArrayReader" and argi = 0
|
||||
or
|
||||
s = "java.io.StringReader" and argi = 0
|
||||
or
|
||||
// data preserved through streams
|
||||
s = "java.io.ObjectInputStream" and argi = 0
|
||||
or
|
||||
s = "java.io.ByteArrayInputStream" and argi = 0
|
||||
or
|
||||
s = "java.io.DataInputStream" and argi = 0
|
||||
or
|
||||
s = "java.io.BufferedInputStream" and argi = 0
|
||||
or
|
||||
s = "com.esotericsoftware.kryo.io.Input" and argi = 0
|
||||
or
|
||||
s = "java.beans.XMLDecoder" and argi = 0
|
||||
or
|
||||
// a tokenizer preserves the content of a string
|
||||
s = "java.util.StringTokenizer" and argi = 0
|
||||
or
|
||||
// unzipping the stream preserves content
|
||||
s = "java.util.zip.ZipInputStream" and argi = 0
|
||||
or
|
||||
s = "java.util.zip.GZIPInputStream" and argi = 0
|
||||
or
|
||||
// a cookie with tainted ingredients is tainted
|
||||
s = "javax.servlet.http.Cookie" and argi = 0
|
||||
or
|
||||
s = "javax.servlet.http.Cookie" and argi = 1
|
||||
or
|
||||
// various xml stream source constructors.
|
||||
s = "org.xml.sax.InputSource" and argi = 0
|
||||
or
|
||||
s = "javax.xml.transform.sax.SAXSource" and argi = 0 and sink.getNumArgument() = 1
|
||||
or
|
||||
s = "javax.xml.transform.sax.SAXSource" and argi = 1 and sink.getNumArgument() = 2
|
||||
or
|
||||
s = "javax.xml.transform.stream.StreamSource" and argi = 0
|
||||
or
|
||||
//a URI constructed from a tainted string is tainted.
|
||||
s = "java.net.URI" and argi = 0 and sink.getNumArgument() = 1
|
||||
or
|
||||
//a File constructed from a tainted string is tainted.
|
||||
s = "java.io.File" and argi = 0
|
||||
or
|
||||
s = "java.io.File" and argi = 1
|
||||
)
|
||||
or
|
||||
// wrappers constructed by extension
|
||||
exists(Constructor c, Parameter p, SuperConstructorInvocationStmt sup |
|
||||
c = sink.getConstructor() and
|
||||
@@ -266,32 +240,12 @@ private int argToParam(Call call, int arg) {
|
||||
/** Access to a method that passes taint from qualifier to argument. */
|
||||
private predicate qualifierToArgumentStep(Expr tracked, Expr sink) {
|
||||
exists(MethodAccess ma, int arg |
|
||||
taintPreservingQualifierToArgument(ma.getMethod(), argToParam(ma, arg)) and
|
||||
ma.getMethod().(TaintPreservingCallable).transfersTaint(-1, argToParam(ma, arg)) and
|
||||
tracked = ma.getQualifier() and
|
||||
sink = ma.getArgument(arg)
|
||||
)
|
||||
}
|
||||
|
||||
/** Methods that passes tainted data from qualifier to argument. */
|
||||
private predicate taintPreservingQualifierToArgument(Method m, int arg) {
|
||||
m.getDeclaringType().hasQualifiedName("java.io", "ByteArrayOutputStream") and
|
||||
m.hasName("writeTo") and
|
||||
arg = 0
|
||||
or
|
||||
exists(Method read |
|
||||
m.overrides*(read) and
|
||||
read.getDeclaringType().hasQualifiedName("java.io", "InputStream") and
|
||||
read.hasName("read") and
|
||||
arg = 0
|
||||
)
|
||||
or
|
||||
m.getDeclaringType().getASupertype*().hasQualifiedName("java.io", "Reader") and
|
||||
m.hasName("read") and
|
||||
arg = 0
|
||||
or
|
||||
m.(TaintPreservingCallable).transfersTaint(-1, arg)
|
||||
}
|
||||
|
||||
/** Access to a method that passes taint from the qualifier. */
|
||||
private predicate qualifierToMethodStep(Expr tracked, MethodAccess sink) {
|
||||
(taintPreservingQualifierToMethod(sink.getMethod()) or unsafeEscape(sink)) and
|
||||
@@ -304,13 +258,6 @@ private predicate qualifierToMethodStep(Expr tracked, MethodAccess sink) {
|
||||
private predicate taintPreservingQualifierToMethod(Method m) {
|
||||
m instanceof CloneMethod
|
||||
or
|
||||
m.getDeclaringType().getASupertype*().hasQualifiedName("java.io", "Reader") and
|
||||
(
|
||||
m.getName() = "read" and m.getNumberOfParameters() = 0
|
||||
or
|
||||
m.getName() = "readLine"
|
||||
)
|
||||
or
|
||||
m.getDeclaringType().getQualifiedName().matches("%StringWriter") and
|
||||
(
|
||||
m.getName() = "getBuffer"
|
||||
@@ -318,36 +265,9 @@ private predicate taintPreservingQualifierToMethod(Method m) {
|
||||
m.getName() = "toString"
|
||||
)
|
||||
or
|
||||
m.getDeclaringType().hasQualifiedName("java.util", "StringTokenizer") and
|
||||
m.getName().matches("next%")
|
||||
or
|
||||
m.getDeclaringType().hasQualifiedName("java.io", "ByteArrayOutputStream") and
|
||||
(m.getName() = "toByteArray" or m.getName() = "toString")
|
||||
or
|
||||
m.getDeclaringType().hasQualifiedName("java.io", "ObjectInputStream") and
|
||||
m.getName().matches("read%")
|
||||
or
|
||||
m.getDeclaringType().hasQualifiedName("javax.xml.transform.sax", "SAXSource") and
|
||||
m.hasName("getInputSource")
|
||||
or
|
||||
m.getDeclaringType().hasQualifiedName("javax.xml.transform.stream", "StreamSource") and
|
||||
m.hasName("getInputStream")
|
||||
or
|
||||
m.getDeclaringType().hasQualifiedName("java.nio", "ByteBuffer") and
|
||||
m.hasName("get")
|
||||
or
|
||||
m.getDeclaringType() instanceof TypeFile and
|
||||
m.hasName("toPath")
|
||||
or
|
||||
m.getDeclaringType() instanceof TypePath and
|
||||
m.hasName("toFile")
|
||||
or
|
||||
m.getDeclaringType() instanceof TypeFile and
|
||||
m.hasName("toURI")
|
||||
or
|
||||
m.getDeclaringType() instanceof TypeUri and
|
||||
m.hasName("toURL")
|
||||
or
|
||||
m instanceof GetterMethod and
|
||||
m.getDeclaringType().getASubtype*() instanceof SpringUntrustedDataType and
|
||||
not m.getDeclaringType() instanceof TypeObject
|
||||
@@ -420,28 +340,6 @@ private predicate argToMethodStep(Expr tracked, MethodAccess sink) {
|
||||
* `arg`th argument is tainted.
|
||||
*/
|
||||
private predicate taintPreservingArgumentToMethod(Method method, int arg) {
|
||||
(
|
||||
method.getDeclaringType().hasQualifiedName("java.util", "Base64$Encoder") or
|
||||
method.getDeclaringType().hasQualifiedName("java.util", "Base64$Decoder") or
|
||||
method
|
||||
.getDeclaringType()
|
||||
.getASupertype*()
|
||||
.hasQualifiedName("org.apache.commons.codec", "Encoder") or
|
||||
method
|
||||
.getDeclaringType()
|
||||
.getASupertype*()
|
||||
.hasQualifiedName("org.apache.commons.codec", "Decoder")
|
||||
) and
|
||||
(
|
||||
method.getName() = "encode" and arg = 0 and method.getNumberOfParameters() = 1
|
||||
or
|
||||
method.getName() = "decode" and arg = 0 and method.getNumberOfParameters() = 1
|
||||
or
|
||||
method.getName() = "encodeToString" and arg = 0
|
||||
or
|
||||
method.getName() = "wrap" and arg = 0
|
||||
)
|
||||
or
|
||||
method.getDeclaringType().hasQualifiedName("org.apache.commons.codec.binary", "Base64") and
|
||||
(
|
||||
method.getName() = "decodeBase64" and arg = 0
|
||||
@@ -449,40 +347,6 @@ private predicate taintPreservingArgumentToMethod(Method method, int arg) {
|
||||
method.getName().matches("encodeBase64%") and arg = 0
|
||||
)
|
||||
or
|
||||
method.getDeclaringType().hasQualifiedName("org.apache.commons.io", "IOUtils") and
|
||||
(
|
||||
method.getName() = "buffer" and arg = 0
|
||||
or
|
||||
method.getName() = "readLines" and arg = 0
|
||||
or
|
||||
method.getName() = "readFully" and arg = 0 and method.getParameterType(1).hasName("int")
|
||||
or
|
||||
method.getName() = "toBufferedInputStream" and arg = 0
|
||||
or
|
||||
method.getName() = "toBufferedReader" and arg = 0
|
||||
or
|
||||
method.getName() = "toByteArray" and arg = 0
|
||||
or
|
||||
method.getName() = "toCharArray" and arg = 0
|
||||
or
|
||||
method.getName() = "toInputStream" and arg = 0
|
||||
or
|
||||
method.getName() = "toString" and arg = 0
|
||||
)
|
||||
or
|
||||
method.getDeclaringType().hasQualifiedName("java.net", "URLDecoder") and
|
||||
method.hasName("decode") and
|
||||
arg = 0
|
||||
or
|
||||
// A URI created from a tainted string is still tainted.
|
||||
method.getDeclaringType() instanceof TypeUri and
|
||||
method.hasName("create") and
|
||||
arg = 0
|
||||
or
|
||||
method.getDeclaringType().hasQualifiedName("javax.xml.transform.sax", "SAXSource") and
|
||||
method.hasName("sourceToInputSource") and
|
||||
arg = 0
|
||||
or
|
||||
method.(TaintPreservingCallable).returnsTaintFrom(arg)
|
||||
}
|
||||
|
||||
@@ -492,48 +356,13 @@ private predicate taintPreservingArgumentToMethod(Method method, int arg) {
|
||||
*/
|
||||
private predicate argToArgStep(Expr tracked, Expr sink) {
|
||||
exists(MethodAccess ma, Method method, int input, int output |
|
||||
taintPreservingArgToArg(method, argToParam(ma, input), argToParam(ma, output)) and
|
||||
method.(TaintPreservingCallable).transfersTaint(argToParam(ma, input), argToParam(ma, output)) and
|
||||
ma.getMethod() = method and
|
||||
ma.getArgument(input) = tracked and
|
||||
ma.getArgument(output) = sink
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `method` is a library method that writes tainted data to the
|
||||
* `output`th argument if the `input`th argument is tainted.
|
||||
*/
|
||||
private predicate taintPreservingArgToArg(Method method, int input, int output) {
|
||||
method.getDeclaringType().hasQualifiedName("org.apache.commons.io", "IOUtils") and
|
||||
(
|
||||
method.hasName("copy") and input = 0 and output = 1
|
||||
or
|
||||
method.hasName("copyLarge") and input = 0 and output = 1
|
||||
or
|
||||
method.hasName("read") and input = 0 and output = 1
|
||||
or
|
||||
method.hasName("readFully") and
|
||||
input = 0 and
|
||||
output = 1 and
|
||||
not method.getParameterType(1).hasName("int")
|
||||
or
|
||||
method.hasName("write") and input = 0 and output = 1
|
||||
or
|
||||
method.hasName("writeChunked") and input = 0 and output = 1
|
||||
or
|
||||
method.hasName("writeLines") and input = 0 and output = 2
|
||||
or
|
||||
method.hasName("writeLines") and input = 1 and output = 2
|
||||
)
|
||||
or
|
||||
method.getDeclaringType().hasQualifiedName("java.lang", "System") and
|
||||
method.hasName("arraycopy") and
|
||||
input = 0 and
|
||||
output = 2
|
||||
or
|
||||
method.(TaintPreservingCallable).transfersTaint(input, output)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `tracked` is the argument of a method that transfers taint
|
||||
* from the argument to the qualifier and `sink` is the qualifier.
|
||||
@@ -717,10 +546,7 @@ module StringBuilderVarModule {
|
||||
* build up a query using string concatenation.
|
||||
*/
|
||||
class StringBuilderVar extends LocalVariableDecl {
|
||||
StringBuilderVar() {
|
||||
this.getType() instanceof TypeStringBuilder or
|
||||
this.getType() instanceof TypeStringBuffer
|
||||
}
|
||||
StringBuilderVar() { getType() instanceof StringBuildingType }
|
||||
|
||||
/**
|
||||
* Gets a call that adds something to this string builder, from the argument at the given index.
|
||||
|
||||
@@ -14,15 +14,6 @@ class TypeApacheRandomStringUtils extends Class {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The class `org.apache.commons.lang.ArrayUtils` or `org.apache.commons.lang3.ArrayUtils`.
|
||||
*/
|
||||
class TypeApacheArrayUtils extends Class {
|
||||
TypeApacheArrayUtils() {
|
||||
hasQualifiedName(["org.apache.commons.lang", "org.apache.commons.lang3"], "ArrayUtils")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The method `deserialize` in either `org.apache.commons.lang.SerializationUtils`
|
||||
* or `org.apache.commons.lang3.SerializationUtils`.
|
||||
@@ -37,179 +28,402 @@ class MethodApacheSerializationUtilsDeserialize extends Method {
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint preserving method on `org.apache.commons.lang.ArrayUtils` or `org.apache.commons.lang3.ArrayUtils`
|
||||
* Taint-propagating models for `ArrayUtils`.
|
||||
*/
|
||||
private class ApacheLangArrayUtilsTaintPreservingMethod extends TaintPreservingCallable {
|
||||
ApacheLangArrayUtilsTaintPreservingMethod() {
|
||||
this.getDeclaringType() instanceof TypeApacheArrayUtils
|
||||
}
|
||||
|
||||
override predicate returnsTaintFrom(int src) {
|
||||
this.hasName(["addAll", "addFirst"]) and
|
||||
src = [0 .. getNumberOfParameters() - 1]
|
||||
or
|
||||
this.hasName([
|
||||
"clone", "nullToEmpty", "remove", "removeAll", "removeElement", "removeElements", "reverse",
|
||||
"shift", "shuffle", "subarray", "swap", "toArray", "toMap", "toObject", "toPrimitive",
|
||||
"toString", "toStringArray"
|
||||
]) and
|
||||
src = 0
|
||||
or
|
||||
this.hasName("add") and
|
||||
this.getNumberOfParameters() = 2 and
|
||||
src = [0, 1]
|
||||
or
|
||||
this.hasName("add") and
|
||||
this.getNumberOfParameters() = 3 and
|
||||
src = [0, 2]
|
||||
private class ApacheArrayUtilsModel extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
"org.apache.commons.lang3;ArrayUtils;false;add;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;ArrayUtils;false;add;;;Argument[2];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;ArrayUtils;false;add;(java.lang.Object[],java.lang.Object);;Argument[1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;ArrayUtils;false;add;(boolean[],boolean);;Argument[1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;ArrayUtils;false;add;(byte[],byte);;Argument[1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;ArrayUtils;false;add;(char[],char);;Argument[1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;ArrayUtils;false;add;(double[],double);;Argument[1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;ArrayUtils;false;add;(float[],float);;Argument[1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;ArrayUtils;false;add;(int[],int);;Argument[1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;ArrayUtils;false;add;(long[],long);;Argument[1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;ArrayUtils;false;add;(short[],short);;Argument[1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;ArrayUtils;false;addAll;;;Argument[0..1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;ArrayUtils;false;addFirst;;;Argument[0..1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;ArrayUtils;false;clone;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;ArrayUtils;false;get;(java.lang.Object[],int,java.lang.Object);;Argument[2];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;ArrayUtils;false;get;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;ArrayUtils;false;insert;;;Argument[1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;ArrayUtils;false;insert;;;Argument[2];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;ArrayUtils;false;insert;;;Argument[3];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;ArrayUtils;false;nullToEmpty;(java.lang.Object[],java.lang.Class);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;ArrayUtils;false;nullToEmpty;(java.lang.String[]);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;ArrayUtils;false;remove;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;ArrayUtils;false;removeAll;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;ArrayUtils;false;removeAllOccurences;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;ArrayUtils;false;removeAllOccurrences;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;ArrayUtils;false;removeElement;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;ArrayUtils;false;removeElements;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;ArrayUtils;false;subarray;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;ArrayUtils;false;toArray;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;ArrayUtils;false;toMap;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;ArrayUtils;false;toObject;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;ArrayUtils;false;toPrimitive;;;Argument[0..1];ReturnValue;taint"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
private Type getAnExcludedParameterType() {
|
||||
result instanceof PrimitiveType or
|
||||
result.(RefType).hasQualifiedName("java.nio.charset", "Charset") or
|
||||
result.(RefType).hasQualifiedName("java.util", "Locale")
|
||||
}
|
||||
|
||||
private class ApacheStringUtilsTaintPreservingMethod extends TaintPreservingCallable {
|
||||
ApacheStringUtilsTaintPreservingMethod() {
|
||||
this.getDeclaringType().hasQualifiedName("org.apache.commons.lang3", "StringUtils") and
|
||||
this.hasName([
|
||||
"abbreviate", "abbreviateMiddle", "appendIfMissing", "appendIfMissingIgnoreCase",
|
||||
"capitalize", "center", "chomp", "chop", "defaultIfBlank", "defaultIfEmpty",
|
||||
"defaultString", "deleteWhitespace", "difference", "firstNonBlank", "firstNonEmpty",
|
||||
"getBytes", "getCommonPrefix", "getDigits", "getIfBlank", "getIfEmpty", "join", "joinWith",
|
||||
"left", "leftPad", "lowerCase", "mid", "normalizeSpace", "overlay", "prependIfMissing",
|
||||
"prependIfMissingIgnoreCase", "remove", "removeAll", "removeEnd", "removeEndIgnoreCase",
|
||||
"removeFirst", "removeIgnoreCase", "removePattern", "removeStart", "removeStartIgnoreCase",
|
||||
"repeat", "replace", "replaceAll", "replaceChars", "replaceEach", "replaceEachRepeatedly",
|
||||
"replaceFirst", "replaceIgnoreCase", "replaceOnce", "replaceOnceIgnoreCase",
|
||||
"replacePattern", "reverse", "reverseDelimited", "right", "rightPad", "rotate", "split",
|
||||
"splitByCharacterType", "splitByCharacterTypeCamelCase", "splitByWholeSeparator",
|
||||
"splitByWholeSeparatorPreserveAllTokens", "splitPreserveAllTokens", "strip", "stripAccents",
|
||||
"stripAll", "stripEnd", "stripStart", "stripToEmpty", "stripToNull", "substring",
|
||||
"substringAfter", "substringAfterLast", "substringBefore", "substringBeforeLast",
|
||||
"substringBetween", "substringsBetween", "swapCase", "toCodePoints", "toEncodedString",
|
||||
"toRootLowerCase", "toRootUpperCase", "toString", "trim", "trimToEmpty", "trimToNull",
|
||||
"truncate", "uncapitalize", "unwrap", "upperCase", "valueOf", "wrap", "wrapIfMissing"
|
||||
])
|
||||
}
|
||||
|
||||
private predicate isExcludedParameter(int arg) {
|
||||
this.getName().matches(["appendIfMissing%", "prependIfMissing%"]) and arg = [2, 3]
|
||||
or
|
||||
this.getName().matches(["remove%", "split%", "substring%", "strip%"]) and
|
||||
arg = [1 .. getNumberOfParameters() - 1]
|
||||
or
|
||||
this.getName().matches(["chomp", "getBytes", "replace%", "toString", "unwrap"]) and arg = 1
|
||||
or
|
||||
this.getName() = "join" and
|
||||
// Exclude joins of types that render numerically (char[] and non-primitive arrays
|
||||
// are still considered taint sources)
|
||||
exists(PrimitiveType pt |
|
||||
this.getParameterType(arg).(Array).getComponentType() = pt and
|
||||
not pt instanceof CharacterType
|
||||
) and
|
||||
arg = 0
|
||||
}
|
||||
|
||||
override predicate returnsTaintFrom(int arg) {
|
||||
arg = [0 .. getNumberOfParameters() - 1] and
|
||||
not this.getParameterType(arg) = getAnExcludedParameterType() and
|
||||
not isExcludedParameter(arg)
|
||||
private class ApacheStringUtilsModel extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
"org.apache.commons.lang3;StringUtils;false;abbreviate;(java.lang.String,java.lang.String,int);;Argument[1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;abbreviate;(java.lang.String,java.lang.String,int,int);;Argument[1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;abbreviate;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;abbreviateMiddle;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;abbreviateMiddle;;;Argument[1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;appendIfMissing;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;appendIfMissing;;;Argument[1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;appendIfMissingIgnoreCase;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;appendIfMissingIgnoreCase;;;Argument[1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;capitalize;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;center;(java.lang.String,int,java.lang.String);;Argument[2];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;center;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;chomp;(java.lang.String);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;chomp;(java.lang.String,java.lang.String);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;chop;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;defaultIfBlank;;;Argument[0..1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;defaultIfEmpty;;;Argument[0..1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;defaultString;;;Argument[0..1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;deleteWhitespace;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;difference;;;Argument[0..1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;firstNonBlank;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;firstNonEmpty;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;getBytes;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;getCommonPrefix;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;getDigits;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;getIfBlank;;;Argument[0..1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;getIfEmpty;;;Argument[0..1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;join;(char[],char);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;join;(char[],char,int,int);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;join;(java.lang.Iterable,char);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;join;(java.lang.Iterable,java.lang.String);;Argument[0..1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;join;(java.lang.Object[]);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;join;(java.lang.Object[],char);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;join;(java.lang.Object[],char,int,int);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;join;(java.lang.Object[],java.lang.String);;Argument[0..1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;join;(java.lang.Object[],java.lang.String,int,int);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;join;(java.lang.Object[],java.lang.String,int,int);;Argument[1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;join;(java.util.Iterator,char);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;join;(java.util.Iterator,java.lang.String);;Argument[0..1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;join;(java.util.List,char,int,int);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;join;(java.util.List,java.lang.String,int,int);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;join;(java.util.List,java.lang.String,int,int);;Argument[1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;joinWith;;;Argument[0..1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;left;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;leftPad;(java.lang.String,int,java.lang.String);;Argument[2];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;leftPad;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;lowerCase;(java.lang.String);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;lowerCase;(java.lang.String,java.util.Locale);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;mid;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;normalizeSpace;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;overlay;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;overlay;;;Argument[1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;prependIfMissing;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;prependIfMissing;;;Argument[1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;prependIfMissingIgnoreCase;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;prependIfMissingIgnoreCase;;;Argument[1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;remove;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;removeAll;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;removeEnd;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;removeEndIgnoreCase;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;removeFirst;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;removeIgnoreCase;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;removePattern;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;removeStart;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;removeStartIgnoreCase;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;repeat;(java.lang.String,java.lang.String,int);;Argument[1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;repeat;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;replace;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;replace;;;Argument[2];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;replaceAll;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;replaceAll;;;Argument[2];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;replaceChars;(java.lang.String,java.lang.String,java.lang.String);;Argument[2];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;replaceChars;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;replaceEach;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;replaceEach;;;Argument[2];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;replaceEachRepeatedly;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;replaceEachRepeatedly;;;Argument[2];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;replaceFirst;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;replaceFirst;;;Argument[2];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;replaceIgnoreCase;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;replaceIgnoreCase;;;Argument[2];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;replaceOnce;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;replaceOnce;;;Argument[2];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;replaceOnceIgnoreCase;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;replaceOnceIgnoreCase;;;Argument[2];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;replacePattern;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;replacePattern;;;Argument[2];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;reverse;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;reverseDelimited;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;right;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;rightPad;(java.lang.String,int,java.lang.String);;Argument[2];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;rightPad;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;rotate;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;split;(java.lang.String);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;split;(java.lang.String,char);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;split;(java.lang.String,java.lang.String);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;split;(java.lang.String,java.lang.String,int);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;splitByCharacterType;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;splitByCharacterTypeCamelCase;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;splitByWholeSeparator;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;splitByWholeSeparatorPreserveAllTokens;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;splitPreserveAllTokens;(java.lang.String);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;splitPreserveAllTokens;(java.lang.String,char);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;splitPreserveAllTokens;(java.lang.String,java.lang.String);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;splitPreserveAllTokens;(java.lang.String,java.lang.String,int);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;strip;(java.lang.String);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;strip;(java.lang.String,java.lang.String);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;stripAccents;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;stripAll;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;stripEnd;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;stripStart;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;stripToEmpty;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;stripToNull;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;substring;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;substringAfter;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;substringAfterLast;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;substringBefore;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;substringBeforeLast;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;substringBetween;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;substringsBetween;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;swapCase;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;toCodePoints;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;toEncodedString;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;toRootLowerCase;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;toRootUpperCase;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;toString;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;trim;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;trimToEmpty;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;trimToNull;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;truncate;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;uncapitalize;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;unwrap;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;upperCase;(java.lang.String);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;upperCase;(java.lang.String,java.util.Locale);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;valueOf;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;wrap;(java.lang.String,char);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;wrap;(java.lang.String,java.lang.String);;Argument[0..1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;wrapIfMissing;(java.lang.String,char);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;StringUtils;false;wrapIfMissing;(java.lang.String,java.lang.String);;Argument[0..1];ReturnValue;taint"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A method declared on Apache Commons Lang's `StrBuilder`, or the same class or its
|
||||
* renamed version `TextStringBuilder` in Commons Text.
|
||||
*/
|
||||
class ApacheStrBuilderCallable extends Callable {
|
||||
ApacheStrBuilderCallable() {
|
||||
this.getDeclaringType().hasQualifiedName("org.apache.commons.lang3.text", "StrBuilder") or
|
||||
this.getDeclaringType()
|
||||
.hasQualifiedName("org.apache.commons.text", ["StrBuilder", "TextStringBuilder"])
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An Apache Commons Lang `StrBuilder` method that adds taint to the `StrBuilder`.
|
||||
*/
|
||||
private class ApacheStrBuilderTaintingMethod extends ApacheStrBuilderCallable,
|
||||
TaintPreservingCallable {
|
||||
ApacheStrBuilderTaintingMethod() {
|
||||
this instanceof Constructor
|
||||
or
|
||||
this.hasName([
|
||||
"append", "appendAll", "appendFixedWidthPadLeft", "appendFixedWidthPadRight", "appendln",
|
||||
"appendSeparator", "appendWithSeparators", "insert", "readFrom", "replace", "replaceAll",
|
||||
"replaceFirst"
|
||||
])
|
||||
}
|
||||
|
||||
private predicate consumesTaintFromAllArgs() {
|
||||
// Specifically the append[ln](String, Object...) overloads also consume taint from their other arguments:
|
||||
this.getName() in ["appendAll", "appendWithSeparators"]
|
||||
or
|
||||
this.getName() = ["append", "appendln"] and this.getAParameter().isVarargs()
|
||||
or
|
||||
this.getName() = "appendSeparator" and this.getParameterType(1) instanceof TypeString
|
||||
}
|
||||
|
||||
override predicate transfersTaint(int fromArg, int toArg) {
|
||||
// Taint the qualifier
|
||||
toArg = -1 and
|
||||
(
|
||||
this.getName().matches(["append%", "readFrom"]) and fromArg = 0
|
||||
or
|
||||
this.getName() = "insert" and fromArg = 1
|
||||
or
|
||||
this.getName().matches("replace%") and
|
||||
(
|
||||
if this.getParameterType(0).(PrimitiveType).getName() = "int"
|
||||
then fromArg = 2
|
||||
else fromArg = 1
|
||||
)
|
||||
or
|
||||
this.consumesTaintFromAllArgs() and fromArg in [0 .. this.getNumberOfParameters() - 1]
|
||||
)
|
||||
}
|
||||
|
||||
override predicate returnsTaintFrom(int arg) { this instanceof Constructor and arg = 0 }
|
||||
}
|
||||
|
||||
/**
|
||||
* An Apache Commons Lang `StrBuilder` method that returns taint from the `StrBuilder`.
|
||||
*/
|
||||
private class ApacheStrBuilderTaintGetter extends ApacheStrBuilderCallable, TaintPreservingCallable {
|
||||
ApacheStrBuilderTaintGetter() {
|
||||
// Taint getters:
|
||||
this.hasName([
|
||||
"asReader", "asTokenizer", "build", "getChars", "leftString", "midString", "rightString",
|
||||
"subSequence", "substring", "toCharArray", "toString", "toStringBuffer", "toStringBuilder"
|
||||
])
|
||||
or
|
||||
// Fluent methods that return an alias of `this`:
|
||||
this.getReturnType() = this.getDeclaringType()
|
||||
}
|
||||
|
||||
override predicate returnsTaintFrom(int arg) { arg = -1 }
|
||||
}
|
||||
|
||||
/**
|
||||
* An Apache Commons Lang `StrBuilder` method that writes taint from the `StrBuilder` to some parameter.
|
||||
*/
|
||||
private class ApacheStrBuilderTaintWriter extends ApacheStrBuilderCallable, TaintPreservingCallable {
|
||||
ApacheStrBuilderTaintWriter() { this.hasName(["appendTo", "getChars"]) }
|
||||
|
||||
override predicate transfersTaint(int fromArg, int toArg) {
|
||||
fromArg = -1 and
|
||||
// appendTo(Readable) and getChars(char[])
|
||||
if this.getNumberOfParameters() = 1
|
||||
then toArg = 0
|
||||
else
|
||||
// getChars(int, int, char[], int)
|
||||
toArg = 2
|
||||
private class ApacheStrBuilderModel extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;StrBuilder;(java.lang.String);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;append;(char[]);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;append;(char[],int,int);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;append;(java.lang.CharSequence);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;append;(java.lang.CharSequence,int,int);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;append;(java.lang.Object);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;append;(java.lang.String);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;append;(java.lang.String,int,int);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;append;(java.lang.String,java.lang.Object[]);;Argument[0..1];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;append;(java.lang.StringBuffer);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;append;(java.lang.StringBuffer,int,int);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;append;(java.lang.StringBuilder);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;append;(java.lang.StringBuilder,int,int);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;append;(java.nio.CharBuffer);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;append;(java.nio.CharBuffer,int,int);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;append;(org.apache.commons.lang3.text.StrBuilder);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;append;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;appendAll;;;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;appendAll;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;appendFixedWidthPadLeft;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;appendFixedWidthPadLeft;;;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;appendFixedWidthPadRight;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;appendFixedWidthPadRight;;;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;appendSeparator;(java.lang.String);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;appendSeparator;(java.lang.String,int);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;appendSeparator;(java.lang.String,java.lang.String);;Argument[0..1];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;appendSeparator;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;appendTo;;;Argument[-1];Argument[0];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;appendWithSeparators;;;Argument[0..1];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;appendWithSeparators;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;appendln;(char[]);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;appendln;(char[],int,int);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;appendln;(java.lang.Object);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;appendln;(java.lang.String);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;appendln;(java.lang.String,int,int);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;appendln;(java.lang.String,java.lang.Object[]);;Argument[0..1];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;appendln;(java.lang.StringBuffer);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;appendln;(java.lang.StringBuffer,int,int);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;appendln;(java.lang.StringBuilder);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;appendln;(java.lang.StringBuilder,int,int);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;appendln;(org.apache.commons.lang3.text.StrBuilder);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;appendln;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;asReader;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;asTokenizer;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;build;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;getChars;(char[]);;Argument[-1];Argument[0];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;getChars;(char[]);;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;getChars;(int,int,char[],int);;Argument[-1];Argument[2];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;insert;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;insert;;;Argument[1];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;leftString;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;midString;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;readFrom;;;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;replace;(int,int,java.lang.String);;Argument[2];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;replace;(org.apache.commons.lang3.text.StrMatcher,java.lang.String,int,int,int);;Argument[1];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;replace;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;replaceAll;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;replaceAll;;;Argument[1];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;replaceFirst;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;replaceFirst;;;Argument[1];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;rightString;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;subSequence;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;substring;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;toCharArray;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;toString;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;toStringBuffer;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrBuilder;false;toStringBuilder;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrBuilder;false;StrBuilder;(java.lang.String);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;append;(char[]);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;append;(char[],int,int);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;append;(java.lang.CharSequence);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;append;(java.lang.CharSequence,int,int);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;append;(java.lang.Object);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;append;(java.lang.String);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;append;(java.lang.String,int,int);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;append;(java.lang.String,java.lang.Object[]);;Argument[0..1];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;append;(java.lang.StringBuffer);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;append;(java.lang.StringBuffer,int,int);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;append;(java.lang.StringBuilder);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;append;(java.lang.StringBuilder,int,int);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;append;(java.nio.CharBuffer);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;append;(java.nio.CharBuffer,int,int);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;append;(org.apache.commons.text.StrBuilder);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;append;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrBuilder;false;appendAll;;;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;appendAll;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrBuilder;false;appendFixedWidthPadLeft;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrBuilder;false;appendFixedWidthPadLeft;;;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;appendFixedWidthPadRight;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrBuilder;false;appendFixedWidthPadRight;;;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;appendSeparator;(java.lang.String);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;appendSeparator;(java.lang.String,int);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;appendSeparator;(java.lang.String,java.lang.String);;Argument[0..1];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;appendSeparator;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrBuilder;false;appendTo;;;Argument[-1];Argument[0];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;appendWithSeparators;;;Argument[0..1];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;appendWithSeparators;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrBuilder;false;appendln;(char[]);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;appendln;(char[],int,int);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;appendln;(java.lang.Object);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;appendln;(java.lang.String);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;appendln;(java.lang.String,int,int);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;appendln;(java.lang.String,java.lang.Object[]);;Argument[0..1];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;appendln;(java.lang.StringBuffer);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;appendln;(java.lang.StringBuffer,int,int);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;appendln;(java.lang.StringBuilder);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;appendln;(java.lang.StringBuilder,int,int);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;appendln;(org.apache.commons.text.StrBuilder);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;appendln;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrBuilder;false;asReader;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrBuilder;false;asTokenizer;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrBuilder;false;build;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrBuilder;false;getChars;(char[]);;Argument[-1];Argument[0];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;getChars;(char[]);;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrBuilder;false;getChars;(int,int,char[],int);;Argument[-1];Argument[2];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;insert;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrBuilder;false;insert;;;Argument[1];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;leftString;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrBuilder;false;midString;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrBuilder;false;readFrom;;;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;replace;(int,int,java.lang.String);;Argument[2];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;replace;(org.apache.commons.text.StrMatcher,java.lang.String,int,int,int);;Argument[1];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;replace;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrBuilder;false;replaceAll;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrBuilder;false;replaceAll;;;Argument[1];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;replaceFirst;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrBuilder;false;replaceFirst;;;Argument[1];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrBuilder;false;rightString;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrBuilder;false;subSequence;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrBuilder;false;substring;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrBuilder;false;toCharArray;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrBuilder;false;toString;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrBuilder;false;toStringBuffer;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrBuilder;false;toStringBuilder;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;TextStringBuilder;(java.lang.String);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;TextStringBuilder;(java.lang.CharSequence);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;append;(char[]);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;append;(char[],int,int);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;append;(java.lang.CharSequence);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;append;(java.lang.CharSequence,int,int);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;append;(java.lang.Object);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;append;(java.lang.String);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;append;(java.lang.String,int,int);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;append;(java.lang.String,java.lang.Object[]);;Argument[0..1];Argument[-1];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;append;(java.lang.StringBuffer);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;append;(java.lang.StringBuffer,int,int);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;append;(java.lang.StringBuilder);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;append;(java.lang.StringBuilder,int,int);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;append;(java.nio.CharBuffer);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;append;(java.nio.CharBuffer,int,int);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;append;(org.apache.commons.text.TextStringBuilder);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;append;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;appendAll;;;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;appendAll;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;appendFixedWidthPadLeft;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;appendFixedWidthPadLeft;;;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;appendFixedWidthPadRight;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;appendFixedWidthPadRight;;;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;appendSeparator;(java.lang.String);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;appendSeparator;(java.lang.String,int);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;appendSeparator;(java.lang.String,java.lang.String);;Argument[0..1];Argument[-1];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;appendSeparator;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;appendTo;;;Argument[-1];Argument[0];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;appendWithSeparators;;;Argument[0..1];Argument[-1];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;appendWithSeparators;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;appendln;(char[]);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;appendln;(char[],int,int);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;appendln;(java.lang.Object);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;appendln;(java.lang.String);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;appendln;(java.lang.String,int,int);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;appendln;(java.lang.String,java.lang.Object[]);;Argument[0..1];Argument[-1];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;appendln;(java.lang.StringBuffer);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;appendln;(java.lang.StringBuffer,int,int);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;appendln;(java.lang.StringBuilder);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;appendln;(java.lang.StringBuilder,int,int);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;appendln;(org.apache.commons.text.TextStringBuilder);;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;appendln;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;asReader;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;asTokenizer;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;build;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;getChars;(char[]);;Argument[-1];Argument[0];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;getChars;(char[]);;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;getChars;(int,int,char[],int);;Argument[-1];Argument[2];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;insert;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;insert;;;Argument[1];Argument[-1];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;leftString;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;midString;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;readFrom;;;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;replace;(int,int,java.lang.String);;Argument[2];Argument[-1];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;replace;(org.apache.commons.text.matcher.StringMatcher,java.lang.String,int,int,int);;Argument[1];Argument[-1];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;replace;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;replaceAll;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;replaceAll;;;Argument[1];Argument[-1];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;replaceFirst;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;replaceFirst;;;Argument[1];Argument[-1];taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;rightString;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;subSequence;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;substring;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;toCharArray;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;toString;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;toStringBuffer;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;TextStringBuilder;false;toStringBuilder;;;Argument[-1];ReturnValue;taint"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,28 +437,28 @@ private class ApacheWordUtilsModel extends SummaryModelCsv {
|
||||
"org.apache.commons.lang3.text;WordUtils;false;wrap;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;WordUtils;false;wrap;(java.lang.String,int,java.lang.String,boolean);;Argument[2];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;WordUtils;false;wrap;(java.lang.String,int,java.lang.String,boolean,java.lang.String);;Argument[2];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;WordUtils;false;uncapitalize;(java.lang.String);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;WordUtils;false;uncapitalize;(java.lang.String);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;WordUtils;false;uncapitalize;(java.lang.String,char[]);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;WordUtils;false;swapCase;;;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;WordUtils;false;capitalize;(java.lang.String);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;WordUtils;false;swapCase;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;WordUtils;false;capitalize;(java.lang.String);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;WordUtils;false;capitalize;(java.lang.String,char[]);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;WordUtils;false;initials;(java.lang.String);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;WordUtils;false;initials;(java.lang.String);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;WordUtils;false;initials;(java.lang.String,char[]);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;WordUtils;false;capitalizeFully;(java.lang.String);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;WordUtils;false;capitalizeFully;(java.lang.String);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;WordUtils;false;capitalizeFully;(java.lang.String,char[]);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;WordUtils;false;wrap;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;WordUtils;false;wrap;(java.lang.String,int,java.lang.String,boolean);;Argument[2];ReturnValue;taint",
|
||||
"org.apache.commons.text;WordUtils;false;wrap;(java.lang.String,int,java.lang.String,boolean,java.lang.String);;Argument[2];ReturnValue;taint",
|
||||
"org.apache.commons.text;WordUtils;false;uncapitalize;(java.lang.String);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.text;WordUtils;false;uncapitalize;(java.lang.String);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;WordUtils;false;uncapitalize;(java.lang.String,char[]);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;WordUtils;false;swapCase;;;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.text;WordUtils;false;capitalize;(java.lang.String);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.text;WordUtils;false;swapCase;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;WordUtils;false;capitalize;(java.lang.String);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;WordUtils;false;capitalize;(java.lang.String,char[]);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;WordUtils;false;abbreviate;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;WordUtils;false;abbreviate;;;Argument[3];ReturnValue;taint",
|
||||
"org.apache.commons.text;WordUtils;false;initials;(java.lang.String);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.text;WordUtils;false;initials;(java.lang.String);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;WordUtils;false;initials;(java.lang.String,char[]);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;WordUtils;false;capitalizeFully;(java.lang.String);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.text;WordUtils;false;capitalizeFully;(java.lang.String);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;WordUtils;false;capitalizeFully;(java.lang.String,char[]);;Argument[0];ReturnValue;taint"
|
||||
]
|
||||
}
|
||||
@@ -257,11 +471,11 @@ private class ApacheStrTokenizerModel extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
"org.apache.commons.lang3.text;StrTokenizer;false;StrTokenizer;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrTokenizer;false;StrTokenizer;;;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrTokenizer;false;clone;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrTokenizer;false;toString;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrTokenizer;false;reset;;;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrTokenizer;false;reset;;;Argument;Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrTokenizer;false;reset;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrTokenizer;false;reset;;;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrTokenizer;false;next;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrTokenizer;false;getContent;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrTokenizer;false;previous;;;Argument[-1];ReturnValue;taint",
|
||||
@@ -269,13 +483,13 @@ private class ApacheStrTokenizerModel extends SummaryModelCsv {
|
||||
"org.apache.commons.lang3.text;StrTokenizer;false;getTokenArray;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrTokenizer;false;previousToken;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrTokenizer;false;nextToken;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrTokenizer;false;getTSVInstance;;;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrTokenizer;false;getCSVInstance;;;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.text;StrTokenizer;false;StrTokenizer;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrTokenizer;false;getTSVInstance;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrTokenizer;false;getCSVInstance;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrTokenizer;false;StrTokenizer;;;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrTokenizer;false;clone;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrTokenizer;false;toString;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrTokenizer;false;reset;;;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.text;StrTokenizer;false;reset;;;Argument;Argument[-1];taint",
|
||||
"org.apache.commons.text;StrTokenizer;false;reset;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrTokenizer;false;reset;;;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;StrTokenizer;false;next;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrTokenizer;false;getContent;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrTokenizer;false;previous;;;Argument[-1];ReturnValue;taint",
|
||||
@@ -283,13 +497,13 @@ private class ApacheStrTokenizerModel extends SummaryModelCsv {
|
||||
"org.apache.commons.text;StrTokenizer;false;getTokenArray;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrTokenizer;false;previousToken;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrTokenizer;false;nextToken;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrTokenizer;false;getTSVInstance;;;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.text;StrTokenizer;false;getCSVInstance;;;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.text;StringTokenizer;false;StringTokenizer;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrTokenizer;false;getTSVInstance;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;StrTokenizer;false;getCSVInstance;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringTokenizer;false;StringTokenizer;;;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;StringTokenizer;false;clone;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringTokenizer;false;toString;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringTokenizer;false;reset;;;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.text;StringTokenizer;false;reset;;;Argument;Argument[-1];taint",
|
||||
"org.apache.commons.text;StringTokenizer;false;reset;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringTokenizer;false;reset;;;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;StringTokenizer;false;next;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringTokenizer;false;getContent;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringTokenizer;false;previous;;;Argument[-1];ReturnValue;taint",
|
||||
@@ -297,8 +511,8 @@ private class ApacheStrTokenizerModel extends SummaryModelCsv {
|
||||
"org.apache.commons.text;StringTokenizer;false;getTokenArray;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringTokenizer;false;previousToken;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringTokenizer;false;nextToken;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringTokenizer;false;getTSVInstance;;;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.text;StringTokenizer;false;getCSVInstance;;;Argument;ReturnValue;taint"
|
||||
"org.apache.commons.text;StringTokenizer;false;getTSVInstance;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringTokenizer;false;getCSVInstance;;;Argument[0];ReturnValue;taint"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -311,9 +525,9 @@ private class ApacheStrLookupModel extends SummaryModelCsv {
|
||||
row =
|
||||
[
|
||||
"org.apache.commons.lang3.text;StrLookup;false;lookup;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrLookup;false;mapLookup;;;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrLookup;false;mapLookup;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text.lookup;StringLookup;true;lookup;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text.lookup;StringLookupFactory;false;mapStringLookup;;;Argument;ReturnValue;taint"
|
||||
"org.apache.commons.text.lookup;StringLookupFactory;false;mapStringLookup;;;Argument[0];ReturnValue;taint"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -325,53 +539,53 @@ private class ApacheStrSubstitutorModel extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;StrSubstitutor;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;StrSubstitutor;;;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replace;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.Object);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replace;(char[]);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.Object);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replace;(char[]);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replace;(char[],int,int);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.CharSequence);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.CharSequence);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.CharSequence,int,int);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.String);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replace;(org.apache.commons.lang3.text.StrBuilder);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.StringBuffer);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.String);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replace;(org.apache.commons.lang3.text.StrBuilder);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.StringBuffer);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.StringBuffer,int,int);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.String,int,int);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replace;(org.apache.commons.lang3.text.StrBuilder,int,int);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.Object,java.util.Map);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.Object,java.util.Map);;Argument[0..1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.Object,java.util.Map,java.lang.String,java.lang.String);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.Object,java.util.Map,java.lang.String,java.lang.String);;Argument[1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.Object,java.util.Properties);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;setVariableResolver;;;Argument;Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replaceIn;(org.apache.commons.lang3.text.StrBuilder);;Argument[-1];Argument;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replaceIn;(java.lang.StringBuffer);;Argument[-1];Argument;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replace;(java.lang.Object,java.util.Properties);;Argument[0..1];ReturnValue;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;setVariableResolver;;;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replaceIn;(org.apache.commons.lang3.text.StrBuilder);;Argument[-1];Argument[0];taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replaceIn;(java.lang.StringBuffer);;Argument[-1];Argument[0];taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replaceIn;(java.lang.StringBuffer,int,int);;Argument[-1];Argument[0];taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replaceIn;(java.lang.StringBuilder);;Argument[-1];Argument;taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replaceIn;(java.lang.StringBuilder);;Argument[-1];Argument[0];taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replaceIn;(java.lang.StringBuilder,int,int);;Argument[-1];Argument[0];taint",
|
||||
"org.apache.commons.lang3.text;StrSubstitutor;false;replaceIn;(org.apache.commons.lang3.text.StrBuilder,int,int);;Argument[-1];Argument[0];taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;StringSubstitutor;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;StringSubstitutor;;;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replace;;;Argument[-1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.Object);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replace;(char[]);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.Object);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replace;(char[]);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replace;(char[],int,int);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.CharSequence);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.CharSequence);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.CharSequence,int,int);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.String);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.StringBuffer);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.String);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.StringBuffer);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.StringBuffer,int,int);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.String,int,int);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.Object,java.util.Map);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.Object,java.util.Map);;Argument[0..1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.Object,java.util.Map,java.lang.String,java.lang.String);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.Object,java.util.Map,java.lang.String,java.lang.String);;Argument[1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.Object,java.util.Properties);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replace;(org.apache.commons.text.TextStringBuilder);;Argument;ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replace;(java.lang.Object,java.util.Properties);;Argument[0..1];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replace;(org.apache.commons.text.TextStringBuilder);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replace;(org.apache.commons.text.TextStringBuilder,int,int);;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;setVariableResolver;;;Argument;Argument[-1];taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replaceIn;(java.lang.StringBuffer);;Argument[-1];Argument;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;setVariableResolver;;;Argument[0];Argument[-1];taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replaceIn;(java.lang.StringBuffer);;Argument[-1];Argument[0];taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replaceIn;(java.lang.StringBuffer,int,int);;Argument[-1];Argument[0];taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replaceIn;(java.lang.StringBuilder);;Argument[-1];Argument;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replaceIn;(java.lang.StringBuilder);;Argument[-1];Argument[0];taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replaceIn;(java.lang.StringBuilder,int,int);;Argument[-1];Argument[0];taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replaceIn;(org.apache.commons.text.TextStringBuilder);;Argument[-1];Argument;taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replaceIn;(org.apache.commons.text.TextStringBuilder);;Argument[-1];Argument[0];taint",
|
||||
"org.apache.commons.text;StringSubstitutor;false;replaceIn;(org.apache.commons.text.TextStringBuilder,int,int);;Argument[-1];Argument[0];taint"
|
||||
]
|
||||
}
|
||||
@@ -396,3 +610,30 @@ private class ApacheRegExUtilsModel extends SummaryModelCsv {
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Taint-propagating models for `ObjectUtils`.
|
||||
*/
|
||||
private class ApacheObjectUtilsModel extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
// Note all the functions annotated with `taint` flow really should have `value` flow,
|
||||
// but we don't support value-preserving varargs functions at the moment.
|
||||
"org.apache.commons.lang3;ObjectUtils;false;clone;;;Argument[0];ReturnValue;value",
|
||||
"org.apache.commons.lang3;ObjectUtils;false;cloneIfPossible;;;Argument[0];ReturnValue;value",
|
||||
"org.apache.commons.lang3;ObjectUtils;false;CONST;;;Argument[0];ReturnValue;value",
|
||||
"org.apache.commons.lang3;ObjectUtils;false;CONST_BYTE;;;Argument[0];ReturnValue;value",
|
||||
"org.apache.commons.lang3;ObjectUtils;false;CONST_SHORT;;;Argument[0];ReturnValue;value",
|
||||
"org.apache.commons.lang3;ObjectUtils;false;defaultIfNull;;;Argument[0..1];ReturnValue;value",
|
||||
"org.apache.commons.lang3;ObjectUtils;false;firstNonNull;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;ObjectUtils;false;getIfNull;;;Argument[0];ReturnValue;value",
|
||||
"org.apache.commons.lang3;ObjectUtils;false;max;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;ObjectUtils;false;median;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;ObjectUtils;false;min;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;ObjectUtils;false;mode;;;Argument[0];ReturnValue;taint",
|
||||
"org.apache.commons.lang3;ObjectUtils;false;requireNonEmpty;;;Argument[0];ReturnValue;value",
|
||||
"org.apache.commons.lang3;ObjectUtils;false;toString;(Object,String);;Argument[1];ReturnValue;value"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
40
java/ql/src/semmle/code/java/frameworks/guava/Base.qll
Normal file
40
java/ql/src/semmle/code/java/frameworks/guava/Base.qll
Normal file
@@ -0,0 +1,40 @@
|
||||
/** Definitions of flow steps through utility methods of `com.google.common.base`. */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.ExternalFlow
|
||||
|
||||
private class GuavaBaseCsv extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
//"package;type;overrides;name;signature;ext;inputspec;outputspec;kind",
|
||||
"com.google.common.base;Strings;false;emptyToNull;(String);;Argument[0];ReturnValue;value",
|
||||
"com.google.common.base;Strings;false;nullToEmpty;(String);;Argument[0];ReturnValue;value",
|
||||
"com.google.common.base;Strings;false;padStart;(String,int,char);;Argument[0];ReturnValue;taint",
|
||||
"com.google.common.base;Strings;false;padEnd;(String,int,char);;Argument[0];ReturnValue;taint",
|
||||
"com.google.common.base;Strings;false;repeat;(String,int);;Argument[0];ReturnValue;taint",
|
||||
"com.google.common.base;Strings;false;lenientFormat;(String,Object[]);;Argument;ReturnValue;taint",
|
||||
"com.google.common.base;Joiner;false;on;(String);;Argument[0];ReturnValue;taint",
|
||||
"com.google.common.base;Joiner;false;skipNulls;();;Argument[-1];ReturnValue;taint",
|
||||
"com.google.common.base;Joiner;false;useForNull;(String);;Argument[-1];ReturnValue;taint",
|
||||
"com.google.common.base;Joiner;false;useForNull;(String);;Argument[0];ReturnValue;taint",
|
||||
"com.google.common.base;Joiner;false;withKeyValueSeparator;(String);;Argument[0];ReturnValue;taint",
|
||||
"com.google.common.base;Joiner;false;withKeyValueSeparator;(String);;Argument[-1];ReturnValue;taint",
|
||||
"com.google.common.base;Joiner;false;withKeyValueSeparator;(char);;Argument[-1];ReturnValue;taint",
|
||||
// Note: The signatures of some of the appendTo methods involve collection flow
|
||||
"com.google.common.base;Joiner;false;appendTo;;;Argument;Argument[0];taint",
|
||||
"com.google.common.base;Joiner;false;appendTo;;;Argument[0];ReturnValue;value",
|
||||
"com.google.common.base;Joiner;false;join;;;Argument;ReturnValue;taint",
|
||||
"com.google.common.base;Joiner$MapJoiner;false;useForNull;(String);;Argument[0];ReturnValue;taint",
|
||||
"com.google.common.base;Joiner$MapJoiner;false;useForNull;(String);;Argument[-1];ReturnValue;taint",
|
||||
"com.google.common.base;Joiner$MapJoiner;false;appendTo;;;Argument;Argument[0];taint",
|
||||
"com.google.common.base;Joiner$MapJoiner;false;appendTo;;;Argument[0];ReturnValue;value",
|
||||
"com.google.common.base;Joiner$MapJoiner;false;join;;;Argument;ReturnValue;taint",
|
||||
"com.google.common.base;Splitter;false;split;(CharSequence);;Argument[0];ReturnValue;taint",
|
||||
"com.google.common.base;Splitter;false;splitToList;(CharSequence);;Argument[0];ReturnValue;taint",
|
||||
"com.google.common.base;Splitter;false;splitToStream;(CharSequence);;Argument[0];ReturnValue;taint",
|
||||
"com.google.common.base;Splitter$MapSplitter;false;split;(CharSequence);;Argument[0];ReturnValue;taint",
|
||||
"com.google.common.base;Preconditions;false;checkNotNull;;;Argument[0];ReturnValue;value"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import StringUtils
|
||||
import Base
|
||||
import Collections
|
||||
import Preconditions
|
||||
import IO
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user