mirror of
https://github.com/github/codeql.git
synced 2026-05-02 12:15:17 +02:00
Merge branch 'main' into delOldDeps
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"markdownMessage": "An Android build may have failed. Ensure the Code Scanning workflow installs required dependencies, and that the [Gradle and Android SDK versions are compatible](https://developer.android.com/studio/releases/gradle-plugin#updating-gradle). Suspicious output line: ` > Minimum supported Gradle version is 7.4. Current version is 7.3. If using the gradle wrapper, try editing the distributionUrl in <test-root-directory>/gradle/wrapper/gradle-wrapper.properties to gradle-7.4-all.zip`",
|
||||
"markdownMessage": "An Android build may have failed. Ensure the Code Scanning workflow installs required dependencies, and that the [Gradle and Android SDK versions are compatible](https://developer.android.com/studio/releases/gradle-plugin#updating-gradle).\n\nSuspicious output line: ` > Minimum supported Gradle version is 7.4. Current version is 7.3. If using the gradle wrapper, try editing the distributionUrl in <test-root-directory>/gradle/wrapper/gradle-wrapper.properties to gradle-7.4-all.zip`",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
"extractorName": "java",
|
||||
@@ -13,7 +13,7 @@
|
||||
}
|
||||
}
|
||||
{
|
||||
"markdownMessage": "An Android build may have failed. Ensure the Code Scanning workflow installs required dependencies, and that the [Gradle and Android SDK versions are compatible](https://developer.android.com/studio/releases/gradle-plugin#updating-gradle). Suspicious output line: `Caused by: java.lang.RuntimeException: Minimum supported Gradle version is 7.4. Current version is 7.3. If using the gradle wrapper, try editing the distributionUrl in <test-root-directory>/gradle/wrapper/gradle-wrapper.properties to gradle-7.4-all.zip`",
|
||||
"markdownMessage": "An Android build may have failed. Ensure the Code Scanning workflow installs required dependencies, and that the [Gradle and Android SDK versions are compatible](https://developer.android.com/studio/releases/gradle-plugin#updating-gradle).\n\nSuspicious output line: `Caused by: java.lang.RuntimeException: Minimum supported Gradle version is 7.4. Current version is 7.3. If using the gradle wrapper, try editing the distributionUrl in <test-root-directory>/gradle/wrapper/gradle-wrapper.properties to gradle-7.4-all.zip`",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
"extractorName": "java",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"markdownMessage": "A compilation error was observed while autobuilding your code. Check that your Code Scanning workflow installs the needed compiler version and dependencies. Suspicious output line: `[ERROR] COMPILATION ERROR : `",
|
||||
"markdownMessage": "A compilation error was observed while autobuilding your code. Check that your Code Scanning workflow installs the needed compiler version and dependencies.\n\nSuspicious output line: `[ERROR] COMPILATION ERROR : `",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
"extractorName": "java",
|
||||
@@ -13,7 +13,7 @@
|
||||
}
|
||||
}
|
||||
{
|
||||
"markdownMessage": "A compilation error was observed while autobuilding your code. Check that your Code Scanning workflow installs the needed compiler version and dependencies. Suspicious output line: `[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.0:compile (default-compile) on project maven-sample: Compilation failure`",
|
||||
"markdownMessage": "A compilation error was observed while autobuilding your code. Check that your Code Scanning workflow installs the needed compiler version and dependencies.\n\nSuspicious output line: `[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.0:compile (default-compile) on project maven-sample: Compilation failure`",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
"extractorName": "java",
|
||||
@@ -27,7 +27,7 @@
|
||||
}
|
||||
}
|
||||
{
|
||||
"markdownMessage": "A compilation error was observed while autobuilding your code. Check that your Code Scanning workflow installs the needed compiler version and dependencies. Suspicious output line: `org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.0:compile (default-compile) on project maven-sample: Compilation failure`",
|
||||
"markdownMessage": "A compilation error was observed while autobuilding your code. Check that your Code Scanning workflow installs the needed compiler version and dependencies.\n\nSuspicious output line: `org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.0:compile (default-compile) on project maven-sample: Compilation failure`",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
"extractorName": "java",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"markdownMessage": "A dependency failed to download. Check that all dependencies are available, and [supply credentials for any private dependencies](https://github.com/Azure/actions-workflow-samples/blob/master/assets/create-secrets-for-GitHub-workflows.md#set-up-secrets-in-github-action-workflows). Suspicious output line: `Caused by: org.eclipse.aether.transfer.ArtifactNotFoundException: Could not find artifact junit:junit-nonesuch:jar:4.11 in central (https://repo.maven.apache.org/maven2)`",
|
||||
"markdownMessage": "A dependency failed to download. Check that all dependencies are available, and [supply credentials for any private dependencies](https://github.com/Azure/actions-workflow-samples/blob/master/assets/create-secrets-for-GitHub-workflows.md#set-up-secrets-in-github-action-workflows).\n\nSuspicious output line: `Caused by: org.eclipse.aether.transfer.ArtifactNotFoundException: Could not find artifact junit:junit-nonesuch:jar:4.11 in central (https://repo.maven.apache.org/maven2)`",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
"extractorName": "java",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"markdownMessage": "Your project may need a different JDK version. Ensure your Code Scanning workflow file has [an appropriate `setup-java` step](https://github.com/actions/setup-java#eclipse-temurin). Suspicious output line: `> Could not target platform: 'Java SE 11' using tool chain: 'JDK 8 (1.8)'.`",
|
||||
"markdownMessage": "Your project may need a different JDK version. Ensure your Code Scanning workflow file has [an appropriate `setup-java` step](https://github.com/actions/setup-java#eclipse-temurin).\n\nSuspicious output line: `> Could not target platform: 'Java SE 11' using tool chain: 'JDK 8 (1.8)'.`",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
"extractorName": "java",
|
||||
@@ -13,7 +13,7 @@
|
||||
}
|
||||
}
|
||||
{
|
||||
"markdownMessage": "Your project may need a different JDK version. Ensure your Code Scanning workflow file has [an appropriate `setup-java` step](https://github.com/actions/setup-java#eclipse-temurin). Suspicious output line: `Caused by: java.lang.IllegalArgumentException: Could not target platform: 'Java SE 11' using tool chain: 'JDK 8 (1.8)'.`",
|
||||
"markdownMessage": "Your project may need a different JDK version. Ensure your Code Scanning workflow file has [an appropriate `setup-java` step](https://github.com/actions/setup-java#eclipse-temurin).\n\nSuspicious output line: `Caused by: java.lang.IllegalArgumentException: Could not target platform: 'Java SE 11' using tool chain: 'JDK 8 (1.8)'.`",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
"extractorName": "java",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"markdownMessage": "Building your code triggered an access to an insecure HTTP Maven repository. Allow access to insecure repositories, or [update your build to use HTTPS](https://maven.apache.org/docs/3.8.1/release-notes.html#how-to-fix-when-i-get-a-http-repository-blocked). Suspicious output line: `Caused by: org.eclipse.aether.resolution.ArtifactResolutionException: Could not transfer artifact junit-nonesuch:junit-nonesuch:pom:4.11 from/to maven-default-http-blocker (http://0.0.0.0/): Blocked mirror for repositories: [insecure (http://repo.maven.apache.org/maven2/, default, releases+snapshots)]`",
|
||||
"markdownMessage": "Building your code triggered an access to an insecure HTTP Maven repository. Allow access to insecure repositories, or [update your build to use HTTPS](https://maven.apache.org/docs/3.8.1/release-notes.html#how-to-fix-when-i-get-a-http-repository-blocked).\n\nSuspicious output line: `Caused by: org.eclipse.aether.resolution.ArtifactResolutionException: Could not transfer artifact junit-nonesuch:junit-nonesuch:pom:4.11 from/to maven-default-http-blocker (http://0.0.0.0/): Blocked mirror for repositories: [insecure (http://repo.maven.apache.org/maven2/, default, releases+snapshots)]`",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
"extractorName": "java",
|
||||
@@ -13,7 +13,7 @@
|
||||
}
|
||||
}
|
||||
{
|
||||
"markdownMessage": "Building your code triggered an access to an insecure HTTP Maven repository. Allow access to insecure repositories, or [update your build to use HTTPS](https://maven.apache.org/docs/3.8.1/release-notes.html#how-to-fix-when-i-get-a-http-repository-blocked). Suspicious output line: `Caused by: org.eclipse.aether.transfer.ArtifactTransferException: Could not transfer artifact junit-nonesuch:junit-nonesuch:pom:4.11 from/to maven-default-http-blocker (http://0.0.0.0/): Blocked mirror for repositories: [insecure (http://repo.maven.apache.org/maven2/, default, releases+snapshots)]`",
|
||||
"markdownMessage": "Building your code triggered an access to an insecure HTTP Maven repository. Allow access to insecure repositories, or [update your build to use HTTPS](https://maven.apache.org/docs/3.8.1/release-notes.html#how-to-fix-when-i-get-a-http-repository-blocked).\n\nSuspicious output line: `Caused by: org.eclipse.aether.transfer.ArtifactTransferException: Could not transfer artifact junit-nonesuch:junit-nonesuch:pom:4.11 from/to maven-default-http-blocker (http://0.0.0.0/): Blocked mirror for repositories: [insecure (http://repo.maven.apache.org/maven2/, default, releases+snapshots)]`",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
"extractorName": "java",
|
||||
@@ -27,7 +27,7 @@
|
||||
}
|
||||
}
|
||||
{
|
||||
"markdownMessage": "Building your code triggered an access to an insecure HTTP Maven repository. Allow access to insecure repositories, or [update your build to use HTTPS](https://maven.apache.org/docs/3.8.1/release-notes.html#how-to-fix-when-i-get-a-http-repository-blocked). Suspicious output line: `Caused by: org.eclipse.aether.transfer.NoRepositoryConnectorException: Blocked mirror for repositories: [insecure (http://repo.maven.apache.org/maven2/, default, releases+snapshots)]`",
|
||||
"markdownMessage": "Building your code triggered an access to an insecure HTTP Maven repository. Allow access to insecure repositories, or [update your build to use HTTPS](https://maven.apache.org/docs/3.8.1/release-notes.html#how-to-fix-when-i-get-a-http-repository-blocked).\n\nSuspicious output line: `Caused by: org.eclipse.aether.transfer.NoRepositoryConnectorException: Blocked mirror for repositories: [insecure (http://repo.maven.apache.org/maven2/, default, releases+snapshots)]`",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
"extractorName": "java",
|
||||
@@ -41,7 +41,7 @@
|
||||
}
|
||||
}
|
||||
{
|
||||
"markdownMessage": "Building your code triggered an access to an insecure HTTP Maven repository. Allow access to insecure repositories, or [update your build to use HTTPS](https://maven.apache.org/docs/3.8.1/release-notes.html#how-to-fix-when-i-get-a-http-repository-blocked). Suspicious output line: `[ERROR] Failed to execute goal on project maven-sample: Could not resolve dependencies for project com.example:maven-sample:jar:1.0-SNAPSHOT: Failed to collect dependencies at junit-nonesuch:junit-nonesuch:jar:4.11: Failed to read artifact descriptor for junit-nonesuch:junit-nonesuch:jar:4.11: Could not transfer artifact junit-nonesuch:junit-nonesuch:pom:4.11 from/to maven-default-http-blocker (http://0.0.0.0/): Blocked mirror for repositories: [insecure (http://repo.maven.apache.org/maven2/, default, releases+snapshots)] -> [Help 1]`",
|
||||
"markdownMessage": "Building your code triggered an access to an insecure HTTP Maven repository. Allow access to insecure repositories, or [update your build to use HTTPS](https://maven.apache.org/docs/3.8.1/release-notes.html#how-to-fix-when-i-get-a-http-repository-blocked).\n\nSuspicious output line: `[ERROR] Failed to execute goal on project maven-sample: Could not resolve dependencies for project com.example:maven-sample:jar:1.0-SNAPSHOT: Failed to collect dependencies at junit-nonesuch:junit-nonesuch:jar:4.11: Failed to read artifact descriptor for junit-nonesuch:junit-nonesuch:jar:4.11: Could not transfer artifact junit-nonesuch:junit-nonesuch:pom:4.11 from/to maven-default-http-blocker (http://0.0.0.0/): Blocked mirror for repositories: [insecure (http://repo.maven.apache.org/maven2/, default, releases+snapshots)] -> [Help 1]`",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
"extractorName": "java",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"markdownMessage": "Building using Maven was skipped because there were multiple sibling build directories containing build files: [./maven-project-1,./maven-project-2]. If you want to use one of these, please [manually supply a build command](https://docs.github.com/en/github-ae@latest/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages#adding-build-steps-for-a-compiled-language)",
|
||||
"markdownMessage": "Building using Maven was skipped because there were multiple sibling build directories containing build files: [./maven-project-1,./maven-project-2]. If you want to use one of these, please [manually supply a build command](https://docs.github.com/en/github-ae@latest/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages#adding-build-steps-for-a-compiled-language).",
|
||||
"severity": "warning",
|
||||
"source": {
|
||||
"extractorName": "java",
|
||||
@@ -13,7 +13,7 @@
|
||||
}
|
||||
}
|
||||
{
|
||||
"markdownMessage": "If you want to use one of the candidate build systems and directories (see previous warnings), please [supply a manual a build command](https://docs.github.com/en/github-ae@latest/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages#adding-build-steps-for-a-compiled-language)",
|
||||
"markdownMessage": "If you want to use one of the candidate build systems and directories (see previous warnings), please [supply a manual a build command](https://docs.github.com/en/github-ae@latest/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages#adding-build-steps-for-a-compiled-language).",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
"extractorName": "java",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"markdownMessage": "Could not find a Gradle, Maven or Ant top-level project to build. Please [supply a manual build command](https://docs.github.com/en/github-ae@latest/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages#adding-build-steps-for-a-compiled-language)",
|
||||
"markdownMessage": "Could not find a Gradle, Maven or Ant top-level project to build. Please [supply a manual build command](https://docs.github.com/en/github-ae@latest/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages#adding-build-steps-for-a-compiled-language).",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
"extractorName": "java",
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
}
|
||||
}
|
||||
{
|
||||
"markdownMessage": "Gradle project does not define a `testClasses` goal. [Supply a manual build command](https://docs.github.com/en/github-ae@latest/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages#adding-build-steps-for-a-compiled-language) that builds the code that should be analyzed. Suspicious output line: `org.gradle.execution.TaskSelectionException: Task 'testClasses' not found in root project 'no-gradle-test-classes'.`",
|
||||
"markdownMessage": "Gradle project does not define a `testClasses` goal. [Supply a manual build command](https://docs.github.com/en/github-ae@latest/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages#adding-build-steps-for-a-compiled-language) that builds the code that should be analyzed.\n\nSuspicious output line: `org.gradle.execution.TaskSelectionException: Task 'testClasses' not found in root project 'no-gradle-test-classes'.`",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
"extractorName": "java",
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"markdownMessage": "The Kotlin version installed (`999.999.999`) is too recent for this version of CodeQL. Install a version lower than 1.8.30",
|
||||
"markdownMessage": "The Kotlin version installed (`999.999.999`) is too recent for this version of CodeQL. Install a version lower than 1.8.30.",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
"extractorName": "java",
|
||||
"id": "java/extractor-agent/kotlin-version-too-new",
|
||||
"name": "Android build failure"
|
||||
"name": "Kotlin version too new"
|
||||
},
|
||||
"visibility": {
|
||||
"cliSummaryTable": true,
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
## 0.5.4
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Added new sinks for `java/hardcoded-credential-api-call` to identify the use of hardcoded secrets in the creation and verification of JWT tokens using `com.auth0.jwt`. These sinks are from [an experimental query submitted by @luchua](https://github.com/github/codeql/pull/9036).
|
||||
* The Java extractor now supports builds against JDK 20.
|
||||
* The query `java/hardcoded-credential-api-call` now recognizes methods that accept user and password from the SQLServerDataSource class of the Microsoft JDBC Driver for SQL Server.
|
||||
|
||||
## 0.5.3
|
||||
|
||||
### New Features
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The query `java/hardcoded-credential-api-call` now recognizes methods that accept user and password from the SQLServerDataSource class of the Microsoft JDBC Driver for SQL Server.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Added new sinks for `java/hardcoded-credential-api-call` to identify the use of hardcoded secrets in the creation and verification of JWT tokens using `com.auth0.jwt`. These sinks are from [an experimental query submitted by @luchua](https://github.com/github/codeql/pull/9036).
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The Java extractor now supports builds against JDK 20.
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
category: majorAnalysis
|
||||
---
|
||||
* The main data flow and taint tracking APIs have been changed. The old APIs
|
||||
remain in place for now and translate to the new through a
|
||||
backwards-compatible wrapper. If multiple configurations are in scope
|
||||
simultaneously, then this may affect results slightly. The new API is quite
|
||||
similar to the old, but makes use of a configuration module instead of a
|
||||
configuration class.
|
||||
7
java/ql/lib/change-notes/released/0.5.4.md
Normal file
7
java/ql/lib/change-notes/released/0.5.4.md
Normal file
@@ -0,0 +1,7 @@
|
||||
## 0.5.4
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Added new sinks for `java/hardcoded-credential-api-call` to identify the use of hardcoded secrets in the creation and verification of JWT tokens using `com.auth0.jwt`. These sinks are from [an experimental query submitted by @luchua](https://github.com/github/codeql/pull/9036).
|
||||
* The Java extractor now supports builds against JDK 20.
|
||||
* The query `java/hardcoded-credential-api-call` now recognizes methods that accept user and password from the SQLServerDataSource class of the Microsoft JDBC Driver for SQL Server.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.5.3
|
||||
lastReleaseVersion: 0.5.4
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/java-all
|
||||
version: 0.5.4-dev
|
||||
version: 0.5.5-dev
|
||||
groups: java
|
||||
dbscheme: config/semmlecode.dbscheme
|
||||
extractor: java
|
||||
|
||||
@@ -6,5 +6,6 @@
|
||||
import java
|
||||
|
||||
module DataFlow {
|
||||
import semmle.code.java.dataflow.internal.DataFlowImpl
|
||||
import semmle.code.java.dataflow.internal.DataFlow
|
||||
import semmle.code.java.dataflow.internal.DataFlowImpl1
|
||||
}
|
||||
|
||||
@@ -8,5 +8,6 @@ import semmle.code.java.dataflow.DataFlow2
|
||||
import semmle.code.java.dataflow.internal.TaintTrackingUtil::StringBuilderVarModule
|
||||
|
||||
module TaintTracking {
|
||||
import semmle.code.java.dataflow.internal.tainttracking1.TaintTracking
|
||||
import semmle.code.java.dataflow.internal.tainttracking1.TaintTrackingImpl
|
||||
}
|
||||
|
||||
245
java/ql/lib/semmle/code/java/dataflow/internal/DataFlow.qll
Normal file
245
java/ql/lib/semmle/code/java/dataflow/internal/DataFlow.qll
Normal file
@@ -0,0 +1,245 @@
|
||||
/**
|
||||
* Provides an implementation of global (interprocedural) data flow. This file
|
||||
* re-exports the local (intraprocedural) data flow analysis from
|
||||
* `DataFlowImplSpecific::Public` and adds a global analysis, mainly exposed
|
||||
* through the `Make` and `MakeWithState` modules.
|
||||
*/
|
||||
|
||||
private import DataFlowImplCommon
|
||||
private import DataFlowImplSpecific::Private
|
||||
import DataFlowImplSpecific::Public
|
||||
import DataFlowImplCommonPublic
|
||||
private import DataFlowImpl
|
||||
|
||||
/** An input configuration for data flow. */
|
||||
signature module ConfigSig {
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source.
|
||||
*/
|
||||
predicate isSource(Node source);
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink.
|
||||
*/
|
||||
predicate isSink(Node sink);
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited. This completely removes
|
||||
* `node` from the data flow graph.
|
||||
*/
|
||||
default predicate isBarrier(Node node) { none() }
|
||||
|
||||
/** Holds if data flow into `node` is prohibited. */
|
||||
default predicate isBarrierIn(Node node) { none() }
|
||||
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
default predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
default predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
default predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
* This can be overridden to a smaller value to improve performance (a
|
||||
* value of 0 disables field flow), or a larger value to get more results.
|
||||
*/
|
||||
default int fieldFlowBranchLimit() { result = 2 }
|
||||
|
||||
/**
|
||||
* Gets a data flow configuration feature to add restrictions to the set of
|
||||
* valid flow paths.
|
||||
*
|
||||
* - `FeatureHasSourceCallContext`:
|
||||
* Assume that sources have some existing call context to disallow
|
||||
* conflicting return-flow directly following the source.
|
||||
* - `FeatureHasSinkCallContext`:
|
||||
* Assume that sinks have some existing call context to disallow
|
||||
* conflicting argument-to-parameter flow directly preceding the sink.
|
||||
* - `FeatureEqualSourceSinkCallContext`:
|
||||
* Implies both of the above and additionally ensures that the entire flow
|
||||
* path preserves the call context.
|
||||
*
|
||||
* These features are generally not relevant for typical end-to-end data flow
|
||||
* queries, but should only be used for constructing paths that need to
|
||||
* somehow be pluggable in another path context.
|
||||
*/
|
||||
default FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
default predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
default predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if hidden nodes should be included in the data flow graph.
|
||||
*
|
||||
* This feature should only be used for debugging or when the data flow graph
|
||||
* is not visualized (as it is in a `path-problem` query).
|
||||
*/
|
||||
default predicate includeHiddenNodes() { none() }
|
||||
}
|
||||
|
||||
/** An input configuration for data flow using flow state. */
|
||||
signature module StateConfigSig {
|
||||
bindingset[this]
|
||||
class FlowState;
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source with the given initial
|
||||
* `state`.
|
||||
*/
|
||||
predicate isSource(Node source, FlowState state);
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink accepting `state`.
|
||||
*/
|
||||
predicate isSink(Node sink, FlowState state);
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited. This completely removes
|
||||
* `node` from the data flow graph.
|
||||
*/
|
||||
default predicate isBarrier(Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited when the flow state is
|
||||
* `state`.
|
||||
*/
|
||||
predicate isBarrier(Node node, FlowState state);
|
||||
|
||||
/** Holds if data flow into `node` is prohibited. */
|
||||
default predicate isBarrierIn(Node node) { none() }
|
||||
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
default predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
default predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2);
|
||||
|
||||
/**
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
default predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
* This can be overridden to a smaller value to improve performance (a
|
||||
* value of 0 disables field flow), or a larger value to get more results.
|
||||
*/
|
||||
default int fieldFlowBranchLimit() { result = 2 }
|
||||
|
||||
/**
|
||||
* Gets a data flow configuration feature to add restrictions to the set of
|
||||
* valid flow paths.
|
||||
*
|
||||
* - `FeatureHasSourceCallContext`:
|
||||
* Assume that sources have some existing call context to disallow
|
||||
* conflicting return-flow directly following the source.
|
||||
* - `FeatureHasSinkCallContext`:
|
||||
* Assume that sinks have some existing call context to disallow
|
||||
* conflicting argument-to-parameter flow directly preceding the sink.
|
||||
* - `FeatureEqualSourceSinkCallContext`:
|
||||
* Implies both of the above and additionally ensures that the entire flow
|
||||
* path preserves the call context.
|
||||
*
|
||||
* These features are generally not relevant for typical end-to-end data flow
|
||||
* queries, but should only be used for constructing paths that need to
|
||||
* somehow be pluggable in another path context.
|
||||
*/
|
||||
default FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
default predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
default predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if hidden nodes should be included in the data flow graph.
|
||||
*
|
||||
* This feature should only be used for debugging or when the data flow graph
|
||||
* is not visualized (as it is in a `path-problem` query).
|
||||
*/
|
||||
default predicate includeHiddenNodes() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
|
||||
* measured in approximate number of interprocedural steps.
|
||||
*/
|
||||
signature int explorationLimitSig();
|
||||
|
||||
/**
|
||||
* The output of a data flow computation.
|
||||
*/
|
||||
signature module DataFlowSig {
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks) and an access path.
|
||||
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
|
||||
*/
|
||||
class PathNode;
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `source` to `sink`.
|
||||
*
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink);
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `source` to `sink`.
|
||||
*/
|
||||
predicate hasFlow(Node source, Node sink);
|
||||
|
||||
/**
|
||||
* Holds if data can flow from some source to `sink`.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink);
|
||||
|
||||
/**
|
||||
* Holds if data can flow from some source to `sink`.
|
||||
*/
|
||||
predicate hasFlowToExpr(DataFlowExpr sink);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a standard data flow computation.
|
||||
*/
|
||||
module Make<ConfigSig Config> implements DataFlowSig {
|
||||
private module C implements FullStateConfigSig {
|
||||
import DefaultState<Config>
|
||||
import Config
|
||||
}
|
||||
|
||||
import Impl<C>
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a data flow computation using flow state.
|
||||
*/
|
||||
module MakeWithState<StateConfigSig Config> implements DataFlowSig {
|
||||
private module C implements FullStateConfigSig {
|
||||
import Config
|
||||
}
|
||||
|
||||
import Impl<C>
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
396
java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl1.qll
Normal file
396
java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl1.qll
Normal file
@@ -0,0 +1,396 @@
|
||||
/**
|
||||
* DEPRECATED: Use `Make` and `MakeWithState` instead.
|
||||
*
|
||||
* Provides a `Configuration` class backwards-compatible interface to the data
|
||||
* flow library.
|
||||
*/
|
||||
|
||||
private import DataFlowImplCommon
|
||||
private import DataFlowImplSpecific::Private
|
||||
import DataFlowImplSpecific::Public
|
||||
private import DataFlowImpl
|
||||
import DataFlowImplCommonPublic
|
||||
import FlowStateString
|
||||
|
||||
/**
|
||||
* A configuration of interprocedural data flow analysis. This defines
|
||||
* sources, sinks, and any other configurable aspect of the analysis. Each
|
||||
* use of the global data flow library must define its own unique extension
|
||||
* of this abstract class. To create a configuration, extend this class with
|
||||
* a subclass whose characteristic predicate is a unique singleton string.
|
||||
* For example, write
|
||||
*
|
||||
* ```ql
|
||||
* class MyAnalysisConfiguration extends DataFlow::Configuration {
|
||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
||||
* // Override `isSource` and `isSink`.
|
||||
* // Optionally override `isBarrier`.
|
||||
* // Optionally override `isAdditionalFlowStep`.
|
||||
* }
|
||||
* ```
|
||||
* Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and
|
||||
* the edges are those data-flow steps that preserve the value of the node
|
||||
* along with any additional edges defined by `isAdditionalFlowStep`.
|
||||
* Specifying nodes in `isBarrier` will remove those nodes from the graph, and
|
||||
* specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going
|
||||
* and/or out-going edges from those nodes, respectively.
|
||||
*
|
||||
* Then, to query whether there is flow between some `source` and `sink`,
|
||||
* write
|
||||
*
|
||||
* ```ql
|
||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
||||
* ```
|
||||
*
|
||||
* Multiple configurations can coexist, but two classes extending
|
||||
* `DataFlow::Configuration` should never depend on each other. One of them
|
||||
* should instead depend on a `DataFlow2::Configuration`, a
|
||||
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
|
||||
*/
|
||||
abstract class Configuration extends string {
|
||||
bindingset[this]
|
||||
Configuration() { any() }
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source.
|
||||
*/
|
||||
predicate isSource(Node source) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source with the given initial
|
||||
* `state`.
|
||||
*/
|
||||
predicate isSource(Node source, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink.
|
||||
*/
|
||||
predicate isSink(Node sink) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink accepting `state`.
|
||||
*/
|
||||
predicate isSink(Node sink, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited. This completely removes
|
||||
* `node` from the data flow graph.
|
||||
*/
|
||||
predicate isBarrier(Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited when the flow state is
|
||||
* `state`.
|
||||
*/
|
||||
predicate isBarrier(Node node, FlowState state) { none() }
|
||||
|
||||
/** Holds if data flow into `node` is prohibited. */
|
||||
predicate isBarrierIn(Node node) { none() }
|
||||
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited.
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited when
|
||||
* the flow state is `state`
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
* This can be overridden to a smaller value to improve performance (a
|
||||
* value of 0 disables field flow), or a larger value to get more results.
|
||||
*/
|
||||
int fieldFlowBranchLimit() { result = 2 }
|
||||
|
||||
/**
|
||||
* Gets a data flow configuration feature to add restrictions to the set of
|
||||
* valid flow paths.
|
||||
*
|
||||
* - `FeatureHasSourceCallContext`:
|
||||
* Assume that sources have some existing call context to disallow
|
||||
* conflicting return-flow directly following the source.
|
||||
* - `FeatureHasSinkCallContext`:
|
||||
* Assume that sinks have some existing call context to disallow
|
||||
* conflicting argument-to-parameter flow directly preceding the sink.
|
||||
* - `FeatureEqualSourceSinkCallContext`:
|
||||
* Implies both of the above and additionally ensures that the entire flow
|
||||
* path preserves the call context.
|
||||
*
|
||||
* These features are generally not relevant for typical end-to-end data flow
|
||||
* queries, but should only be used for constructing paths that need to
|
||||
* somehow be pluggable in another path context.
|
||||
*/
|
||||
FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlow(Node source, Node sink) { hasFlow(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `FlowExploration<explorationLimit>` instead.
|
||||
*
|
||||
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
|
||||
* measured in approximate number of interprocedural steps.
|
||||
*/
|
||||
deprecated int explorationLimit() { none() }
|
||||
|
||||
/**
|
||||
* Holds if hidden nodes should be included in the data flow graph.
|
||||
*
|
||||
* This feature should only be used for debugging or when the data flow graph
|
||||
* is not visualized (for example in a `path-problem` query).
|
||||
*/
|
||||
predicate includeHiddenNodes() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* This class exists to prevent mutual recursion between the user-overridden
|
||||
* member predicates of `Configuration` and the rest of the data-flow library.
|
||||
* Good performance cannot be guaranteed in the presence of such recursion, so
|
||||
* it should be replaced by using more than one copy of the data flow library.
|
||||
*/
|
||||
abstract private class ConfigurationRecursionPrevention extends Configuration {
|
||||
bindingset[this]
|
||||
ConfigurationRecursionPrevention() { any() }
|
||||
|
||||
override predicate hasFlow(Node source, Node sink) {
|
||||
strictcount(Node n | this.isSource(n)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSource(n, _)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSink(n)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSink(n, _)) < 0
|
||||
or
|
||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, n2)) < 0
|
||||
or
|
||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, _, n2, _)) < 0
|
||||
or
|
||||
super.hasFlow(source, sink)
|
||||
}
|
||||
}
|
||||
|
||||
/** A bridge class to access the deprecated `isBarrierGuard`. */
|
||||
private class BarrierGuardGuardedNodeBridge extends Unit {
|
||||
abstract predicate guardedNode(Node n, Configuration config);
|
||||
|
||||
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
|
||||
}
|
||||
|
||||
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
|
||||
deprecated override predicate guardedNode(Node n, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
|
||||
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g, state) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private FlowState relevantState(Configuration config) {
|
||||
config.isSource(_, result) or
|
||||
config.isSink(_, result) or
|
||||
config.isBarrier(_, result) or
|
||||
config.isAdditionalFlowStep(_, result, _, _) or
|
||||
config.isAdditionalFlowStep(_, _, _, result)
|
||||
}
|
||||
|
||||
private newtype TConfigState =
|
||||
TMkConfigState(Configuration config, FlowState state) {
|
||||
state = relevantState(config) or state instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
|
||||
|
||||
private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
|
||||
|
||||
private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
|
||||
|
||||
private module Config implements FullStateConfigSig {
|
||||
class FlowState = TConfigState;
|
||||
|
||||
predicate isSource(Node source, FlowState state) {
|
||||
getConfig(state).isSource(source, getState(state))
|
||||
or
|
||||
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
predicate isSink(Node sink, FlowState state) {
|
||||
getConfig(state).isSink(sink, getState(state))
|
||||
or
|
||||
getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
predicate isBarrier(Node node) { none() }
|
||||
|
||||
predicate isBarrier(Node node, FlowState state) {
|
||||
getConfig(state).isBarrier(node, getState(state)) or
|
||||
getConfig(state).isBarrier(node) or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getState(state), getConfig(state)) or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getConfig(state))
|
||||
}
|
||||
|
||||
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }
|
||||
|
||||
predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) }
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2) {
|
||||
singleConfiguration() and
|
||||
any(Configuration config).isAdditionalFlowStep(node1, node2)
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
||||
getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and
|
||||
getConfig(state2) = getConfig(state1)
|
||||
or
|
||||
not singleConfiguration() and
|
||||
getConfig(state1).isAdditionalFlowStep(node1, node2) and
|
||||
state2 = state1
|
||||
}
|
||||
|
||||
predicate allowImplicitRead(Node node, ContentSet c) {
|
||||
any(Configuration config).allowImplicitRead(node, c)
|
||||
}
|
||||
|
||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
||||
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
predicate sourceGrouping(Node source, string sourceGroup) {
|
||||
any(Configuration config).sourceGrouping(source, sourceGroup)
|
||||
}
|
||||
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) {
|
||||
any(Configuration config).sinkGrouping(sink, sinkGroup)
|
||||
}
|
||||
|
||||
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
|
||||
*/
|
||||
class PathNode instanceof I::PathNode {
|
||||
/** Gets a textual representation of this element. */
|
||||
final string toString() { result = super.toString() }
|
||||
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
final string toStringWithContext() { result = super.toStringWithContext() }
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
final predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
/** Gets the underlying `Node`. */
|
||||
final Node getNode() { result = super.getNode() }
|
||||
|
||||
/** Gets the `FlowState` of this node. */
|
||||
final FlowState getState() { result = getState(super.getState()) }
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
final Configuration getConfiguration() { result = getConfig(super.getState()) }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() { result = super.getASuccessor() }
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
final predicate isSource() { super.isSource() }
|
||||
|
||||
/** Holds if this node is a grouping of source nodes. */
|
||||
final predicate isSourceGroup(string group) { super.isSourceGroup(group) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
source0.getNode() = source and
|
||||
sink0.getNode() = sink
|
||||
)
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
hasFlowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
predicate flowsTo = hasFlow/3;
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -3,15 +3,18 @@ private import DataFlowImplSpecific::Public
|
||||
import Cached
|
||||
|
||||
module DataFlowImplCommonPublic {
|
||||
/** A state value to track during data flow. */
|
||||
class FlowState = string;
|
||||
/** Provides `FlowState = string`. */
|
||||
module FlowStateString {
|
||||
/** A state value to track during data flow. */
|
||||
class FlowState = string;
|
||||
|
||||
/**
|
||||
* The default state, which is used when the state is unspecified for a source
|
||||
* or a sink.
|
||||
*/
|
||||
class FlowStateEmpty extends FlowState {
|
||||
FlowStateEmpty() { this = "" }
|
||||
/**
|
||||
* The default state, which is used when the state is unspecified for a source
|
||||
* or a sink.
|
||||
*/
|
||||
class FlowStateEmpty extends FlowState {
|
||||
FlowStateEmpty() { this = "" }
|
||||
}
|
||||
}
|
||||
|
||||
private newtype TFlowFeature =
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -478,3 +478,12 @@ predicate containerContent(Content c) {
|
||||
c instanceof MapKeyContent or
|
||||
c instanceof MapValueContent
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an additional term that is added to the `join` and `branch` computations to reflect
|
||||
* an additional forward or backwards branching factor that is not taken into account
|
||||
* when calculating the (virtual) dispatch cost.
|
||||
*
|
||||
* Argument `arg` is part of a path from a source to a sink, and `p` is the target parameter.
|
||||
*/
|
||||
int getAdditionalFlowIntoCallNodeTerm(ArgumentNode arg, ParameterNode p) { none() }
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* Provides classes for performing local (intra-procedural) and
|
||||
* global (inter-procedural) taint-tracking analyses.
|
||||
*/
|
||||
|
||||
import TaintTrackingParameter::Public
|
||||
private import TaintTrackingParameter::Private
|
||||
|
||||
private module AddTaintDefaults<DataFlowInternal::FullStateConfigSig Config> implements
|
||||
DataFlowInternal::FullStateConfigSig
|
||||
{
|
||||
import Config
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
Config::isBarrier(node) or defaultTaintSanitizer(node)
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
Config::isAdditionalFlowStep(node1, node2) or
|
||||
defaultAdditionalTaintStep(node1, node2)
|
||||
}
|
||||
|
||||
predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||
Config::allowImplicitRead(node, c)
|
||||
or
|
||||
(
|
||||
Config::isSink(node, _) or
|
||||
Config::isAdditionalFlowStep(node, _) or
|
||||
Config::isAdditionalFlowStep(node, _, _, _)
|
||||
) and
|
||||
defaultImplicitTaintRead(node, c)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a standard taint tracking computation.
|
||||
*/
|
||||
module Make<DataFlow::ConfigSig Config> implements DataFlow::DataFlowSig {
|
||||
private module Config0 implements DataFlowInternal::FullStateConfigSig {
|
||||
import DataFlowInternal::DefaultState<Config>
|
||||
import Config
|
||||
}
|
||||
|
||||
private module C implements DataFlowInternal::FullStateConfigSig {
|
||||
import AddTaintDefaults<Config0>
|
||||
}
|
||||
|
||||
import DataFlowInternal::Impl<C>
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a taint tracking computation using flow state.
|
||||
*/
|
||||
module MakeWithState<DataFlow::StateConfigSig Config> implements DataFlow::DataFlowSig {
|
||||
private module Config0 implements DataFlowInternal::FullStateConfigSig {
|
||||
import Config
|
||||
}
|
||||
|
||||
private module C implements DataFlowInternal::FullStateConfigSig {
|
||||
import AddTaintDefaults<Config0>
|
||||
}
|
||||
|
||||
import DataFlowInternal::Impl<C>
|
||||
}
|
||||
@@ -2,4 +2,5 @@ import semmle.code.java.dataflow.internal.TaintTrackingUtil as Public
|
||||
|
||||
module Private {
|
||||
import semmle.code.java.dataflow.DataFlow::DataFlow as DataFlow
|
||||
import semmle.code.java.dataflow.internal.DataFlowImpl as DataFlowInternal
|
||||
}
|
||||
|
||||
@@ -138,7 +138,8 @@ class ClassReflectivelyReadField extends ReflectivelyReadField {
|
||||
* Consider all `JacksonSerializableField`s as reflectively read.
|
||||
*/
|
||||
class JacksonSerializableReflectivelyReadField extends ReflectivelyReadField,
|
||||
JacksonSerializableField { }
|
||||
JacksonSerializableField
|
||||
{ }
|
||||
|
||||
/**
|
||||
* A field that is used when applying Jackson mixins.
|
||||
|
||||
@@ -94,7 +94,8 @@ abstract class ReflectivelyConstructedClass extends EntryPoint, Class {
|
||||
/**
|
||||
* Classes that are deserialized by Jackson are reflectively constructed.
|
||||
*/
|
||||
library class JacksonReflectivelyConstructedClass extends ReflectivelyConstructedClass instanceof JacksonDeserializableType {
|
||||
library class JacksonReflectivelyConstructedClass extends ReflectivelyConstructedClass instanceof JacksonDeserializableType
|
||||
{
|
||||
override Callable getALiveCallable() {
|
||||
// Constructors may be called by Jackson, if they are a no-arg, they have a suitable annotation,
|
||||
// or inherit a suitable annotation through a mixin.
|
||||
@@ -308,8 +309,8 @@ class FacesAccessibleMethodEntryPoint extends CallableEntryPoint {
|
||||
* A Java Server Faces custom component, that is reflectively constructed by the framework when
|
||||
* used in a view (JSP or facelet).
|
||||
*/
|
||||
class FacesComponentReflectivelyConstructedClass extends ReflectivelyConstructedClass instanceof FacesComponent {
|
||||
}
|
||||
class FacesComponentReflectivelyConstructedClass extends ReflectivelyConstructedClass instanceof FacesComponent
|
||||
{ }
|
||||
|
||||
/**
|
||||
* Entry point for EJB home interfaces.
|
||||
@@ -459,5 +460,5 @@ class ArbitraryXmlEntryPoint extends ReflectivelyConstructedClass {
|
||||
deprecated class ArbitraryXMLEntryPoint = ArbitraryXmlEntryPoint;
|
||||
|
||||
/** A Selenium PageObject, created by a call to PageFactory.initElements(..). */
|
||||
class SeleniumPageObjectEntryPoint extends ReflectivelyConstructedClass instanceof SeleniumPageObject {
|
||||
}
|
||||
class SeleniumPageObjectEntryPoint extends ReflectivelyConstructedClass instanceof SeleniumPageObject
|
||||
{ }
|
||||
|
||||
@@ -33,8 +33,8 @@ class Struts1ActionEntryPoint extends EntryPoint, Class {
|
||||
/**
|
||||
* A struts 2 action class that is reflectively constructed.
|
||||
*/
|
||||
class Struts2ReflectivelyConstructedAction extends ReflectivelyConstructedClass instanceof Struts2ActionClass {
|
||||
}
|
||||
class Struts2ReflectivelyConstructedAction extends ReflectivelyConstructedClass instanceof Struts2ActionClass
|
||||
{ }
|
||||
|
||||
/**
|
||||
* A method called on a struts 2 action class when the action is activated.
|
||||
|
||||
@@ -78,7 +78,8 @@ class JUnitCategory extends WhitelistedLiveClass {
|
||||
/**
|
||||
* A listener that will be reflectively constructed by TestNG.
|
||||
*/
|
||||
class TestNGReflectivelyConstructedListener extends ReflectivelyConstructedClass instanceof TestNGListenerImpl {
|
||||
class TestNGReflectivelyConstructedListener extends ReflectivelyConstructedClass instanceof TestNGListenerImpl
|
||||
{
|
||||
// Consider any class that implements a TestNG listener interface to be live. Listeners can be
|
||||
// specified on the command line, in `testng.xml` files and in Ant build files, so it is safest
|
||||
// to assume that all such listeners are live.
|
||||
|
||||
@@ -123,7 +123,8 @@ class StartServiceMethod extends Method {
|
||||
|
||||
/** Specifies that if an `Intent` is tainted, then so are its synthetic fields. */
|
||||
private class IntentFieldsInheritTaint extends DataFlow::SyntheticFieldContent,
|
||||
TaintInheritingContent {
|
||||
TaintInheritingContent
|
||||
{
|
||||
IntentFieldsInheritTaint() { this.getField().matches("android.content.Intent.%") }
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ private class SliceProviderLifecycleStep extends AdditionalValueStep {
|
||||
}
|
||||
|
||||
private class SliceActionsInheritTaint extends DataFlow::SyntheticFieldContent,
|
||||
TaintInheritingContent {
|
||||
TaintInheritingContent
|
||||
{
|
||||
SliceActionsInheritTaint() { this.getField() = "androidx.slice.Slice.action" }
|
||||
}
|
||||
|
||||
@@ -11,7 +11,8 @@ private class ParseAsMethod extends Method {
|
||||
}
|
||||
}
|
||||
|
||||
private class TypeLiteralToParseAsFlowConfiguration extends DataFlowForSerializability::Configuration {
|
||||
private class TypeLiteralToParseAsFlowConfiguration extends DataFlowForSerializability::Configuration
|
||||
{
|
||||
TypeLiteralToParseAsFlowConfiguration() {
|
||||
this = "GoogleHttpClientApi::TypeLiteralToParseAsFlowConfiguration"
|
||||
}
|
||||
|
||||
@@ -91,7 +91,8 @@ private class FieldReferencedJacksonSerializableType extends JacksonSerializable
|
||||
/** A type whose values may be deserialized by the Jackson JSON framework. */
|
||||
abstract class JacksonDeserializableType extends Type { }
|
||||
|
||||
private class TypeLiteralToJacksonDatabindFlowConfiguration extends DataFlowForSerializability::Configuration {
|
||||
private class TypeLiteralToJacksonDatabindFlowConfiguration extends DataFlowForSerializability::Configuration
|
||||
{
|
||||
TypeLiteralToJacksonDatabindFlowConfiguration() {
|
||||
this = "TypeLiteralToJacksonDatabindFlowConfiguration"
|
||||
}
|
||||
|
||||
@@ -75,8 +75,8 @@ class ForbiddenSecurityConfigurationCallable extends ForbiddenCallable {
|
||||
}
|
||||
|
||||
/** A method or constructor involving serialization that may not be called by an EJB. */
|
||||
class ForbiddenSerializationCallable extends ForbiddenCallable instanceof ForbiddenSerializationMethod {
|
||||
}
|
||||
class ForbiddenSerializationCallable extends ForbiddenCallable instanceof ForbiddenSerializationMethod
|
||||
{ }
|
||||
|
||||
/** A method or constructor involving network factory operations that may not be called by an EJB. */
|
||||
class ForbiddenSetFactoryCallable extends ForbiddenCallable instanceof ForbiddenSetFactoryMethod { }
|
||||
|
||||
@@ -115,7 +115,8 @@ private class IsWindowsFromApacheCommons extends IsWindowsGuard instanceof Field
|
||||
IsWindowsFromApacheCommons() { isOsFromApacheCommons(this, "IS\\_OS\\_WINDOWS") }
|
||||
}
|
||||
|
||||
private class IsSpecificWindowsVariantFromApacheCommons extends IsSpecificWindowsVariant instanceof FieldAccess {
|
||||
private class IsSpecificWindowsVariantFromApacheCommons extends IsSpecificWindowsVariant instanceof FieldAccess
|
||||
{
|
||||
IsSpecificWindowsVariantFromApacheCommons() {
|
||||
isOsFromApacheCommons(this, "IS\\_OS\\_WINDOWS\\_%")
|
||||
}
|
||||
@@ -125,7 +126,8 @@ private class IsUnixFromApacheCommons extends IsUnixGuard instanceof FieldAccess
|
||||
IsUnixFromApacheCommons() { isOsFromApacheCommons(this, "IS\\_OS\\_UNIX") }
|
||||
}
|
||||
|
||||
private class IsSpecificUnixVariantFromApacheCommons extends IsSpecificUnixVariant instanceof FieldAccess {
|
||||
private class IsSpecificUnixVariantFromApacheCommons extends IsSpecificUnixVariant instanceof FieldAccess
|
||||
{
|
||||
IsSpecificUnixVariantFromApacheCommons() {
|
||||
isOsFromApacheCommons(this,
|
||||
[
|
||||
|
||||
@@ -47,7 +47,8 @@ private class DefaultFragmentInjectionSink extends FragmentInjectionSink {
|
||||
DefaultFragmentInjectionSink() { sinkNode(this, "fragment-injection") }
|
||||
}
|
||||
|
||||
private class DefaultFragmentInjectionAdditionalTaintStep extends FragmentInjectionAdditionalTaintStep {
|
||||
private class DefaultFragmentInjectionAdditionalTaintStep extends FragmentInjectionAdditionalTaintStep
|
||||
{
|
||||
override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
|
||||
exists(ReflectiveClassIdentifierMethodAccess ma |
|
||||
ma.getArgument(0) = n1.asExpr() and ma = n2.asExpr()
|
||||
|
||||
@@ -45,7 +45,8 @@ class IntentUriPermissionManipulationAdditionalTaintStep extends Unit {
|
||||
abstract predicate step(DataFlow::Node node1, DataFlow::Node node2);
|
||||
}
|
||||
|
||||
private class DefaultIntentUriPermissionManipulationSink extends IntentUriPermissionManipulationSink {
|
||||
private class DefaultIntentUriPermissionManipulationSink extends IntentUriPermissionManipulationSink
|
||||
{
|
||||
DefaultIntentUriPermissionManipulationSink() {
|
||||
exists(MethodAccess ma | ma.getMethod() instanceof ActivitySetResultMethod |
|
||||
ma.getArgument(1) = this.asExpr()
|
||||
|
||||
@@ -55,7 +55,8 @@ class JwtParserWithInsecureParseAdditionalFlowStep extends Unit {
|
||||
}
|
||||
|
||||
/** A set of additional flow steps to consider when working with JWT parsing related data flows. */
|
||||
private class DefaultJwtParserWithInsecureParseAdditionalFlowStep extends JwtParserWithInsecureParseAdditionalFlowStep {
|
||||
private class DefaultJwtParserWithInsecureParseAdditionalFlowStep extends JwtParserWithInsecureParseAdditionalFlowStep
|
||||
{
|
||||
override predicate step(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
jwtParserStep(node1.asExpr(), node2.asExpr())
|
||||
}
|
||||
|
||||
@@ -34,7 +34,8 @@ private class DefaultRequestForgeryAdditionalTaintStep extends RequestForgeryAdd
|
||||
}
|
||||
}
|
||||
|
||||
private class TypePropertiesRequestForgeryAdditionalTaintStep extends RequestForgeryAdditionalTaintStep {
|
||||
private class TypePropertiesRequestForgeryAdditionalTaintStep extends RequestForgeryAdditionalTaintStep
|
||||
{
|
||||
override predicate propagatesTaint(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(MethodAccess ma |
|
||||
// Properties props = new Properties();
|
||||
|
||||
@@ -8,9 +8,11 @@ import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.security.RequestForgery
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `RequestForgeryConfiguration` module instead.
|
||||
*
|
||||
* A taint-tracking configuration characterising request-forgery risks.
|
||||
*/
|
||||
class RequestForgeryConfiguration extends TaintTracking::Configuration {
|
||||
deprecated class RequestForgeryConfiguration extends TaintTracking::Configuration {
|
||||
RequestForgeryConfiguration() { this = "Server-Side Request Forgery" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
@@ -29,3 +31,26 @@ class RequestForgeryConfiguration extends TaintTracking::Configuration {
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) { node instanceof RequestForgerySanitizer }
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration characterising request-forgery risks.
|
||||
*/
|
||||
private module RequestForgeryConfiguration implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source instanceof RemoteFlowSource and
|
||||
// Exclude results of remote HTTP requests: fetching something else based on that result
|
||||
// is no worse than following a redirect returned by the remote server, and typically
|
||||
// we're requesting a resource via https which we trust to only send us to safe URLs.
|
||||
not source.asExpr().(MethodAccess).getCallee() instanceof UrlConnectionGetInputStreamMethod
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof RequestForgerySink }
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
any(RequestForgeryAdditionalTaintStep r).propagatesTaint(pred, succ)
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) { node instanceof RequestForgerySanitizer }
|
||||
}
|
||||
|
||||
module RequestForgeryFlow = TaintTracking::Make<RequestForgeryConfiguration>;
|
||||
|
||||
@@ -25,8 +25,12 @@ private class TypeType extends RefType {
|
||||
}
|
||||
}
|
||||
|
||||
/** A data-flow configuration for identifying potentially-sensitive data flowing to a log output. */
|
||||
class SensitiveLoggerConfiguration extends TaintTracking::Configuration {
|
||||
/**
|
||||
* DEPRECATED: Use `SensitiveLoggerConfiguration` module instead.
|
||||
*
|
||||
* A data-flow configuration for identifying potentially-sensitive data flowing to a log output.
|
||||
*/
|
||||
deprecated class SensitiveLoggerConfiguration extends TaintTracking::Configuration {
|
||||
SensitiveLoggerConfiguration() { this = "SensitiveLoggerConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source.asExpr() instanceof CredentialExpr }
|
||||
@@ -43,3 +47,22 @@ class SensitiveLoggerConfiguration extends TaintTracking::Configuration {
|
||||
|
||||
override predicate isSanitizerIn(Node node) { this.isSource(node) }
|
||||
}
|
||||
|
||||
/** A data-flow configuration for identifying potentially-sensitive data flowing to a log output. */
|
||||
private module SensitiveLoggerConfiguration implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof CredentialExpr }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sinkNode(sink, "logging") }
|
||||
|
||||
predicate isBarrier(DataFlow::Node sanitizer) {
|
||||
sanitizer.asExpr() instanceof LiveLiteral or
|
||||
sanitizer.getType() instanceof PrimitiveType or
|
||||
sanitizer.getType() instanceof BoxedType or
|
||||
sanitizer.getType() instanceof NumberType or
|
||||
sanitizer.getType() instanceof TypeType
|
||||
}
|
||||
|
||||
predicate isBarrierIn(Node node) { isSource(node) }
|
||||
}
|
||||
|
||||
module SensitiveLoggerFlow = TaintTracking::Make<SensitiveLoggerConfiguration>;
|
||||
|
||||
@@ -21,7 +21,8 @@ class SpelExpressionInjectionAdditionalTaintStep extends Unit {
|
||||
}
|
||||
|
||||
/** A set of additional taint steps to consider when taint tracking SpEL related data flows. */
|
||||
private class DefaultSpelExpressionInjectionAdditionalTaintStep extends SpelExpressionInjectionAdditionalTaintStep {
|
||||
private class DefaultSpelExpressionInjectionAdditionalTaintStep extends SpelExpressionInjectionAdditionalTaintStep
|
||||
{
|
||||
override predicate step(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
expressionParsingStep(node1, node2)
|
||||
}
|
||||
|
||||
@@ -62,8 +62,8 @@ abstract class TemplateInjectionSanitizerWithState extends DataFlow::Node {
|
||||
abstract predicate hasState(DataFlow::FlowState state);
|
||||
}
|
||||
|
||||
private class DefaultTemplateInjectionSource extends TemplateInjectionSource instanceof RemoteFlowSource {
|
||||
}
|
||||
private class DefaultTemplateInjectionSource extends TemplateInjectionSource instanceof RemoteFlowSource
|
||||
{ }
|
||||
|
||||
private class DefaultTemplateInjectionSink extends TemplateInjectionSink {
|
||||
DefaultTemplateInjectionSink() { sinkNode(this, "ssti") }
|
||||
|
||||
@@ -7,7 +7,7 @@ import semmle.code.java.frameworks.spring.SpringController
|
||||
import semmle.code.java.frameworks.spring.SpringHttp
|
||||
import semmle.code.java.frameworks.javaee.jsf.JSFRenderer
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import semmle.code.java.dataflow.TaintTracking2
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
private import semmle.code.java.dataflow.ExternalFlow
|
||||
|
||||
/** A sink that represent a method that outputs data without applying contextual output encoding. */
|
||||
@@ -41,9 +41,9 @@ private class DefaultXssSink extends XssSink {
|
||||
DefaultXssSink() {
|
||||
sinkNode(this, "xss")
|
||||
or
|
||||
exists(XssVulnerableWriterSourceToWritingMethodFlowConfig writer, MethodAccess ma |
|
||||
exists(MethodAccess ma |
|
||||
ma.getMethod() instanceof WritingMethod and
|
||||
writer.hasFlowToExpr(ma.getQualifier()) and
|
||||
XssVulnerableWriterSourceToWritingMethodFlow::hasFlowToExpr(ma.getQualifier()) and
|
||||
this.asExpr() = ma.getArgument(_)
|
||||
)
|
||||
}
|
||||
@@ -60,22 +60,19 @@ private class DefaultXssSanitizer extends XssSanitizer {
|
||||
}
|
||||
|
||||
/** A configuration that tracks data from a servlet writer to an output method. */
|
||||
private class XssVulnerableWriterSourceToWritingMethodFlowConfig extends TaintTracking2::Configuration {
|
||||
XssVulnerableWriterSourceToWritingMethodFlowConfig() {
|
||||
this = "XSS::XssVulnerableWriterSourceToWritingMethodFlowConfig"
|
||||
}
|
||||
private module XssVulnerableWriterSourceToWritingMethodFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof XssVulnerableWriterSource }
|
||||
|
||||
override predicate isSource(DataFlow::Node src) {
|
||||
src.asExpr() instanceof XssVulnerableWriterSource
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodAccess ma |
|
||||
sink.asExpr() = ma.getQualifier() and ma.getMethod() instanceof WritingMethod
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private module XssVulnerableWriterSourceToWritingMethodFlow =
|
||||
TaintTracking::Make<XssVulnerableWriterSourceToWritingMethodFlowConfig>;
|
||||
|
||||
/** A method that can be used to output data to an output stream or writer. */
|
||||
private class WritingMethod extends Method {
|
||||
WritingMethod() {
|
||||
|
||||
@@ -198,7 +198,8 @@ private class DocumentBuilderConstruction extends MethodAccess {
|
||||
}
|
||||
}
|
||||
|
||||
private class SafeDocumentBuilderFactoryToDocumentBuilderConstructionFlowConfig extends DataFlow3::Configuration {
|
||||
private class SafeDocumentBuilderFactoryToDocumentBuilderConstructionFlowConfig extends DataFlow3::Configuration
|
||||
{
|
||||
SafeDocumentBuilderFactoryToDocumentBuilderConstructionFlowConfig() {
|
||||
this = "XmlParsers::SafeDocumentBuilderFactoryToDocumentBuilderConstructionFlowConfig"
|
||||
}
|
||||
|
||||
@@ -55,7 +55,8 @@ private predicate newTransformerOrTemplatesStep(DataFlow::Node n1, DataFlow::Nod
|
||||
/**
|
||||
* A data flow configuration for secure processing feature that is enabled on `TransformerFactory`.
|
||||
*/
|
||||
private class TransformerFactoryWithSecureProcessingFeatureFlowConfig extends DataFlow2::Configuration {
|
||||
private class TransformerFactoryWithSecureProcessingFeatureFlowConfig extends DataFlow2::Configuration
|
||||
{
|
||||
TransformerFactoryWithSecureProcessingFeatureFlowConfig() {
|
||||
this = "TransformerFactoryWithSecureProcessingFeatureFlowConfig"
|
||||
}
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 0.5.4
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.5.3
|
||||
|
||||
### New Queries
|
||||
|
||||
@@ -18,32 +18,33 @@ import semmle.code.java.dataflow.FlowSources
|
||||
private import semmle.code.java.dataflow.ExternalFlow
|
||||
import semmle.code.java.security.PathCreation
|
||||
import semmle.code.java.security.PathSanitizer
|
||||
import DataFlow::PathGraph
|
||||
import TaintedPathCommon
|
||||
|
||||
class TaintedPathConfig extends TaintTracking::Configuration {
|
||||
TaintedPathConfig() { this = "TaintedPathConfig" }
|
||||
module TaintedPathConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink.asExpr() = any(PathCreation p).getAnInput()
|
||||
or
|
||||
sinkNode(sink, ["create-file", "read-file"])
|
||||
}
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node sanitizer) {
|
||||
predicate isBarrier(DataFlow::Node sanitizer) {
|
||||
sanitizer.getType() instanceof BoxedType or
|
||||
sanitizer.getType() instanceof PrimitiveType or
|
||||
sanitizer.getType() instanceof NumberType or
|
||||
sanitizer instanceof PathInjectionSanitizer
|
||||
}
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node n1, DataFlow::Node n2) {
|
||||
predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
|
||||
any(TaintedPathAdditionalTaintStep s).step(n1, n2)
|
||||
}
|
||||
}
|
||||
|
||||
module TaintedPath = TaintTracking::Make<TaintedPathConfig>;
|
||||
|
||||
import TaintedPath::PathGraph
|
||||
|
||||
/**
|
||||
* Gets the data-flow node at which to report a path ending at `sink`.
|
||||
*
|
||||
@@ -52,13 +53,13 @@ class TaintedPathConfig extends TaintTracking::Configuration {
|
||||
* continue to report there; otherwise we report directly at `sink`.
|
||||
*/
|
||||
DataFlow::Node getReportingNode(DataFlow::Node sink) {
|
||||
any(TaintedPathConfig c).hasFlowTo(sink) and
|
||||
TaintedPath::hasFlowTo(sink) and
|
||||
if exists(PathCreation pc | pc.getAnInput() = sink.asExpr())
|
||||
then result.asExpr() = any(PathCreation pc | pc.getAnInput() = sink.asExpr())
|
||||
else result = sink
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, TaintedPathConfig conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
from TaintedPath::PathNode source, TaintedPath::PathNode sink
|
||||
where TaintedPath::hasFlowPath(source, sink)
|
||||
select getReportingNode(sink.getNode()), source, sink, "This path depends on a $@.",
|
||||
source.getNode(), "user-provided value"
|
||||
|
||||
@@ -14,25 +14,26 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.security.XSS
|
||||
import DataFlow::PathGraph
|
||||
|
||||
class XssConfig extends TaintTracking::Configuration {
|
||||
XssConfig() { this = "XSSConfig" }
|
||||
module XssConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof XssSink }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof XssSink }
|
||||
predicate isBarrier(DataFlow::Node node) { node instanceof XssSanitizer }
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) { node instanceof XssSanitizer }
|
||||
predicate isBarrierOut(DataFlow::Node node) { node instanceof XssSinkBarrier }
|
||||
|
||||
override predicate isSanitizerOut(DataFlow::Node node) { node instanceof XssSinkBarrier }
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
any(XssAdditionalTaintStep s).step(node1, node2)
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, XssConfig conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
module XssFlow = TaintTracking::Make<XssConfig>;
|
||||
|
||||
import XssFlow::PathGraph
|
||||
|
||||
from XssFlow::PathNode source, XssFlow::PathNode sink
|
||||
where XssFlow::hasFlowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "Cross-site scripting vulnerability due to a $@.",
|
||||
source.getNode(), "user-provided value"
|
||||
|
||||
@@ -27,25 +27,29 @@ abstract private class InsecureNettyObjectCreation extends ClassInstanceExpr {
|
||||
abstract string splittingType();
|
||||
}
|
||||
|
||||
abstract private class RequestOrResponseSplittingInsecureNettyObjectCreation extends InsecureNettyObjectCreation {
|
||||
abstract private class RequestOrResponseSplittingInsecureNettyObjectCreation extends InsecureNettyObjectCreation
|
||||
{
|
||||
override string splittingType() { result = "Request splitting or response splitting" }
|
||||
}
|
||||
|
||||
/**
|
||||
* Request splitting can allowing an attacker to inject/smuggle an additional HTTP request into the socket connection.
|
||||
*/
|
||||
abstract private class RequestSplittingInsecureNettyObjectCreation extends InsecureNettyObjectCreation {
|
||||
abstract private class RequestSplittingInsecureNettyObjectCreation extends InsecureNettyObjectCreation
|
||||
{
|
||||
override string splittingType() { result = "Request splitting" }
|
||||
}
|
||||
|
||||
/**
|
||||
* Response splitting can lead to HTTP vulnerabilities like XSS and cache poisoning.
|
||||
*/
|
||||
abstract private class ResponseSplittingInsecureNettyObjectCreation extends InsecureNettyObjectCreation {
|
||||
abstract private class ResponseSplittingInsecureNettyObjectCreation extends InsecureNettyObjectCreation
|
||||
{
|
||||
override string splittingType() { result = "Response splitting" }
|
||||
}
|
||||
|
||||
private class InsecureDefaultHttpHeadersClassInstantiation extends RequestOrResponseSplittingInsecureNettyObjectCreation {
|
||||
private class InsecureDefaultHttpHeadersClassInstantiation extends RequestOrResponseSplittingInsecureNettyObjectCreation
|
||||
{
|
||||
InsecureDefaultHttpHeadersClassInstantiation() {
|
||||
this.getConstructedType()
|
||||
.hasQualifiedName("io.netty.handler.codec.http",
|
||||
@@ -54,21 +58,24 @@ private class InsecureDefaultHttpHeadersClassInstantiation extends RequestOrResp
|
||||
}
|
||||
}
|
||||
|
||||
private class InsecureDefaultHttpResponseClassInstantiation extends ResponseSplittingInsecureNettyObjectCreation {
|
||||
private class InsecureDefaultHttpResponseClassInstantiation extends ResponseSplittingInsecureNettyObjectCreation
|
||||
{
|
||||
InsecureDefaultHttpResponseClassInstantiation() {
|
||||
this.getConstructedType().hasQualifiedName("io.netty.handler.codec.http", "DefaultHttpResponse") and
|
||||
vulnerableArgumentIndex = 2
|
||||
}
|
||||
}
|
||||
|
||||
private class InsecureDefaultHttpRequestClassInstantiation extends RequestSplittingInsecureNettyObjectCreation {
|
||||
private class InsecureDefaultHttpRequestClassInstantiation extends RequestSplittingInsecureNettyObjectCreation
|
||||
{
|
||||
InsecureDefaultHttpRequestClassInstantiation() {
|
||||
this.getConstructedType().hasQualifiedName("io.netty.handler.codec.http", "DefaultHttpRequest") and
|
||||
vulnerableArgumentIndex = 3
|
||||
}
|
||||
}
|
||||
|
||||
private class InsecureDefaultFullHttpResponseClassInstantiation extends ResponseSplittingInsecureNettyObjectCreation {
|
||||
private class InsecureDefaultFullHttpResponseClassInstantiation extends ResponseSplittingInsecureNettyObjectCreation
|
||||
{
|
||||
InsecureDefaultFullHttpResponseClassInstantiation() {
|
||||
this.getConstructedType()
|
||||
.hasQualifiedName("io.netty.handler.codec.http", "DefaultFullHttpResponse") and
|
||||
@@ -76,7 +83,8 @@ private class InsecureDefaultFullHttpResponseClassInstantiation extends Response
|
||||
}
|
||||
}
|
||||
|
||||
private class InsecureDefaultFullHttpRequestClassInstantiation extends RequestSplittingInsecureNettyObjectCreation {
|
||||
private class InsecureDefaultFullHttpRequestClassInstantiation extends RequestSplittingInsecureNettyObjectCreation
|
||||
{
|
||||
InsecureDefaultFullHttpRequestClassInstantiation() {
|
||||
this.getConstructedType()
|
||||
.hasQualifiedName("io.netty.handler.codec.http", "DefaultFullHttpRequest") and
|
||||
|
||||
@@ -14,19 +14,16 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.security.ResponseSplitting
|
||||
import DataFlow::PathGraph
|
||||
|
||||
class ResponseSplittingConfig extends TaintTracking::Configuration {
|
||||
ResponseSplittingConfig() { this = "ResponseSplittingConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
module ResponseSplittingConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source instanceof RemoteFlowSource and
|
||||
not source instanceof SafeHeaderSplittingSource
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof HeaderSplittingSink }
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof HeaderSplittingSink }
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
node.getType() instanceof PrimitiveType
|
||||
or
|
||||
node.getType() instanceof BoxedType
|
||||
@@ -45,8 +42,12 @@ class ResponseSplittingConfig extends TaintTracking::Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, ResponseSplittingConfig conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
module ResponseSplitting = TaintTracking::Make<ResponseSplittingConfig>;
|
||||
|
||||
import ResponseSplitting::PathGraph
|
||||
|
||||
from ResponseSplitting::PathNode source, ResponseSplitting::PathNode sink
|
||||
where ResponseSplitting::hasFlowPath(source, sink)
|
||||
select sink.getNode(), source, sink,
|
||||
"This header depends on a $@, which may cause a response-splitting vulnerability.",
|
||||
source.getNode(), "user-provided value"
|
||||
|
||||
@@ -14,23 +14,24 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.security.ResponseSplitting
|
||||
import DataFlow::PathGraph
|
||||
|
||||
class ResponseSplittingLocalConfig extends TaintTracking::Configuration {
|
||||
ResponseSplittingLocalConfig() { this = "ResponseSplittingLocalConfig" }
|
||||
module ResponseSplittingLocalConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof LocalUserInput }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof LocalUserInput }
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof HeaderSplittingSink }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof HeaderSplittingSink }
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
node.getType() instanceof PrimitiveType or
|
||||
node.getType() instanceof BoxedType
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, ResponseSplittingLocalConfig conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
module ResponseSplitting = TaintTracking::Make<ResponseSplittingLocalConfig>;
|
||||
|
||||
import ResponseSplitting::PathGraph
|
||||
|
||||
from ResponseSplitting::PathNode source, ResponseSplitting::PathNode sink
|
||||
where ResponseSplitting::hasFlowPath(source, sink)
|
||||
select sink.getNode(), source, sink,
|
||||
"This header depends on a $@, which may cause a response-splitting vulnerability.",
|
||||
source.getNode(), "user-provided value"
|
||||
|
||||
@@ -31,33 +31,27 @@ class PrintStackTraceMethod extends Method {
|
||||
}
|
||||
}
|
||||
|
||||
class ServletWriterSourceToPrintStackTraceMethodFlowConfig extends TaintTracking::Configuration {
|
||||
ServletWriterSourceToPrintStackTraceMethodFlowConfig() {
|
||||
this = "StackTraceExposure::ServletWriterSourceToPrintStackTraceMethodFlowConfig"
|
||||
}
|
||||
module ServletWriterSourceToPrintStackTraceMethodFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof XssVulnerableWriterSource }
|
||||
|
||||
override predicate isSource(DataFlow::Node src) {
|
||||
src.asExpr() instanceof XssVulnerableWriterSource
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodAccess ma |
|
||||
sink.asExpr() = ma.getAnArgument() and ma.getMethod() instanceof PrintStackTraceMethod
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module ServletWriterSourceToPrintStackTraceMethodFlow =
|
||||
TaintTracking::Make<ServletWriterSourceToPrintStackTraceMethodFlowConfig>;
|
||||
|
||||
/**
|
||||
* A call that uses `Throwable.printStackTrace()` on a stream that is connected
|
||||
* to external output.
|
||||
*/
|
||||
predicate printsStackToWriter(MethodAccess call) {
|
||||
exists(
|
||||
ServletWriterSourceToPrintStackTraceMethodFlowConfig writerSource,
|
||||
PrintStackTraceMethod printStackTrace
|
||||
|
|
||||
exists(PrintStackTraceMethod printStackTrace |
|
||||
call.getMethod() = printStackTrace and
|
||||
writerSource.hasFlowToExpr(call.getAnArgument())
|
||||
ServletWriterSourceToPrintStackTraceMethodFlow::hasFlowToExpr(call.getAnArgument())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -86,16 +80,15 @@ predicate stackTraceExpr(Expr exception, MethodAccess stackTraceString) {
|
||||
)
|
||||
}
|
||||
|
||||
class StackTraceStringToHttpResponseSinkFlowConfig extends TaintTracking::Configuration {
|
||||
StackTraceStringToHttpResponseSinkFlowConfig() {
|
||||
this = "StackTraceExposure::StackTraceStringToHttpResponseSinkFlowConfig"
|
||||
}
|
||||
module StackTraceStringToHttpResponseSinkFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { stackTraceExpr(_, src.asExpr()) }
|
||||
|
||||
override predicate isSource(DataFlow::Node src) { stackTraceExpr(_, src.asExpr()) }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof InformationLeakSink }
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof InformationLeakSink }
|
||||
}
|
||||
|
||||
module StackTraceStringToHttpResponseSinkFlow =
|
||||
TaintTracking::Make<StackTraceStringToHttpResponseSinkFlowConfig>;
|
||||
|
||||
/**
|
||||
* A write of stack trace data to an external stream.
|
||||
*/
|
||||
@@ -109,9 +102,10 @@ predicate printsStackExternally(MethodAccess call, Expr stackTrace) {
|
||||
* A stringified stack trace flows to an external sink.
|
||||
*/
|
||||
predicate stringifiedStackFlowsExternally(DataFlow::Node externalExpr, Expr stackTrace) {
|
||||
exists(MethodAccess stackTraceString, StackTraceStringToHttpResponseSinkFlowConfig conf |
|
||||
exists(MethodAccess stackTraceString |
|
||||
stackTraceExpr(stackTrace, stackTraceString) and
|
||||
conf.hasFlow(DataFlow::exprNode(stackTraceString), externalExpr)
|
||||
StackTraceStringToHttpResponseSinkFlow::hasFlow(DataFlow::exprNode(stackTraceString),
|
||||
externalExpr)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ import java
|
||||
import semmle.code.java.security.Encryption
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import DataFlow
|
||||
import PathGraph
|
||||
|
||||
private class ShortStringLiteral extends StringLiteral {
|
||||
ShortStringLiteral() { getValue().length() < 100 }
|
||||
@@ -29,24 +28,26 @@ class BrokenAlgoLiteral extends ShortStringLiteral {
|
||||
}
|
||||
}
|
||||
|
||||
class InsecureCryptoConfiguration extends TaintTracking::Configuration {
|
||||
InsecureCryptoConfiguration() { this = "BrokenCryptoAlgortihm::InsecureCryptoConfiguration" }
|
||||
module InsecureCryptoConfiguration implements ConfigSig {
|
||||
predicate isSource(Node n) { n.asExpr() instanceof BrokenAlgoLiteral }
|
||||
|
||||
override predicate isSource(Node n) { n.asExpr() instanceof BrokenAlgoLiteral }
|
||||
predicate isSink(Node n) { exists(CryptoAlgoSpec c | n.asExpr() = c.getAlgoSpec()) }
|
||||
|
||||
override predicate isSink(Node n) { exists(CryptoAlgoSpec c | n.asExpr() = c.getAlgoSpec()) }
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType
|
||||
}
|
||||
}
|
||||
|
||||
module InsecureCryptoFlow = TaintTracking::Make<InsecureCryptoConfiguration>;
|
||||
|
||||
import InsecureCryptoFlow::PathGraph
|
||||
|
||||
from
|
||||
PathNode source, PathNode sink, CryptoAlgoSpec c, BrokenAlgoLiteral s,
|
||||
InsecureCryptoConfiguration conf
|
||||
InsecureCryptoFlow::PathNode source, InsecureCryptoFlow::PathNode sink, CryptoAlgoSpec c,
|
||||
BrokenAlgoLiteral s
|
||||
where
|
||||
sink.getNode().asExpr() = c.getAlgoSpec() and
|
||||
source.getNode().asExpr() = s and
|
||||
conf.hasFlowPath(source, sink)
|
||||
InsecureCryptoFlow::hasFlowPath(source, sink)
|
||||
select c, source, sink, "Cryptographic algorithm $@ is weak and should not be used.", s,
|
||||
s.getValue()
|
||||
|
||||
@@ -16,7 +16,6 @@ import semmle.code.java.security.Encryption
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import DataFlow
|
||||
import semmle.code.java.dispatch.VirtualDispatch
|
||||
import PathGraph
|
||||
|
||||
private class ShortStringLiteral extends StringLiteral {
|
||||
ShortStringLiteral() { this.getValue().length() < 100 }
|
||||
@@ -51,26 +50,28 @@ class StringContainer extends RefType {
|
||||
}
|
||||
}
|
||||
|
||||
class InsecureCryptoConfiguration extends TaintTracking::Configuration {
|
||||
InsecureCryptoConfiguration() { this = "InsecureCryptoConfiguration" }
|
||||
module InsecureCryptoConfiguration implements ConfigSig {
|
||||
predicate isSource(Node n) { n.asExpr() instanceof InsecureAlgoLiteral }
|
||||
|
||||
override predicate isSource(Node n) { n.asExpr() instanceof InsecureAlgoLiteral }
|
||||
predicate isSink(Node n) { exists(CryptoAlgoSpec c | n.asExpr() = c.getAlgoSpec()) }
|
||||
|
||||
override predicate isSink(Node n) { exists(CryptoAlgoSpec c | n.asExpr() = c.getAlgoSpec()) }
|
||||
|
||||
override predicate isSanitizer(Node n) {
|
||||
predicate isBarrier(Node n) {
|
||||
objectToString(n.asExpr()) or
|
||||
not n.getType().getErasure() instanceof StringContainer
|
||||
}
|
||||
}
|
||||
|
||||
module InsecureCryptoFlow = TaintTracking::Make<InsecureCryptoConfiguration>;
|
||||
|
||||
import InsecureCryptoFlow::PathGraph
|
||||
|
||||
from
|
||||
PathNode source, PathNode sink, CryptoAlgoSpec c, InsecureAlgoLiteral s,
|
||||
InsecureCryptoConfiguration conf
|
||||
InsecureCryptoFlow::PathNode source, InsecureCryptoFlow::PathNode sink, CryptoAlgoSpec c,
|
||||
InsecureAlgoLiteral s
|
||||
where
|
||||
sink.getNode().asExpr() = c.getAlgoSpec() and
|
||||
source.getNode().asExpr() = s and
|
||||
conf.hasFlowPath(source, sink)
|
||||
InsecureCryptoFlow::hasFlowPath(source, sink)
|
||||
select c, source, sink,
|
||||
"Cryptographic algorithm $@ may not be secure, consider using a different algorithm.", s,
|
||||
s.getValue()
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
|
||||
import java
|
||||
import semmle.code.java.security.SensitiveLoggingQuery
|
||||
import PathGraph
|
||||
import SensitiveLoggerFlow::PathGraph
|
||||
|
||||
from SensitiveLoggerConfiguration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where cfg.hasFlowPath(source, sink)
|
||||
from SensitiveLoggerFlow::PathNode source, SensitiveLoggerFlow::PathNode sink
|
||||
where SensitiveLoggerFlow::hasFlowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "This $@ is written to a log file.", source.getNode(),
|
||||
"potentially sensitive information"
|
||||
|
||||
@@ -15,19 +15,16 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import NumericCastCommon
|
||||
import DataFlow::PathGraph
|
||||
|
||||
private class NumericCastFlowConfig extends TaintTracking::Configuration {
|
||||
NumericCastFlowConfig() { this = "NumericCastTainted::RemoteUserInputToNumericNarrowingCastExpr" }
|
||||
module NumericCastFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink.asExpr() = any(NumericNarrowingCastExpr cast).getExpr() and
|
||||
sink.asExpr() instanceof VarAccess
|
||||
}
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
boundedRead(node.asExpr()) or
|
||||
castCheck(node.asExpr()) or
|
||||
node.getType() instanceof SmallType or
|
||||
@@ -37,12 +34,14 @@ private class NumericCastFlowConfig extends TaintTracking::Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
from
|
||||
DataFlow::PathNode source, DataFlow::PathNode sink, NumericNarrowingCastExpr exp,
|
||||
NumericCastFlowConfig conf
|
||||
module NumericCastFlow = TaintTracking::Make<NumericCastFlowConfig>;
|
||||
|
||||
import NumericCastFlow::PathGraph
|
||||
|
||||
from NumericCastFlow::PathNode source, NumericCastFlow::PathNode sink, NumericNarrowingCastExpr exp
|
||||
where
|
||||
sink.getNode().asExpr() = exp.getExpr() and
|
||||
conf.hasFlowPath(source, sink)
|
||||
NumericCastFlow::hasFlowPath(source, sink)
|
||||
select exp, source, sink,
|
||||
"This cast to a narrower type depends on a $@, potentially causing truncation.", source.getNode(),
|
||||
"user-provided value"
|
||||
|
||||
@@ -15,20 +15,15 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import NumericCastCommon
|
||||
import DataFlow::PathGraph
|
||||
|
||||
private class NumericCastFlowConfig extends TaintTracking::Configuration {
|
||||
NumericCastFlowConfig() {
|
||||
this = "NumericCastTaintedLocal::LocalUserInputToNumericNarrowingCastExpr"
|
||||
}
|
||||
module NumericCastFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src instanceof LocalUserInput }
|
||||
|
||||
override predicate isSource(DataFlow::Node src) { src instanceof LocalUserInput }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink.asExpr() = any(NumericNarrowingCastExpr cast).getExpr()
|
||||
}
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
boundedRead(node.asExpr()) or
|
||||
castCheck(node.asExpr()) or
|
||||
node.getType() instanceof SmallType or
|
||||
@@ -37,13 +32,17 @@ private class NumericCastFlowConfig extends TaintTracking::Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
module NumericCastFlow = TaintTracking::Make<NumericCastFlowConfig>;
|
||||
|
||||
import NumericCastFlow::PathGraph
|
||||
|
||||
from
|
||||
DataFlow::PathNode source, DataFlow::PathNode sink, NumericNarrowingCastExpr exp,
|
||||
VarAccess tainted, NumericCastFlowConfig conf
|
||||
NumericCastFlow::PathNode source, NumericCastFlow::PathNode sink, NumericNarrowingCastExpr exp,
|
||||
VarAccess tainted
|
||||
where
|
||||
exp.getExpr() = tainted and
|
||||
sink.getNode().asExpr() = tainted and
|
||||
conf.hasFlowPath(source, sink) and
|
||||
NumericCastFlow::hasFlowPath(source, sink) and
|
||||
not exists(RightShiftOp e | e.getShiftedVariable() = tainted.getVariable())
|
||||
select exp, source, sink,
|
||||
"This cast to a narrower type depends on a $@, potentially causing truncation.", source.getNode(),
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
|
||||
import java
|
||||
import semmle.code.java.security.RequestForgeryConfig
|
||||
import DataFlow::PathGraph
|
||||
import RequestForgeryFlow::PathGraph
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, RequestForgeryConfiguration conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
from RequestForgeryFlow::PathNode source, RequestForgeryFlow::PathNode sink
|
||||
where RequestForgeryFlow::hasFlowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "Potential server-side request forgery due to a $@.",
|
||||
source.getNode(), "user-provided value"
|
||||
|
||||
3
java/ql/src/change-notes/released/0.5.4.md
Normal file
3
java/ql/src/change-notes/released/0.5.4.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.5.4
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.5.3
|
||||
lastReleaseVersion: 0.5.4
|
||||
|
||||
@@ -81,8 +81,8 @@ private class CompareSink extends ClientSuppliedIpUsedInSecurityCheckSink {
|
||||
}
|
||||
|
||||
/** A data flow sink for sql operation. */
|
||||
private class SqlOperationSink extends ClientSuppliedIpUsedInSecurityCheckSink instanceof QueryInjectionSink {
|
||||
}
|
||||
private class SqlOperationSink extends ClientSuppliedIpUsedInSecurityCheckSink instanceof QueryInjectionSink
|
||||
{ }
|
||||
|
||||
/** A method that split string. */
|
||||
class SplitMethod extends Method {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/java-queries
|
||||
version: 0.5.4-dev
|
||||
version: 0.5.5-dev
|
||||
groups:
|
||||
- java
|
||||
- queries
|
||||
|
||||
@@ -47,6 +47,20 @@ private predicate defaultSource(DataFlow::Node src) {
|
||||
src.asExpr().(MethodAccess).getMethod().getName() = ["source", "taint"]
|
||||
}
|
||||
|
||||
module DefaultFlowConf implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node n) { defaultSource(n) }
|
||||
|
||||
predicate isSink(DataFlow::Node n) {
|
||||
exists(MethodAccess ma | ma.getMethod().hasName("sink") | n.asExpr() = ma.getAnArgument())
|
||||
}
|
||||
|
||||
int fieldFlowBranchLimit() { result = 1000 }
|
||||
}
|
||||
|
||||
private module DefaultValueFlow = DataFlow::Make<DefaultFlowConf>;
|
||||
|
||||
private module DefaultTaintFlow = TaintTracking::Make<DefaultFlowConf>;
|
||||
|
||||
class DefaultValueFlowConf extends DataFlow::Configuration {
|
||||
DefaultValueFlowConf() { this = "qltest:defaultValueFlowConf" }
|
||||
|
||||
@@ -76,6 +90,8 @@ private string getSourceArgString(DataFlow::Node src) {
|
||||
src.asExpr().(MethodAccess).getAnArgument().(StringLiteral).getValue() = result
|
||||
}
|
||||
|
||||
abstract class EnableLegacyConfiguration extends Unit { }
|
||||
|
||||
class InlineFlowTest extends InlineExpectationsTest {
|
||||
InlineFlowTest() { this = "HasFlowTest" }
|
||||
|
||||
@@ -83,7 +99,7 @@ class InlineFlowTest extends InlineExpectationsTest {
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
tag = "hasValueFlow" and
|
||||
exists(DataFlow::Node src, DataFlow::Node sink | getValueFlowConfig().hasFlow(src, sink) |
|
||||
exists(DataFlow::Node src, DataFlow::Node sink | hasValueFlow(src, sink) |
|
||||
sink.getLocation() = location and
|
||||
element = sink.toString() and
|
||||
if exists(getSourceArgString(src)) then value = getSourceArgString(src) else value = ""
|
||||
@@ -91,7 +107,7 @@ class InlineFlowTest extends InlineExpectationsTest {
|
||||
or
|
||||
tag = "hasTaintFlow" and
|
||||
exists(DataFlow::Node src, DataFlow::Node sink |
|
||||
getTaintFlowConfig().hasFlow(src, sink) and not getValueFlowConfig().hasFlow(src, sink)
|
||||
hasTaintFlow(src, sink) and not hasValueFlow(src, sink)
|
||||
|
|
||||
sink.getLocation() = location and
|
||||
element = sink.toString() and
|
||||
@@ -99,6 +115,18 @@ class InlineFlowTest extends InlineExpectationsTest {
|
||||
)
|
||||
}
|
||||
|
||||
predicate hasValueFlow(DataFlow::Node src, DataFlow::Node sink) {
|
||||
if exists(EnableLegacyConfiguration e)
|
||||
then getValueFlowConfig().hasFlow(src, sink)
|
||||
else DefaultValueFlow::hasFlow(src, sink)
|
||||
}
|
||||
|
||||
predicate hasTaintFlow(DataFlow::Node src, DataFlow::Node sink) {
|
||||
if exists(EnableLegacyConfiguration e)
|
||||
then getTaintFlowConfig().hasFlow(src, sink)
|
||||
else DefaultTaintFlow::hasFlow(src, sink)
|
||||
}
|
||||
|
||||
DataFlow::Configuration getValueFlowConfig() { result = any(DefaultValueFlowConf config) }
|
||||
|
||||
DataFlow::Configuration getTaintFlowConfig() { result = any(DefaultTaintFlowConf config) }
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import TestUtilities.InlineFlowTest
|
||||
|
||||
class HasFlowTest extends InlineFlowTest {
|
||||
override DataFlow::Configuration getTaintFlowConfig() { none() }
|
||||
}
|
||||
|
||||
@@ -42,31 +42,31 @@ public class Test {
|
||||
public static void test1() {
|
||||
Test t = new Test();
|
||||
t.fluentNoop().fluentSet(source()).fluentNoop();
|
||||
sink(t.get()); // $hasTaintFlow
|
||||
sink(t.get()); // $hasValueFlow
|
||||
}
|
||||
|
||||
public static void test2() {
|
||||
Test t = new Test();
|
||||
Test.identity(t).fluentNoop().fluentSet(source()).fluentNoop();
|
||||
sink(t.get()); // $hasTaintFlow
|
||||
sink(t.get()); // $hasValueFlow
|
||||
}
|
||||
|
||||
public static void test3() {
|
||||
Test t = new Test();
|
||||
t.indirectlyFluentNoop().fluentSet(source()).fluentNoop();
|
||||
sink(t.get()); // $hasTaintFlow
|
||||
sink(t.get()); // $hasValueFlow
|
||||
}
|
||||
|
||||
public static void testModel1() {
|
||||
Test t = new Test();
|
||||
t.indirectlyFluentNoop().modelledFluentMethod().fluentSet(source()).fluentNoop();
|
||||
sink(t.get()); // $hasTaintFlow
|
||||
sink(t.get()); // $hasValueFlow
|
||||
}
|
||||
|
||||
public static void testModel2() {
|
||||
Test t = new Test();
|
||||
Test.modelledIdentity(t).indirectlyFluentNoop().modelledFluentMethod().fluentSet(source()).fluentNoop();
|
||||
sink(t.get()); // $hasTaintFlow
|
||||
sink(t.get()); // $hasValueFlow
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,7 +12,3 @@ class IdentityModel extends ValuePreservingMethod {
|
||||
|
||||
override predicate returnsValue(int arg) { arg = 0 }
|
||||
}
|
||||
|
||||
class HasFlowTest extends InlineFlowTest {
|
||||
override DataFlow::Configuration getValueFlowConfig() { none() }
|
||||
}
|
||||
|
||||
@@ -14,54 +14,46 @@ predicate sink0(Node n) {
|
||||
)
|
||||
}
|
||||
|
||||
class Conf1 extends Configuration {
|
||||
Conf1() { this = "inoutbarriers1" }
|
||||
module Conf1 implements ConfigSig {
|
||||
predicate isSource(Node n) { src0(n) }
|
||||
|
||||
override predicate isSource(Node n) { src0(n) }
|
||||
|
||||
override predicate isSink(Node n) { sink0(n) }
|
||||
predicate isSink(Node n) { sink0(n) }
|
||||
}
|
||||
|
||||
class Conf2 extends Configuration {
|
||||
Conf2() { this = "inoutbarriers2" }
|
||||
module Conf2 implements ConfigSig {
|
||||
predicate isSource(Node n) { src0(n) }
|
||||
|
||||
override predicate isSource(Node n) { src0(n) }
|
||||
predicate isSink(Node n) { sink0(n) }
|
||||
|
||||
override predicate isSink(Node n) { sink0(n) }
|
||||
|
||||
override predicate isBarrierIn(Node n) { src0(n) }
|
||||
predicate isBarrierIn(Node n) { src0(n) }
|
||||
}
|
||||
|
||||
class Conf3 extends Configuration {
|
||||
Conf3() { this = "inoutbarriers3" }
|
||||
module Conf3 implements ConfigSig {
|
||||
predicate isSource(Node n) { src0(n) }
|
||||
|
||||
override predicate isSource(Node n) { src0(n) }
|
||||
predicate isSink(Node n) { sink0(n) }
|
||||
|
||||
override predicate isSink(Node n) { sink0(n) }
|
||||
|
||||
override predicate isBarrierOut(Node n) { sink0(n) }
|
||||
predicate isBarrierOut(Node n) { sink0(n) }
|
||||
}
|
||||
|
||||
class Conf4 extends Configuration {
|
||||
Conf4() { this = "inoutbarriers4" }
|
||||
module Conf4 implements ConfigSig {
|
||||
predicate isSource(Node n) { src0(n) }
|
||||
|
||||
override predicate isSource(Node n) { src0(n) }
|
||||
predicate isSink(Node n) { sink0(n) }
|
||||
|
||||
override predicate isSink(Node n) { sink0(n) }
|
||||
predicate isBarrierIn(Node n) { src0(n) }
|
||||
|
||||
override predicate isBarrierIn(Node n) { src0(n) }
|
||||
|
||||
override predicate isBarrierOut(Node n) { sink0(n) }
|
||||
predicate isBarrierOut(Node n) { sink0(n) }
|
||||
}
|
||||
|
||||
predicate flow(Node src, Node sink, string s) {
|
||||
any(Conf1 c).hasFlow(src, sink) and s = "nobarrier"
|
||||
Make<Conf1>::hasFlow(src, sink) and s = "nobarrier"
|
||||
or
|
||||
any(Conf2 c).hasFlow(src, sink) and s = "srcbarrier"
|
||||
Make<Conf2>::hasFlow(src, sink) and s = "srcbarrier"
|
||||
or
|
||||
any(Conf3 c).hasFlow(src, sink) and s = "sinkbarrier"
|
||||
Make<Conf3>::hasFlow(src, sink) and s = "sinkbarrier"
|
||||
or
|
||||
any(Conf4 c).hasFlow(src, sink) and s = "both"
|
||||
Make<Conf4>::hasFlow(src, sink) and s = "both"
|
||||
}
|
||||
|
||||
from Node src, Node sink, string s
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import DataFlow
|
||||
import PartialPathGraph
|
||||
|
||||
class Conf extends Configuration {
|
||||
Conf() { this = "partial flow" }
|
||||
module Config implements ConfigSig {
|
||||
predicate isSource(Node n) { n.asExpr().(MethodAccess).getMethod().hasName("src") }
|
||||
|
||||
override predicate isSource(Node n) { n.asExpr().(MethodAccess).getMethod().hasName("src") }
|
||||
|
||||
override predicate isSink(Node n) { n.asExpr().(Argument).getCall().getCallee().hasName("sink") }
|
||||
|
||||
override int explorationLimit() { result = 10 }
|
||||
predicate isSink(Node n) { n.asExpr().(Argument).getCall().getCallee().hasName("sink") }
|
||||
}
|
||||
|
||||
from PartialPathNode n, int dist
|
||||
where any(Conf c).hasPartialFlow(_, n, dist)
|
||||
int explorationLimit() { result = 10 }
|
||||
|
||||
module PartialFlow = Make<Config>::FlowExploration<explorationLimit/0>;
|
||||
|
||||
import PartialFlow::PartialPathGraph
|
||||
|
||||
from PartialFlow::PartialPathNode n, int dist
|
||||
where PartialFlow::hasPartialFlow(_, n, dist)
|
||||
select dist, n
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import DataFlow
|
||||
import PartialPathGraph
|
||||
|
||||
class Conf extends Configuration {
|
||||
Conf() { this = "partial flow" }
|
||||
module Config implements ConfigSig {
|
||||
predicate isSource(Node n) { n.asExpr().(MethodAccess).getMethod().hasName("src") }
|
||||
|
||||
override predicate isSource(Node n) { n.asExpr().(MethodAccess).getMethod().hasName("src") }
|
||||
|
||||
override predicate isSink(Node n) { n.asExpr().(Argument).getCall().getCallee().hasName("sink") }
|
||||
|
||||
override int explorationLimit() { result = 10 }
|
||||
predicate isSink(Node n) { n.asExpr().(Argument).getCall().getCallee().hasName("sink") }
|
||||
}
|
||||
|
||||
from PartialPathNode n, int dist
|
||||
where any(Conf c).hasPartialFlowRev(n, _, dist)
|
||||
int explorationLimit() { result = 10 }
|
||||
|
||||
module PartialFlow = Make<Config>::FlowExploration<explorationLimit/0>;
|
||||
|
||||
import PartialFlow::PartialPathGraph
|
||||
|
||||
from PartialFlow::PartialPathNode n, int dist
|
||||
where PartialFlow::hasPartialFlowRev(n, _, dist)
|
||||
select dist, n
|
||||
|
||||
@@ -39,22 +39,26 @@ predicate step(Node n1, Node n2, string s1, string s2) {
|
||||
|
||||
predicate checkNode(Node n) { n.asExpr().(Argument).getCall().getCallee().hasName("check") }
|
||||
|
||||
class Conf extends TaintTracking::Configuration {
|
||||
Conf() { this = "qltest:state" }
|
||||
module Conf implements DataFlow::StateConfigSig {
|
||||
class FlowState = string;
|
||||
|
||||
override predicate isSource(Node n, FlowState s) { src(n, s) }
|
||||
predicate isSource(Node n, FlowState s) { src(n, s) }
|
||||
|
||||
override predicate isSink(Node n, FlowState s) { sink(n, s) }
|
||||
predicate isSink(Node n, FlowState s) { sink(n, s) }
|
||||
|
||||
override predicate isSanitizer(Node n, FlowState s) { bar(n, s) }
|
||||
predicate isBarrier(Node n, FlowState s) { bar(n, s) }
|
||||
|
||||
override predicate isAdditionalTaintStep(Node n1, FlowState s1, Node n2, FlowState s2) {
|
||||
predicate isAdditionalFlowStep(Node n1, FlowState s1, Node n2, FlowState s2) {
|
||||
step(n1, n2, s1, s2)
|
||||
}
|
||||
|
||||
override int explorationLimit() { result = 0 }
|
||||
}
|
||||
|
||||
int explorationLimit() { result = 0 }
|
||||
|
||||
module Flow = TaintTracking::MakeWithState<Conf>;
|
||||
|
||||
module PartialFlow = Flow::FlowExploration<explorationLimit/0>;
|
||||
|
||||
class HasFlowTest extends InlineExpectationsTest {
|
||||
HasFlowTest() { this = "HasFlowTest" }
|
||||
|
||||
@@ -62,16 +66,16 @@ class HasFlowTest extends InlineExpectationsTest {
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
tag = "flow" and
|
||||
exists(PathNode src, PathNode sink, Conf conf |
|
||||
conf.hasFlowPath(src, sink) and
|
||||
exists(Flow::PathNode src, Flow::PathNode sink |
|
||||
Flow::hasFlowPath(src, sink) and
|
||||
sink.getNode().getLocation() = location and
|
||||
element = sink.toString() and
|
||||
value = src.getState()
|
||||
)
|
||||
or
|
||||
tag = "pFwd" and
|
||||
exists(PartialPathNode src, PartialPathNode node, Conf conf |
|
||||
conf.hasPartialFlow(src, node, _) and
|
||||
exists(PartialFlow::PartialPathNode src, PartialFlow::PartialPathNode node |
|
||||
PartialFlow::hasPartialFlow(src, node, _) and
|
||||
checkNode(node.getNode()) and
|
||||
node.getNode().getLocation() = location and
|
||||
element = node.toString() and
|
||||
@@ -79,8 +83,8 @@ class HasFlowTest extends InlineExpectationsTest {
|
||||
)
|
||||
or
|
||||
tag = "pRev" and
|
||||
exists(PartialPathNode node, PartialPathNode sink, Conf conf |
|
||||
conf.hasPartialFlowRev(node, sink, _) and
|
||||
exists(PartialFlow::PartialPathNode node, PartialFlow::PartialPathNode sink |
|
||||
PartialFlow::hasPartialFlowRev(node, sink, _) and
|
||||
checkNode(node.getNode()) and
|
||||
node.getNode().getLocation() = location and
|
||||
element = node.toString() and
|
||||
|
||||
@@ -6,42 +6,44 @@ class A {
|
||||
return "tainted";
|
||||
}
|
||||
|
||||
public static void sink(Object o) { }
|
||||
|
||||
public static void test1() {
|
||||
String bad = source(); // $ hasTaintFlow
|
||||
String bad = source();
|
||||
String good = "hi";
|
||||
|
||||
bad.formatted(good); // $ hasTaintFlow
|
||||
good.formatted("a", bad, "b", good); // $ hasTaintFlow
|
||||
String.format("%s%s", bad, good); // $ hasTaintFlow
|
||||
String.format("%s", good);
|
||||
String.format("%s %s %s %s %s %s %s %s %s %s ", "a", "a", "a", "a", "a", "a", "a", "a", "a", bad); // $ hasTaintFlow
|
||||
sink(bad.formatted(good)); // $ hasTaintFlow
|
||||
sink(good.formatted("a", bad, "b", good)); // $ hasTaintFlow
|
||||
sink(String.format("%s%s", bad, good)); // $ hasTaintFlow
|
||||
sink(String.format("%s", good));
|
||||
sink(String.format("%s %s %s %s %s %s %s %s %s %s ", "a", "a", "a", "a", "a", "a", "a", "a", "a", bad)); // $ hasTaintFlow
|
||||
}
|
||||
|
||||
public static void test2() {
|
||||
String bad = source(); // $ hasTaintFlow
|
||||
String bad = source();
|
||||
Formatter f = new Formatter();
|
||||
|
||||
f.toString();
|
||||
f.format("%s", bad); // $ hasTaintFlow
|
||||
f.toString(); // $ hasTaintFlow
|
||||
sink(f.toString());
|
||||
sink(f.format("%s", bad)); // $ hasTaintFlow
|
||||
sink(f.toString()); // $ hasTaintFlow
|
||||
}
|
||||
|
||||
public static void test3() {
|
||||
String bad = source(); // $ hasTaintFlow
|
||||
String bad = source();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
Formatter f = new Formatter(sb);
|
||||
|
||||
sb.toString(); // $ hasTaintFlow false positive
|
||||
f.format("%s", bad); // $ hasTaintFlow
|
||||
sb.toString(); // $ hasTaintFlow
|
||||
sink(sb.toString()); // $ SPURIOUS: hasTaintFlow
|
||||
sink(f.format("%s", bad)); // $ hasTaintFlow
|
||||
sink(sb.toString()); // $ hasTaintFlow
|
||||
}
|
||||
|
||||
public static void test4() {
|
||||
String bad = source(); // $ hasTaintFlow
|
||||
String bad = source();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append(bad); // $ hasTaintFlow
|
||||
sink(sb.append(bad)); // $ hasTaintFlow
|
||||
|
||||
new Formatter(sb).format("ok").toString(); // $ hasTaintFlow
|
||||
sink(new Formatter(sb).format("ok").toString()); // $ hasTaintFlow
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,2 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import TestUtilities.InlineFlowTest
|
||||
|
||||
class TaintFlowConf extends DefaultTaintFlowConf {
|
||||
override predicate isSink(DataFlow::Node n) { n instanceof DataFlow::ExprNode }
|
||||
}
|
||||
|
||||
@@ -3,6 +3,10 @@ import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import TestUtilities.InlineFlowTest
|
||||
|
||||
class EnableLegacy extends EnableLegacyConfiguration {
|
||||
EnableLegacy() { exists(this) }
|
||||
}
|
||||
|
||||
class TaintFlowConf extends DefaultTaintFlowConf {
|
||||
override predicate isSource(DataFlow::Node n) {
|
||||
super.isSource(n)
|
||||
|
||||
@@ -2,6 +2,10 @@ import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import TestUtilities.InlineFlowTest
|
||||
|
||||
class EnableLegacy extends EnableLegacyConfiguration {
|
||||
EnableLegacy() { exists(this) }
|
||||
}
|
||||
|
||||
class ProviderTaintFlowConf extends DefaultTaintFlowConf {
|
||||
override predicate isSource(DataFlow::Node n) { n instanceof RemoteFlowSource }
|
||||
}
|
||||
|
||||
@@ -3,6 +3,10 @@ import semmle.code.java.dataflow.DataFlow
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import TestUtilities.InlineFlowTest
|
||||
|
||||
class EnableLegacy extends EnableLegacyConfiguration {
|
||||
EnableLegacy() { exists(this) }
|
||||
}
|
||||
|
||||
class Conf extends TaintTracking::Configuration {
|
||||
Conf() { this = "test:AndroidExternalFlowConf" }
|
||||
|
||||
|
||||
@@ -2,6 +2,10 @@ import java
|
||||
import TestUtilities.InlineFlowTest
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
|
||||
class EnableLegacy extends EnableLegacyConfiguration {
|
||||
EnableLegacy() { exists(this) }
|
||||
}
|
||||
|
||||
class SliceValueFlowConf extends DefaultValueFlowConf {
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
super.isSource(source) or source instanceof RemoteFlowSource
|
||||
|
||||
@@ -2,6 +2,10 @@ import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import TestUtilities.InlineFlowTest
|
||||
|
||||
class EnableLegacy extends EnableLegacyConfiguration {
|
||||
EnableLegacy() { exists(this) }
|
||||
}
|
||||
|
||||
class SourceValueFlowConf extends DefaultValueFlowConf {
|
||||
override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
|
||||
}
|
||||
|
||||
@@ -5,6 +5,10 @@ import semmle.code.java.security.XSS
|
||||
import semmle.code.java.security.UrlRedirect
|
||||
import TestUtilities.InlineFlowTest
|
||||
|
||||
class EnableLegacy extends EnableLegacyConfiguration {
|
||||
EnableLegacy() { exists(this) }
|
||||
}
|
||||
|
||||
class Conf extends TaintTracking::Configuration {
|
||||
Conf() { this = "qltest:frameworks:apache-http" }
|
||||
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import java
|
||||
import TestUtilities.InlineFlowTest
|
||||
|
||||
class EnableLegacy extends EnableLegacyConfiguration {
|
||||
EnableLegacy() { exists(this) }
|
||||
}
|
||||
|
||||
class FlowConf extends DefaultValueFlowConf {
|
||||
override predicate isSink(DataFlow::Node n) { super.isSink(n) or sinkNode(n, "open-url") }
|
||||
}
|
||||
|
||||
@@ -3,6 +3,10 @@ import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import TestUtilities.InlineFlowTest
|
||||
|
||||
class EnableLegacy extends EnableLegacyConfiguration {
|
||||
EnableLegacy() { exists(this) }
|
||||
}
|
||||
|
||||
class Conf extends TaintTracking::Configuration {
|
||||
Conf() { this = "qltest:frameworks:rabbitmq" }
|
||||
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import java
|
||||
import TestUtilities.InlineFlowTest
|
||||
|
||||
class EnableLegacy extends EnableLegacyConfiguration {
|
||||
EnableLegacy() { exists(this) }
|
||||
}
|
||||
|
||||
class FlowConf extends DefaultValueFlowConf {
|
||||
override predicate isSink(DataFlow::Node n) { super.isSink(n) or sinkNode(n, "open-url") }
|
||||
}
|
||||
|
||||
@@ -2,6 +2,10 @@ import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import TestUtilities.InlineFlowTest
|
||||
|
||||
class EnableLegacy extends EnableLegacyConfiguration {
|
||||
EnableLegacy() { exists(this) }
|
||||
}
|
||||
|
||||
class ValueFlowConf extends DataFlow::Configuration {
|
||||
ValueFlowConf() { this = "ValueFlowConf" }
|
||||
|
||||
|
||||
@@ -2,6 +2,10 @@ import java
|
||||
import semmle.code.java.security.PathSanitizer
|
||||
import TestUtilities.InlineFlowTest
|
||||
|
||||
class EnableLegacy extends EnableLegacyConfiguration {
|
||||
EnableLegacy() { exists(this) }
|
||||
}
|
||||
|
||||
class PathSanitizerConf extends DefaultTaintFlowConf {
|
||||
override predicate isSanitizer(DataFlow::Node sanitizer) {
|
||||
sanitizer instanceof PathInjectionSanitizer
|
||||
|
||||
@@ -2,6 +2,10 @@ import java
|
||||
import TestUtilities.InlineFlowTest
|
||||
import semmle.code.java.security.PartialPathTraversalQuery
|
||||
|
||||
class EnableLegacy extends EnableLegacyConfiguration {
|
||||
EnableLegacy() { exists(this) }
|
||||
}
|
||||
|
||||
class TestRemoteSource extends RemoteFlowSource {
|
||||
TestRemoteSource() { this.asParameter().hasName(["dir", "path"]) }
|
||||
|
||||
|
||||
@@ -2,6 +2,10 @@ import java
|
||||
import semmle.code.java.security.LogInjectionQuery
|
||||
import TestUtilities.InlineFlowTest
|
||||
|
||||
class EnableLegacy extends EnableLegacyConfiguration {
|
||||
EnableLegacy() { exists(this) }
|
||||
}
|
||||
|
||||
private class TestSource extends RemoteFlowSource {
|
||||
TestSource() { this.asExpr().(MethodAccess).getMethod().hasName("source") }
|
||||
|
||||
|
||||
@@ -2,6 +2,10 @@ import java
|
||||
import TestUtilities.InlineFlowTest
|
||||
import semmle.code.java.security.IntentUriPermissionManipulationQuery
|
||||
|
||||
class EnableLegacy extends EnableLegacyConfiguration {
|
||||
EnableLegacy() { exists(this) }
|
||||
}
|
||||
|
||||
class IntentUriPermissionManipulationTest extends InlineFlowTest {
|
||||
override DataFlow::Configuration getValueFlowConfig() { none() }
|
||||
|
||||
|
||||
@@ -2,6 +2,10 @@ import java
|
||||
import semmle.code.java.security.InsecureTrustManagerQuery
|
||||
import TestUtilities.InlineFlowTest
|
||||
|
||||
class EnableLegacy extends EnableLegacyConfiguration {
|
||||
EnableLegacy() { exists(this) }
|
||||
}
|
||||
|
||||
class InsecureTrustManagerTest extends InlineFlowTest {
|
||||
override DataFlow::Configuration getValueFlowConfig() {
|
||||
result = any(InsecureTrustManagerConfiguration c)
|
||||
|
||||
@@ -2,6 +2,10 @@ import java
|
||||
import TestUtilities.InlineFlowTest
|
||||
import semmle.code.java.security.UnsafeContentUriResolutionQuery
|
||||
|
||||
class EnableLegacy extends EnableLegacyConfiguration {
|
||||
EnableLegacy() { exists(this) }
|
||||
}
|
||||
|
||||
class Test extends InlineFlowTest {
|
||||
override DataFlow::Configuration getValueFlowConfig() { none() }
|
||||
|
||||
|
||||
@@ -2,6 +2,10 @@ import java
|
||||
import semmle.code.java.security.FragmentInjectionQuery
|
||||
import TestUtilities.InlineFlowTest
|
||||
|
||||
class EnableLegacy extends EnableLegacyConfiguration {
|
||||
EnableLegacy() { exists(this) }
|
||||
}
|
||||
|
||||
class Test extends InlineFlowTest {
|
||||
override DataFlow::Configuration getValueFlowConfig() { none() }
|
||||
|
||||
|
||||
@@ -2,6 +2,10 @@ import java
|
||||
import TestUtilities.InlineFlowTest
|
||||
import semmle.code.java.security.WebviewDubuggingEnabledQuery
|
||||
|
||||
class EnableLegacy extends EnableLegacyConfiguration {
|
||||
EnableLegacy() { exists(this) }
|
||||
}
|
||||
|
||||
class HasFlowTest extends InlineFlowTest {
|
||||
override DataFlow::Configuration getTaintFlowConfig() { none() }
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@ import TestUtilities.InlineFlowTest
|
||||
import semmle.code.java.security.SensitiveLoggingQuery
|
||||
|
||||
class HasFlowTest extends InlineFlowTest {
|
||||
override DataFlow::Configuration getTaintFlowConfig() {
|
||||
result instanceof SensitiveLoggerConfiguration
|
||||
override predicate hasTaintFlow(DataFlow::Node src, DataFlow::Node sink) {
|
||||
SensitiveLoggerFlow::hasFlow(src, sink)
|
||||
}
|
||||
|
||||
override DataFlow::Configuration getValueFlowConfig() { none() }
|
||||
override predicate hasValueFlow(DataFlow::Node src, DataFlow::Node sink) { none() }
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user