mirror of
https://github.com/github/codeql.git
synced 2025-12-24 12:46:34 +01:00
Merge branch 'main' into new-nosql-examples
This commit is contained in:
3
.bazelrc
Normal file
3
.bazelrc
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
build --repo_env=CC=clang --repo_env=CXX=clang++ --copt="-std=c++17"
|
||||||
|
|
||||||
|
try-import %workspace%/local.bazelrc
|
||||||
1
.bazelversion
Normal file
1
.bazelversion
Normal file
@@ -0,0 +1 @@
|
|||||||
|
5.0.0
|
||||||
14
.github/actions/fetch-codeql/action.yml
vendored
14
.github/actions/fetch-codeql/action.yml
vendored
@@ -3,12 +3,22 @@ description: Fetches the latest version of CodeQL
|
|||||||
runs:
|
runs:
|
||||||
using: composite
|
using: composite
|
||||||
steps:
|
steps:
|
||||||
|
- name: Select platform - Linux
|
||||||
|
if: runner.os == 'Linux'
|
||||||
|
shell: bash
|
||||||
|
run: echo "GA_CODEQL_CLI_PLATFORM=linux64" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Select platform - MacOS
|
||||||
|
if: runner.os == 'MacOS'
|
||||||
|
shell: bash
|
||||||
|
run: echo "GA_CODEQL_CLI_PLATFORM=osx64" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Fetch CodeQL
|
- name: Fetch CodeQL
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
LATEST=$(gh release list --repo https://github.com/github/codeql-cli-binaries | cut -f 1 | grep -v beta | sort --version-sort | tail -1)
|
LATEST=$(gh release list --repo https://github.com/github/codeql-cli-binaries | cut -f 1 | grep -v beta | sort --version-sort | tail -1)
|
||||||
gh release download --repo https://github.com/github/codeql-cli-binaries --pattern codeql-linux64.zip "$LATEST"
|
gh release download --repo https://github.com/github/codeql-cli-binaries --pattern codeql-$GA_CODEQL_CLI_PLATFORM.zip "$LATEST"
|
||||||
unzip -q -d "${RUNNER_TEMP}" codeql-linux64.zip
|
unzip -q -d "${RUNNER_TEMP}" codeql-$GA_CODEQL_CLI_PLATFORM.zip
|
||||||
echo "${RUNNER_TEMP}/codeql" >> "${GITHUB_PATH}"
|
echo "${RUNNER_TEMP}/codeql" >> "${GITHUB_PATH}"
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ github.token }}
|
GITHUB_TOKEN: ${{ github.token }}
|
||||||
|
|||||||
8
.github/dependabot.yml
vendored
8
.github/dependabot.yml
vendored
@@ -16,3 +16,11 @@ updates:
|
|||||||
directory: "ruby/autobuilder"
|
directory: "ruby/autobuilder"
|
||||||
schedule:
|
schedule:
|
||||||
interval: "daily"
|
interval: "daily"
|
||||||
|
|
||||||
|
- package-ecosystem: "github-actions"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "daily"
|
||||||
|
ignore:
|
||||||
|
- dependency-name: '*'
|
||||||
|
update-types: ['version-update:semver-patch', 'version-update:semver-minor']
|
||||||
|
|||||||
6
.github/labeler.yml
vendored
6
.github/labeler.yml
vendored
@@ -21,6 +21,10 @@ Python:
|
|||||||
Ruby:
|
Ruby:
|
||||||
- ruby/**/*
|
- ruby/**/*
|
||||||
- change-notes/**/*ruby*
|
- change-notes/**/*ruby*
|
||||||
|
|
||||||
|
Swift:
|
||||||
|
- swift/**/*
|
||||||
|
- change-notes/**/*swift*
|
||||||
|
|
||||||
documentation:
|
documentation:
|
||||||
- "**/*.qhelp"
|
- "**/*.qhelp"
|
||||||
@@ -28,4 +32,4 @@ documentation:
|
|||||||
- docs/**/*
|
- docs/**/*
|
||||||
|
|
||||||
"QL-for-QL":
|
"QL-for-QL":
|
||||||
- ql/**/*
|
- ql/**/*
|
||||||
|
|||||||
5
.github/workflows/check-qldoc.yml
vendored
5
.github/workflows/check-qldoc.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ github.token }}
|
GITHUB_TOKEN: ${{ github.token }}
|
||||||
|
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 2
|
fetch-depth: 2
|
||||||
|
|
||||||
@@ -30,7 +30,8 @@ jobs:
|
|||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
EXIT_CODE=0
|
EXIT_CODE=0
|
||||||
changed_lib_packs="$(git diff --name-only --diff-filter=ACMRT HEAD^ HEAD | { grep -o '^[a-z]*/ql/lib' || true; } | sort -u)"
|
# TODO: remove the swift exception from the regex when we fix generated QLdoc
|
||||||
|
changed_lib_packs="$(git diff --name-only --diff-filter=ACMRT HEAD^ HEAD | { grep -Po '^(?!swift)[a-z]*/ql/lib' || true; } | sort -u)"
|
||||||
for pack_dir in ${changed_lib_packs}; do
|
for pack_dir in ${changed_lib_packs}; do
|
||||||
lang="${pack_dir%/ql/lib}"
|
lang="${pack_dir%/ql/lib}"
|
||||||
gh codeql generate library-doc-coverage --output="${RUNNER_TEMP}/${lang}-current.txt" --dir="${pack_dir}"
|
gh codeql generate library-doc-coverage --output="${RUNNER_TEMP}/${lang}-current.txt" --dir="${pack_dir}"
|
||||||
|
|||||||
2
.github/workflows/close-stale.yml
vendored
2
.github/workflows/close-stale.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/stale@v3
|
- uses: actions/stale@v5
|
||||||
with:
|
with:
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
stale-issue-message: 'This issue is stale because it has been open 14 days with no activity. Comment or remove the `Stale` label in order to avoid having this issue closed in 7 days.'
|
stale-issue-message: 'This issue is stale because it has been open 14 days with no activity. Comment or remove the `Stale` label in order to avoid having this issue closed in 7 days.'
|
||||||
|
|||||||
6
.github/workflows/codeql-analysis.yml
vendored
6
.github/workflows/codeql-analysis.yml
vendored
@@ -28,12 +28,12 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Setup dotnet
|
- name: Setup dotnet
|
||||||
uses: actions/setup-dotnet@v1
|
uses: actions/setup-dotnet@v2
|
||||||
with:
|
with:
|
||||||
dotnet-version: 6.0.101
|
dotnet-version: 6.0.101
|
||||||
|
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
@@ -49,7 +49,7 @@ jobs:
|
|||||||
# uses: github/codeql-action/autobuild@main
|
# uses: github/codeql-action/autobuild@main
|
||||||
|
|
||||||
# ℹ️ Command-line programs to run using the OS shell.
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
# 📚 https://git.io/JvXDl
|
# 📚 https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||||
|
|
||||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||||
# and modify them (or add more) to build your code if your project
|
# and modify them (or add more) to build your code if your project
|
||||||
|
|||||||
43
.github/workflows/csv-coverage-metrics.yml
vendored
43
.github/workflows/csv-coverage-metrics.yml
vendored
@@ -14,11 +14,11 @@ on:
|
|||||||
- ".github/workflows/csv-coverage-metrics.yml"
|
- ".github/workflows/csv-coverage-metrics.yml"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
publish:
|
publish-java:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
- name: Setup CodeQL
|
- name: Setup CodeQL
|
||||||
uses: ./.github/actions/fetch-codeql
|
uses: ./.github/actions/fetch-codeql
|
||||||
- name: Create empty database
|
- name: Create empty database
|
||||||
@@ -31,13 +31,40 @@ jobs:
|
|||||||
- name: Capture coverage information
|
- name: Capture coverage information
|
||||||
run: |
|
run: |
|
||||||
DATABASE="${{ runner.temp }}/java-database"
|
DATABASE="${{ runner.temp }}/java-database"
|
||||||
codeql database analyze --format=sarif-latest --output=metrics.sarif -- "$DATABASE" ./java/ql/src/Metrics/Summaries/FrameworkCoverage.ql
|
codeql database analyze --format=sarif-latest --output=metrics-java.sarif -- "$DATABASE" ./java/ql/src/Metrics/Summaries/FrameworkCoverage.ql
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: metrics.sarif
|
name: metrics-java.sarif
|
||||||
path: metrics.sarif
|
path: metrics-java.sarif
|
||||||
retention-days: 20
|
retention-days: 20
|
||||||
- name: Upload SARIF file
|
- name: Upload SARIF file
|
||||||
uses: github/codeql-action/upload-sarif@v1
|
uses: github/codeql-action/upload-sarif@main
|
||||||
with:
|
with:
|
||||||
sarif_file: metrics.sarif
|
sarif_file: metrics-java.sarif
|
||||||
|
|
||||||
|
publish-csharp:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: Setup CodeQL
|
||||||
|
uses: ./.github/actions/fetch-codeql
|
||||||
|
- name: Create empty database
|
||||||
|
run: |
|
||||||
|
DATABASE="${{ runner.temp }}/csharp-database"
|
||||||
|
PROJECT="${{ runner.temp }}/csharp-project"
|
||||||
|
dotnet new classlib --language=C# --output="$PROJECT"
|
||||||
|
codeql database create "$DATABASE" --language=csharp --source-root="$PROJECT" --command 'dotnet build /t:rebuild csharp-project.csproj /p:UseSharedCompilation=false'
|
||||||
|
- name: Capture coverage information
|
||||||
|
run: |
|
||||||
|
DATABASE="${{ runner.temp }}/csharp-database"
|
||||||
|
codeql database analyze --format=sarif-latest --output=metrics-csharp.sarif -- "$DATABASE" ./csharp/ql/src/Metrics/Summaries/FrameworkCoverage.ql
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: metrics-csharp.sarif
|
||||||
|
path: metrics-csharp.sarif
|
||||||
|
retention-days: 20
|
||||||
|
- name: Upload SARIF file
|
||||||
|
uses: github/codeql-action/upload-sarif@main
|
||||||
|
with:
|
||||||
|
sarif_file: metrics-csharp.sarif
|
||||||
|
|||||||
14
.github/workflows/csv-coverage-pr-artifacts.yml
vendored
14
.github/workflows/csv-coverage-pr-artifacts.yml
vendored
@@ -28,11 +28,11 @@ jobs:
|
|||||||
GITHUB_CONTEXT: ${{ toJSON(github.event) }}
|
GITHUB_CONTEXT: ${{ toJSON(github.event) }}
|
||||||
run: echo "$GITHUB_CONTEXT"
|
run: echo "$GITHUB_CONTEXT"
|
||||||
- name: Clone self (github/codeql) - MERGE
|
- name: Clone self (github/codeql) - MERGE
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
path: merge
|
path: merge
|
||||||
- name: Clone self (github/codeql) - BASE
|
- name: Clone self (github/codeql) - BASE
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 2
|
fetch-depth: 2
|
||||||
path: base
|
path: base
|
||||||
@@ -41,7 +41,7 @@ jobs:
|
|||||||
git log -1 --format='%H'
|
git log -1 --format='%H'
|
||||||
working-directory: base
|
working-directory: base
|
||||||
- name: Set up Python 3.8
|
- name: Set up Python 3.8
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v3
|
||||||
with:
|
with:
|
||||||
python-version: 3.8
|
python-version: 3.8
|
||||||
- name: Download CodeQL CLI
|
- name: Download CodeQL CLI
|
||||||
@@ -69,21 +69,21 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
python base/misc/scripts/library-coverage/compare-folders.py out_base out_merge comparison.md
|
python base/misc/scripts/library-coverage/compare-folders.py out_base out_merge comparison.md
|
||||||
- name: Upload CSV package list
|
- name: Upload CSV package list
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: csv-framework-coverage-merge
|
name: csv-framework-coverage-merge
|
||||||
path: |
|
path: |
|
||||||
out_merge/framework-coverage-*.csv
|
out_merge/framework-coverage-*.csv
|
||||||
out_merge/framework-coverage-*.rst
|
out_merge/framework-coverage-*.rst
|
||||||
- name: Upload CSV package list
|
- name: Upload CSV package list
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: csv-framework-coverage-base
|
name: csv-framework-coverage-base
|
||||||
path: |
|
path: |
|
||||||
out_base/framework-coverage-*.csv
|
out_base/framework-coverage-*.csv
|
||||||
out_base/framework-coverage-*.rst
|
out_base/framework-coverage-*.rst
|
||||||
- name: Upload comparison results
|
- name: Upload comparison results
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: comparison
|
name: comparison
|
||||||
path: |
|
path: |
|
||||||
@@ -93,7 +93,7 @@ jobs:
|
|||||||
mkdir -p pr
|
mkdir -p pr
|
||||||
echo ${{ github.event.pull_request.number }} > pr/NR
|
echo ${{ github.event.pull_request.number }} > pr/NR
|
||||||
- name: Upload PR number
|
- name: Upload PR number
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: pr
|
name: pr
|
||||||
path: pr/
|
path: pr/
|
||||||
|
|||||||
@@ -20,9 +20,9 @@ jobs:
|
|||||||
GITHUB_CONTEXT: ${{ toJSON(github.event) }}
|
GITHUB_CONTEXT: ${{ toJSON(github.event) }}
|
||||||
run: echo "$GITHUB_CONTEXT"
|
run: echo "$GITHUB_CONTEXT"
|
||||||
- name: Clone self (github/codeql)
|
- name: Clone self (github/codeql)
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
- name: Set up Python 3.8
|
- name: Set up Python 3.8
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v3
|
||||||
with:
|
with:
|
||||||
python-version: 3.8
|
python-version: 3.8
|
||||||
|
|
||||||
|
|||||||
@@ -10,16 +10,16 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Clone self (github/codeql)
|
- name: Clone self (github/codeql)
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
path: script
|
path: script
|
||||||
- name: Clone self (github/codeql) for analysis
|
- name: Clone self (github/codeql) for analysis
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
path: codeqlModels
|
path: codeqlModels
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Set up Python 3.8
|
- name: Set up Python 3.8
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v3
|
||||||
with:
|
with:
|
||||||
python-version: 3.8
|
python-version: 3.8
|
||||||
- name: Download CodeQL CLI
|
- name: Download CodeQL CLI
|
||||||
@@ -35,7 +35,7 @@ jobs:
|
|||||||
echo $CLI
|
echo $CLI
|
||||||
PATH="$PATH:$CLI" python script/misc/scripts/library-coverage/generate-timeseries.py codeqlModels
|
PATH="$PATH:$CLI" python script/misc/scripts/library-coverage/generate-timeseries.py codeqlModels
|
||||||
- name: Upload timeseries CSV
|
- name: Upload timeseries CSV
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: framework-coverage-timeseries
|
name: framework-coverage-timeseries
|
||||||
path: framework-coverage-timeseries-*.csv
|
path: framework-coverage-timeseries-*.csv
|
||||||
|
|||||||
4
.github/workflows/csv-coverage-update.yml
vendored
4
.github/workflows/csv-coverage-update.yml
vendored
@@ -17,12 +17,12 @@ jobs:
|
|||||||
GITHUB_CONTEXT: ${{ toJSON(github.event) }}
|
GITHUB_CONTEXT: ${{ toJSON(github.event) }}
|
||||||
run: echo "$GITHUB_CONTEXT"
|
run: echo "$GITHUB_CONTEXT"
|
||||||
- name: Clone self (github/codeql)
|
- name: Clone self (github/codeql)
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
path: ql
|
path: ql
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Set up Python 3.8
|
- name: Set up Python 3.8
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v3
|
||||||
with:
|
with:
|
||||||
python-version: 3.8
|
python-version: 3.8
|
||||||
- name: Download CodeQL CLI
|
- name: Download CodeQL CLI
|
||||||
|
|||||||
10
.github/workflows/csv-coverage.yml
vendored
10
.github/workflows/csv-coverage.yml
vendored
@@ -14,16 +14,16 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Clone self (github/codeql)
|
- name: Clone self (github/codeql)
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
path: script
|
path: script
|
||||||
- name: Clone self (github/codeql) for analysis
|
- name: Clone self (github/codeql) for analysis
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
path: codeqlModels
|
path: codeqlModels
|
||||||
ref: ${{ github.event.inputs.qlModelShaOverride || github.ref }}
|
ref: ${{ github.event.inputs.qlModelShaOverride || github.ref }}
|
||||||
- name: Set up Python 3.8
|
- name: Set up Python 3.8
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v3
|
||||||
with:
|
with:
|
||||||
python-version: 3.8
|
python-version: 3.8
|
||||||
- name: Download CodeQL CLI
|
- name: Download CodeQL CLI
|
||||||
@@ -37,12 +37,12 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
PATH="$PATH:codeql-cli/codeql" python script/misc/scripts/library-coverage/generate-report.py ci codeqlModels script
|
PATH="$PATH:codeql-cli/codeql" python script/misc/scripts/library-coverage/generate-report.py ci codeqlModels script
|
||||||
- name: Upload CSV package list
|
- name: Upload CSV package list
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: framework-coverage-csv
|
name: framework-coverage-csv
|
||||||
path: framework-coverage-*.csv
|
path: framework-coverage-*.csv
|
||||||
- name: Upload RST package list
|
- name: Upload RST package list
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: framework-coverage-rst
|
name: framework-coverage-rst
|
||||||
path: framework-coverage-*.rst
|
path: framework-coverage-*.rst
|
||||||
|
|||||||
6
.github/workflows/js-ml-tests.yml
vendored
6
.github/workflows/js-ml-tests.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
|||||||
name: Check QL formatting
|
name: Check QL formatting
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- uses: ./.github/actions/fetch-codeql
|
- uses: ./.github/actions/fetch-codeql
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ jobs:
|
|||||||
name: Check QL compilation
|
name: Check QL compilation
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- uses: ./.github/actions/fetch-codeql
|
- uses: ./.github/actions/fetch-codeql
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ jobs:
|
|||||||
name: Run QL tests
|
name: Run QL tests
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- uses: ./.github/actions/fetch-codeql
|
- uses: ./.github/actions/fetch-codeql
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/labeler.yml
vendored
2
.github/workflows/labeler.yml
vendored
@@ -6,6 +6,6 @@ jobs:
|
|||||||
triage:
|
triage:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/labeler@v2
|
- uses: actions/labeler@v4
|
||||||
with:
|
with:
|
||||||
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
||||||
|
|||||||
8
.github/workflows/mad_modelDiff.yml
vendored
8
.github/workflows/mad_modelDiff.yml
vendored
@@ -27,12 +27,12 @@ jobs:
|
|||||||
slug: ${{fromJson(github.event.inputs.projects || '["apache/commons-codec", "apache/commons-io", "apache/commons-beanutils", "apache/commons-logging", "apache/commons-fileupload", "apache/commons-lang", "apache/commons-validator", "apache/commons-csv", "apache/dubbo"]' )}}
|
slug: ${{fromJson(github.event.inputs.projects || '["apache/commons-codec", "apache/commons-io", "apache/commons-beanutils", "apache/commons-logging", "apache/commons-fileupload", "apache/commons-lang", "apache/commons-validator", "apache/commons-csv", "apache/dubbo"]' )}}
|
||||||
steps:
|
steps:
|
||||||
- name: Clone github/codeql from PR
|
- name: Clone github/codeql from PR
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
if: github.event.pull_request
|
if: github.event.pull_request
|
||||||
with:
|
with:
|
||||||
path: codeql-pr
|
path: codeql-pr
|
||||||
- name: Clone github/codeql from main
|
- name: Clone github/codeql from main
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
path: codeql-main
|
path: codeql-main
|
||||||
ref: main
|
ref: main
|
||||||
@@ -91,12 +91,12 @@ jobs:
|
|||||||
name="diff_${basename/_main.qll/""}"
|
name="diff_${basename/_main.qll/""}"
|
||||||
(diff -w -u $m $t | diff2html -i stdin -F $MODELS/$name.html) || true
|
(diff -w -u $m $t | diff2html -i stdin -F $MODELS/$name.html) || true
|
||||||
done
|
done
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: models
|
name: models
|
||||||
path: tmp-models/*.qll
|
path: tmp-models/*.qll
|
||||||
retention-days: 20
|
retention-days: 20
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: diffs
|
name: diffs
|
||||||
path: tmp-models/*.html
|
path: tmp-models/*.html
|
||||||
|
|||||||
6
.github/workflows/mad_regenerate-models.yml
vendored
6
.github/workflows/mad_regenerate-models.yml
vendored
@@ -26,11 +26,11 @@ jobs:
|
|||||||
ref: "placeholder"
|
ref: "placeholder"
|
||||||
steps:
|
steps:
|
||||||
- name: Clone self (github/codeql)
|
- name: Clone self (github/codeql)
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
- name: Setup CodeQL binaries
|
- name: Setup CodeQL binaries
|
||||||
uses: ./.github/actions/fetch-codeql
|
uses: ./.github/actions/fetch-codeql
|
||||||
- name: Clone repositories
|
- name: Clone repositories
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
path: repos/${{ matrix.ref }}
|
path: repos/${{ matrix.ref }}
|
||||||
ref: ${{ matrix.ref }}
|
ref: ${{ matrix.ref }}
|
||||||
@@ -55,7 +55,7 @@ jobs:
|
|||||||
find java -name "*.qll" -print0 | xargs -0 git add
|
find java -name "*.qll" -print0 | xargs -0 git add
|
||||||
git status
|
git status
|
||||||
git diff --cached > models.patch
|
git diff --cached > models.patch
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: patch
|
name: patch
|
||||||
path: models.patch
|
path: models.patch
|
||||||
|
|||||||
53
.github/workflows/post-pr-comment.yml
vendored
53
.github/workflows/post-pr-comment.yml
vendored
@@ -1,12 +1,17 @@
|
|||||||
name: Post pull-request comment
|
# This workflow is the second part of the process described in
|
||||||
|
# .github/workflows/qhelp-pr-preview.yml
|
||||||
|
# See that file for more info.
|
||||||
|
|
||||||
|
name: Post PR comment
|
||||||
on:
|
on:
|
||||||
workflow_run:
|
workflow_run:
|
||||||
workflows: ["Query help preview"]
|
workflows: [Render QHelp changes]
|
||||||
types:
|
types:
|
||||||
- completed
|
- completed
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
|
actions: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
post_comment:
|
post_comment:
|
||||||
@@ -17,15 +22,53 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ github.token }}
|
GITHUB_TOKEN: ${{ github.token }}
|
||||||
WORKFLOW_RUN_ID: ${{ github.event.workflow_run.id }}
|
WORKFLOW_RUN_ID: ${{ github.event.workflow_run.id }}
|
||||||
- run: |
|
|
||||||
PR="$(grep -o '^[0-9]\+$' pr.txt)"
|
- name: Check that PR SHA matches workflow SHA
|
||||||
|
run: |
|
||||||
|
PR="$(grep -o '^[0-9]\+$' pr_number.txt)"
|
||||||
PR_HEAD_SHA="$(gh api "/repos/${GITHUB_REPOSITORY}/pulls/${PR}" --jq .head.sha)"
|
PR_HEAD_SHA="$(gh api "/repos/${GITHUB_REPOSITORY}/pulls/${PR}" --jq .head.sha)"
|
||||||
# Check that the pull-request head SHA matches the head SHA of the workflow run
|
# Check that the pull-request head SHA matches the head SHA of the workflow run
|
||||||
if [ "${WORKFLOW_RUN_HEAD_SHA}" != "${PR_HEAD_SHA}" ]; then
|
if [ "${WORKFLOW_RUN_HEAD_SHA}" != "${PR_HEAD_SHA}" ]; then
|
||||||
echo "PR head SHA ${PR_HEAD_SHA} does not match workflow_run event SHA ${WORKFLOW_RUN_HEAD_SHA}. Stopping." 1>&2
|
echo "PR head SHA ${PR_HEAD_SHA} does not match workflow_run event SHA ${WORKFLOW_RUN_HEAD_SHA}. Stopping." 1>&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
gh pr comment "${PR}" --repo "${GITHUB_REPOSITORY}" -F comment.txt
|
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ github.token }}
|
GITHUB_TOKEN: ${{ github.token }}
|
||||||
WORKFLOW_RUN_HEAD_SHA: ${{ github.event.workflow_run.head_commit.id }}
|
WORKFLOW_RUN_HEAD_SHA: ${{ github.event.workflow_run.head_commit.id }}
|
||||||
|
|
||||||
|
- name: Create or update comment
|
||||||
|
run: |
|
||||||
|
COMMENT_PREFIX="QHelp previews"
|
||||||
|
COMMENT_AUTHOR="github-actions[bot]"
|
||||||
|
PR_NUMBER="$(grep -o '^[0-9]\+$' pr_number.txt)"
|
||||||
|
|
||||||
|
# If there is no existing comment, comment_id.txt will contain just a
|
||||||
|
# newline (due to jq & gh behaviour). This will cause grep to fail, so
|
||||||
|
# we catch that.
|
||||||
|
RAW_COMMENT_ID=$(grep -o '^[0-9]\+$' comment_id.txt || true)
|
||||||
|
|
||||||
|
if [ $RAW_COMMENT_ID ]
|
||||||
|
then
|
||||||
|
# Fetch existing comment, and validate:
|
||||||
|
# - comment belongs to the PR with number $PR_NUMBER
|
||||||
|
# - comment starts with the expected prefix ("QHelp previews")
|
||||||
|
# - comment author is github-actions[bot]
|
||||||
|
FILTER='select(.issue_url | endswith($repo+"/issues/"+$pr))
|
||||||
|
| select(.body | startswith($prefix))
|
||||||
|
| select(.user.login == $author)
|
||||||
|
| .id'
|
||||||
|
COMMENT_ID=$(gh api "repos/${GITHUB_REPOSITORY}/issues/comments/${RAW_COMMENT_ID}" | jq --arg repo "${GITHUB_REPOSITORY}" --arg pr "${PR_NUMBER}" --arg prefix "${COMMENT_PREFIX}" --arg author "${COMMENT_AUTHOR}" "${FILTER}")
|
||||||
|
if [ $COMMENT_ID ]
|
||||||
|
then
|
||||||
|
# Update existing comment
|
||||||
|
jq --rawfile body comment_body.txt '{"body":$body}' -n | gh api "repos/${GITHUB_REPOSITORY}/issues/comments/${COMMENT_ID}" -X PATCH --input -
|
||||||
|
else
|
||||||
|
echo "Comment ${RAW_COMMENT_ID} did not pass validations: not editing." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# Create new comment
|
||||||
|
jq --rawfile body comment_body.txt '{"body":$body}' -n | gh api "repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/comments" -X POST --input -
|
||||||
|
fi
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ github.token }}
|
||||||
|
|||||||
57
.github/workflows/qhelp-pr-preview.yml
vendored
57
.github/workflows/qhelp-pr-preview.yml
vendored
@@ -1,7 +1,25 @@
|
|||||||
name: Query help preview
|
# This workflow checks for any changes in .qhelp files in pull requests.
|
||||||
|
# For any changed files, it renders them to markdown in a file called `comment_body.txt`.
|
||||||
|
# It then checks if there's an existing comment on the pull request generated by
|
||||||
|
# this workflow, and writes the comment ID to `comment_id.txt`.
|
||||||
|
# It also writes the PR number to `pr_number.txt`.
|
||||||
|
# These three files are uploaded as an artifact.
|
||||||
|
|
||||||
|
# When this workflow completes, the workflow "Post PR comment" runs.
|
||||||
|
# It downloads the artifact and adds a comment to the PR with the rendered
|
||||||
|
# QHelp.
|
||||||
|
|
||||||
|
# The task is split like this because creating PR comments requires extra
|
||||||
|
# permissions that we don't want to expose to PRs from external forks.
|
||||||
|
|
||||||
|
# For more info see:
|
||||||
|
# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflow_run
|
||||||
|
# https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token
|
||||||
|
name: Render QHelp changes
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
pull-requests: read
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
@@ -15,13 +33,17 @@ jobs:
|
|||||||
qhelp:
|
qhelp:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- run: echo "${{ github.event.number }}" > pr.txt
|
- run: echo "${PR_NUMBER}" > pr_number.txt
|
||||||
- uses: actions/upload-artifact@v2
|
env:
|
||||||
|
PR_NUMBER: ${{ github.event.number }}
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: comment
|
name: comment
|
||||||
path: pr.txt
|
path: pr_number.txt
|
||||||
|
if-no-files-found: error
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
- uses: actions/checkout@v2
|
|
||||||
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 2
|
fetch-depth: 2
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
@@ -36,7 +58,7 @@ jobs:
|
|||||||
- name: QHelp preview
|
- name: QHelp preview
|
||||||
run: |
|
run: |
|
||||||
EXIT_CODE=0
|
EXIT_CODE=0
|
||||||
echo "QHelp previews:" > comment.txt
|
echo "QHelp previews:" > comment_body.txt
|
||||||
while read -r -d $'\0' path; do
|
while read -r -d $'\0' path; do
|
||||||
if [ ! -f "${path}" ]; then
|
if [ ! -f "${path}" ]; then
|
||||||
exit 1
|
exit 1
|
||||||
@@ -52,12 +74,29 @@ jobs:
|
|||||||
echo '```'
|
echo '```'
|
||||||
fi
|
fi
|
||||||
echo "</details>"
|
echo "</details>"
|
||||||
done < "${RUNNER_TEMP}/paths.txt" >> comment.txt
|
done < "${RUNNER_TEMP}/paths.txt" >> comment_body.txt
|
||||||
exit "${EXIT_CODE}"
|
exit "${EXIT_CODE}"
|
||||||
|
|
||||||
- if: always()
|
- if: always()
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: comment
|
name: comment
|
||||||
path: comment.txt
|
path: comment_body.txt
|
||||||
|
if-no-files-found: error
|
||||||
|
retention-days: 1
|
||||||
|
|
||||||
|
- name: Save ID of existing QHelp comment (if it exists)
|
||||||
|
run: |
|
||||||
|
# Find the latest comment starting with "QHelp previews"
|
||||||
|
COMMENT_PREFIX="QHelp previews"
|
||||||
|
gh api "repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/comments" --paginate | jq --arg prefix "${COMMENT_PREFIX}" '[.[] | select(.body|startswith($prefix)) | .id] | max' > comment_id.txt
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ github.token }}
|
||||||
|
PR_NUMBER: ${{ github.event.number }}
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: comment
|
||||||
|
path: comment_id.txt
|
||||||
|
if-no-files-found: error
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
|
|||||||
30
.github/workflows/ql-for-ql-build.yml
vendored
30
.github/workflows/ql-for-ql-build.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
|||||||
queries:
|
queries:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- name: Find codeql
|
- name: Find codeql
|
||||||
id: find-codeql
|
id: find-codeql
|
||||||
uses: github/codeql-action/init@aa93aea877e5fb8841bcb1193f672abf6e9f2980
|
uses: github/codeql-action/init@aa93aea877e5fb8841bcb1193f672abf6e9f2980
|
||||||
@@ -29,7 +29,7 @@ jobs:
|
|||||||
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||||
- name: Cache queries
|
- name: Cache queries
|
||||||
id: cache-queries
|
id: cache-queries
|
||||||
uses: actions/cache@v2
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: ${{ runner.temp }}/query-pack.zip
|
path: ${{ runner.temp }}/query-pack.zip
|
||||||
key: queries-${{ hashFiles('ql/**/*.ql*') }}-${{ hashFiles('ql/**/qlpack.yml') }}-${{ hashFiles('ql/ql/src/ql.dbscheme*') }}-${{ steps.get-codeql-version.outputs.version }}
|
key: queries-${{ hashFiles('ql/**/*.ql*') }}-${{ hashFiles('ql/**/qlpack.yml') }}-${{ hashFiles('ql/ql/src/ql.dbscheme*') }}-${{ steps.get-codeql-version.outputs.version }}
|
||||||
@@ -44,7 +44,7 @@ jobs:
|
|||||||
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||||
PACKZIP: ${{ runner.temp }}/query-pack.zip
|
PACKZIP: ${{ runner.temp }}/query-pack.zip
|
||||||
- name: Upload query pack
|
- name: Upload query pack
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: query-pack-zip
|
name: query-pack-zip
|
||||||
path: ${{ runner.temp }}/query-pack.zip
|
path: ${{ runner.temp }}/query-pack.zip
|
||||||
@@ -56,10 +56,10 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- name: Cache entire extractor
|
- name: Cache entire extractor
|
||||||
id: cache-extractor
|
id: cache-extractor
|
||||||
uses: actions/cache@v2
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
ql/target/release/ql-autobuilder
|
ql/target/release/ql-autobuilder
|
||||||
@@ -69,7 +69,7 @@ jobs:
|
|||||||
key: ${{ runner.os }}-extractor-${{ hashFiles('ql/**/Cargo.lock') }}-${{ hashFiles('ql/**/*.rs') }}
|
key: ${{ runner.os }}-extractor-${{ hashFiles('ql/**/Cargo.lock') }}-${{ hashFiles('ql/**/*.rs') }}
|
||||||
- name: Cache cargo
|
- name: Cache cargo
|
||||||
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
||||||
uses: actions/cache@v2
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.cargo/registry
|
~/.cargo/registry
|
||||||
@@ -91,7 +91,7 @@ jobs:
|
|||||||
- name: Generate dbscheme
|
- name: Generate dbscheme
|
||||||
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
||||||
run: ql/target/release/ql-generator --dbscheme ql/ql/src/ql.dbscheme --library ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll
|
run: ql/target/release/ql-generator --dbscheme ql/ql/src/ql.dbscheme --library ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: extractor-ubuntu-latest
|
name: extractor-ubuntu-latest
|
||||||
path: |
|
path: |
|
||||||
@@ -108,12 +108,12 @@ jobs:
|
|||||||
- queries
|
- queries
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/download-artifact@v2
|
- uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: query-pack-zip
|
name: query-pack-zip
|
||||||
path: query-pack-zip
|
path: query-pack-zip
|
||||||
- uses: actions/download-artifact@v2
|
- uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: extractor-ubuntu-latest
|
name: extractor-ubuntu-latest
|
||||||
path: linux64
|
path: linux64
|
||||||
@@ -131,7 +131,7 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
cd pack
|
cd pack
|
||||||
zip -rq ../codeql-ql.zip .
|
zip -rq ../codeql-ql.zip .
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: codeql-ql-pack
|
name: codeql-ql-pack
|
||||||
path: codeql-ql.zip
|
path: codeql-ql.zip
|
||||||
@@ -140,14 +140,14 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
folder: [cpp, csharp, java, javascript, python, ql, ruby]
|
folder: [cpp, csharp, java, javascript, python, ql, ruby, swift]
|
||||||
|
|
||||||
needs:
|
needs:
|
||||||
- package
|
- package
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Download pack
|
- name: Download pack
|
||||||
uses: actions/download-artifact@v2
|
uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: codeql-ql-pack
|
name: codeql-ql-pack
|
||||||
path: ${{ runner.temp }}/codeql-ql-pack-artifact
|
path: ${{ runner.temp }}/codeql-ql-pack-artifact
|
||||||
@@ -166,7 +166,7 @@ jobs:
|
|||||||
PACK: ${{ runner.temp }}/pack
|
PACK: ${{ runner.temp }}/pack
|
||||||
|
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
- name: Create CodeQL config file
|
- name: Create CodeQL config file
|
||||||
run: |
|
run: |
|
||||||
echo "paths:" > ${CONF}
|
echo "paths:" > ${CONF}
|
||||||
@@ -196,7 +196,7 @@ jobs:
|
|||||||
- name: Copy sarif file to CWD
|
- name: Copy sarif file to CWD
|
||||||
run: cp ../results/ql.sarif ./${{ matrix.folder }}.sarif
|
run: cp ../results/ql.sarif ./${{ matrix.folder }}.sarif
|
||||||
- name: Sarif as artifact
|
- name: Sarif as artifact
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: ${{ matrix.folder }}.sarif
|
name: ${{ matrix.folder }}.sarif
|
||||||
path: ${{ matrix.folder }}.sarif
|
path: ${{ matrix.folder }}.sarif
|
||||||
|
|||||||
14
.github/workflows/ql-for-ql-dataset_measure.yml
vendored
14
.github/workflows/ql-for-ql-dataset_measure.yml
vendored
@@ -22,14 +22,14 @@ jobs:
|
|||||||
- github/codeql-go
|
- github/codeql-go
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Find codeql
|
- name: Find codeql
|
||||||
id: find-codeql
|
id: find-codeql
|
||||||
uses: github/codeql-action/init@aa93aea877e5fb8841bcb1193f672abf6e9f2980
|
uses: github/codeql-action/init@aa93aea877e5fb8841bcb1193f672abf6e9f2980
|
||||||
with:
|
with:
|
||||||
languages: javascript # does not matter
|
languages: javascript # does not matter
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.cargo/registry
|
~/.cargo/registry
|
||||||
@@ -41,7 +41,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||||
- name: Checkout ${{ matrix.repo }}
|
- name: Checkout ${{ matrix.repo }}
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
repository: ${{ matrix.repo }}
|
repository: ${{ matrix.repo }}
|
||||||
path: ${{ github.workspace }}/repo
|
path: ${{ github.workspace }}/repo
|
||||||
@@ -60,7 +60,7 @@ jobs:
|
|||||||
"${CODEQL}" dataset measure --threads 4 --output "stats/${{ matrix.repo }}/stats.xml" "${{ runner.temp }}/database/db-ql"
|
"${CODEQL}" dataset measure --threads 4 --output "stats/${{ matrix.repo }}/stats.xml" "${{ runner.temp }}/database/db-ql"
|
||||||
env:
|
env:
|
||||||
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: measurements
|
name: measurements
|
||||||
path: stats
|
path: stats
|
||||||
@@ -70,15 +70,15 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: measure
|
needs: measure
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/download-artifact@v2
|
- uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: measurements
|
name: measurements
|
||||||
path: stats
|
path: stats
|
||||||
- run: |
|
- run: |
|
||||||
python -m pip install --user lxml
|
python -m pip install --user lxml
|
||||||
find stats -name 'stats.xml' -print0 | sort -z | xargs -0 python ql/scripts/merge_stats.py --output ql/ql/src/ql.dbscheme.stats --normalise ql_tokeninfo
|
find stats -name 'stats.xml' -print0 | sort -z | xargs -0 python ql/scripts/merge_stats.py --output ql/ql/src/ql.dbscheme.stats --normalise ql_tokeninfo
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: ql.dbscheme.stats
|
name: ql.dbscheme.stats
|
||||||
path: ql/ql/src/ql.dbscheme.stats
|
path: ql/ql/src/ql.dbscheme.stats
|
||||||
|
|||||||
4
.github/workflows/ql-for-ql-tests.yml
vendored
4
.github/workflows/ql-for-ql-tests.yml
vendored
@@ -17,13 +17,13 @@ jobs:
|
|||||||
qltest:
|
qltest:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- name: Find codeql
|
- name: Find codeql
|
||||||
id: find-codeql
|
id: find-codeql
|
||||||
uses: github/codeql-action/init@aa93aea877e5fb8841bcb1193f672abf6e9f2980
|
uses: github/codeql-action/init@aa93aea877e5fb8841bcb1193f672abf6e9f2980
|
||||||
with:
|
with:
|
||||||
languages: javascript # does not matter
|
languages: javascript # does not matter
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.cargo/registry
|
~/.cargo/registry
|
||||||
|
|||||||
8
.github/workflows/query-list.yml
vendored
8
.github/workflows/query-list.yml
vendored
@@ -17,16 +17,16 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Clone self (github/codeql)
|
- name: Clone self (github/codeql)
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
path: codeql
|
path: codeql
|
||||||
- name: Clone github/codeql-go
|
- name: Clone github/codeql-go
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
repository: 'github/codeql-go'
|
repository: 'github/codeql-go'
|
||||||
path: codeql-go
|
path: codeql-go
|
||||||
- name: Set up Python 3.8
|
- name: Set up Python 3.8
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v3
|
||||||
with:
|
with:
|
||||||
python-version: 3.8
|
python-version: 3.8
|
||||||
- name: Download CodeQL CLI
|
- name: Download CodeQL CLI
|
||||||
@@ -42,7 +42,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
PATH="$PATH:codeql-cli/codeql" python codeql/misc/scripts/generate-code-scanning-query-list.py > code-scanning-query-list.csv
|
PATH="$PATH:codeql-cli/codeql" python codeql/misc/scripts/generate-code-scanning-query-list.py > code-scanning-query-list.csv
|
||||||
- name: Upload code scanning query list
|
- name: Upload code scanning query list
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: code-scanning-query-list
|
name: code-scanning-query-list
|
||||||
path: code-scanning-query-list.csv
|
path: code-scanning-query-list.csv
|
||||||
|
|||||||
34
.github/workflows/ruby-build.yml
vendored
34
.github/workflows/ruby-build.yml
vendored
@@ -38,13 +38,13 @@ jobs:
|
|||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- name: Install GNU tar
|
- name: Install GNU tar
|
||||||
if: runner.os == 'macOS'
|
if: runner.os == 'macOS'
|
||||||
run: |
|
run: |
|
||||||
brew install gnu-tar
|
brew install gnu-tar
|
||||||
echo "/usr/local/opt/gnu-tar/libexec/gnubin" >> $GITHUB_PATH
|
echo "/usr/local/opt/gnu-tar/libexec/gnubin" >> $GITHUB_PATH
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.cargo/registry
|
~/.cargo/registry
|
||||||
@@ -62,17 +62,17 @@ jobs:
|
|||||||
- name: Generate dbscheme
|
- name: Generate dbscheme
|
||||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||||
run: target/release/ruby-generator --dbscheme ql/lib/ruby.dbscheme --library ql/lib/codeql/ruby/ast/internal/TreeSitter.qll
|
run: target/release/ruby-generator --dbscheme ql/lib/ruby.dbscheme --library ql/lib/codeql/ruby/ast/internal/TreeSitter.qll
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v3
|
||||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||||
with:
|
with:
|
||||||
name: ruby.dbscheme
|
name: ruby.dbscheme
|
||||||
path: ruby/ql/lib/ruby.dbscheme
|
path: ruby/ql/lib/ruby.dbscheme
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v3
|
||||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||||
with:
|
with:
|
||||||
name: TreeSitter.qll
|
name: TreeSitter.qll
|
||||||
path: ruby/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll
|
path: ruby/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: extractor-${{ matrix.os }}
|
name: extractor-${{ matrix.os }}
|
||||||
path: |
|
path: |
|
||||||
@@ -86,7 +86,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
CODEQL_THREADS: 4 # TODO: remove this once it's set by the CLI
|
CODEQL_THREADS: 4 # TODO: remove this once it's set by the CLI
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- name: Fetch CodeQL
|
- name: Fetch CodeQL
|
||||||
run: |
|
run: |
|
||||||
LATEST=$(gh release list --repo https://github.com/github/codeql-cli-binaries | cut -f 1 | grep -v beta | sort --version-sort | tail -1)
|
LATEST=$(gh release list --repo https://github.com/github/codeql-cli-binaries | cut -f 1 | grep -v beta | sort --version-sort | tail -1)
|
||||||
@@ -102,7 +102,7 @@ jobs:
|
|||||||
PACK_FOLDER=$(readlink -f target/packs/codeql/ruby-queries/*)
|
PACK_FOLDER=$(readlink -f target/packs/codeql/ruby-queries/*)
|
||||||
codeql/codeql generate query-help --format=sarifv2.1.0 --output="${PACK_FOLDER}/rules.sarif" ql/src
|
codeql/codeql generate query-help --format=sarifv2.1.0 --output="${PACK_FOLDER}/rules.sarif" ql/src
|
||||||
(cd ql/src; find queries \( -name '*.qhelp' -o -name '*.rb' -o -name '*.erb' \) -exec bash -c 'mkdir -p "'"${PACK_FOLDER}"'/$(dirname "{}")"' \; -exec cp "{}" "${PACK_FOLDER}/{}" \;)
|
(cd ql/src; find queries \( -name '*.qhelp' -o -name '*.rb' -o -name '*.erb' \) -exec bash -c 'mkdir -p "'"${PACK_FOLDER}"'/$(dirname "{}")"' \; -exec cp "{}" "${PACK_FOLDER}/{}" \;)
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: codeql-ruby-queries
|
name: codeql-ruby-queries
|
||||||
path: |
|
path: |
|
||||||
@@ -113,20 +113,20 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [build, compile-queries]
|
needs: [build, compile-queries]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/download-artifact@v2
|
- uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: ruby.dbscheme
|
name: ruby.dbscheme
|
||||||
path: ruby/ruby
|
path: ruby/ruby
|
||||||
- uses: actions/download-artifact@v2
|
- uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: extractor-ubuntu-latest
|
name: extractor-ubuntu-latest
|
||||||
path: ruby/linux64
|
path: ruby/linux64
|
||||||
- uses: actions/download-artifact@v2
|
- uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: extractor-windows-latest
|
name: extractor-windows-latest
|
||||||
path: ruby/win64
|
path: ruby/win64
|
||||||
- uses: actions/download-artifact@v2
|
- uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: extractor-macos-latest
|
name: extractor-macos-latest
|
||||||
path: ruby/osx64
|
path: ruby/osx64
|
||||||
@@ -142,12 +142,12 @@ jobs:
|
|||||||
cp win64/ruby-extractor.exe ruby/tools/win64/extractor.exe
|
cp win64/ruby-extractor.exe ruby/tools/win64/extractor.exe
|
||||||
chmod +x ruby/tools/{linux64,osx64}/{autobuilder,extractor}
|
chmod +x ruby/tools/{linux64,osx64}/{autobuilder,extractor}
|
||||||
zip -rq codeql-ruby.zip ruby
|
zip -rq codeql-ruby.zip ruby
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: codeql-ruby-pack
|
name: codeql-ruby-pack
|
||||||
path: ruby/codeql-ruby.zip
|
path: ruby/codeql-ruby.zip
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
- uses: actions/download-artifact@v2
|
- uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: codeql-ruby-queries
|
name: codeql-ruby-queries
|
||||||
path: ruby/qlpacks
|
path: ruby/qlpacks
|
||||||
@@ -159,7 +159,7 @@ jobs:
|
|||||||
]
|
]
|
||||||
}' > .codeqlmanifest.json
|
}' > .codeqlmanifest.json
|
||||||
zip -rq codeql-ruby-bundle.zip .codeqlmanifest.json ruby qlpacks
|
zip -rq codeql-ruby-bundle.zip .codeqlmanifest.json ruby qlpacks
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: codeql-ruby-bundle
|
name: codeql-ruby-bundle
|
||||||
path: ruby/codeql-ruby-bundle.zip
|
path: ruby/codeql-ruby-bundle.zip
|
||||||
@@ -177,7 +177,7 @@ jobs:
|
|||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
needs: [package]
|
needs: [package]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
repository: Shopify/example-ruby-app
|
repository: Shopify/example-ruby-app
|
||||||
ref: 67a0decc5eb550f3a9228eda53925c3afd40dfe9
|
ref: 67a0decc5eb550f3a9228eda53925c3afd40dfe9
|
||||||
@@ -191,7 +191,7 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ github.token }}
|
GITHUB_TOKEN: ${{ github.token }}
|
||||||
working-directory: ${{ runner.temp }}
|
working-directory: ${{ runner.temp }}
|
||||||
- name: Download Ruby bundle
|
- name: Download Ruby bundle
|
||||||
uses: actions/download-artifact@v2
|
uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: codeql-ruby-bundle
|
name: codeql-ruby-bundle
|
||||||
path: ${{ runner.temp }}
|
path: ${{ runner.temp }}
|
||||||
|
|||||||
12
.github/workflows/ruby-dataset-measure.yml
vendored
12
.github/workflows/ruby-dataset-measure.yml
vendored
@@ -27,14 +27,14 @@ jobs:
|
|||||||
repo: [rails/rails, discourse/discourse, spree/spree, ruby/ruby]
|
repo: [rails/rails, discourse/discourse, spree/spree, ruby/ruby]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- uses: ./.github/actions/fetch-codeql
|
- uses: ./.github/actions/fetch-codeql
|
||||||
|
|
||||||
- uses: ./ruby/actions/create-extractor-pack
|
- uses: ./ruby/actions/create-extractor-pack
|
||||||
|
|
||||||
- name: Checkout ${{ matrix.repo }}
|
- name: Checkout ${{ matrix.repo }}
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
repository: ${{ matrix.repo }}
|
repository: ${{ matrix.repo }}
|
||||||
path: ${{ github.workspace }}/repo
|
path: ${{ github.workspace }}/repo
|
||||||
@@ -49,7 +49,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
mkdir -p "stats/${{ matrix.repo }}"
|
mkdir -p "stats/${{ matrix.repo }}"
|
||||||
codeql dataset measure --threads 4 --output "stats/${{ matrix.repo }}/stats.xml" "${{ runner.temp }}/database/db-ruby"
|
codeql dataset measure --threads 4 --output "stats/${{ matrix.repo }}/stats.xml" "${{ runner.temp }}/database/db-ruby"
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: measurements
|
name: measurements
|
||||||
path: stats
|
path: stats
|
||||||
@@ -59,15 +59,15 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: measure
|
needs: measure
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/download-artifact@v2
|
- uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: measurements
|
name: measurements
|
||||||
path: stats
|
path: stats
|
||||||
- run: |
|
- run: |
|
||||||
python -m pip install --user lxml
|
python -m pip install --user lxml
|
||||||
find stats -name 'stats.xml' | sort | xargs python ruby/scripts/merge_stats.py --output ruby/ql/lib/ruby.dbscheme.stats --normalise ruby_tokeninfo
|
find stats -name 'stats.xml' | sort | xargs python ruby/scripts/merge_stats.py --output ruby/ql/lib/ruby.dbscheme.stats --normalise ruby_tokeninfo
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: ruby.dbscheme.stats
|
name: ruby.dbscheme.stats
|
||||||
path: ruby/ql/lib/ruby.dbscheme.stats
|
path: ruby/ql/lib/ruby.dbscheme.stats
|
||||||
|
|||||||
8
.github/workflows/ruby-qltest.yml
vendored
8
.github/workflows/ruby-qltest.yml
vendored
@@ -27,14 +27,14 @@ jobs:
|
|||||||
qlformat:
|
qlformat:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: ./.github/actions/fetch-codeql
|
- uses: ./.github/actions/fetch-codeql
|
||||||
- name: Check QL formatting
|
- name: Check QL formatting
|
||||||
run: find ql "(" -name "*.ql" -or -name "*.qll" ")" -print0 | xargs -0 codeql query format --check-only
|
run: find ql "(" -name "*.ql" -or -name "*.qll" ")" -print0 | xargs -0 codeql query format --check-only
|
||||||
qlcompile:
|
qlcompile:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: ./.github/actions/fetch-codeql
|
- uses: ./.github/actions/fetch-codeql
|
||||||
- name: Check QL compilation
|
- name: Check QL compilation
|
||||||
run: |
|
run: |
|
||||||
@@ -44,7 +44,7 @@ jobs:
|
|||||||
qlupgrade:
|
qlupgrade:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: ./.github/actions/fetch-codeql
|
- uses: ./.github/actions/fetch-codeql
|
||||||
- name: Check DB upgrade scripts
|
- name: Check DB upgrade scripts
|
||||||
run: |
|
run: |
|
||||||
@@ -67,7 +67,7 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
slice: ["1/2", "2/2"]
|
slice: ["1/2", "2/2"]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: ./.github/actions/fetch-codeql
|
- uses: ./.github/actions/fetch-codeql
|
||||||
- uses: ./ruby/actions/create-extractor-pack
|
- uses: ./ruby/actions/create-extractor-pack
|
||||||
- name: Run QL tests
|
- name: Run QL tests
|
||||||
|
|||||||
25
.github/workflows/swift-codegen.yml
vendored
Normal file
25
.github/workflows/swift-codegen.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
name: "Swift: Check code generation"
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- "swift/**"
|
||||||
|
- .github/workflows/swift-codegen.yml
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
codegen:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: ./.github/actions/fetch-codeql
|
||||||
|
- uses: bazelbuild/setup-bazelisk@v2
|
||||||
|
- name: Run unit tests
|
||||||
|
run: |
|
||||||
|
bazel test //swift/codegen/test --test_output=errors
|
||||||
|
- name: Check that code was generated
|
||||||
|
run: |
|
||||||
|
bazel run //swift/codegen
|
||||||
|
git add swift
|
||||||
|
git diff --exit-code --stat HEAD
|
||||||
39
.github/workflows/swift-qltest.yml
vendored
Normal file
39
.github/workflows/swift-qltest.yml
vendored
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
name: "Swift: Run QL Tests"
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- "swift/**"
|
||||||
|
- .github/workflows/swift-qltest.yml
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: swift
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
qlformat:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: ./.github/actions/fetch-codeql
|
||||||
|
- name: Check QL formatting
|
||||||
|
run: find ql "(" -name "*.ql" -or -name "*.qll" ")" -print0 | xargs -0 codeql query format --check-only
|
||||||
|
qltest:
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
os : [ubuntu-20.04, macos-latest]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: ./.github/actions/fetch-codeql
|
||||||
|
- uses: bazelbuild/setup-bazelisk@v2
|
||||||
|
- name: Build Swift extractor
|
||||||
|
run: |
|
||||||
|
bazel run //swift:create-extractor-pack
|
||||||
|
- name: Run QL tests
|
||||||
|
run: |
|
||||||
|
codeql test run --threads=0 --ram 5000 --search-path "${{ github.workspace }}/swift/extractor-pack" --check-databases --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition ql/test
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ github.token }}
|
||||||
2
.github/workflows/sync-files.yml
vendored
2
.github/workflows/sync-files.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
|||||||
sync:
|
sync:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- name: Check synchronized files
|
- name: Check synchronized files
|
||||||
run: python config/sync-files.py
|
run: python config/sync-files.py
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/validate-change-notes.yml
vendored
2
.github/workflows/validate-change-notes.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Setup CodeQL
|
- name: Setup CodeQL
|
||||||
uses: ./.github/actions/fetch-codeql
|
uses: ./.github/actions/fetch-codeql
|
||||||
|
|||||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -20,6 +20,9 @@
|
|||||||
# python virtual environment folder
|
# python virtual environment folder
|
||||||
.venv/
|
.venv/
|
||||||
|
|
||||||
|
# binary files created by pytest-cov
|
||||||
|
.coverage
|
||||||
|
|
||||||
# It's useful (though not required) to be able to unpack codeql in the ql checkout itself
|
# It's useful (though not required) to be able to unpack codeql in the ql checkout itself
|
||||||
/codeql/
|
/codeql/
|
||||||
|
|
||||||
@@ -31,5 +34,8 @@ csharp/extractor/Semmle.Extraction.CSharp.Driver/Properties/launchSettings.json
|
|||||||
# Compiled class file
|
# Compiled class file
|
||||||
*.class
|
*.class
|
||||||
|
|
||||||
# links create by bazel
|
# links created by bazel
|
||||||
/bazel-*
|
/bazel-*
|
||||||
|
|
||||||
|
# CLion project files
|
||||||
|
/.clwb
|
||||||
|
|||||||
@@ -1,29 +1,51 @@
|
|||||||
# See https://pre-commit.com for more information
|
# See https://pre-commit.com for more information
|
||||||
# See https://pre-commit.com/hooks.html for more hooks
|
# See https://pre-commit.com/hooks.html for more hooks
|
||||||
exclude: /test/.*$(?<!\.ql)(?<!\.qll)(?<!\.qlref)
|
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: v3.2.0
|
rev: v3.2.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
- id: end-of-file-fixer
|
exclude: /test/.*$(?<!\.ql)(?<!\.qll)(?<!\.qlref)
|
||||||
|
- id: end-of-file-fixer
|
||||||
|
exclude: /test/.*$(?<!\.ql)(?<!\.qll)(?<!\.qlref)
|
||||||
|
|
||||||
- repo: local
|
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||||
|
rev: v13.0.1
|
||||||
hooks:
|
hooks:
|
||||||
- id: codeql-format
|
- id: clang-format
|
||||||
|
files: ^swift/.*\.(h|c|cpp)$
|
||||||
|
|
||||||
|
- repo: local
|
||||||
|
hooks:
|
||||||
|
- id: codeql-format
|
||||||
name: Fix QL file formatting
|
name: Fix QL file formatting
|
||||||
files: \.qll?$
|
files: \.qll?$
|
||||||
language: system
|
language: system
|
||||||
entry: codeql query format --in-place
|
entry: codeql query format --in-place
|
||||||
|
|
||||||
- id: sync-files
|
- id: sync-files
|
||||||
name: Fix files required to be identical
|
name: Fix files required to be identical
|
||||||
|
files: \.(qll?|qhelp)$
|
||||||
language: system
|
language: system
|
||||||
entry: python3 config/sync-files.py --latest
|
entry: python3 config/sync-files.py --latest
|
||||||
pass_filenames: false
|
pass_filenames: false
|
||||||
|
|
||||||
- id: qhelp
|
- id: qhelp
|
||||||
name: Check query help generation
|
name: Check query help generation
|
||||||
files: \.qhelp$
|
files: \.qhelp$
|
||||||
language: system
|
language: system
|
||||||
entry: python3 misc/scripts/check-qhelp.py
|
entry: python3 misc/scripts/check-qhelp.py
|
||||||
|
|
||||||
|
- id: swift-codegen
|
||||||
|
name: Run Swift checked in code generation
|
||||||
|
files: ^swift/(codegen/|.*/generated/|ql/lib/(swift\.dbscheme$|codeql/swift/elements))
|
||||||
|
language: system
|
||||||
|
entry: bazel run //swift/codegen
|
||||||
|
pass_filenames: false
|
||||||
|
|
||||||
|
- id: swift-codegen-unit-tests
|
||||||
|
name: Run Swift code generation unit tests
|
||||||
|
files: ^swift/codegen/.*\.py$
|
||||||
|
language: system
|
||||||
|
entry: bazel test //swift/codegen/test
|
||||||
|
pass_filenames: false
|
||||||
|
|||||||
0
BUILD.bazel
Normal file
0
BUILD.bazel
Normal file
10
CODEOWNERS
10
CODEOWNERS
@@ -27,3 +27,13 @@
|
|||||||
# Bazel
|
# Bazel
|
||||||
**/*.bazel @github/codeql-ci-reviewers
|
**/*.bazel @github/codeql-ci-reviewers
|
||||||
**/*.bzl @github/codeql-ci-reviewers
|
**/*.bzl @github/codeql-ci-reviewers
|
||||||
|
|
||||||
|
# Documentation etc
|
||||||
|
/*.md @github/code-scanning-product
|
||||||
|
/LICENSE @github/code-scanning-product
|
||||||
|
|
||||||
|
# Workflows
|
||||||
|
/.github/workflows/ @github/codeql-ci-reviewers
|
||||||
|
/.github/workflows/js-ml-tests.yml @github/codeql-ml-powered-queries-reviewers
|
||||||
|
/.github/workflows/ql-for-ql-* @github/codeql-ql-for-ql-reviewers
|
||||||
|
/.github/workflows/ruby-* @github/codeql-ruby
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
We welcome contributions to our CodeQL libraries and queries. Got an idea for a new check, or how to improve an existing query? Then please go ahead and open a pull request! Contributions to this project are [released](https://help.github.com/articles/github-terms-of-service/#6-contributions-under-repository-license) to the public under the [project's open source license](LICENSE).
|
We welcome contributions to our CodeQL libraries and queries. Got an idea for a new check, or how to improve an existing query? Then please go ahead and open a pull request! Contributions to this project are [released](https://help.github.com/articles/github-terms-of-service/#6-contributions-under-repository-license) to the public under the [project's open source license](LICENSE).
|
||||||
|
|
||||||
There is lots of useful documentation to help you write queries, ranging from information about query file structure to tutorials for specific target languages. For more information on the documentation available, see [CodeQL queries](https://help.semmle.com/QL/learn-ql/writing-queries/writing-queries.html) on [help.semmle.com](https://help.semmle.com).
|
There is lots of useful documentation to help you write queries, ranging from information about query file structure to tutorials for specific target languages. For more information on the documentation available, see [CodeQL queries](https://codeql.github.com/docs/writing-codeql-queries/codeql-queries) on [codeql.github.com](https://codeql.github.com).
|
||||||
|
|
||||||
## Change notes
|
## Change notes
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@ If you have an idea for a query that you would like to share with other CodeQL u
|
|||||||
|
|
||||||
3. **Formatting**
|
3. **Formatting**
|
||||||
|
|
||||||
- The queries and libraries must be autoformatted, for example using the "Format Document" command in [CodeQL for Visual Studio Code](https://help.semmle.com/codeql/codeql-for-vscode/procedures/about-codeql-for-vscode.html).
|
- The queries and libraries must be autoformatted, for example using the "Format Document" command in [CodeQL for Visual Studio Code](https://codeql.github.com/docs/codeql-for-visual-studio-code/about-codeql-for-visual-studio-code).
|
||||||
|
|
||||||
If you prefer, you can either:
|
If you prefer, you can either:
|
||||||
1. install the [pre-commit framework](https://pre-commit.com/) and install the configured hooks on this repo via `pre-commit install`, or
|
1. install the [pre-commit framework](https://pre-commit.com/) and install the configured hooks on this repo via `pre-commit install`, or
|
||||||
|
|||||||
@@ -13,7 +13,9 @@ We welcome contributions to our standard library and standard checks. Do you hav
|
|||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
The code in this repository is licensed under the [MIT License](LICENSE) by [GitHub](https://github.com). The use of CodeQL on open source code is licensed under specific [Terms & Conditions](https://securitylab.github.com/tools/codeql/license/) UNLESS you have a commercial license in place. If you'd like to use CodeQL with a commercial codebase, please [contact us](https://github.com/enterprise/contact) for further help.
|
The code in this repository is licensed under the [MIT License](LICENSE) by [GitHub](https://github.com).
|
||||||
|
|
||||||
|
The CodeQL CLI (including the CodeQL engine) is hosted in a [different repository](https://github.com/github/codeql-cli-binaries) and is [licensed separately](https://github.com/github/codeql-cli-binaries/blob/main/LICENSE.md). If you'd like to use the CodeQL CLI to analyze closed-source code, you will need a separate commercial license; please [contact us](https://github.com/enterprise/contact) for further help.
|
||||||
|
|
||||||
## Visual Studio Code integration
|
## Visual Studio Code integration
|
||||||
|
|
||||||
|
|||||||
@@ -1,2 +1,12 @@
|
|||||||
# Please notice that any bazel targets and definitions in this repository are currently experimental
|
# Please notice that any bazel targets and definitions in this repository are currently experimental
|
||||||
# and for internal use only.
|
# and for internal use only.
|
||||||
|
|
||||||
|
workspace(name = "codeql")
|
||||||
|
|
||||||
|
load("//misc/bazel:workspace.bzl", "codeql_workspace")
|
||||||
|
|
||||||
|
codeql_workspace()
|
||||||
|
|
||||||
|
load("//misc/bazel:workspace_deps.bzl", "codeql_workspace_deps")
|
||||||
|
|
||||||
|
codeql_workspace_deps()
|
||||||
|
|||||||
@@ -51,6 +51,7 @@
|
|||||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll",
|
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll",
|
||||||
"java/ql/lib/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
|
"java/ql/lib/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
|
||||||
"java/ql/lib/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll",
|
"java/ql/lib/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll",
|
||||||
|
"java/ql/lib/semmle/code/java/dataflow/internal/tainttracking3/TaintTrackingImpl.qll",
|
||||||
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking1/TaintTrackingImpl.qll",
|
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking1/TaintTrackingImpl.qll",
|
||||||
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking2/TaintTrackingImpl.qll",
|
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking2/TaintTrackingImpl.qll",
|
||||||
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking3/TaintTrackingImpl.qll",
|
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking3/TaintTrackingImpl.qll",
|
||||||
@@ -383,7 +384,8 @@
|
|||||||
"csharp/ql/test/TestUtilities/InlineExpectationsTest.qll",
|
"csharp/ql/test/TestUtilities/InlineExpectationsTest.qll",
|
||||||
"java/ql/test/TestUtilities/InlineExpectationsTest.qll",
|
"java/ql/test/TestUtilities/InlineExpectationsTest.qll",
|
||||||
"python/ql/test/TestUtilities/InlineExpectationsTest.qll",
|
"python/ql/test/TestUtilities/InlineExpectationsTest.qll",
|
||||||
"ruby/ql/test/TestUtilities/InlineExpectationsTest.qll"
|
"ruby/ql/test/TestUtilities/InlineExpectationsTest.qll",
|
||||||
|
"ql/ql/test/TestUtilities/InlineExpectationsTest.qll"
|
||||||
],
|
],
|
||||||
"C++ ExternalAPIs": [
|
"C++ ExternalAPIs": [
|
||||||
"cpp/ql/src/Security/CWE/CWE-020/ExternalAPIs.qll",
|
"cpp/ql/src/Security/CWE/CWE-020/ExternalAPIs.qll",
|
||||||
@@ -549,4 +551,4 @@
|
|||||||
"javascript/ql/lib/semmle/javascript/security/dataflow/HttpToFileAccessCustomizations.qll",
|
"javascript/ql/lib/semmle/javascript/security/dataflow/HttpToFileAccessCustomizations.qll",
|
||||||
"ruby/ql/lib/codeql/ruby/security/HttpToFileAccessCustomizations.qll"
|
"ruby/ql/lib/codeql/ruby/security/HttpToFileAccessCustomizations.qll"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
1
conftest.py
Normal file
1
conftest.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# this empty file adds the repo root to PYTHON_PATH when running pytest
|
||||||
@@ -1,3 +1,40 @@
|
|||||||
|
## 0.1.0
|
||||||
|
|
||||||
|
### Breaking Changes
|
||||||
|
|
||||||
|
* The recently added flow-state versions of `isBarrierIn`, `isBarrierOut`, `isSanitizerIn`, and `isSanitizerOut` in the data flow and taint tracking libraries have been removed.
|
||||||
|
|
||||||
|
### New Features
|
||||||
|
|
||||||
|
* A new library `semmle.code.cpp.security.PrivateData` has been added. The new library heuristically detects variables and functions dealing with sensitive private data, such as e-mail addresses and credit card numbers.
|
||||||
|
|
||||||
|
### Minor Analysis Improvements
|
||||||
|
|
||||||
|
* The `semmle.code.cpp.security.SensitiveExprs` library has been enhanced with some additional rules for detecting credentials.
|
||||||
|
|
||||||
|
## 0.0.13
|
||||||
|
|
||||||
|
## 0.0.12
|
||||||
|
|
||||||
|
### Breaking Changes
|
||||||
|
|
||||||
|
* The flow state variants of `isBarrier` and `isAdditionalFlowStep` are no longer exposed in the taint tracking library. The `isSanitizer` and `isAdditionalTaintStep` predicates should be used instead.
|
||||||
|
|
||||||
|
### Deprecated APIs
|
||||||
|
|
||||||
|
* Many classes/predicates/modules that had upper-case acronyms have been renamed to follow our style-guide.
|
||||||
|
The old name still exists as a deprecated alias.
|
||||||
|
|
||||||
|
### New Features
|
||||||
|
|
||||||
|
* The data flow and taint tracking libraries have been extended with versions of `isBarrierIn`, `isBarrierOut`, and `isBarrierGuard`, respectively `isSanitizerIn`, `isSanitizerOut`, and `isSanitizerGuard`, that support flow states.
|
||||||
|
|
||||||
|
### Minor Analysis Improvements
|
||||||
|
|
||||||
|
* `DefaultOptions::exits` now holds for C11 functions with the `_Noreturn` or `noreturn` specifier.
|
||||||
|
* `hasImplicitCopyConstructor` and `hasImplicitCopyAssignmentOperator` now correctly handle implicitly-deleted operators in templates.
|
||||||
|
* All deprecated predicates/classes/modules that have been deprecated for over a year have been deleted.
|
||||||
|
|
||||||
## 0.0.11
|
## 0.0.11
|
||||||
|
|
||||||
### Minor Analysis Improvements
|
### Minor Analysis Improvements
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
---
|
|
||||||
category: minorAnalysis
|
|
||||||
---
|
|
||||||
* All deprecated predicates/classes/modules that have been deprecated for over a year have been deleted.
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
---
|
|
||||||
category: deprecated
|
|
||||||
---
|
|
||||||
* Many classes/predicates/modules that had upper-case acronyms have been renamed to follow our style-guide.
|
|
||||||
The old name still exists as a deprecated alias.
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
---
|
|
||||||
category: minorAnalysis
|
|
||||||
---
|
|
||||||
* `hasImplicitCopyConstructor` and `hasImplicitCopyAssignmentOperator` now correctly handle implicitly-deleted operators in templates.
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
---
|
|
||||||
category: minorAnalysis
|
|
||||||
---
|
|
||||||
* `DefaultOptions::exits` now holds for C11 functions with the `_Noreturn` or `noreturn` specifier.
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
---
|
|
||||||
category: feature
|
|
||||||
---
|
|
||||||
* The data flow and taint tracking libraries have been extended with versions of `isBarrierIn`, `isBarrierOut`, and `isBarrierGuard`, respectively `isSanitizerIn`, `isSanitizerOut`, and `isSanitizerGuard`, that support flow states.
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
---
|
|
||||||
category: breaking
|
|
||||||
---
|
|
||||||
* The flow state variants of `isBarrier` and `isAdditionalFlowStep` are no longer exposed in the taint tracking library. The `isSanitizer` and `isAdditionalTaintStep` predicates should be used instead.
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
---
|
|
||||||
category: feature
|
|
||||||
---
|
|
||||||
* A new library `semmle.code.cpp.security.PrivateData` has been added. The new library heuristically detects variables and functions dealing with sensitive private data, such as e-mail addresses and credit card numbers.
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
---
|
|
||||||
category: minorAnalysis
|
|
||||||
---
|
|
||||||
* The `semmle.code.cpp.security.SensitiveExprs` library has been enhanced with some additional rules for detecting credentials.
|
|
||||||
4
cpp/ql/lib/change-notes/2022-04-22-no-size-array.md
Normal file
4
cpp/ql/lib/change-notes/2022-04-22-no-size-array.md
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
category: minorAnalysis
|
||||||
|
---
|
||||||
|
* The `semmle.code.cpp.commons.Buffer` library has been enhanced to handle array members of classes that do not specify a size.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
category: breaking
|
||||||
|
---
|
||||||
|
The signature of `allowImplicitRead` on `DataFlow::Configuration` and `TaintTracking::Configuration` has changed from `allowImplicitRead(DataFlow::Node node, DataFlow::Content c)` to `allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c)`.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
category: minorAnalysis
|
||||||
|
---
|
||||||
|
* More Windows pool allocation functions are now detected as `AllocationFunction`s.
|
||||||
20
cpp/ql/lib/change-notes/released/0.0.12.md
Normal file
20
cpp/ql/lib/change-notes/released/0.0.12.md
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
## 0.0.12
|
||||||
|
|
||||||
|
### Breaking Changes
|
||||||
|
|
||||||
|
* The flow state variants of `isBarrier` and `isAdditionalFlowStep` are no longer exposed in the taint tracking library. The `isSanitizer` and `isAdditionalTaintStep` predicates should be used instead.
|
||||||
|
|
||||||
|
### Deprecated APIs
|
||||||
|
|
||||||
|
* Many classes/predicates/modules that had upper-case acronyms have been renamed to follow our style-guide.
|
||||||
|
The old name still exists as a deprecated alias.
|
||||||
|
|
||||||
|
### New Features
|
||||||
|
|
||||||
|
* The data flow and taint tracking libraries have been extended with versions of `isBarrierIn`, `isBarrierOut`, and `isBarrierGuard`, respectively `isSanitizerIn`, `isSanitizerOut`, and `isSanitizerGuard`, that support flow states.
|
||||||
|
|
||||||
|
### Minor Analysis Improvements
|
||||||
|
|
||||||
|
* `DefaultOptions::exits` now holds for C11 functions with the `_Noreturn` or `noreturn` specifier.
|
||||||
|
* `hasImplicitCopyConstructor` and `hasImplicitCopyAssignmentOperator` now correctly handle implicitly-deleted operators in templates.
|
||||||
|
* All deprecated predicates/classes/modules that have been deprecated for over a year have been deleted.
|
||||||
1
cpp/ql/lib/change-notes/released/0.0.13.md
Normal file
1
cpp/ql/lib/change-notes/released/0.0.13.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
## 0.0.13
|
||||||
13
cpp/ql/lib/change-notes/released/0.1.0.md
Normal file
13
cpp/ql/lib/change-notes/released/0.1.0.md
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
## 0.1.0
|
||||||
|
|
||||||
|
### Breaking Changes
|
||||||
|
|
||||||
|
* The recently added flow-state versions of `isBarrierIn`, `isBarrierOut`, `isSanitizerIn`, and `isSanitizerOut` in the data flow and taint tracking libraries have been removed.
|
||||||
|
|
||||||
|
### New Features
|
||||||
|
|
||||||
|
* A new library `semmle.code.cpp.security.PrivateData` has been added. The new library heuristically detects variables and functions dealing with sensitive private data, such as e-mail addresses and credit card numbers.
|
||||||
|
|
||||||
|
### Minor Analysis Improvements
|
||||||
|
|
||||||
|
* The `semmle.code.cpp.security.SensitiveExprs` library has been enhanced with some additional rules for detecting credentials.
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
---
|
---
|
||||||
lastReleaseVersion: 0.0.11
|
lastReleaseVersion: 0.1.0
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: codeql/cpp-all
|
name: codeql/cpp-all
|
||||||
version: 0.0.12-dev
|
version: 0.1.1-dev
|
||||||
groups: cpp
|
groups: cpp
|
||||||
dbscheme: semmlecode.cpp.dbscheme
|
dbscheme: semmlecode.cpp.dbscheme
|
||||||
extractor: cpp
|
extractor: cpp
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ private int fileHeaderLimit(File f) {
|
|||||||
fc = fileFirstComment(f) and
|
fc = fileFirstComment(f) and
|
||||||
result =
|
result =
|
||||||
min(int line |
|
min(int line |
|
||||||
|
// code ending the initial comments
|
||||||
exists(DeclarationEntry de, Location l |
|
exists(DeclarationEntry de, Location l |
|
||||||
l = de.getLocation() and
|
l = de.getLocation() and
|
||||||
l.getFile() = f and
|
l.getFile() = f and
|
||||||
@@ -105,7 +106,13 @@ private int fileHeaderLimit(File f) {
|
|||||||
line > fc
|
line > fc
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
|
// end of the file
|
||||||
line = f.getMetrics().getNumberOfLines()
|
line = f.getMetrics().getNumberOfLines()
|
||||||
|
or
|
||||||
|
// rarely, we've seen extremely long sequences of initial comments
|
||||||
|
// (and/or limitations in the above constraints) cause an overflow of
|
||||||
|
// the maximum string length. So don't look past 1000 lines regardless.
|
||||||
|
line = 1000
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,10 +109,7 @@ class Element extends ElementBase {
|
|||||||
then
|
then
|
||||||
exists(MacroInvocation mi |
|
exists(MacroInvocation mi |
|
||||||
this = mi.getAGeneratedElement() and
|
this = mi.getAGeneratedElement() and
|
||||||
not exists(MacroInvocation closer |
|
not hasCloserMacroInvocation(this, mi) and
|
||||||
this = closer.getAGeneratedElement() and
|
|
||||||
mi = closer.getParentInvocation+()
|
|
||||||
) and
|
|
||||||
result = mi.getMacro()
|
result = mi.getMacro()
|
||||||
)
|
)
|
||||||
else result = this
|
else result = this
|
||||||
@@ -236,6 +233,14 @@ class Element extends ElementBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[noinline]
|
||||||
|
private predicate hasCloserMacroInvocation(Element elem, MacroInvocation mi) {
|
||||||
|
exists(MacroInvocation closer |
|
||||||
|
elem = closer.getAGeneratedElement() and
|
||||||
|
mi = closer.getParentInvocation()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private predicate isFromTemplateInstantiationRec(Element e, Element instantiation) {
|
private predicate isFromTemplateInstantiationRec(Element e, Element instantiation) {
|
||||||
instantiation.(Function).isConstructedFrom(_) and
|
instantiation.(Function).isConstructedFrom(_) and
|
||||||
e = instantiation
|
e = instantiation
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
import semmle.code.cpp.Variable
|
import semmle.code.cpp.Variable
|
||||||
import semmle.code.cpp.Enum
|
import semmle.code.cpp.Enum
|
||||||
import semmle.code.cpp.exprs.Access
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A C structure member or C++ non-static member variable. For example the
|
* A C structure member or C++ non-static member variable. For example the
|
||||||
|
|||||||
@@ -10,11 +10,18 @@ import semmle.code.cpp.dataflow.DataFlow
|
|||||||
* char data[1]; // v
|
* char data[1]; // v
|
||||||
* };
|
* };
|
||||||
* ```
|
* ```
|
||||||
* This requires that `v` is an array of size 0 or 1.
|
* or
|
||||||
|
* ```
|
||||||
|
* struct myStruct { // c
|
||||||
|
* int amount;
|
||||||
|
* char data[]; // v
|
||||||
|
* };
|
||||||
|
* ```
|
||||||
|
* This requires that `v` is an array of size 0 or 1, or that the array has no size.
|
||||||
*/
|
*/
|
||||||
predicate memberMayBeVarSize(Class c, MemberVariable v) {
|
predicate memberMayBeVarSize(Class c, MemberVariable v) {
|
||||||
c = v.getDeclaringType() and
|
c = v.getDeclaringType() and
|
||||||
v.getUnspecifiedType().(ArrayType).getArraySize() <= 1
|
exists(ArrayType t | t = v.getUnspecifiedType() | not t.getArraySize() > 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -27,11 +34,11 @@ int getBufferSize(Expr bufferExpr, Element why) {
|
|||||||
result = bufferVar.getUnspecifiedType().(ArrayType).getSize() and
|
result = bufferVar.getUnspecifiedType().(ArrayType).getSize() and
|
||||||
why = bufferVar and
|
why = bufferVar and
|
||||||
not memberMayBeVarSize(_, bufferVar) and
|
not memberMayBeVarSize(_, bufferVar) and
|
||||||
not result = 0 // zero sized arrays are likely to have special usage, for example
|
// zero sized arrays are likely to have special usage, for example
|
||||||
or
|
|
||||||
// behaving a bit like a 'union' overlapping other fields.
|
// behaving a bit like a 'union' overlapping other fields.
|
||||||
// buffer is an initialized array
|
not result = 0
|
||||||
// e.g. int buffer[] = {1, 2, 3};
|
or
|
||||||
|
// buffer is an initialized array, e.g., int buffer[] = {1, 2, 3};
|
||||||
why = bufferVar.getInitializer().getExpr() and
|
why = bufferVar.getInitializer().getExpr() and
|
||||||
(
|
(
|
||||||
why instanceof AggregateLiteral or
|
why instanceof AggregateLiteral or
|
||||||
@@ -40,13 +47,18 @@ int getBufferSize(Expr bufferExpr, Element why) {
|
|||||||
result = why.(Expr).getType().(ArrayType).getSize() and
|
result = why.(Expr).getType().(ArrayType).getSize() and
|
||||||
not exists(bufferVar.getUnspecifiedType().(ArrayType).getSize())
|
not exists(bufferVar.getUnspecifiedType().(ArrayType).getSize())
|
||||||
or
|
or
|
||||||
exists(Class parentClass, VariableAccess parentPtr |
|
exists(Class parentClass, VariableAccess parentPtr, int bufferSize |
|
||||||
// buffer is the parentPtr->bufferVar of a 'variable size struct'
|
// buffer is the parentPtr->bufferVar of a 'variable size struct'
|
||||||
memberMayBeVarSize(parentClass, bufferVar) and
|
memberMayBeVarSize(parentClass, bufferVar) and
|
||||||
why = bufferVar and
|
why = bufferVar and
|
||||||
parentPtr = bufferExpr.(VariableAccess).getQualifier() and
|
parentPtr = bufferExpr.(VariableAccess).getQualifier() and
|
||||||
parentPtr.getTarget().getUnspecifiedType().(PointerType).getBaseType() = parentClass and
|
parentPtr.getTarget().getUnspecifiedType().(PointerType).getBaseType() = parentClass and
|
||||||
result = getBufferSize(parentPtr, _) + bufferVar.getType().getSize() - parentClass.getSize()
|
(
|
||||||
|
if exists(bufferVar.getType().getSize())
|
||||||
|
then bufferSize = bufferVar.getType().getSize()
|
||||||
|
else bufferSize = 0
|
||||||
|
) and
|
||||||
|
result = getBufferSize(parentPtr, _) + bufferSize - parentClass.getSize()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
|
|||||||
@@ -80,7 +80,11 @@ abstract class StackVariableReachability extends string {
|
|||||||
j > i and
|
j > i and
|
||||||
sink = bb.getNode(j) and
|
sink = bb.getNode(j) and
|
||||||
this.isSink(sink, v) and
|
this.isSink(sink, v) and
|
||||||
not exists(int k | this.isBarrier(bb.getNode(k), v) | k in [i + 1 .. j - 1])
|
not exists(int k, ControlFlowNode node |
|
||||||
|
node = bb.getNode(k) and this.isBarrier(pragma[only_bind_into](node), v)
|
||||||
|
|
|
||||||
|
k in [i + 1 .. j - 1]
|
||||||
|
)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
not exists(int k | this.isBarrier(bb.getNode(k), v) | k > i) and
|
not exists(int k | this.isBarrier(bb.getNode(k), v) | k > i) and
|
||||||
|
|||||||
@@ -87,21 +87,9 @@ abstract class Configuration extends string {
|
|||||||
/** Holds if data flow into `node` is prohibited. */
|
/** Holds if data flow into `node` is prohibited. */
|
||||||
predicate isBarrierIn(Node node) { none() }
|
predicate isBarrierIn(Node node) { none() }
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data flow into `node` is prohibited when the flow state is
|
|
||||||
* `state`
|
|
||||||
*/
|
|
||||||
predicate isBarrierIn(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
/** Holds if data flow out of `node` is prohibited. */
|
/** Holds if data flow out of `node` is prohibited. */
|
||||||
predicate isBarrierOut(Node node) { none() }
|
predicate isBarrierOut(Node node) { none() }
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data flow out of `node` is prohibited when the flow state is
|
|
||||||
* `state`
|
|
||||||
*/
|
|
||||||
predicate isBarrierOut(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||||
|
|
||||||
@@ -128,7 +116,7 @@ abstract class Configuration extends string {
|
|||||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||||
* taken at `node`.
|
* taken at `node`.
|
||||||
*/
|
*/
|
||||||
predicate allowImplicitRead(Node node, Content c) { none() }
|
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||||
@@ -321,7 +309,7 @@ private class RetNodeEx extends NodeEx {
|
|||||||
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate fullInBarrier(NodeEx node, Configuration config) {
|
private predicate inBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
node.asNode() = n and
|
node.asNode() = n and
|
||||||
config.isBarrierIn(n)
|
config.isBarrierIn(n)
|
||||||
@@ -330,16 +318,7 @@ private predicate fullInBarrier(NodeEx node, Configuration config) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
|
private predicate outBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n |
|
|
||||||
node.asNode() = n and
|
|
||||||
config.isBarrierIn(n, state)
|
|
||||||
|
|
|
||||||
config.isSource(n, state)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate fullOutBarrier(NodeEx node, Configuration config) {
|
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
node.asNode() = n and
|
node.asNode() = n and
|
||||||
config.isBarrierOut(n)
|
config.isBarrierOut(n)
|
||||||
@@ -348,15 +327,6 @@ private predicate fullOutBarrier(NodeEx node, Configuration config) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
|
|
||||||
exists(Node n |
|
|
||||||
node.asNode() = n and
|
|
||||||
config.isBarrierOut(n, state)
|
|
||||||
|
|
|
||||||
config.isSink(n, state)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fullBarrier(NodeEx node, Configuration config) {
|
private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n | node.asNode() = n |
|
exists(Node n | node.asNode() = n |
|
||||||
@@ -382,12 +352,6 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
|
|||||||
exists(Node n | node.asNode() = n |
|
exists(Node n | node.asNode() = n |
|
||||||
config.isBarrier(n, state)
|
config.isBarrier(n, state)
|
||||||
or
|
or
|
||||||
config.isBarrierIn(n, state) and
|
|
||||||
not config.isSource(n, state)
|
|
||||||
or
|
|
||||||
config.isBarrierOut(n, state) and
|
|
||||||
not config.isSink(n, state)
|
|
||||||
or
|
|
||||||
exists(BarrierGuard g |
|
exists(BarrierGuard g |
|
||||||
config.isBarrierGuard(g, state) and
|
config.isBarrierGuard(g, state) and
|
||||||
n = g.getAGuardedNode()
|
n = g.getAGuardedNode()
|
||||||
@@ -420,8 +384,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
|
|||||||
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
||||||
not fullOutBarrier(node1, config) and
|
not outBarrier(node1, config) and
|
||||||
not fullInBarrier(node2, config) and
|
not inBarrier(node2, config) and
|
||||||
not fullBarrier(node1, config) and
|
not fullBarrier(node1, config) and
|
||||||
not fullBarrier(node2, config)
|
not fullBarrier(node2, config)
|
||||||
}
|
}
|
||||||
@@ -474,8 +438,6 @@ private predicate additionalLocalStateStep(
|
|||||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
||||||
stepFilter(node1, node2, config) and
|
stepFilter(node1, node2, config) and
|
||||||
not stateOutBarrier(node1, s1, config) and
|
|
||||||
not stateInBarrier(node2, s2, config) and
|
|
||||||
not stateBarrier(node1, s1, config) and
|
not stateBarrier(node1, s1, config) and
|
||||||
not stateBarrier(node2, s2, config)
|
not stateBarrier(node2, s2, config)
|
||||||
)
|
)
|
||||||
@@ -517,16 +479,15 @@ private predicate additionalJumpStateStep(
|
|||||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
||||||
stepFilter(node1, node2, config) and
|
stepFilter(node1, node2, config) and
|
||||||
not stateOutBarrier(node1, s1, config) and
|
|
||||||
not stateInBarrier(node2, s2, config) and
|
|
||||||
not stateBarrier(node1, s1, config) and
|
not stateBarrier(node1, s1, config) and
|
||||||
not stateBarrier(node2, s2, config) and
|
not stateBarrier(node2, s2, config) and
|
||||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
pragma[nomagic]
|
||||||
read(node1.asNode(), c, node2.asNode()) and
|
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||||
|
readSet(node1.asNode(), c, node2.asNode()) and
|
||||||
stepFilter(node1, node2, config)
|
stepFilter(node1, node2, config)
|
||||||
or
|
or
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
@@ -536,6 +497,25 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
pragma[inline]
|
||||||
|
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
readSet(node1, cs, node2, config) and
|
||||||
|
c = cs.getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
pragma[inline]
|
||||||
|
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
clearsContentCached(n.asNode(), cs) and
|
||||||
|
c = cs.getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
) {
|
) {
|
||||||
@@ -613,9 +593,9 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(Content c |
|
exists(ContentSet c |
|
||||||
fwdFlowRead(c, node, cc, config) and
|
fwdFlowReadSet(c, node, cc, config) and
|
||||||
fwdFlowConsCand(c, config)
|
fwdFlowConsCandSet(c, _, config)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
@@ -639,10 +619,10 @@ private module Stage1 {
|
|||||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
|
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
fwdFlow(mid, cc, config) and
|
fwdFlow(mid, cc, config) and
|
||||||
read(mid, c, node, config)
|
readSet(mid, c, node, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -660,6 +640,16 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `cs` may be interpreted in a read as the target of some store
|
||||||
|
* into `c`, in the flow covered by `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowConsCandSet(ContentSet cs, Content c, Configuration config) {
|
||||||
|
fwdFlowConsCand(c, config) and
|
||||||
|
c = cs.getAReadContent()
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
||||||
exists(RetNodeEx ret |
|
exists(RetNodeEx ret |
|
||||||
@@ -752,9 +742,9 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(NodeEx mid, Content c |
|
exists(NodeEx mid, ContentSet c |
|
||||||
read(node, c, mid, config) and
|
readSet(node, c, mid, config) and
|
||||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
fwdFlowConsCandSet(c, _, pragma[only_bind_into](config)) and
|
||||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
@@ -780,10 +770,10 @@ private module Stage1 {
|
|||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||||
exists(NodeEx mid, NodeEx node |
|
exists(NodeEx mid, NodeEx node, ContentSet cs |
|
||||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||||
read(node, c, mid, config) and
|
readSet(node, cs, mid, config) and
|
||||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
fwdFlowConsCandSet(cs, c, pragma[only_bind_into](config)) and
|
||||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -802,6 +792,7 @@ private module Stage1 {
|
|||||||
* Holds if `c` is the target of both a read and a store in the flow covered
|
* Holds if `c` is the target of both a read and a store in the flow covered
|
||||||
* by `revFlow`.
|
* by `revFlow`.
|
||||||
*/
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||||
revFlowConsCand(c, conf) and
|
revFlowConsCand(c, conf) and
|
||||||
revFlowStore(c, _, _, conf)
|
revFlowStore(c, _, _, conf)
|
||||||
@@ -900,9 +891,9 @@ private module Stage1 {
|
|||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
|
||||||
revFlow(n2, pragma[only_bind_into](config)) and
|
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||||
read(n1, c, n2, pragma[only_bind_into](config))
|
revFlow(n2, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -912,14 +903,17 @@ private module Stage1 {
|
|||||||
predicate revFlow(
|
predicate revFlow(
|
||||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
revFlow(node, toReturn, config) and exists(state) and exists(returnAp) and exists(ap)
|
revFlow(node, toReturn, pragma[only_bind_into](config)) and
|
||||||
|
exists(state) and
|
||||||
|
exists(returnAp) and
|
||||||
|
exists(ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||||
revFlow(node, true, config) and
|
revFlow(node, true, config) and
|
||||||
fwdFlow(node, true, config) and
|
fwdFlow(node, true, config) and
|
||||||
not fullInBarrier(node, config) and
|
not inBarrier(node, config) and
|
||||||
not fullOutBarrier(node, config)
|
not outBarrier(node, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if flow may return from `callable`. */
|
/** Holds if flow may return from `callable`. */
|
||||||
@@ -1014,8 +1008,8 @@ private predicate flowOutOfCallNodeCand1(
|
|||||||
) {
|
) {
|
||||||
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
||||||
Stage1::revFlow(ret, config) and
|
Stage1::revFlow(ret, config) and
|
||||||
not fullOutBarrier(ret, config) and
|
not outBarrier(ret, config) and
|
||||||
not fullInBarrier(out, config)
|
not inBarrier(out, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -1036,8 +1030,8 @@ private predicate flowIntoCallNodeCand1(
|
|||||||
) {
|
) {
|
||||||
viableParamArgNodeCand1(call, p, arg, config) and
|
viableParamArgNodeCand1(call, p, arg, config) and
|
||||||
Stage1::revFlow(p, config) and
|
Stage1::revFlow(p, config) and
|
||||||
not fullOutBarrier(arg, config) and
|
not outBarrier(arg, config) and
|
||||||
not fullInBarrier(p, config)
|
not inBarrier(p, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1189,7 +1183,7 @@ private module Stage2 {
|
|||||||
|
|
||||||
bindingset[node, state, ap, config]
|
bindingset[node, state, ap, config]
|
||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
PrevStage::revFlowState(state, config) and
|
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||||
exists(ap) and
|
exists(ap) and
|
||||||
not stateBarrier(node, state, config)
|
not stateBarrier(node, state, config)
|
||||||
}
|
}
|
||||||
@@ -1614,7 +1608,7 @@ private module Stage2 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -1769,9 +1763,9 @@ private module LocalFlowBigStep {
|
|||||||
or
|
or
|
||||||
node.asNode() instanceof OutNodeExt
|
node.asNode() instanceof OutNodeExt
|
||||||
or
|
or
|
||||||
store(_, _, node, _, config)
|
Stage2::storeStepCand(_, _, _, node, _, config)
|
||||||
or
|
or
|
||||||
read(_, _, node, config)
|
Stage2::readStepCand(_, _, node, config)
|
||||||
or
|
or
|
||||||
node instanceof FlowCheckNode
|
node instanceof FlowCheckNode
|
||||||
or
|
or
|
||||||
@@ -1792,8 +1786,8 @@ private module LocalFlowBigStep {
|
|||||||
additionalJumpStep(node, next, config) or
|
additionalJumpStep(node, next, config) or
|
||||||
flowIntoCallNodeCand1(_, node, next, config) or
|
flowIntoCallNodeCand1(_, node, next, config) or
|
||||||
flowOutOfCallNodeCand1(_, node, next, config) or
|
flowOutOfCallNodeCand1(_, node, next, config) or
|
||||||
store(node, _, next, _, config) or
|
Stage2::storeStepCand(node, _, _, next, _, config) or
|
||||||
read(node, _, next, config)
|
Stage2::readStepCand(node, _, next, config)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||||
@@ -1966,7 +1960,24 @@ private module Stage3 {
|
|||||||
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
|
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||||
|
PrevStage::revFlow(node, config) and
|
||||||
|
clearsContentCached(node.asNode(), c)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate clearContent(NodeEx node, Content c, Configuration config) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
|
||||||
|
c = cs.getAReadContent() and
|
||||||
|
clearSet(node, cs, pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate clear(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
clearContent(node, ap.getHead().getContent(), config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
@@ -1975,7 +1986,7 @@ private module Stage3 {
|
|||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
exists(state) and
|
exists(state) and
|
||||||
exists(config) and
|
exists(config) and
|
||||||
not clear(node, ap) and
|
not clear(node, ap, config) and
|
||||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2403,7 +2414,7 @@ private module Stage3 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -3230,7 +3241,7 @@ private module Stage4 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -4242,7 +4253,7 @@ private module Subpaths {
|
|||||||
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
||||||
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
||||||
store(n1, _, n2, _, _) or
|
store(n1, _, n2, _, _) or
|
||||||
read(n1, _, n2, _)
|
readSet(n1, _, n2, _)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4597,7 +4608,7 @@ private module FlowExploration {
|
|||||||
or
|
or
|
||||||
exists(PartialPathNodeRev mid |
|
exists(PartialPathNodeRev mid |
|
||||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||||
not clearsContentCached(node.asNode(), ap.getHead()) and
|
not clearsContentEx(node, ap.getHead()) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||||
@@ -4613,7 +4624,7 @@ private module FlowExploration {
|
|||||||
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
|
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||||
if node.asNode() instanceof CastingNode
|
if node.asNode() instanceof CastingNode
|
||||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||||
else any()
|
else any()
|
||||||
@@ -5047,6 +5058,7 @@ private module FlowExploration {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
private predicate revPartialPathStep(
|
private predicate revPartialPathStep(
|
||||||
PartialPathNodeRev mid, NodeEx node, FlowState state, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
|
PartialPathNodeRev mid, NodeEx node, FlowState state, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
|
||||||
TRevSummaryCtx3 sc3, RevPartialAccessPath ap, Configuration config
|
TRevSummaryCtx3 sc3, RevPartialAccessPath ap, Configuration config
|
||||||
|
|||||||
@@ -87,21 +87,9 @@ abstract class Configuration extends string {
|
|||||||
/** Holds if data flow into `node` is prohibited. */
|
/** Holds if data flow into `node` is prohibited. */
|
||||||
predicate isBarrierIn(Node node) { none() }
|
predicate isBarrierIn(Node node) { none() }
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data flow into `node` is prohibited when the flow state is
|
|
||||||
* `state`
|
|
||||||
*/
|
|
||||||
predicate isBarrierIn(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
/** Holds if data flow out of `node` is prohibited. */
|
/** Holds if data flow out of `node` is prohibited. */
|
||||||
predicate isBarrierOut(Node node) { none() }
|
predicate isBarrierOut(Node node) { none() }
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data flow out of `node` is prohibited when the flow state is
|
|
||||||
* `state`
|
|
||||||
*/
|
|
||||||
predicate isBarrierOut(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||||
|
|
||||||
@@ -128,7 +116,7 @@ abstract class Configuration extends string {
|
|||||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||||
* taken at `node`.
|
* taken at `node`.
|
||||||
*/
|
*/
|
||||||
predicate allowImplicitRead(Node node, Content c) { none() }
|
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||||
@@ -321,7 +309,7 @@ private class RetNodeEx extends NodeEx {
|
|||||||
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate fullInBarrier(NodeEx node, Configuration config) {
|
private predicate inBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
node.asNode() = n and
|
node.asNode() = n and
|
||||||
config.isBarrierIn(n)
|
config.isBarrierIn(n)
|
||||||
@@ -330,16 +318,7 @@ private predicate fullInBarrier(NodeEx node, Configuration config) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
|
private predicate outBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n |
|
|
||||||
node.asNode() = n and
|
|
||||||
config.isBarrierIn(n, state)
|
|
||||||
|
|
|
||||||
config.isSource(n, state)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate fullOutBarrier(NodeEx node, Configuration config) {
|
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
node.asNode() = n and
|
node.asNode() = n and
|
||||||
config.isBarrierOut(n)
|
config.isBarrierOut(n)
|
||||||
@@ -348,15 +327,6 @@ private predicate fullOutBarrier(NodeEx node, Configuration config) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
|
|
||||||
exists(Node n |
|
|
||||||
node.asNode() = n and
|
|
||||||
config.isBarrierOut(n, state)
|
|
||||||
|
|
|
||||||
config.isSink(n, state)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fullBarrier(NodeEx node, Configuration config) {
|
private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n | node.asNode() = n |
|
exists(Node n | node.asNode() = n |
|
||||||
@@ -382,12 +352,6 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
|
|||||||
exists(Node n | node.asNode() = n |
|
exists(Node n | node.asNode() = n |
|
||||||
config.isBarrier(n, state)
|
config.isBarrier(n, state)
|
||||||
or
|
or
|
||||||
config.isBarrierIn(n, state) and
|
|
||||||
not config.isSource(n, state)
|
|
||||||
or
|
|
||||||
config.isBarrierOut(n, state) and
|
|
||||||
not config.isSink(n, state)
|
|
||||||
or
|
|
||||||
exists(BarrierGuard g |
|
exists(BarrierGuard g |
|
||||||
config.isBarrierGuard(g, state) and
|
config.isBarrierGuard(g, state) and
|
||||||
n = g.getAGuardedNode()
|
n = g.getAGuardedNode()
|
||||||
@@ -420,8 +384,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
|
|||||||
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
||||||
not fullOutBarrier(node1, config) and
|
not outBarrier(node1, config) and
|
||||||
not fullInBarrier(node2, config) and
|
not inBarrier(node2, config) and
|
||||||
not fullBarrier(node1, config) and
|
not fullBarrier(node1, config) and
|
||||||
not fullBarrier(node2, config)
|
not fullBarrier(node2, config)
|
||||||
}
|
}
|
||||||
@@ -474,8 +438,6 @@ private predicate additionalLocalStateStep(
|
|||||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
||||||
stepFilter(node1, node2, config) and
|
stepFilter(node1, node2, config) and
|
||||||
not stateOutBarrier(node1, s1, config) and
|
|
||||||
not stateInBarrier(node2, s2, config) and
|
|
||||||
not stateBarrier(node1, s1, config) and
|
not stateBarrier(node1, s1, config) and
|
||||||
not stateBarrier(node2, s2, config)
|
not stateBarrier(node2, s2, config)
|
||||||
)
|
)
|
||||||
@@ -517,16 +479,15 @@ private predicate additionalJumpStateStep(
|
|||||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
||||||
stepFilter(node1, node2, config) and
|
stepFilter(node1, node2, config) and
|
||||||
not stateOutBarrier(node1, s1, config) and
|
|
||||||
not stateInBarrier(node2, s2, config) and
|
|
||||||
not stateBarrier(node1, s1, config) and
|
not stateBarrier(node1, s1, config) and
|
||||||
not stateBarrier(node2, s2, config) and
|
not stateBarrier(node2, s2, config) and
|
||||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
pragma[nomagic]
|
||||||
read(node1.asNode(), c, node2.asNode()) and
|
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||||
|
readSet(node1.asNode(), c, node2.asNode()) and
|
||||||
stepFilter(node1, node2, config)
|
stepFilter(node1, node2, config)
|
||||||
or
|
or
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
@@ -536,6 +497,25 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
pragma[inline]
|
||||||
|
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
readSet(node1, cs, node2, config) and
|
||||||
|
c = cs.getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
pragma[inline]
|
||||||
|
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
clearsContentCached(n.asNode(), cs) and
|
||||||
|
c = cs.getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
) {
|
) {
|
||||||
@@ -613,9 +593,9 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(Content c |
|
exists(ContentSet c |
|
||||||
fwdFlowRead(c, node, cc, config) and
|
fwdFlowReadSet(c, node, cc, config) and
|
||||||
fwdFlowConsCand(c, config)
|
fwdFlowConsCandSet(c, _, config)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
@@ -639,10 +619,10 @@ private module Stage1 {
|
|||||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
|
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
fwdFlow(mid, cc, config) and
|
fwdFlow(mid, cc, config) and
|
||||||
read(mid, c, node, config)
|
readSet(mid, c, node, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -660,6 +640,16 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `cs` may be interpreted in a read as the target of some store
|
||||||
|
* into `c`, in the flow covered by `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowConsCandSet(ContentSet cs, Content c, Configuration config) {
|
||||||
|
fwdFlowConsCand(c, config) and
|
||||||
|
c = cs.getAReadContent()
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
||||||
exists(RetNodeEx ret |
|
exists(RetNodeEx ret |
|
||||||
@@ -752,9 +742,9 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(NodeEx mid, Content c |
|
exists(NodeEx mid, ContentSet c |
|
||||||
read(node, c, mid, config) and
|
readSet(node, c, mid, config) and
|
||||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
fwdFlowConsCandSet(c, _, pragma[only_bind_into](config)) and
|
||||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
@@ -780,10 +770,10 @@ private module Stage1 {
|
|||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||||
exists(NodeEx mid, NodeEx node |
|
exists(NodeEx mid, NodeEx node, ContentSet cs |
|
||||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||||
read(node, c, mid, config) and
|
readSet(node, cs, mid, config) and
|
||||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
fwdFlowConsCandSet(cs, c, pragma[only_bind_into](config)) and
|
||||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -802,6 +792,7 @@ private module Stage1 {
|
|||||||
* Holds if `c` is the target of both a read and a store in the flow covered
|
* Holds if `c` is the target of both a read and a store in the flow covered
|
||||||
* by `revFlow`.
|
* by `revFlow`.
|
||||||
*/
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||||
revFlowConsCand(c, conf) and
|
revFlowConsCand(c, conf) and
|
||||||
revFlowStore(c, _, _, conf)
|
revFlowStore(c, _, _, conf)
|
||||||
@@ -900,9 +891,9 @@ private module Stage1 {
|
|||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
|
||||||
revFlow(n2, pragma[only_bind_into](config)) and
|
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||||
read(n1, c, n2, pragma[only_bind_into](config))
|
revFlow(n2, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -912,14 +903,17 @@ private module Stage1 {
|
|||||||
predicate revFlow(
|
predicate revFlow(
|
||||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
revFlow(node, toReturn, config) and exists(state) and exists(returnAp) and exists(ap)
|
revFlow(node, toReturn, pragma[only_bind_into](config)) and
|
||||||
|
exists(state) and
|
||||||
|
exists(returnAp) and
|
||||||
|
exists(ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||||
revFlow(node, true, config) and
|
revFlow(node, true, config) and
|
||||||
fwdFlow(node, true, config) and
|
fwdFlow(node, true, config) and
|
||||||
not fullInBarrier(node, config) and
|
not inBarrier(node, config) and
|
||||||
not fullOutBarrier(node, config)
|
not outBarrier(node, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if flow may return from `callable`. */
|
/** Holds if flow may return from `callable`. */
|
||||||
@@ -1014,8 +1008,8 @@ private predicate flowOutOfCallNodeCand1(
|
|||||||
) {
|
) {
|
||||||
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
||||||
Stage1::revFlow(ret, config) and
|
Stage1::revFlow(ret, config) and
|
||||||
not fullOutBarrier(ret, config) and
|
not outBarrier(ret, config) and
|
||||||
not fullInBarrier(out, config)
|
not inBarrier(out, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -1036,8 +1030,8 @@ private predicate flowIntoCallNodeCand1(
|
|||||||
) {
|
) {
|
||||||
viableParamArgNodeCand1(call, p, arg, config) and
|
viableParamArgNodeCand1(call, p, arg, config) and
|
||||||
Stage1::revFlow(p, config) and
|
Stage1::revFlow(p, config) and
|
||||||
not fullOutBarrier(arg, config) and
|
not outBarrier(arg, config) and
|
||||||
not fullInBarrier(p, config)
|
not inBarrier(p, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1189,7 +1183,7 @@ private module Stage2 {
|
|||||||
|
|
||||||
bindingset[node, state, ap, config]
|
bindingset[node, state, ap, config]
|
||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
PrevStage::revFlowState(state, config) and
|
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||||
exists(ap) and
|
exists(ap) and
|
||||||
not stateBarrier(node, state, config)
|
not stateBarrier(node, state, config)
|
||||||
}
|
}
|
||||||
@@ -1614,7 +1608,7 @@ private module Stage2 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -1769,9 +1763,9 @@ private module LocalFlowBigStep {
|
|||||||
or
|
or
|
||||||
node.asNode() instanceof OutNodeExt
|
node.asNode() instanceof OutNodeExt
|
||||||
or
|
or
|
||||||
store(_, _, node, _, config)
|
Stage2::storeStepCand(_, _, _, node, _, config)
|
||||||
or
|
or
|
||||||
read(_, _, node, config)
|
Stage2::readStepCand(_, _, node, config)
|
||||||
or
|
or
|
||||||
node instanceof FlowCheckNode
|
node instanceof FlowCheckNode
|
||||||
or
|
or
|
||||||
@@ -1792,8 +1786,8 @@ private module LocalFlowBigStep {
|
|||||||
additionalJumpStep(node, next, config) or
|
additionalJumpStep(node, next, config) or
|
||||||
flowIntoCallNodeCand1(_, node, next, config) or
|
flowIntoCallNodeCand1(_, node, next, config) or
|
||||||
flowOutOfCallNodeCand1(_, node, next, config) or
|
flowOutOfCallNodeCand1(_, node, next, config) or
|
||||||
store(node, _, next, _, config) or
|
Stage2::storeStepCand(node, _, _, next, _, config) or
|
||||||
read(node, _, next, config)
|
Stage2::readStepCand(node, _, next, config)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||||
@@ -1966,7 +1960,24 @@ private module Stage3 {
|
|||||||
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
|
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||||
|
PrevStage::revFlow(node, config) and
|
||||||
|
clearsContentCached(node.asNode(), c)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate clearContent(NodeEx node, Content c, Configuration config) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
|
||||||
|
c = cs.getAReadContent() and
|
||||||
|
clearSet(node, cs, pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate clear(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
clearContent(node, ap.getHead().getContent(), config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
@@ -1975,7 +1986,7 @@ private module Stage3 {
|
|||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
exists(state) and
|
exists(state) and
|
||||||
exists(config) and
|
exists(config) and
|
||||||
not clear(node, ap) and
|
not clear(node, ap, config) and
|
||||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2403,7 +2414,7 @@ private module Stage3 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -3230,7 +3241,7 @@ private module Stage4 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -4242,7 +4253,7 @@ private module Subpaths {
|
|||||||
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
||||||
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
||||||
store(n1, _, n2, _, _) or
|
store(n1, _, n2, _, _) or
|
||||||
read(n1, _, n2, _)
|
readSet(n1, _, n2, _)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4597,7 +4608,7 @@ private module FlowExploration {
|
|||||||
or
|
or
|
||||||
exists(PartialPathNodeRev mid |
|
exists(PartialPathNodeRev mid |
|
||||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||||
not clearsContentCached(node.asNode(), ap.getHead()) and
|
not clearsContentEx(node, ap.getHead()) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||||
@@ -4613,7 +4624,7 @@ private module FlowExploration {
|
|||||||
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
|
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||||
if node.asNode() instanceof CastingNode
|
if node.asNode() instanceof CastingNode
|
||||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||||
else any()
|
else any()
|
||||||
@@ -5047,6 +5058,7 @@ private module FlowExploration {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
private predicate revPartialPathStep(
|
private predicate revPartialPathStep(
|
||||||
PartialPathNodeRev mid, NodeEx node, FlowState state, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
|
PartialPathNodeRev mid, NodeEx node, FlowState state, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
|
||||||
TRevSummaryCtx3 sc3, RevPartialAccessPath ap, Configuration config
|
TRevSummaryCtx3 sc3, RevPartialAccessPath ap, Configuration config
|
||||||
|
|||||||
@@ -87,21 +87,9 @@ abstract class Configuration extends string {
|
|||||||
/** Holds if data flow into `node` is prohibited. */
|
/** Holds if data flow into `node` is prohibited. */
|
||||||
predicate isBarrierIn(Node node) { none() }
|
predicate isBarrierIn(Node node) { none() }
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data flow into `node` is prohibited when the flow state is
|
|
||||||
* `state`
|
|
||||||
*/
|
|
||||||
predicate isBarrierIn(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
/** Holds if data flow out of `node` is prohibited. */
|
/** Holds if data flow out of `node` is prohibited. */
|
||||||
predicate isBarrierOut(Node node) { none() }
|
predicate isBarrierOut(Node node) { none() }
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data flow out of `node` is prohibited when the flow state is
|
|
||||||
* `state`
|
|
||||||
*/
|
|
||||||
predicate isBarrierOut(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||||
|
|
||||||
@@ -128,7 +116,7 @@ abstract class Configuration extends string {
|
|||||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||||
* taken at `node`.
|
* taken at `node`.
|
||||||
*/
|
*/
|
||||||
predicate allowImplicitRead(Node node, Content c) { none() }
|
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||||
@@ -321,7 +309,7 @@ private class RetNodeEx extends NodeEx {
|
|||||||
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate fullInBarrier(NodeEx node, Configuration config) {
|
private predicate inBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
node.asNode() = n and
|
node.asNode() = n and
|
||||||
config.isBarrierIn(n)
|
config.isBarrierIn(n)
|
||||||
@@ -330,16 +318,7 @@ private predicate fullInBarrier(NodeEx node, Configuration config) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
|
private predicate outBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n |
|
|
||||||
node.asNode() = n and
|
|
||||||
config.isBarrierIn(n, state)
|
|
||||||
|
|
|
||||||
config.isSource(n, state)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate fullOutBarrier(NodeEx node, Configuration config) {
|
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
node.asNode() = n and
|
node.asNode() = n and
|
||||||
config.isBarrierOut(n)
|
config.isBarrierOut(n)
|
||||||
@@ -348,15 +327,6 @@ private predicate fullOutBarrier(NodeEx node, Configuration config) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
|
|
||||||
exists(Node n |
|
|
||||||
node.asNode() = n and
|
|
||||||
config.isBarrierOut(n, state)
|
|
||||||
|
|
|
||||||
config.isSink(n, state)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fullBarrier(NodeEx node, Configuration config) {
|
private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n | node.asNode() = n |
|
exists(Node n | node.asNode() = n |
|
||||||
@@ -382,12 +352,6 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
|
|||||||
exists(Node n | node.asNode() = n |
|
exists(Node n | node.asNode() = n |
|
||||||
config.isBarrier(n, state)
|
config.isBarrier(n, state)
|
||||||
or
|
or
|
||||||
config.isBarrierIn(n, state) and
|
|
||||||
not config.isSource(n, state)
|
|
||||||
or
|
|
||||||
config.isBarrierOut(n, state) and
|
|
||||||
not config.isSink(n, state)
|
|
||||||
or
|
|
||||||
exists(BarrierGuard g |
|
exists(BarrierGuard g |
|
||||||
config.isBarrierGuard(g, state) and
|
config.isBarrierGuard(g, state) and
|
||||||
n = g.getAGuardedNode()
|
n = g.getAGuardedNode()
|
||||||
@@ -420,8 +384,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
|
|||||||
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
||||||
not fullOutBarrier(node1, config) and
|
not outBarrier(node1, config) and
|
||||||
not fullInBarrier(node2, config) and
|
not inBarrier(node2, config) and
|
||||||
not fullBarrier(node1, config) and
|
not fullBarrier(node1, config) and
|
||||||
not fullBarrier(node2, config)
|
not fullBarrier(node2, config)
|
||||||
}
|
}
|
||||||
@@ -474,8 +438,6 @@ private predicate additionalLocalStateStep(
|
|||||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
||||||
stepFilter(node1, node2, config) and
|
stepFilter(node1, node2, config) and
|
||||||
not stateOutBarrier(node1, s1, config) and
|
|
||||||
not stateInBarrier(node2, s2, config) and
|
|
||||||
not stateBarrier(node1, s1, config) and
|
not stateBarrier(node1, s1, config) and
|
||||||
not stateBarrier(node2, s2, config)
|
not stateBarrier(node2, s2, config)
|
||||||
)
|
)
|
||||||
@@ -517,16 +479,15 @@ private predicate additionalJumpStateStep(
|
|||||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
||||||
stepFilter(node1, node2, config) and
|
stepFilter(node1, node2, config) and
|
||||||
not stateOutBarrier(node1, s1, config) and
|
|
||||||
not stateInBarrier(node2, s2, config) and
|
|
||||||
not stateBarrier(node1, s1, config) and
|
not stateBarrier(node1, s1, config) and
|
||||||
not stateBarrier(node2, s2, config) and
|
not stateBarrier(node2, s2, config) and
|
||||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
pragma[nomagic]
|
||||||
read(node1.asNode(), c, node2.asNode()) and
|
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||||
|
readSet(node1.asNode(), c, node2.asNode()) and
|
||||||
stepFilter(node1, node2, config)
|
stepFilter(node1, node2, config)
|
||||||
or
|
or
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
@@ -536,6 +497,25 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
pragma[inline]
|
||||||
|
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
readSet(node1, cs, node2, config) and
|
||||||
|
c = cs.getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
pragma[inline]
|
||||||
|
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
clearsContentCached(n.asNode(), cs) and
|
||||||
|
c = cs.getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
) {
|
) {
|
||||||
@@ -613,9 +593,9 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(Content c |
|
exists(ContentSet c |
|
||||||
fwdFlowRead(c, node, cc, config) and
|
fwdFlowReadSet(c, node, cc, config) and
|
||||||
fwdFlowConsCand(c, config)
|
fwdFlowConsCandSet(c, _, config)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
@@ -639,10 +619,10 @@ private module Stage1 {
|
|||||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
|
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
fwdFlow(mid, cc, config) and
|
fwdFlow(mid, cc, config) and
|
||||||
read(mid, c, node, config)
|
readSet(mid, c, node, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -660,6 +640,16 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `cs` may be interpreted in a read as the target of some store
|
||||||
|
* into `c`, in the flow covered by `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowConsCandSet(ContentSet cs, Content c, Configuration config) {
|
||||||
|
fwdFlowConsCand(c, config) and
|
||||||
|
c = cs.getAReadContent()
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
||||||
exists(RetNodeEx ret |
|
exists(RetNodeEx ret |
|
||||||
@@ -752,9 +742,9 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(NodeEx mid, Content c |
|
exists(NodeEx mid, ContentSet c |
|
||||||
read(node, c, mid, config) and
|
readSet(node, c, mid, config) and
|
||||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
fwdFlowConsCandSet(c, _, pragma[only_bind_into](config)) and
|
||||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
@@ -780,10 +770,10 @@ private module Stage1 {
|
|||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||||
exists(NodeEx mid, NodeEx node |
|
exists(NodeEx mid, NodeEx node, ContentSet cs |
|
||||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||||
read(node, c, mid, config) and
|
readSet(node, cs, mid, config) and
|
||||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
fwdFlowConsCandSet(cs, c, pragma[only_bind_into](config)) and
|
||||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -802,6 +792,7 @@ private module Stage1 {
|
|||||||
* Holds if `c` is the target of both a read and a store in the flow covered
|
* Holds if `c` is the target of both a read and a store in the flow covered
|
||||||
* by `revFlow`.
|
* by `revFlow`.
|
||||||
*/
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||||
revFlowConsCand(c, conf) and
|
revFlowConsCand(c, conf) and
|
||||||
revFlowStore(c, _, _, conf)
|
revFlowStore(c, _, _, conf)
|
||||||
@@ -900,9 +891,9 @@ private module Stage1 {
|
|||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
|
||||||
revFlow(n2, pragma[only_bind_into](config)) and
|
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||||
read(n1, c, n2, pragma[only_bind_into](config))
|
revFlow(n2, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -912,14 +903,17 @@ private module Stage1 {
|
|||||||
predicate revFlow(
|
predicate revFlow(
|
||||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
revFlow(node, toReturn, config) and exists(state) and exists(returnAp) and exists(ap)
|
revFlow(node, toReturn, pragma[only_bind_into](config)) and
|
||||||
|
exists(state) and
|
||||||
|
exists(returnAp) and
|
||||||
|
exists(ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||||
revFlow(node, true, config) and
|
revFlow(node, true, config) and
|
||||||
fwdFlow(node, true, config) and
|
fwdFlow(node, true, config) and
|
||||||
not fullInBarrier(node, config) and
|
not inBarrier(node, config) and
|
||||||
not fullOutBarrier(node, config)
|
not outBarrier(node, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if flow may return from `callable`. */
|
/** Holds if flow may return from `callable`. */
|
||||||
@@ -1014,8 +1008,8 @@ private predicate flowOutOfCallNodeCand1(
|
|||||||
) {
|
) {
|
||||||
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
||||||
Stage1::revFlow(ret, config) and
|
Stage1::revFlow(ret, config) and
|
||||||
not fullOutBarrier(ret, config) and
|
not outBarrier(ret, config) and
|
||||||
not fullInBarrier(out, config)
|
not inBarrier(out, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -1036,8 +1030,8 @@ private predicate flowIntoCallNodeCand1(
|
|||||||
) {
|
) {
|
||||||
viableParamArgNodeCand1(call, p, arg, config) and
|
viableParamArgNodeCand1(call, p, arg, config) and
|
||||||
Stage1::revFlow(p, config) and
|
Stage1::revFlow(p, config) and
|
||||||
not fullOutBarrier(arg, config) and
|
not outBarrier(arg, config) and
|
||||||
not fullInBarrier(p, config)
|
not inBarrier(p, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1189,7 +1183,7 @@ private module Stage2 {
|
|||||||
|
|
||||||
bindingset[node, state, ap, config]
|
bindingset[node, state, ap, config]
|
||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
PrevStage::revFlowState(state, config) and
|
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||||
exists(ap) and
|
exists(ap) and
|
||||||
not stateBarrier(node, state, config)
|
not stateBarrier(node, state, config)
|
||||||
}
|
}
|
||||||
@@ -1614,7 +1608,7 @@ private module Stage2 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -1769,9 +1763,9 @@ private module LocalFlowBigStep {
|
|||||||
or
|
or
|
||||||
node.asNode() instanceof OutNodeExt
|
node.asNode() instanceof OutNodeExt
|
||||||
or
|
or
|
||||||
store(_, _, node, _, config)
|
Stage2::storeStepCand(_, _, _, node, _, config)
|
||||||
or
|
or
|
||||||
read(_, _, node, config)
|
Stage2::readStepCand(_, _, node, config)
|
||||||
or
|
or
|
||||||
node instanceof FlowCheckNode
|
node instanceof FlowCheckNode
|
||||||
or
|
or
|
||||||
@@ -1792,8 +1786,8 @@ private module LocalFlowBigStep {
|
|||||||
additionalJumpStep(node, next, config) or
|
additionalJumpStep(node, next, config) or
|
||||||
flowIntoCallNodeCand1(_, node, next, config) or
|
flowIntoCallNodeCand1(_, node, next, config) or
|
||||||
flowOutOfCallNodeCand1(_, node, next, config) or
|
flowOutOfCallNodeCand1(_, node, next, config) or
|
||||||
store(node, _, next, _, config) or
|
Stage2::storeStepCand(node, _, _, next, _, config) or
|
||||||
read(node, _, next, config)
|
Stage2::readStepCand(node, _, next, config)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||||
@@ -1966,7 +1960,24 @@ private module Stage3 {
|
|||||||
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
|
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||||
|
PrevStage::revFlow(node, config) and
|
||||||
|
clearsContentCached(node.asNode(), c)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate clearContent(NodeEx node, Content c, Configuration config) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
|
||||||
|
c = cs.getAReadContent() and
|
||||||
|
clearSet(node, cs, pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate clear(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
clearContent(node, ap.getHead().getContent(), config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
@@ -1975,7 +1986,7 @@ private module Stage3 {
|
|||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
exists(state) and
|
exists(state) and
|
||||||
exists(config) and
|
exists(config) and
|
||||||
not clear(node, ap) and
|
not clear(node, ap, config) and
|
||||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2403,7 +2414,7 @@ private module Stage3 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -3230,7 +3241,7 @@ private module Stage4 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -4242,7 +4253,7 @@ private module Subpaths {
|
|||||||
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
||||||
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
||||||
store(n1, _, n2, _, _) or
|
store(n1, _, n2, _, _) or
|
||||||
read(n1, _, n2, _)
|
readSet(n1, _, n2, _)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4597,7 +4608,7 @@ private module FlowExploration {
|
|||||||
or
|
or
|
||||||
exists(PartialPathNodeRev mid |
|
exists(PartialPathNodeRev mid |
|
||||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||||
not clearsContentCached(node.asNode(), ap.getHead()) and
|
not clearsContentEx(node, ap.getHead()) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||||
@@ -4613,7 +4624,7 @@ private module FlowExploration {
|
|||||||
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
|
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||||
if node.asNode() instanceof CastingNode
|
if node.asNode() instanceof CastingNode
|
||||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||||
else any()
|
else any()
|
||||||
@@ -5047,6 +5058,7 @@ private module FlowExploration {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
private predicate revPartialPathStep(
|
private predicate revPartialPathStep(
|
||||||
PartialPathNodeRev mid, NodeEx node, FlowState state, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
|
PartialPathNodeRev mid, NodeEx node, FlowState state, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
|
||||||
TRevSummaryCtx3 sc3, RevPartialAccessPath ap, Configuration config
|
TRevSummaryCtx3 sc3, RevPartialAccessPath ap, Configuration config
|
||||||
|
|||||||
@@ -87,21 +87,9 @@ abstract class Configuration extends string {
|
|||||||
/** Holds if data flow into `node` is prohibited. */
|
/** Holds if data flow into `node` is prohibited. */
|
||||||
predicate isBarrierIn(Node node) { none() }
|
predicate isBarrierIn(Node node) { none() }
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data flow into `node` is prohibited when the flow state is
|
|
||||||
* `state`
|
|
||||||
*/
|
|
||||||
predicate isBarrierIn(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
/** Holds if data flow out of `node` is prohibited. */
|
/** Holds if data flow out of `node` is prohibited. */
|
||||||
predicate isBarrierOut(Node node) { none() }
|
predicate isBarrierOut(Node node) { none() }
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data flow out of `node` is prohibited when the flow state is
|
|
||||||
* `state`
|
|
||||||
*/
|
|
||||||
predicate isBarrierOut(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||||
|
|
||||||
@@ -128,7 +116,7 @@ abstract class Configuration extends string {
|
|||||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||||
* taken at `node`.
|
* taken at `node`.
|
||||||
*/
|
*/
|
||||||
predicate allowImplicitRead(Node node, Content c) { none() }
|
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||||
@@ -321,7 +309,7 @@ private class RetNodeEx extends NodeEx {
|
|||||||
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate fullInBarrier(NodeEx node, Configuration config) {
|
private predicate inBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
node.asNode() = n and
|
node.asNode() = n and
|
||||||
config.isBarrierIn(n)
|
config.isBarrierIn(n)
|
||||||
@@ -330,16 +318,7 @@ private predicate fullInBarrier(NodeEx node, Configuration config) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
|
private predicate outBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n |
|
|
||||||
node.asNode() = n and
|
|
||||||
config.isBarrierIn(n, state)
|
|
||||||
|
|
|
||||||
config.isSource(n, state)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate fullOutBarrier(NodeEx node, Configuration config) {
|
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
node.asNode() = n and
|
node.asNode() = n and
|
||||||
config.isBarrierOut(n)
|
config.isBarrierOut(n)
|
||||||
@@ -348,15 +327,6 @@ private predicate fullOutBarrier(NodeEx node, Configuration config) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
|
|
||||||
exists(Node n |
|
|
||||||
node.asNode() = n and
|
|
||||||
config.isBarrierOut(n, state)
|
|
||||||
|
|
|
||||||
config.isSink(n, state)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fullBarrier(NodeEx node, Configuration config) {
|
private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n | node.asNode() = n |
|
exists(Node n | node.asNode() = n |
|
||||||
@@ -382,12 +352,6 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
|
|||||||
exists(Node n | node.asNode() = n |
|
exists(Node n | node.asNode() = n |
|
||||||
config.isBarrier(n, state)
|
config.isBarrier(n, state)
|
||||||
or
|
or
|
||||||
config.isBarrierIn(n, state) and
|
|
||||||
not config.isSource(n, state)
|
|
||||||
or
|
|
||||||
config.isBarrierOut(n, state) and
|
|
||||||
not config.isSink(n, state)
|
|
||||||
or
|
|
||||||
exists(BarrierGuard g |
|
exists(BarrierGuard g |
|
||||||
config.isBarrierGuard(g, state) and
|
config.isBarrierGuard(g, state) and
|
||||||
n = g.getAGuardedNode()
|
n = g.getAGuardedNode()
|
||||||
@@ -420,8 +384,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
|
|||||||
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
||||||
not fullOutBarrier(node1, config) and
|
not outBarrier(node1, config) and
|
||||||
not fullInBarrier(node2, config) and
|
not inBarrier(node2, config) and
|
||||||
not fullBarrier(node1, config) and
|
not fullBarrier(node1, config) and
|
||||||
not fullBarrier(node2, config)
|
not fullBarrier(node2, config)
|
||||||
}
|
}
|
||||||
@@ -474,8 +438,6 @@ private predicate additionalLocalStateStep(
|
|||||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
||||||
stepFilter(node1, node2, config) and
|
stepFilter(node1, node2, config) and
|
||||||
not stateOutBarrier(node1, s1, config) and
|
|
||||||
not stateInBarrier(node2, s2, config) and
|
|
||||||
not stateBarrier(node1, s1, config) and
|
not stateBarrier(node1, s1, config) and
|
||||||
not stateBarrier(node2, s2, config)
|
not stateBarrier(node2, s2, config)
|
||||||
)
|
)
|
||||||
@@ -517,16 +479,15 @@ private predicate additionalJumpStateStep(
|
|||||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
||||||
stepFilter(node1, node2, config) and
|
stepFilter(node1, node2, config) and
|
||||||
not stateOutBarrier(node1, s1, config) and
|
|
||||||
not stateInBarrier(node2, s2, config) and
|
|
||||||
not stateBarrier(node1, s1, config) and
|
not stateBarrier(node1, s1, config) and
|
||||||
not stateBarrier(node2, s2, config) and
|
not stateBarrier(node2, s2, config) and
|
||||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
pragma[nomagic]
|
||||||
read(node1.asNode(), c, node2.asNode()) and
|
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||||
|
readSet(node1.asNode(), c, node2.asNode()) and
|
||||||
stepFilter(node1, node2, config)
|
stepFilter(node1, node2, config)
|
||||||
or
|
or
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
@@ -536,6 +497,25 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
pragma[inline]
|
||||||
|
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
readSet(node1, cs, node2, config) and
|
||||||
|
c = cs.getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
pragma[inline]
|
||||||
|
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
clearsContentCached(n.asNode(), cs) and
|
||||||
|
c = cs.getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
) {
|
) {
|
||||||
@@ -613,9 +593,9 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(Content c |
|
exists(ContentSet c |
|
||||||
fwdFlowRead(c, node, cc, config) and
|
fwdFlowReadSet(c, node, cc, config) and
|
||||||
fwdFlowConsCand(c, config)
|
fwdFlowConsCandSet(c, _, config)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
@@ -639,10 +619,10 @@ private module Stage1 {
|
|||||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
|
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
fwdFlow(mid, cc, config) and
|
fwdFlow(mid, cc, config) and
|
||||||
read(mid, c, node, config)
|
readSet(mid, c, node, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -660,6 +640,16 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `cs` may be interpreted in a read as the target of some store
|
||||||
|
* into `c`, in the flow covered by `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowConsCandSet(ContentSet cs, Content c, Configuration config) {
|
||||||
|
fwdFlowConsCand(c, config) and
|
||||||
|
c = cs.getAReadContent()
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
||||||
exists(RetNodeEx ret |
|
exists(RetNodeEx ret |
|
||||||
@@ -752,9 +742,9 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(NodeEx mid, Content c |
|
exists(NodeEx mid, ContentSet c |
|
||||||
read(node, c, mid, config) and
|
readSet(node, c, mid, config) and
|
||||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
fwdFlowConsCandSet(c, _, pragma[only_bind_into](config)) and
|
||||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
@@ -780,10 +770,10 @@ private module Stage1 {
|
|||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||||
exists(NodeEx mid, NodeEx node |
|
exists(NodeEx mid, NodeEx node, ContentSet cs |
|
||||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||||
read(node, c, mid, config) and
|
readSet(node, cs, mid, config) and
|
||||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
fwdFlowConsCandSet(cs, c, pragma[only_bind_into](config)) and
|
||||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -802,6 +792,7 @@ private module Stage1 {
|
|||||||
* Holds if `c` is the target of both a read and a store in the flow covered
|
* Holds if `c` is the target of both a read and a store in the flow covered
|
||||||
* by `revFlow`.
|
* by `revFlow`.
|
||||||
*/
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||||
revFlowConsCand(c, conf) and
|
revFlowConsCand(c, conf) and
|
||||||
revFlowStore(c, _, _, conf)
|
revFlowStore(c, _, _, conf)
|
||||||
@@ -900,9 +891,9 @@ private module Stage1 {
|
|||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
|
||||||
revFlow(n2, pragma[only_bind_into](config)) and
|
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||||
read(n1, c, n2, pragma[only_bind_into](config))
|
revFlow(n2, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -912,14 +903,17 @@ private module Stage1 {
|
|||||||
predicate revFlow(
|
predicate revFlow(
|
||||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
revFlow(node, toReturn, config) and exists(state) and exists(returnAp) and exists(ap)
|
revFlow(node, toReturn, pragma[only_bind_into](config)) and
|
||||||
|
exists(state) and
|
||||||
|
exists(returnAp) and
|
||||||
|
exists(ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||||
revFlow(node, true, config) and
|
revFlow(node, true, config) and
|
||||||
fwdFlow(node, true, config) and
|
fwdFlow(node, true, config) and
|
||||||
not fullInBarrier(node, config) and
|
not inBarrier(node, config) and
|
||||||
not fullOutBarrier(node, config)
|
not outBarrier(node, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if flow may return from `callable`. */
|
/** Holds if flow may return from `callable`. */
|
||||||
@@ -1014,8 +1008,8 @@ private predicate flowOutOfCallNodeCand1(
|
|||||||
) {
|
) {
|
||||||
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
||||||
Stage1::revFlow(ret, config) and
|
Stage1::revFlow(ret, config) and
|
||||||
not fullOutBarrier(ret, config) and
|
not outBarrier(ret, config) and
|
||||||
not fullInBarrier(out, config)
|
not inBarrier(out, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -1036,8 +1030,8 @@ private predicate flowIntoCallNodeCand1(
|
|||||||
) {
|
) {
|
||||||
viableParamArgNodeCand1(call, p, arg, config) and
|
viableParamArgNodeCand1(call, p, arg, config) and
|
||||||
Stage1::revFlow(p, config) and
|
Stage1::revFlow(p, config) and
|
||||||
not fullOutBarrier(arg, config) and
|
not outBarrier(arg, config) and
|
||||||
not fullInBarrier(p, config)
|
not inBarrier(p, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1189,7 +1183,7 @@ private module Stage2 {
|
|||||||
|
|
||||||
bindingset[node, state, ap, config]
|
bindingset[node, state, ap, config]
|
||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
PrevStage::revFlowState(state, config) and
|
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||||
exists(ap) and
|
exists(ap) and
|
||||||
not stateBarrier(node, state, config)
|
not stateBarrier(node, state, config)
|
||||||
}
|
}
|
||||||
@@ -1614,7 +1608,7 @@ private module Stage2 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -1769,9 +1763,9 @@ private module LocalFlowBigStep {
|
|||||||
or
|
or
|
||||||
node.asNode() instanceof OutNodeExt
|
node.asNode() instanceof OutNodeExt
|
||||||
or
|
or
|
||||||
store(_, _, node, _, config)
|
Stage2::storeStepCand(_, _, _, node, _, config)
|
||||||
or
|
or
|
||||||
read(_, _, node, config)
|
Stage2::readStepCand(_, _, node, config)
|
||||||
or
|
or
|
||||||
node instanceof FlowCheckNode
|
node instanceof FlowCheckNode
|
||||||
or
|
or
|
||||||
@@ -1792,8 +1786,8 @@ private module LocalFlowBigStep {
|
|||||||
additionalJumpStep(node, next, config) or
|
additionalJumpStep(node, next, config) or
|
||||||
flowIntoCallNodeCand1(_, node, next, config) or
|
flowIntoCallNodeCand1(_, node, next, config) or
|
||||||
flowOutOfCallNodeCand1(_, node, next, config) or
|
flowOutOfCallNodeCand1(_, node, next, config) or
|
||||||
store(node, _, next, _, config) or
|
Stage2::storeStepCand(node, _, _, next, _, config) or
|
||||||
read(node, _, next, config)
|
Stage2::readStepCand(node, _, next, config)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||||
@@ -1966,7 +1960,24 @@ private module Stage3 {
|
|||||||
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
|
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||||
|
PrevStage::revFlow(node, config) and
|
||||||
|
clearsContentCached(node.asNode(), c)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate clearContent(NodeEx node, Content c, Configuration config) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
|
||||||
|
c = cs.getAReadContent() and
|
||||||
|
clearSet(node, cs, pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate clear(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
clearContent(node, ap.getHead().getContent(), config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
@@ -1975,7 +1986,7 @@ private module Stage3 {
|
|||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
exists(state) and
|
exists(state) and
|
||||||
exists(config) and
|
exists(config) and
|
||||||
not clear(node, ap) and
|
not clear(node, ap, config) and
|
||||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2403,7 +2414,7 @@ private module Stage3 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -3230,7 +3241,7 @@ private module Stage4 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -4242,7 +4253,7 @@ private module Subpaths {
|
|||||||
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
||||||
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
||||||
store(n1, _, n2, _, _) or
|
store(n1, _, n2, _, _) or
|
||||||
read(n1, _, n2, _)
|
readSet(n1, _, n2, _)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4597,7 +4608,7 @@ private module FlowExploration {
|
|||||||
or
|
or
|
||||||
exists(PartialPathNodeRev mid |
|
exists(PartialPathNodeRev mid |
|
||||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||||
not clearsContentCached(node.asNode(), ap.getHead()) and
|
not clearsContentEx(node, ap.getHead()) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||||
@@ -4613,7 +4624,7 @@ private module FlowExploration {
|
|||||||
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
|
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||||
if node.asNode() instanceof CastingNode
|
if node.asNode() instanceof CastingNode
|
||||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||||
else any()
|
else any()
|
||||||
@@ -5047,6 +5058,7 @@ private module FlowExploration {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
private predicate revPartialPathStep(
|
private predicate revPartialPathStep(
|
||||||
PartialPathNodeRev mid, NodeEx node, FlowState state, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
|
PartialPathNodeRev mid, NodeEx node, FlowState state, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
|
||||||
TRevSummaryCtx3 sc3, RevPartialAccessPath ap, Configuration config
|
TRevSummaryCtx3 sc3, RevPartialAccessPath ap, Configuration config
|
||||||
|
|||||||
@@ -326,7 +326,7 @@ private module Cached {
|
|||||||
predicate jumpStepCached(Node node1, Node node2) { jumpStep(node1, node2) }
|
predicate jumpStepCached(Node node1, Node node2) { jumpStep(node1, node2) }
|
||||||
|
|
||||||
cached
|
cached
|
||||||
predicate clearsContentCached(Node n, Content c) { clearsContent(n, c) }
|
predicate clearsContentCached(Node n, ContentSet c) { clearsContent(n, c) }
|
||||||
|
|
||||||
cached
|
cached
|
||||||
predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) }
|
predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) }
|
||||||
@@ -373,7 +373,7 @@ private module Cached {
|
|||||||
// For reads, `x.f`, we want to check that the tracked type after the read (which
|
// For reads, `x.f`, we want to check that the tracked type after the read (which
|
||||||
// is obtained by popping the head of the access path stack) is compatible with
|
// is obtained by popping the head of the access path stack) is compatible with
|
||||||
// the type of `x.f`.
|
// the type of `x.f`.
|
||||||
read(_, _, n)
|
readSet(_, _, n)
|
||||||
}
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
@@ -469,7 +469,7 @@ private module Cached {
|
|||||||
// read
|
// read
|
||||||
exists(Node mid |
|
exists(Node mid |
|
||||||
parameterValueFlowCand(p, mid, false) and
|
parameterValueFlowCand(p, mid, false) and
|
||||||
read(mid, _, node) and
|
readSet(mid, _, node) and
|
||||||
read = true
|
read = true
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
@@ -657,8 +657,10 @@ private module Cached {
|
|||||||
* Holds if `arg` flows to `out` through a call using only
|
* Holds if `arg` flows to `out` through a call using only
|
||||||
* value-preserving steps and a single read step, not taking call
|
* value-preserving steps and a single read step, not taking call
|
||||||
* contexts into account, thus representing a getter-step.
|
* contexts into account, thus representing a getter-step.
|
||||||
|
*
|
||||||
|
* This predicate is exposed for testing only.
|
||||||
*/
|
*/
|
||||||
predicate getterStep(ArgNode arg, Content c, Node out) {
|
predicate getterStep(ArgNode arg, ContentSet c, Node out) {
|
||||||
argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out)
|
argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -781,28 +783,30 @@ private module Cached {
|
|||||||
parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone())
|
parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cached
|
||||||
|
predicate readSet(Node node1, ContentSet c, Node node2) { readStep(node1, c, node2) }
|
||||||
|
|
||||||
private predicate store(
|
private predicate store(
|
||||||
Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType
|
Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType
|
||||||
) {
|
) {
|
||||||
storeStep(node1, c, node2) and
|
exists(ContentSet cs | c = cs.getAStoreContent() |
|
||||||
contentType = getNodeDataFlowType(node1) and
|
storeStep(node1, cs, node2) and
|
||||||
containerType = getNodeDataFlowType(node2)
|
contentType = getNodeDataFlowType(node1) and
|
||||||
or
|
containerType = getNodeDataFlowType(node2)
|
||||||
exists(Node n1, Node n2 |
|
|
||||||
n1 = node1.(PostUpdateNode).getPreUpdateNode() and
|
|
||||||
n2 = node2.(PostUpdateNode).getPreUpdateNode()
|
|
||||||
|
|
|
||||||
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1)
|
|
||||||
or
|
or
|
||||||
read(n2, c, n1) and
|
exists(Node n1, Node n2 |
|
||||||
contentType = getNodeDataFlowType(n1) and
|
n1 = node1.(PostUpdateNode).getPreUpdateNode() and
|
||||||
containerType = getNodeDataFlowType(n2)
|
n2 = node2.(PostUpdateNode).getPreUpdateNode()
|
||||||
|
|
|
||||||
|
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, cs, contentType), n1)
|
||||||
|
or
|
||||||
|
readSet(n2, cs, n1) and
|
||||||
|
contentType = getNodeDataFlowType(n1) and
|
||||||
|
containerType = getNodeDataFlowType(n2)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
cached
|
|
||||||
predicate read(Node node1, Content c, Node node2) { readStep(node1, c, node2) }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if data can flow from `node1` to `node2` via a direct assignment to
|
* Holds if data can flow from `node1` to `node2` via a direct assignment to
|
||||||
* `f`.
|
* `f`.
|
||||||
@@ -932,16 +936,16 @@ class CastingNode extends Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private predicate readStepWithTypes(
|
private predicate readStepWithTypes(
|
||||||
Node n1, DataFlowType container, Content c, Node n2, DataFlowType content
|
Node n1, DataFlowType container, ContentSet c, Node n2, DataFlowType content
|
||||||
) {
|
) {
|
||||||
read(n1, c, n2) and
|
readSet(n1, c, n2) and
|
||||||
container = getNodeDataFlowType(n1) and
|
container = getNodeDataFlowType(n1) and
|
||||||
content = getNodeDataFlowType(n2)
|
content = getNodeDataFlowType(n2)
|
||||||
}
|
}
|
||||||
|
|
||||||
private newtype TReadStepTypesOption =
|
private newtype TReadStepTypesOption =
|
||||||
TReadStepTypesNone() or
|
TReadStepTypesNone() or
|
||||||
TReadStepTypesSome(DataFlowType container, Content c, DataFlowType content) {
|
TReadStepTypesSome(DataFlowType container, ContentSet c, DataFlowType content) {
|
||||||
readStepWithTypes(_, container, c, _, content)
|
readStepWithTypes(_, container, c, _, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -950,7 +954,7 @@ private class ReadStepTypesOption extends TReadStepTypesOption {
|
|||||||
|
|
||||||
DataFlowType getContainerType() { this = TReadStepTypesSome(result, _, _) }
|
DataFlowType getContainerType() { this = TReadStepTypesSome(result, _, _) }
|
||||||
|
|
||||||
Content getContent() { this = TReadStepTypesSome(_, result, _) }
|
ContentSet getContent() { this = TReadStepTypesSome(_, result, _) }
|
||||||
|
|
||||||
DataFlowType getContentType() { this = TReadStepTypesSome(_, _, result) }
|
DataFlowType getContentType() { this = TReadStepTypesSome(_, _, result) }
|
||||||
|
|
||||||
@@ -1325,8 +1329,6 @@ abstract class AccessPathFront extends TAccessPathFront {
|
|||||||
abstract boolean toBoolNonEmpty();
|
abstract boolean toBoolNonEmpty();
|
||||||
|
|
||||||
TypedContent getHead() { this = TFrontHead(result) }
|
TypedContent getHead() { this = TFrontHead(result) }
|
||||||
|
|
||||||
predicate isClearedAt(Node n) { clearsContentCached(n, this.getHead().getContent()) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class AccessPathFrontNil extends AccessPathFront, TFrontNil {
|
class AccessPathFrontNil extends AccessPathFront, TFrontNil {
|
||||||
|
|||||||
@@ -87,21 +87,9 @@ abstract class Configuration extends string {
|
|||||||
/** Holds if data flow into `node` is prohibited. */
|
/** Holds if data flow into `node` is prohibited. */
|
||||||
predicate isBarrierIn(Node node) { none() }
|
predicate isBarrierIn(Node node) { none() }
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data flow into `node` is prohibited when the flow state is
|
|
||||||
* `state`
|
|
||||||
*/
|
|
||||||
predicate isBarrierIn(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
/** Holds if data flow out of `node` is prohibited. */
|
/** Holds if data flow out of `node` is prohibited. */
|
||||||
predicate isBarrierOut(Node node) { none() }
|
predicate isBarrierOut(Node node) { none() }
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data flow out of `node` is prohibited when the flow state is
|
|
||||||
* `state`
|
|
||||||
*/
|
|
||||||
predicate isBarrierOut(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||||
|
|
||||||
@@ -128,7 +116,7 @@ abstract class Configuration extends string {
|
|||||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||||
* taken at `node`.
|
* taken at `node`.
|
||||||
*/
|
*/
|
||||||
predicate allowImplicitRead(Node node, Content c) { none() }
|
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||||
@@ -321,7 +309,7 @@ private class RetNodeEx extends NodeEx {
|
|||||||
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate fullInBarrier(NodeEx node, Configuration config) {
|
private predicate inBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
node.asNode() = n and
|
node.asNode() = n and
|
||||||
config.isBarrierIn(n)
|
config.isBarrierIn(n)
|
||||||
@@ -330,16 +318,7 @@ private predicate fullInBarrier(NodeEx node, Configuration config) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
|
private predicate outBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n |
|
|
||||||
node.asNode() = n and
|
|
||||||
config.isBarrierIn(n, state)
|
|
||||||
|
|
|
||||||
config.isSource(n, state)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate fullOutBarrier(NodeEx node, Configuration config) {
|
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
node.asNode() = n and
|
node.asNode() = n and
|
||||||
config.isBarrierOut(n)
|
config.isBarrierOut(n)
|
||||||
@@ -348,15 +327,6 @@ private predicate fullOutBarrier(NodeEx node, Configuration config) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
|
|
||||||
exists(Node n |
|
|
||||||
node.asNode() = n and
|
|
||||||
config.isBarrierOut(n, state)
|
|
||||||
|
|
|
||||||
config.isSink(n, state)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fullBarrier(NodeEx node, Configuration config) {
|
private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n | node.asNode() = n |
|
exists(Node n | node.asNode() = n |
|
||||||
@@ -382,12 +352,6 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
|
|||||||
exists(Node n | node.asNode() = n |
|
exists(Node n | node.asNode() = n |
|
||||||
config.isBarrier(n, state)
|
config.isBarrier(n, state)
|
||||||
or
|
or
|
||||||
config.isBarrierIn(n, state) and
|
|
||||||
not config.isSource(n, state)
|
|
||||||
or
|
|
||||||
config.isBarrierOut(n, state) and
|
|
||||||
not config.isSink(n, state)
|
|
||||||
or
|
|
||||||
exists(BarrierGuard g |
|
exists(BarrierGuard g |
|
||||||
config.isBarrierGuard(g, state) and
|
config.isBarrierGuard(g, state) and
|
||||||
n = g.getAGuardedNode()
|
n = g.getAGuardedNode()
|
||||||
@@ -420,8 +384,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
|
|||||||
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
||||||
not fullOutBarrier(node1, config) and
|
not outBarrier(node1, config) and
|
||||||
not fullInBarrier(node2, config) and
|
not inBarrier(node2, config) and
|
||||||
not fullBarrier(node1, config) and
|
not fullBarrier(node1, config) and
|
||||||
not fullBarrier(node2, config)
|
not fullBarrier(node2, config)
|
||||||
}
|
}
|
||||||
@@ -474,8 +438,6 @@ private predicate additionalLocalStateStep(
|
|||||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
||||||
stepFilter(node1, node2, config) and
|
stepFilter(node1, node2, config) and
|
||||||
not stateOutBarrier(node1, s1, config) and
|
|
||||||
not stateInBarrier(node2, s2, config) and
|
|
||||||
not stateBarrier(node1, s1, config) and
|
not stateBarrier(node1, s1, config) and
|
||||||
not stateBarrier(node2, s2, config)
|
not stateBarrier(node2, s2, config)
|
||||||
)
|
)
|
||||||
@@ -517,16 +479,15 @@ private predicate additionalJumpStateStep(
|
|||||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
||||||
stepFilter(node1, node2, config) and
|
stepFilter(node1, node2, config) and
|
||||||
not stateOutBarrier(node1, s1, config) and
|
|
||||||
not stateInBarrier(node2, s2, config) and
|
|
||||||
not stateBarrier(node1, s1, config) and
|
not stateBarrier(node1, s1, config) and
|
||||||
not stateBarrier(node2, s2, config) and
|
not stateBarrier(node2, s2, config) and
|
||||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
pragma[nomagic]
|
||||||
read(node1.asNode(), c, node2.asNode()) and
|
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||||
|
readSet(node1.asNode(), c, node2.asNode()) and
|
||||||
stepFilter(node1, node2, config)
|
stepFilter(node1, node2, config)
|
||||||
or
|
or
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
@@ -536,6 +497,25 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
pragma[inline]
|
||||||
|
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
readSet(node1, cs, node2, config) and
|
||||||
|
c = cs.getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
pragma[inline]
|
||||||
|
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
clearsContentCached(n.asNode(), cs) and
|
||||||
|
c = cs.getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
) {
|
) {
|
||||||
@@ -613,9 +593,9 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(Content c |
|
exists(ContentSet c |
|
||||||
fwdFlowRead(c, node, cc, config) and
|
fwdFlowReadSet(c, node, cc, config) and
|
||||||
fwdFlowConsCand(c, config)
|
fwdFlowConsCandSet(c, _, config)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
@@ -639,10 +619,10 @@ private module Stage1 {
|
|||||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
|
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
fwdFlow(mid, cc, config) and
|
fwdFlow(mid, cc, config) and
|
||||||
read(mid, c, node, config)
|
readSet(mid, c, node, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -660,6 +640,16 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `cs` may be interpreted in a read as the target of some store
|
||||||
|
* into `c`, in the flow covered by `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowConsCandSet(ContentSet cs, Content c, Configuration config) {
|
||||||
|
fwdFlowConsCand(c, config) and
|
||||||
|
c = cs.getAReadContent()
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
||||||
exists(RetNodeEx ret |
|
exists(RetNodeEx ret |
|
||||||
@@ -752,9 +742,9 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(NodeEx mid, Content c |
|
exists(NodeEx mid, ContentSet c |
|
||||||
read(node, c, mid, config) and
|
readSet(node, c, mid, config) and
|
||||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
fwdFlowConsCandSet(c, _, pragma[only_bind_into](config)) and
|
||||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
@@ -780,10 +770,10 @@ private module Stage1 {
|
|||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||||
exists(NodeEx mid, NodeEx node |
|
exists(NodeEx mid, NodeEx node, ContentSet cs |
|
||||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||||
read(node, c, mid, config) and
|
readSet(node, cs, mid, config) and
|
||||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
fwdFlowConsCandSet(cs, c, pragma[only_bind_into](config)) and
|
||||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -802,6 +792,7 @@ private module Stage1 {
|
|||||||
* Holds if `c` is the target of both a read and a store in the flow covered
|
* Holds if `c` is the target of both a read and a store in the flow covered
|
||||||
* by `revFlow`.
|
* by `revFlow`.
|
||||||
*/
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||||
revFlowConsCand(c, conf) and
|
revFlowConsCand(c, conf) and
|
||||||
revFlowStore(c, _, _, conf)
|
revFlowStore(c, _, _, conf)
|
||||||
@@ -900,9 +891,9 @@ private module Stage1 {
|
|||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
|
||||||
revFlow(n2, pragma[only_bind_into](config)) and
|
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||||
read(n1, c, n2, pragma[only_bind_into](config))
|
revFlow(n2, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -912,14 +903,17 @@ private module Stage1 {
|
|||||||
predicate revFlow(
|
predicate revFlow(
|
||||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
revFlow(node, toReturn, config) and exists(state) and exists(returnAp) and exists(ap)
|
revFlow(node, toReturn, pragma[only_bind_into](config)) and
|
||||||
|
exists(state) and
|
||||||
|
exists(returnAp) and
|
||||||
|
exists(ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||||
revFlow(node, true, config) and
|
revFlow(node, true, config) and
|
||||||
fwdFlow(node, true, config) and
|
fwdFlow(node, true, config) and
|
||||||
not fullInBarrier(node, config) and
|
not inBarrier(node, config) and
|
||||||
not fullOutBarrier(node, config)
|
not outBarrier(node, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if flow may return from `callable`. */
|
/** Holds if flow may return from `callable`. */
|
||||||
@@ -1014,8 +1008,8 @@ private predicate flowOutOfCallNodeCand1(
|
|||||||
) {
|
) {
|
||||||
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
||||||
Stage1::revFlow(ret, config) and
|
Stage1::revFlow(ret, config) and
|
||||||
not fullOutBarrier(ret, config) and
|
not outBarrier(ret, config) and
|
||||||
not fullInBarrier(out, config)
|
not inBarrier(out, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -1036,8 +1030,8 @@ private predicate flowIntoCallNodeCand1(
|
|||||||
) {
|
) {
|
||||||
viableParamArgNodeCand1(call, p, arg, config) and
|
viableParamArgNodeCand1(call, p, arg, config) and
|
||||||
Stage1::revFlow(p, config) and
|
Stage1::revFlow(p, config) and
|
||||||
not fullOutBarrier(arg, config) and
|
not outBarrier(arg, config) and
|
||||||
not fullInBarrier(p, config)
|
not inBarrier(p, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1189,7 +1183,7 @@ private module Stage2 {
|
|||||||
|
|
||||||
bindingset[node, state, ap, config]
|
bindingset[node, state, ap, config]
|
||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
PrevStage::revFlowState(state, config) and
|
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||||
exists(ap) and
|
exists(ap) and
|
||||||
not stateBarrier(node, state, config)
|
not stateBarrier(node, state, config)
|
||||||
}
|
}
|
||||||
@@ -1614,7 +1608,7 @@ private module Stage2 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -1769,9 +1763,9 @@ private module LocalFlowBigStep {
|
|||||||
or
|
or
|
||||||
node.asNode() instanceof OutNodeExt
|
node.asNode() instanceof OutNodeExt
|
||||||
or
|
or
|
||||||
store(_, _, node, _, config)
|
Stage2::storeStepCand(_, _, _, node, _, config)
|
||||||
or
|
or
|
||||||
read(_, _, node, config)
|
Stage2::readStepCand(_, _, node, config)
|
||||||
or
|
or
|
||||||
node instanceof FlowCheckNode
|
node instanceof FlowCheckNode
|
||||||
or
|
or
|
||||||
@@ -1792,8 +1786,8 @@ private module LocalFlowBigStep {
|
|||||||
additionalJumpStep(node, next, config) or
|
additionalJumpStep(node, next, config) or
|
||||||
flowIntoCallNodeCand1(_, node, next, config) or
|
flowIntoCallNodeCand1(_, node, next, config) or
|
||||||
flowOutOfCallNodeCand1(_, node, next, config) or
|
flowOutOfCallNodeCand1(_, node, next, config) or
|
||||||
store(node, _, next, _, config) or
|
Stage2::storeStepCand(node, _, _, next, _, config) or
|
||||||
read(node, _, next, config)
|
Stage2::readStepCand(node, _, next, config)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||||
@@ -1966,7 +1960,24 @@ private module Stage3 {
|
|||||||
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
|
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||||
|
PrevStage::revFlow(node, config) and
|
||||||
|
clearsContentCached(node.asNode(), c)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate clearContent(NodeEx node, Content c, Configuration config) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
|
||||||
|
c = cs.getAReadContent() and
|
||||||
|
clearSet(node, cs, pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate clear(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
clearContent(node, ap.getHead().getContent(), config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
@@ -1975,7 +1986,7 @@ private module Stage3 {
|
|||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
exists(state) and
|
exists(state) and
|
||||||
exists(config) and
|
exists(config) and
|
||||||
not clear(node, ap) and
|
not clear(node, ap, config) and
|
||||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2403,7 +2414,7 @@ private module Stage3 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -3230,7 +3241,7 @@ private module Stage4 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -4242,7 +4253,7 @@ private module Subpaths {
|
|||||||
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
||||||
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
||||||
store(n1, _, n2, _, _) or
|
store(n1, _, n2, _, _) or
|
||||||
read(n1, _, n2, _)
|
readSet(n1, _, n2, _)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4597,7 +4608,7 @@ private module FlowExploration {
|
|||||||
or
|
or
|
||||||
exists(PartialPathNodeRev mid |
|
exists(PartialPathNodeRev mid |
|
||||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||||
not clearsContentCached(node.asNode(), ap.getHead()) and
|
not clearsContentEx(node, ap.getHead()) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||||
@@ -4613,7 +4624,7 @@ private module FlowExploration {
|
|||||||
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
|
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||||
if node.asNode() instanceof CastingNode
|
if node.asNode() instanceof CastingNode
|
||||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||||
else any()
|
else any()
|
||||||
@@ -5047,6 +5058,7 @@ private module FlowExploration {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
private predicate revPartialPathStep(
|
private predicate revPartialPathStep(
|
||||||
PartialPathNodeRev mid, NodeEx node, FlowState state, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
|
PartialPathNodeRev mid, NodeEx node, FlowState state, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
|
||||||
TRevSummaryCtx3 sc3, RevPartialAccessPath ap, Configuration config
|
TRevSummaryCtx3 sc3, RevPartialAccessPath ap, Configuration config
|
||||||
|
|||||||
@@ -821,6 +821,34 @@ private class CollectionContent extends Content, TCollectionContent {
|
|||||||
override string toString() { result = "<element>" }
|
override string toString() { result = "<element>" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An entity that represents a set of `Content`s.
|
||||||
|
*
|
||||||
|
* The set may be interpreted differently depending on whether it is
|
||||||
|
* stored into (`getAStoreContent`) or read from (`getAReadContent`).
|
||||||
|
*/
|
||||||
|
class ContentSet instanceof Content {
|
||||||
|
/** Gets a content that may be stored into when storing into this set. */
|
||||||
|
Content getAStoreContent() { result = this }
|
||||||
|
|
||||||
|
/** Gets a content that may be read from when reading from this set. */
|
||||||
|
Content getAReadContent() { result = this }
|
||||||
|
|
||||||
|
/** Gets a textual representation of this content set. */
|
||||||
|
string toString() { result = super.toString() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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/).
|
||||||
|
*/
|
||||||
|
predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
|
||||||
|
super.hasLocationInfo(path, sl, sc, el, ec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A guard that validates some expression.
|
* A guard that validates some expression.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -109,16 +109,6 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
/** Holds if taint propagation into `node` is prohibited. */
|
/** Holds if taint propagation into `node` is prohibited. */
|
||||||
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if taint propagation into `node` is prohibited when the flow state is
|
|
||||||
* `state`.
|
|
||||||
*/
|
|
||||||
predicate isSanitizerIn(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
|
||||||
|
|
||||||
final override predicate isBarrierIn(DataFlow::Node node, DataFlow::FlowState state) {
|
|
||||||
this.isSanitizerIn(node, state)
|
|
||||||
}
|
|
||||||
|
|
||||||
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
|
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
|
||||||
|
|
||||||
/** Holds if taint propagation out of `node` is prohibited. */
|
/** Holds if taint propagation out of `node` is prohibited. */
|
||||||
@@ -126,16 +116,6 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
|
|
||||||
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if taint propagation out of `node` is prohibited when the flow state is
|
|
||||||
* `state`.
|
|
||||||
*/
|
|
||||||
predicate isSanitizerOut(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
|
||||||
|
|
||||||
final override predicate isBarrierOut(DataFlow::Node node, DataFlow::FlowState state) {
|
|
||||||
this.isSanitizerOut(node, state)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
||||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||||
|
|
||||||
@@ -181,7 +161,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
|
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||||
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
||||||
defaultImplicitTaintRead(node, c)
|
defaultImplicitTaintRead(node, c)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,16 +109,6 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
/** Holds if taint propagation into `node` is prohibited. */
|
/** Holds if taint propagation into `node` is prohibited. */
|
||||||
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if taint propagation into `node` is prohibited when the flow state is
|
|
||||||
* `state`.
|
|
||||||
*/
|
|
||||||
predicate isSanitizerIn(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
|
||||||
|
|
||||||
final override predicate isBarrierIn(DataFlow::Node node, DataFlow::FlowState state) {
|
|
||||||
this.isSanitizerIn(node, state)
|
|
||||||
}
|
|
||||||
|
|
||||||
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
|
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
|
||||||
|
|
||||||
/** Holds if taint propagation out of `node` is prohibited. */
|
/** Holds if taint propagation out of `node` is prohibited. */
|
||||||
@@ -126,16 +116,6 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
|
|
||||||
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if taint propagation out of `node` is prohibited when the flow state is
|
|
||||||
* `state`.
|
|
||||||
*/
|
|
||||||
predicate isSanitizerOut(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
|
||||||
|
|
||||||
final override predicate isBarrierOut(DataFlow::Node node, DataFlow::FlowState state) {
|
|
||||||
this.isSanitizerOut(node, state)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
||||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||||
|
|
||||||
@@ -181,7 +161,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
|
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||||
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
||||||
defaultImplicitTaintRead(node, c)
|
defaultImplicitTaintRead(node, c)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,21 +87,9 @@ abstract class Configuration extends string {
|
|||||||
/** Holds if data flow into `node` is prohibited. */
|
/** Holds if data flow into `node` is prohibited. */
|
||||||
predicate isBarrierIn(Node node) { none() }
|
predicate isBarrierIn(Node node) { none() }
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data flow into `node` is prohibited when the flow state is
|
|
||||||
* `state`
|
|
||||||
*/
|
|
||||||
predicate isBarrierIn(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
/** Holds if data flow out of `node` is prohibited. */
|
/** Holds if data flow out of `node` is prohibited. */
|
||||||
predicate isBarrierOut(Node node) { none() }
|
predicate isBarrierOut(Node node) { none() }
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data flow out of `node` is prohibited when the flow state is
|
|
||||||
* `state`
|
|
||||||
*/
|
|
||||||
predicate isBarrierOut(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||||
|
|
||||||
@@ -128,7 +116,7 @@ abstract class Configuration extends string {
|
|||||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||||
* taken at `node`.
|
* taken at `node`.
|
||||||
*/
|
*/
|
||||||
predicate allowImplicitRead(Node node, Content c) { none() }
|
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||||
@@ -321,7 +309,7 @@ private class RetNodeEx extends NodeEx {
|
|||||||
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate fullInBarrier(NodeEx node, Configuration config) {
|
private predicate inBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
node.asNode() = n and
|
node.asNode() = n and
|
||||||
config.isBarrierIn(n)
|
config.isBarrierIn(n)
|
||||||
@@ -330,16 +318,7 @@ private predicate fullInBarrier(NodeEx node, Configuration config) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
|
private predicate outBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n |
|
|
||||||
node.asNode() = n and
|
|
||||||
config.isBarrierIn(n, state)
|
|
||||||
|
|
|
||||||
config.isSource(n, state)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate fullOutBarrier(NodeEx node, Configuration config) {
|
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
node.asNode() = n and
|
node.asNode() = n and
|
||||||
config.isBarrierOut(n)
|
config.isBarrierOut(n)
|
||||||
@@ -348,15 +327,6 @@ private predicate fullOutBarrier(NodeEx node, Configuration config) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
|
|
||||||
exists(Node n |
|
|
||||||
node.asNode() = n and
|
|
||||||
config.isBarrierOut(n, state)
|
|
||||||
|
|
|
||||||
config.isSink(n, state)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fullBarrier(NodeEx node, Configuration config) {
|
private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n | node.asNode() = n |
|
exists(Node n | node.asNode() = n |
|
||||||
@@ -382,12 +352,6 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
|
|||||||
exists(Node n | node.asNode() = n |
|
exists(Node n | node.asNode() = n |
|
||||||
config.isBarrier(n, state)
|
config.isBarrier(n, state)
|
||||||
or
|
or
|
||||||
config.isBarrierIn(n, state) and
|
|
||||||
not config.isSource(n, state)
|
|
||||||
or
|
|
||||||
config.isBarrierOut(n, state) and
|
|
||||||
not config.isSink(n, state)
|
|
||||||
or
|
|
||||||
exists(BarrierGuard g |
|
exists(BarrierGuard g |
|
||||||
config.isBarrierGuard(g, state) and
|
config.isBarrierGuard(g, state) and
|
||||||
n = g.getAGuardedNode()
|
n = g.getAGuardedNode()
|
||||||
@@ -420,8 +384,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
|
|||||||
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
||||||
not fullOutBarrier(node1, config) and
|
not outBarrier(node1, config) and
|
||||||
not fullInBarrier(node2, config) and
|
not inBarrier(node2, config) and
|
||||||
not fullBarrier(node1, config) and
|
not fullBarrier(node1, config) and
|
||||||
not fullBarrier(node2, config)
|
not fullBarrier(node2, config)
|
||||||
}
|
}
|
||||||
@@ -474,8 +438,6 @@ private predicate additionalLocalStateStep(
|
|||||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
||||||
stepFilter(node1, node2, config) and
|
stepFilter(node1, node2, config) and
|
||||||
not stateOutBarrier(node1, s1, config) and
|
|
||||||
not stateInBarrier(node2, s2, config) and
|
|
||||||
not stateBarrier(node1, s1, config) and
|
not stateBarrier(node1, s1, config) and
|
||||||
not stateBarrier(node2, s2, config)
|
not stateBarrier(node2, s2, config)
|
||||||
)
|
)
|
||||||
@@ -517,16 +479,15 @@ private predicate additionalJumpStateStep(
|
|||||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
||||||
stepFilter(node1, node2, config) and
|
stepFilter(node1, node2, config) and
|
||||||
not stateOutBarrier(node1, s1, config) and
|
|
||||||
not stateInBarrier(node2, s2, config) and
|
|
||||||
not stateBarrier(node1, s1, config) and
|
not stateBarrier(node1, s1, config) and
|
||||||
not stateBarrier(node2, s2, config) and
|
not stateBarrier(node2, s2, config) and
|
||||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
pragma[nomagic]
|
||||||
read(node1.asNode(), c, node2.asNode()) and
|
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||||
|
readSet(node1.asNode(), c, node2.asNode()) and
|
||||||
stepFilter(node1, node2, config)
|
stepFilter(node1, node2, config)
|
||||||
or
|
or
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
@@ -536,6 +497,25 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
pragma[inline]
|
||||||
|
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
readSet(node1, cs, node2, config) and
|
||||||
|
c = cs.getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
pragma[inline]
|
||||||
|
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
clearsContentCached(n.asNode(), cs) and
|
||||||
|
c = cs.getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
) {
|
) {
|
||||||
@@ -613,9 +593,9 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(Content c |
|
exists(ContentSet c |
|
||||||
fwdFlowRead(c, node, cc, config) and
|
fwdFlowReadSet(c, node, cc, config) and
|
||||||
fwdFlowConsCand(c, config)
|
fwdFlowConsCandSet(c, _, config)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
@@ -639,10 +619,10 @@ private module Stage1 {
|
|||||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
|
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
fwdFlow(mid, cc, config) and
|
fwdFlow(mid, cc, config) and
|
||||||
read(mid, c, node, config)
|
readSet(mid, c, node, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -660,6 +640,16 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `cs` may be interpreted in a read as the target of some store
|
||||||
|
* into `c`, in the flow covered by `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowConsCandSet(ContentSet cs, Content c, Configuration config) {
|
||||||
|
fwdFlowConsCand(c, config) and
|
||||||
|
c = cs.getAReadContent()
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
||||||
exists(RetNodeEx ret |
|
exists(RetNodeEx ret |
|
||||||
@@ -752,9 +742,9 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(NodeEx mid, Content c |
|
exists(NodeEx mid, ContentSet c |
|
||||||
read(node, c, mid, config) and
|
readSet(node, c, mid, config) and
|
||||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
fwdFlowConsCandSet(c, _, pragma[only_bind_into](config)) and
|
||||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
@@ -780,10 +770,10 @@ private module Stage1 {
|
|||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||||
exists(NodeEx mid, NodeEx node |
|
exists(NodeEx mid, NodeEx node, ContentSet cs |
|
||||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||||
read(node, c, mid, config) and
|
readSet(node, cs, mid, config) and
|
||||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
fwdFlowConsCandSet(cs, c, pragma[only_bind_into](config)) and
|
||||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -802,6 +792,7 @@ private module Stage1 {
|
|||||||
* Holds if `c` is the target of both a read and a store in the flow covered
|
* Holds if `c` is the target of both a read and a store in the flow covered
|
||||||
* by `revFlow`.
|
* by `revFlow`.
|
||||||
*/
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||||
revFlowConsCand(c, conf) and
|
revFlowConsCand(c, conf) and
|
||||||
revFlowStore(c, _, _, conf)
|
revFlowStore(c, _, _, conf)
|
||||||
@@ -900,9 +891,9 @@ private module Stage1 {
|
|||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
|
||||||
revFlow(n2, pragma[only_bind_into](config)) and
|
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||||
read(n1, c, n2, pragma[only_bind_into](config))
|
revFlow(n2, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -912,14 +903,17 @@ private module Stage1 {
|
|||||||
predicate revFlow(
|
predicate revFlow(
|
||||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
revFlow(node, toReturn, config) and exists(state) and exists(returnAp) and exists(ap)
|
revFlow(node, toReturn, pragma[only_bind_into](config)) and
|
||||||
|
exists(state) and
|
||||||
|
exists(returnAp) and
|
||||||
|
exists(ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||||
revFlow(node, true, config) and
|
revFlow(node, true, config) and
|
||||||
fwdFlow(node, true, config) and
|
fwdFlow(node, true, config) and
|
||||||
not fullInBarrier(node, config) and
|
not inBarrier(node, config) and
|
||||||
not fullOutBarrier(node, config)
|
not outBarrier(node, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if flow may return from `callable`. */
|
/** Holds if flow may return from `callable`. */
|
||||||
@@ -1014,8 +1008,8 @@ private predicate flowOutOfCallNodeCand1(
|
|||||||
) {
|
) {
|
||||||
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
||||||
Stage1::revFlow(ret, config) and
|
Stage1::revFlow(ret, config) and
|
||||||
not fullOutBarrier(ret, config) and
|
not outBarrier(ret, config) and
|
||||||
not fullInBarrier(out, config)
|
not inBarrier(out, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -1036,8 +1030,8 @@ private predicate flowIntoCallNodeCand1(
|
|||||||
) {
|
) {
|
||||||
viableParamArgNodeCand1(call, p, arg, config) and
|
viableParamArgNodeCand1(call, p, arg, config) and
|
||||||
Stage1::revFlow(p, config) and
|
Stage1::revFlow(p, config) and
|
||||||
not fullOutBarrier(arg, config) and
|
not outBarrier(arg, config) and
|
||||||
not fullInBarrier(p, config)
|
not inBarrier(p, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1189,7 +1183,7 @@ private module Stage2 {
|
|||||||
|
|
||||||
bindingset[node, state, ap, config]
|
bindingset[node, state, ap, config]
|
||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
PrevStage::revFlowState(state, config) and
|
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||||
exists(ap) and
|
exists(ap) and
|
||||||
not stateBarrier(node, state, config)
|
not stateBarrier(node, state, config)
|
||||||
}
|
}
|
||||||
@@ -1614,7 +1608,7 @@ private module Stage2 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -1769,9 +1763,9 @@ private module LocalFlowBigStep {
|
|||||||
or
|
or
|
||||||
node.asNode() instanceof OutNodeExt
|
node.asNode() instanceof OutNodeExt
|
||||||
or
|
or
|
||||||
store(_, _, node, _, config)
|
Stage2::storeStepCand(_, _, _, node, _, config)
|
||||||
or
|
or
|
||||||
read(_, _, node, config)
|
Stage2::readStepCand(_, _, node, config)
|
||||||
or
|
or
|
||||||
node instanceof FlowCheckNode
|
node instanceof FlowCheckNode
|
||||||
or
|
or
|
||||||
@@ -1792,8 +1786,8 @@ private module LocalFlowBigStep {
|
|||||||
additionalJumpStep(node, next, config) or
|
additionalJumpStep(node, next, config) or
|
||||||
flowIntoCallNodeCand1(_, node, next, config) or
|
flowIntoCallNodeCand1(_, node, next, config) or
|
||||||
flowOutOfCallNodeCand1(_, node, next, config) or
|
flowOutOfCallNodeCand1(_, node, next, config) or
|
||||||
store(node, _, next, _, config) or
|
Stage2::storeStepCand(node, _, _, next, _, config) or
|
||||||
read(node, _, next, config)
|
Stage2::readStepCand(node, _, next, config)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||||
@@ -1966,7 +1960,24 @@ private module Stage3 {
|
|||||||
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
|
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||||
|
PrevStage::revFlow(node, config) and
|
||||||
|
clearsContentCached(node.asNode(), c)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate clearContent(NodeEx node, Content c, Configuration config) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
|
||||||
|
c = cs.getAReadContent() and
|
||||||
|
clearSet(node, cs, pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate clear(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
clearContent(node, ap.getHead().getContent(), config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
@@ -1975,7 +1986,7 @@ private module Stage3 {
|
|||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
exists(state) and
|
exists(state) and
|
||||||
exists(config) and
|
exists(config) and
|
||||||
not clear(node, ap) and
|
not clear(node, ap, config) and
|
||||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2403,7 +2414,7 @@ private module Stage3 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -3230,7 +3241,7 @@ private module Stage4 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -4242,7 +4253,7 @@ private module Subpaths {
|
|||||||
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
||||||
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
||||||
store(n1, _, n2, _, _) or
|
store(n1, _, n2, _, _) or
|
||||||
read(n1, _, n2, _)
|
readSet(n1, _, n2, _)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4597,7 +4608,7 @@ private module FlowExploration {
|
|||||||
or
|
or
|
||||||
exists(PartialPathNodeRev mid |
|
exists(PartialPathNodeRev mid |
|
||||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||||
not clearsContentCached(node.asNode(), ap.getHead()) and
|
not clearsContentEx(node, ap.getHead()) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||||
@@ -4613,7 +4624,7 @@ private module FlowExploration {
|
|||||||
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
|
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||||
if node.asNode() instanceof CastingNode
|
if node.asNode() instanceof CastingNode
|
||||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||||
else any()
|
else any()
|
||||||
@@ -5047,6 +5058,7 @@ private module FlowExploration {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
private predicate revPartialPathStep(
|
private predicate revPartialPathStep(
|
||||||
PartialPathNodeRev mid, NodeEx node, FlowState state, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
|
PartialPathNodeRev mid, NodeEx node, FlowState state, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
|
||||||
TRevSummaryCtx3 sc3, RevPartialAccessPath ap, Configuration config
|
TRevSummaryCtx3 sc3, RevPartialAccessPath ap, Configuration config
|
||||||
|
|||||||
@@ -87,21 +87,9 @@ abstract class Configuration extends string {
|
|||||||
/** Holds if data flow into `node` is prohibited. */
|
/** Holds if data flow into `node` is prohibited. */
|
||||||
predicate isBarrierIn(Node node) { none() }
|
predicate isBarrierIn(Node node) { none() }
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data flow into `node` is prohibited when the flow state is
|
|
||||||
* `state`
|
|
||||||
*/
|
|
||||||
predicate isBarrierIn(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
/** Holds if data flow out of `node` is prohibited. */
|
/** Holds if data flow out of `node` is prohibited. */
|
||||||
predicate isBarrierOut(Node node) { none() }
|
predicate isBarrierOut(Node node) { none() }
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data flow out of `node` is prohibited when the flow state is
|
|
||||||
* `state`
|
|
||||||
*/
|
|
||||||
predicate isBarrierOut(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||||
|
|
||||||
@@ -128,7 +116,7 @@ abstract class Configuration extends string {
|
|||||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||||
* taken at `node`.
|
* taken at `node`.
|
||||||
*/
|
*/
|
||||||
predicate allowImplicitRead(Node node, Content c) { none() }
|
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||||
@@ -321,7 +309,7 @@ private class RetNodeEx extends NodeEx {
|
|||||||
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate fullInBarrier(NodeEx node, Configuration config) {
|
private predicate inBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
node.asNode() = n and
|
node.asNode() = n and
|
||||||
config.isBarrierIn(n)
|
config.isBarrierIn(n)
|
||||||
@@ -330,16 +318,7 @@ private predicate fullInBarrier(NodeEx node, Configuration config) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
|
private predicate outBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n |
|
|
||||||
node.asNode() = n and
|
|
||||||
config.isBarrierIn(n, state)
|
|
||||||
|
|
|
||||||
config.isSource(n, state)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate fullOutBarrier(NodeEx node, Configuration config) {
|
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
node.asNode() = n and
|
node.asNode() = n and
|
||||||
config.isBarrierOut(n)
|
config.isBarrierOut(n)
|
||||||
@@ -348,15 +327,6 @@ private predicate fullOutBarrier(NodeEx node, Configuration config) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
|
|
||||||
exists(Node n |
|
|
||||||
node.asNode() = n and
|
|
||||||
config.isBarrierOut(n, state)
|
|
||||||
|
|
|
||||||
config.isSink(n, state)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fullBarrier(NodeEx node, Configuration config) {
|
private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n | node.asNode() = n |
|
exists(Node n | node.asNode() = n |
|
||||||
@@ -382,12 +352,6 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
|
|||||||
exists(Node n | node.asNode() = n |
|
exists(Node n | node.asNode() = n |
|
||||||
config.isBarrier(n, state)
|
config.isBarrier(n, state)
|
||||||
or
|
or
|
||||||
config.isBarrierIn(n, state) and
|
|
||||||
not config.isSource(n, state)
|
|
||||||
or
|
|
||||||
config.isBarrierOut(n, state) and
|
|
||||||
not config.isSink(n, state)
|
|
||||||
or
|
|
||||||
exists(BarrierGuard g |
|
exists(BarrierGuard g |
|
||||||
config.isBarrierGuard(g, state) and
|
config.isBarrierGuard(g, state) and
|
||||||
n = g.getAGuardedNode()
|
n = g.getAGuardedNode()
|
||||||
@@ -420,8 +384,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
|
|||||||
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
||||||
not fullOutBarrier(node1, config) and
|
not outBarrier(node1, config) and
|
||||||
not fullInBarrier(node2, config) and
|
not inBarrier(node2, config) and
|
||||||
not fullBarrier(node1, config) and
|
not fullBarrier(node1, config) and
|
||||||
not fullBarrier(node2, config)
|
not fullBarrier(node2, config)
|
||||||
}
|
}
|
||||||
@@ -474,8 +438,6 @@ private predicate additionalLocalStateStep(
|
|||||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
||||||
stepFilter(node1, node2, config) and
|
stepFilter(node1, node2, config) and
|
||||||
not stateOutBarrier(node1, s1, config) and
|
|
||||||
not stateInBarrier(node2, s2, config) and
|
|
||||||
not stateBarrier(node1, s1, config) and
|
not stateBarrier(node1, s1, config) and
|
||||||
not stateBarrier(node2, s2, config)
|
not stateBarrier(node2, s2, config)
|
||||||
)
|
)
|
||||||
@@ -517,16 +479,15 @@ private predicate additionalJumpStateStep(
|
|||||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
||||||
stepFilter(node1, node2, config) and
|
stepFilter(node1, node2, config) and
|
||||||
not stateOutBarrier(node1, s1, config) and
|
|
||||||
not stateInBarrier(node2, s2, config) and
|
|
||||||
not stateBarrier(node1, s1, config) and
|
not stateBarrier(node1, s1, config) and
|
||||||
not stateBarrier(node2, s2, config) and
|
not stateBarrier(node2, s2, config) and
|
||||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
pragma[nomagic]
|
||||||
read(node1.asNode(), c, node2.asNode()) and
|
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||||
|
readSet(node1.asNode(), c, node2.asNode()) and
|
||||||
stepFilter(node1, node2, config)
|
stepFilter(node1, node2, config)
|
||||||
or
|
or
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
@@ -536,6 +497,25 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
pragma[inline]
|
||||||
|
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
readSet(node1, cs, node2, config) and
|
||||||
|
c = cs.getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
pragma[inline]
|
||||||
|
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
clearsContentCached(n.asNode(), cs) and
|
||||||
|
c = cs.getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
) {
|
) {
|
||||||
@@ -613,9 +593,9 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(Content c |
|
exists(ContentSet c |
|
||||||
fwdFlowRead(c, node, cc, config) and
|
fwdFlowReadSet(c, node, cc, config) and
|
||||||
fwdFlowConsCand(c, config)
|
fwdFlowConsCandSet(c, _, config)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
@@ -639,10 +619,10 @@ private module Stage1 {
|
|||||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
|
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
fwdFlow(mid, cc, config) and
|
fwdFlow(mid, cc, config) and
|
||||||
read(mid, c, node, config)
|
readSet(mid, c, node, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -660,6 +640,16 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `cs` may be interpreted in a read as the target of some store
|
||||||
|
* into `c`, in the flow covered by `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowConsCandSet(ContentSet cs, Content c, Configuration config) {
|
||||||
|
fwdFlowConsCand(c, config) and
|
||||||
|
c = cs.getAReadContent()
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
||||||
exists(RetNodeEx ret |
|
exists(RetNodeEx ret |
|
||||||
@@ -752,9 +742,9 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(NodeEx mid, Content c |
|
exists(NodeEx mid, ContentSet c |
|
||||||
read(node, c, mid, config) and
|
readSet(node, c, mid, config) and
|
||||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
fwdFlowConsCandSet(c, _, pragma[only_bind_into](config)) and
|
||||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
@@ -780,10 +770,10 @@ private module Stage1 {
|
|||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||||
exists(NodeEx mid, NodeEx node |
|
exists(NodeEx mid, NodeEx node, ContentSet cs |
|
||||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||||
read(node, c, mid, config) and
|
readSet(node, cs, mid, config) and
|
||||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
fwdFlowConsCandSet(cs, c, pragma[only_bind_into](config)) and
|
||||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -802,6 +792,7 @@ private module Stage1 {
|
|||||||
* Holds if `c` is the target of both a read and a store in the flow covered
|
* Holds if `c` is the target of both a read and a store in the flow covered
|
||||||
* by `revFlow`.
|
* by `revFlow`.
|
||||||
*/
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||||
revFlowConsCand(c, conf) and
|
revFlowConsCand(c, conf) and
|
||||||
revFlowStore(c, _, _, conf)
|
revFlowStore(c, _, _, conf)
|
||||||
@@ -900,9 +891,9 @@ private module Stage1 {
|
|||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
|
||||||
revFlow(n2, pragma[only_bind_into](config)) and
|
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||||
read(n1, c, n2, pragma[only_bind_into](config))
|
revFlow(n2, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -912,14 +903,17 @@ private module Stage1 {
|
|||||||
predicate revFlow(
|
predicate revFlow(
|
||||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
revFlow(node, toReturn, config) and exists(state) and exists(returnAp) and exists(ap)
|
revFlow(node, toReturn, pragma[only_bind_into](config)) and
|
||||||
|
exists(state) and
|
||||||
|
exists(returnAp) and
|
||||||
|
exists(ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||||
revFlow(node, true, config) and
|
revFlow(node, true, config) and
|
||||||
fwdFlow(node, true, config) and
|
fwdFlow(node, true, config) and
|
||||||
not fullInBarrier(node, config) and
|
not inBarrier(node, config) and
|
||||||
not fullOutBarrier(node, config)
|
not outBarrier(node, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if flow may return from `callable`. */
|
/** Holds if flow may return from `callable`. */
|
||||||
@@ -1014,8 +1008,8 @@ private predicate flowOutOfCallNodeCand1(
|
|||||||
) {
|
) {
|
||||||
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
||||||
Stage1::revFlow(ret, config) and
|
Stage1::revFlow(ret, config) and
|
||||||
not fullOutBarrier(ret, config) and
|
not outBarrier(ret, config) and
|
||||||
not fullInBarrier(out, config)
|
not inBarrier(out, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -1036,8 +1030,8 @@ private predicate flowIntoCallNodeCand1(
|
|||||||
) {
|
) {
|
||||||
viableParamArgNodeCand1(call, p, arg, config) and
|
viableParamArgNodeCand1(call, p, arg, config) and
|
||||||
Stage1::revFlow(p, config) and
|
Stage1::revFlow(p, config) and
|
||||||
not fullOutBarrier(arg, config) and
|
not outBarrier(arg, config) and
|
||||||
not fullInBarrier(p, config)
|
not inBarrier(p, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1189,7 +1183,7 @@ private module Stage2 {
|
|||||||
|
|
||||||
bindingset[node, state, ap, config]
|
bindingset[node, state, ap, config]
|
||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
PrevStage::revFlowState(state, config) and
|
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||||
exists(ap) and
|
exists(ap) and
|
||||||
not stateBarrier(node, state, config)
|
not stateBarrier(node, state, config)
|
||||||
}
|
}
|
||||||
@@ -1614,7 +1608,7 @@ private module Stage2 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -1769,9 +1763,9 @@ private module LocalFlowBigStep {
|
|||||||
or
|
or
|
||||||
node.asNode() instanceof OutNodeExt
|
node.asNode() instanceof OutNodeExt
|
||||||
or
|
or
|
||||||
store(_, _, node, _, config)
|
Stage2::storeStepCand(_, _, _, node, _, config)
|
||||||
or
|
or
|
||||||
read(_, _, node, config)
|
Stage2::readStepCand(_, _, node, config)
|
||||||
or
|
or
|
||||||
node instanceof FlowCheckNode
|
node instanceof FlowCheckNode
|
||||||
or
|
or
|
||||||
@@ -1792,8 +1786,8 @@ private module LocalFlowBigStep {
|
|||||||
additionalJumpStep(node, next, config) or
|
additionalJumpStep(node, next, config) or
|
||||||
flowIntoCallNodeCand1(_, node, next, config) or
|
flowIntoCallNodeCand1(_, node, next, config) or
|
||||||
flowOutOfCallNodeCand1(_, node, next, config) or
|
flowOutOfCallNodeCand1(_, node, next, config) or
|
||||||
store(node, _, next, _, config) or
|
Stage2::storeStepCand(node, _, _, next, _, config) or
|
||||||
read(node, _, next, config)
|
Stage2::readStepCand(node, _, next, config)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||||
@@ -1966,7 +1960,24 @@ private module Stage3 {
|
|||||||
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
|
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||||
|
PrevStage::revFlow(node, config) and
|
||||||
|
clearsContentCached(node.asNode(), c)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate clearContent(NodeEx node, Content c, Configuration config) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
|
||||||
|
c = cs.getAReadContent() and
|
||||||
|
clearSet(node, cs, pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate clear(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
clearContent(node, ap.getHead().getContent(), config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
@@ -1975,7 +1986,7 @@ private module Stage3 {
|
|||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
exists(state) and
|
exists(state) and
|
||||||
exists(config) and
|
exists(config) and
|
||||||
not clear(node, ap) and
|
not clear(node, ap, config) and
|
||||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2403,7 +2414,7 @@ private module Stage3 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -3230,7 +3241,7 @@ private module Stage4 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -4242,7 +4253,7 @@ private module Subpaths {
|
|||||||
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
||||||
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
||||||
store(n1, _, n2, _, _) or
|
store(n1, _, n2, _, _) or
|
||||||
read(n1, _, n2, _)
|
readSet(n1, _, n2, _)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4597,7 +4608,7 @@ private module FlowExploration {
|
|||||||
or
|
or
|
||||||
exists(PartialPathNodeRev mid |
|
exists(PartialPathNodeRev mid |
|
||||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||||
not clearsContentCached(node.asNode(), ap.getHead()) and
|
not clearsContentEx(node, ap.getHead()) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||||
@@ -4613,7 +4624,7 @@ private module FlowExploration {
|
|||||||
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
|
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||||
if node.asNode() instanceof CastingNode
|
if node.asNode() instanceof CastingNode
|
||||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||||
else any()
|
else any()
|
||||||
@@ -5047,6 +5058,7 @@ private module FlowExploration {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
private predicate revPartialPathStep(
|
private predicate revPartialPathStep(
|
||||||
PartialPathNodeRev mid, NodeEx node, FlowState state, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
|
PartialPathNodeRev mid, NodeEx node, FlowState state, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
|
||||||
TRevSummaryCtx3 sc3, RevPartialAccessPath ap, Configuration config
|
TRevSummaryCtx3 sc3, RevPartialAccessPath ap, Configuration config
|
||||||
|
|||||||
@@ -87,21 +87,9 @@ abstract class Configuration extends string {
|
|||||||
/** Holds if data flow into `node` is prohibited. */
|
/** Holds if data flow into `node` is prohibited. */
|
||||||
predicate isBarrierIn(Node node) { none() }
|
predicate isBarrierIn(Node node) { none() }
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data flow into `node` is prohibited when the flow state is
|
|
||||||
* `state`
|
|
||||||
*/
|
|
||||||
predicate isBarrierIn(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
/** Holds if data flow out of `node` is prohibited. */
|
/** Holds if data flow out of `node` is prohibited. */
|
||||||
predicate isBarrierOut(Node node) { none() }
|
predicate isBarrierOut(Node node) { none() }
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data flow out of `node` is prohibited when the flow state is
|
|
||||||
* `state`
|
|
||||||
*/
|
|
||||||
predicate isBarrierOut(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||||
|
|
||||||
@@ -128,7 +116,7 @@ abstract class Configuration extends string {
|
|||||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||||
* taken at `node`.
|
* taken at `node`.
|
||||||
*/
|
*/
|
||||||
predicate allowImplicitRead(Node node, Content c) { none() }
|
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||||
@@ -321,7 +309,7 @@ private class RetNodeEx extends NodeEx {
|
|||||||
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate fullInBarrier(NodeEx node, Configuration config) {
|
private predicate inBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
node.asNode() = n and
|
node.asNode() = n and
|
||||||
config.isBarrierIn(n)
|
config.isBarrierIn(n)
|
||||||
@@ -330,16 +318,7 @@ private predicate fullInBarrier(NodeEx node, Configuration config) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
|
private predicate outBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n |
|
|
||||||
node.asNode() = n and
|
|
||||||
config.isBarrierIn(n, state)
|
|
||||||
|
|
|
||||||
config.isSource(n, state)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate fullOutBarrier(NodeEx node, Configuration config) {
|
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
node.asNode() = n and
|
node.asNode() = n and
|
||||||
config.isBarrierOut(n)
|
config.isBarrierOut(n)
|
||||||
@@ -348,15 +327,6 @@ private predicate fullOutBarrier(NodeEx node, Configuration config) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
|
|
||||||
exists(Node n |
|
|
||||||
node.asNode() = n and
|
|
||||||
config.isBarrierOut(n, state)
|
|
||||||
|
|
|
||||||
config.isSink(n, state)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fullBarrier(NodeEx node, Configuration config) {
|
private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n | node.asNode() = n |
|
exists(Node n | node.asNode() = n |
|
||||||
@@ -382,12 +352,6 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
|
|||||||
exists(Node n | node.asNode() = n |
|
exists(Node n | node.asNode() = n |
|
||||||
config.isBarrier(n, state)
|
config.isBarrier(n, state)
|
||||||
or
|
or
|
||||||
config.isBarrierIn(n, state) and
|
|
||||||
not config.isSource(n, state)
|
|
||||||
or
|
|
||||||
config.isBarrierOut(n, state) and
|
|
||||||
not config.isSink(n, state)
|
|
||||||
or
|
|
||||||
exists(BarrierGuard g |
|
exists(BarrierGuard g |
|
||||||
config.isBarrierGuard(g, state) and
|
config.isBarrierGuard(g, state) and
|
||||||
n = g.getAGuardedNode()
|
n = g.getAGuardedNode()
|
||||||
@@ -420,8 +384,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
|
|||||||
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
||||||
not fullOutBarrier(node1, config) and
|
not outBarrier(node1, config) and
|
||||||
not fullInBarrier(node2, config) and
|
not inBarrier(node2, config) and
|
||||||
not fullBarrier(node1, config) and
|
not fullBarrier(node1, config) and
|
||||||
not fullBarrier(node2, config)
|
not fullBarrier(node2, config)
|
||||||
}
|
}
|
||||||
@@ -474,8 +438,6 @@ private predicate additionalLocalStateStep(
|
|||||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
||||||
stepFilter(node1, node2, config) and
|
stepFilter(node1, node2, config) and
|
||||||
not stateOutBarrier(node1, s1, config) and
|
|
||||||
not stateInBarrier(node2, s2, config) and
|
|
||||||
not stateBarrier(node1, s1, config) and
|
not stateBarrier(node1, s1, config) and
|
||||||
not stateBarrier(node2, s2, config)
|
not stateBarrier(node2, s2, config)
|
||||||
)
|
)
|
||||||
@@ -517,16 +479,15 @@ private predicate additionalJumpStateStep(
|
|||||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
||||||
stepFilter(node1, node2, config) and
|
stepFilter(node1, node2, config) and
|
||||||
not stateOutBarrier(node1, s1, config) and
|
|
||||||
not stateInBarrier(node2, s2, config) and
|
|
||||||
not stateBarrier(node1, s1, config) and
|
not stateBarrier(node1, s1, config) and
|
||||||
not stateBarrier(node2, s2, config) and
|
not stateBarrier(node2, s2, config) and
|
||||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
pragma[nomagic]
|
||||||
read(node1.asNode(), c, node2.asNode()) and
|
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||||
|
readSet(node1.asNode(), c, node2.asNode()) and
|
||||||
stepFilter(node1, node2, config)
|
stepFilter(node1, node2, config)
|
||||||
or
|
or
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
@@ -536,6 +497,25 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
pragma[inline]
|
||||||
|
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
readSet(node1, cs, node2, config) and
|
||||||
|
c = cs.getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
pragma[inline]
|
||||||
|
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
clearsContentCached(n.asNode(), cs) and
|
||||||
|
c = cs.getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
) {
|
) {
|
||||||
@@ -613,9 +593,9 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(Content c |
|
exists(ContentSet c |
|
||||||
fwdFlowRead(c, node, cc, config) and
|
fwdFlowReadSet(c, node, cc, config) and
|
||||||
fwdFlowConsCand(c, config)
|
fwdFlowConsCandSet(c, _, config)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
@@ -639,10 +619,10 @@ private module Stage1 {
|
|||||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
|
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
fwdFlow(mid, cc, config) and
|
fwdFlow(mid, cc, config) and
|
||||||
read(mid, c, node, config)
|
readSet(mid, c, node, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -660,6 +640,16 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `cs` may be interpreted in a read as the target of some store
|
||||||
|
* into `c`, in the flow covered by `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowConsCandSet(ContentSet cs, Content c, Configuration config) {
|
||||||
|
fwdFlowConsCand(c, config) and
|
||||||
|
c = cs.getAReadContent()
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
||||||
exists(RetNodeEx ret |
|
exists(RetNodeEx ret |
|
||||||
@@ -752,9 +742,9 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(NodeEx mid, Content c |
|
exists(NodeEx mid, ContentSet c |
|
||||||
read(node, c, mid, config) and
|
readSet(node, c, mid, config) and
|
||||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
fwdFlowConsCandSet(c, _, pragma[only_bind_into](config)) and
|
||||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
@@ -780,10 +770,10 @@ private module Stage1 {
|
|||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||||
exists(NodeEx mid, NodeEx node |
|
exists(NodeEx mid, NodeEx node, ContentSet cs |
|
||||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||||
read(node, c, mid, config) and
|
readSet(node, cs, mid, config) and
|
||||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
fwdFlowConsCandSet(cs, c, pragma[only_bind_into](config)) and
|
||||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -802,6 +792,7 @@ private module Stage1 {
|
|||||||
* Holds if `c` is the target of both a read and a store in the flow covered
|
* Holds if `c` is the target of both a read and a store in the flow covered
|
||||||
* by `revFlow`.
|
* by `revFlow`.
|
||||||
*/
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||||
revFlowConsCand(c, conf) and
|
revFlowConsCand(c, conf) and
|
||||||
revFlowStore(c, _, _, conf)
|
revFlowStore(c, _, _, conf)
|
||||||
@@ -900,9 +891,9 @@ private module Stage1 {
|
|||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
|
||||||
revFlow(n2, pragma[only_bind_into](config)) and
|
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||||
read(n1, c, n2, pragma[only_bind_into](config))
|
revFlow(n2, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -912,14 +903,17 @@ private module Stage1 {
|
|||||||
predicate revFlow(
|
predicate revFlow(
|
||||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
revFlow(node, toReturn, config) and exists(state) and exists(returnAp) and exists(ap)
|
revFlow(node, toReturn, pragma[only_bind_into](config)) and
|
||||||
|
exists(state) and
|
||||||
|
exists(returnAp) and
|
||||||
|
exists(ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||||
revFlow(node, true, config) and
|
revFlow(node, true, config) and
|
||||||
fwdFlow(node, true, config) and
|
fwdFlow(node, true, config) and
|
||||||
not fullInBarrier(node, config) and
|
not inBarrier(node, config) and
|
||||||
not fullOutBarrier(node, config)
|
not outBarrier(node, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if flow may return from `callable`. */
|
/** Holds if flow may return from `callable`. */
|
||||||
@@ -1014,8 +1008,8 @@ private predicate flowOutOfCallNodeCand1(
|
|||||||
) {
|
) {
|
||||||
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
||||||
Stage1::revFlow(ret, config) and
|
Stage1::revFlow(ret, config) and
|
||||||
not fullOutBarrier(ret, config) and
|
not outBarrier(ret, config) and
|
||||||
not fullInBarrier(out, config)
|
not inBarrier(out, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -1036,8 +1030,8 @@ private predicate flowIntoCallNodeCand1(
|
|||||||
) {
|
) {
|
||||||
viableParamArgNodeCand1(call, p, arg, config) and
|
viableParamArgNodeCand1(call, p, arg, config) and
|
||||||
Stage1::revFlow(p, config) and
|
Stage1::revFlow(p, config) and
|
||||||
not fullOutBarrier(arg, config) and
|
not outBarrier(arg, config) and
|
||||||
not fullInBarrier(p, config)
|
not inBarrier(p, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1189,7 +1183,7 @@ private module Stage2 {
|
|||||||
|
|
||||||
bindingset[node, state, ap, config]
|
bindingset[node, state, ap, config]
|
||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
PrevStage::revFlowState(state, config) and
|
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||||
exists(ap) and
|
exists(ap) and
|
||||||
not stateBarrier(node, state, config)
|
not stateBarrier(node, state, config)
|
||||||
}
|
}
|
||||||
@@ -1614,7 +1608,7 @@ private module Stage2 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -1769,9 +1763,9 @@ private module LocalFlowBigStep {
|
|||||||
or
|
or
|
||||||
node.asNode() instanceof OutNodeExt
|
node.asNode() instanceof OutNodeExt
|
||||||
or
|
or
|
||||||
store(_, _, node, _, config)
|
Stage2::storeStepCand(_, _, _, node, _, config)
|
||||||
or
|
or
|
||||||
read(_, _, node, config)
|
Stage2::readStepCand(_, _, node, config)
|
||||||
or
|
or
|
||||||
node instanceof FlowCheckNode
|
node instanceof FlowCheckNode
|
||||||
or
|
or
|
||||||
@@ -1792,8 +1786,8 @@ private module LocalFlowBigStep {
|
|||||||
additionalJumpStep(node, next, config) or
|
additionalJumpStep(node, next, config) or
|
||||||
flowIntoCallNodeCand1(_, node, next, config) or
|
flowIntoCallNodeCand1(_, node, next, config) or
|
||||||
flowOutOfCallNodeCand1(_, node, next, config) or
|
flowOutOfCallNodeCand1(_, node, next, config) or
|
||||||
store(node, _, next, _, config) or
|
Stage2::storeStepCand(node, _, _, next, _, config) or
|
||||||
read(node, _, next, config)
|
Stage2::readStepCand(node, _, next, config)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||||
@@ -1966,7 +1960,24 @@ private module Stage3 {
|
|||||||
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
|
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||||
|
PrevStage::revFlow(node, config) and
|
||||||
|
clearsContentCached(node.asNode(), c)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate clearContent(NodeEx node, Content c, Configuration config) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
|
||||||
|
c = cs.getAReadContent() and
|
||||||
|
clearSet(node, cs, pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate clear(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
clearContent(node, ap.getHead().getContent(), config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
@@ -1975,7 +1986,7 @@ private module Stage3 {
|
|||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
exists(state) and
|
exists(state) and
|
||||||
exists(config) and
|
exists(config) and
|
||||||
not clear(node, ap) and
|
not clear(node, ap, config) and
|
||||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2403,7 +2414,7 @@ private module Stage3 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -3230,7 +3241,7 @@ private module Stage4 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -4242,7 +4253,7 @@ private module Subpaths {
|
|||||||
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
||||||
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
||||||
store(n1, _, n2, _, _) or
|
store(n1, _, n2, _, _) or
|
||||||
read(n1, _, n2, _)
|
readSet(n1, _, n2, _)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4597,7 +4608,7 @@ private module FlowExploration {
|
|||||||
or
|
or
|
||||||
exists(PartialPathNodeRev mid |
|
exists(PartialPathNodeRev mid |
|
||||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||||
not clearsContentCached(node.asNode(), ap.getHead()) and
|
not clearsContentEx(node, ap.getHead()) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||||
@@ -4613,7 +4624,7 @@ private module FlowExploration {
|
|||||||
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
|
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||||
if node.asNode() instanceof CastingNode
|
if node.asNode() instanceof CastingNode
|
||||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||||
else any()
|
else any()
|
||||||
@@ -5047,6 +5058,7 @@ private module FlowExploration {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
private predicate revPartialPathStep(
|
private predicate revPartialPathStep(
|
||||||
PartialPathNodeRev mid, NodeEx node, FlowState state, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
|
PartialPathNodeRev mid, NodeEx node, FlowState state, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
|
||||||
TRevSummaryCtx3 sc3, RevPartialAccessPath ap, Configuration config
|
TRevSummaryCtx3 sc3, RevPartialAccessPath ap, Configuration config
|
||||||
|
|||||||
@@ -87,21 +87,9 @@ abstract class Configuration extends string {
|
|||||||
/** Holds if data flow into `node` is prohibited. */
|
/** Holds if data flow into `node` is prohibited. */
|
||||||
predicate isBarrierIn(Node node) { none() }
|
predicate isBarrierIn(Node node) { none() }
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data flow into `node` is prohibited when the flow state is
|
|
||||||
* `state`
|
|
||||||
*/
|
|
||||||
predicate isBarrierIn(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
/** Holds if data flow out of `node` is prohibited. */
|
/** Holds if data flow out of `node` is prohibited. */
|
||||||
predicate isBarrierOut(Node node) { none() }
|
predicate isBarrierOut(Node node) { none() }
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if data flow out of `node` is prohibited when the flow state is
|
|
||||||
* `state`
|
|
||||||
*/
|
|
||||||
predicate isBarrierOut(Node node, FlowState state) { none() }
|
|
||||||
|
|
||||||
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
|
||||||
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||||
|
|
||||||
@@ -128,7 +116,7 @@ abstract class Configuration extends string {
|
|||||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||||
* taken at `node`.
|
* taken at `node`.
|
||||||
*/
|
*/
|
||||||
predicate allowImplicitRead(Node node, Content c) { none() }
|
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||||
@@ -321,7 +309,7 @@ private class RetNodeEx extends NodeEx {
|
|||||||
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate fullInBarrier(NodeEx node, Configuration config) {
|
private predicate inBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
node.asNode() = n and
|
node.asNode() = n and
|
||||||
config.isBarrierIn(n)
|
config.isBarrierIn(n)
|
||||||
@@ -330,16 +318,7 @@ private predicate fullInBarrier(NodeEx node, Configuration config) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
|
private predicate outBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n |
|
|
||||||
node.asNode() = n and
|
|
||||||
config.isBarrierIn(n, state)
|
|
||||||
|
|
|
||||||
config.isSource(n, state)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate fullOutBarrier(NodeEx node, Configuration config) {
|
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
node.asNode() = n and
|
node.asNode() = n and
|
||||||
config.isBarrierOut(n)
|
config.isBarrierOut(n)
|
||||||
@@ -348,15 +327,6 @@ private predicate fullOutBarrier(NodeEx node, Configuration config) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
|
|
||||||
exists(Node n |
|
|
||||||
node.asNode() = n and
|
|
||||||
config.isBarrierOut(n, state)
|
|
||||||
|
|
|
||||||
config.isSink(n, state)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fullBarrier(NodeEx node, Configuration config) {
|
private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n | node.asNode() = n |
|
exists(Node n | node.asNode() = n |
|
||||||
@@ -382,12 +352,6 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
|
|||||||
exists(Node n | node.asNode() = n |
|
exists(Node n | node.asNode() = n |
|
||||||
config.isBarrier(n, state)
|
config.isBarrier(n, state)
|
||||||
or
|
or
|
||||||
config.isBarrierIn(n, state) and
|
|
||||||
not config.isSource(n, state)
|
|
||||||
or
|
|
||||||
config.isBarrierOut(n, state) and
|
|
||||||
not config.isSink(n, state)
|
|
||||||
or
|
|
||||||
exists(BarrierGuard g |
|
exists(BarrierGuard g |
|
||||||
config.isBarrierGuard(g, state) and
|
config.isBarrierGuard(g, state) and
|
||||||
n = g.getAGuardedNode()
|
n = g.getAGuardedNode()
|
||||||
@@ -420,8 +384,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
|
|||||||
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
/** Provides the relevant barriers for a step from `node1` to `node2`. */
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
|
||||||
not fullOutBarrier(node1, config) and
|
not outBarrier(node1, config) and
|
||||||
not fullInBarrier(node2, config) and
|
not inBarrier(node2, config) and
|
||||||
not fullBarrier(node1, config) and
|
not fullBarrier(node1, config) and
|
||||||
not fullBarrier(node2, config)
|
not fullBarrier(node2, config)
|
||||||
}
|
}
|
||||||
@@ -474,8 +438,6 @@ private predicate additionalLocalStateStep(
|
|||||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||||
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
|
||||||
stepFilter(node1, node2, config) and
|
stepFilter(node1, node2, config) and
|
||||||
not stateOutBarrier(node1, s1, config) and
|
|
||||||
not stateInBarrier(node2, s2, config) and
|
|
||||||
not stateBarrier(node1, s1, config) and
|
not stateBarrier(node1, s1, config) and
|
||||||
not stateBarrier(node2, s2, config)
|
not stateBarrier(node2, s2, config)
|
||||||
)
|
)
|
||||||
@@ -517,16 +479,15 @@ private predicate additionalJumpStateStep(
|
|||||||
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
config.isAdditionalFlowStep(n1, s1, n2, s2) and
|
||||||
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
|
||||||
stepFilter(node1, node2, config) and
|
stepFilter(node1, node2, config) and
|
||||||
not stateOutBarrier(node1, s1, config) and
|
|
||||||
not stateInBarrier(node2, s2, config) and
|
|
||||||
not stateBarrier(node1, s1, config) and
|
not stateBarrier(node1, s1, config) and
|
||||||
not stateBarrier(node2, s2, config) and
|
not stateBarrier(node2, s2, config) and
|
||||||
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
pragma[nomagic]
|
||||||
read(node1.asNode(), c, node2.asNode()) and
|
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
|
||||||
|
readSet(node1.asNode(), c, node2.asNode()) and
|
||||||
stepFilter(node1, node2, config)
|
stepFilter(node1, node2, config)
|
||||||
or
|
or
|
||||||
exists(Node n |
|
exists(Node n |
|
||||||
@@ -536,6 +497,25 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
pragma[inline]
|
||||||
|
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
readSet(node1, cs, node2, config) and
|
||||||
|
c = cs.getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// inline to reduce fan-out via `getAReadContent`
|
||||||
|
pragma[inline]
|
||||||
|
private predicate clearsContentEx(NodeEx n, Content c) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
clearsContentCached(n.asNode(), cs) and
|
||||||
|
c = cs.getAReadContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
private predicate store(
|
private predicate store(
|
||||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||||
) {
|
) {
|
||||||
@@ -613,9 +593,9 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(Content c |
|
exists(ContentSet c |
|
||||||
fwdFlowRead(c, node, cc, config) and
|
fwdFlowReadSet(c, node, cc, config) and
|
||||||
fwdFlowConsCand(c, config)
|
fwdFlowConsCandSet(c, _, config)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
@@ -639,10 +619,10 @@ private module Stage1 {
|
|||||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
|
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
fwdFlow(mid, cc, config) and
|
fwdFlow(mid, cc, config) and
|
||||||
read(mid, c, node, config)
|
readSet(mid, c, node, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -660,6 +640,16 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `cs` may be interpreted in a read as the target of some store
|
||||||
|
* into `c`, in the flow covered by `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowConsCandSet(ContentSet cs, Content c, Configuration config) {
|
||||||
|
fwdFlowConsCand(c, config) and
|
||||||
|
c = cs.getAReadContent()
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
|
||||||
exists(RetNodeEx ret |
|
exists(RetNodeEx ret |
|
||||||
@@ -752,9 +742,9 @@ private module Stage1 {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(NodeEx mid, Content c |
|
exists(NodeEx mid, ContentSet c |
|
||||||
read(node, c, mid, config) and
|
readSet(node, c, mid, config) and
|
||||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
fwdFlowConsCandSet(c, _, pragma[only_bind_into](config)) and
|
||||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
@@ -780,10 +770,10 @@ private module Stage1 {
|
|||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||||
exists(NodeEx mid, NodeEx node |
|
exists(NodeEx mid, NodeEx node, ContentSet cs |
|
||||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||||
read(node, c, mid, config) and
|
readSet(node, cs, mid, config) and
|
||||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
fwdFlowConsCandSet(cs, c, pragma[only_bind_into](config)) and
|
||||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -802,6 +792,7 @@ private module Stage1 {
|
|||||||
* Holds if `c` is the target of both a read and a store in the flow covered
|
* Holds if `c` is the target of both a read and a store in the flow covered
|
||||||
* by `revFlow`.
|
* by `revFlow`.
|
||||||
*/
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||||
revFlowConsCand(c, conf) and
|
revFlowConsCand(c, conf) and
|
||||||
revFlowStore(c, _, _, conf)
|
revFlowStore(c, _, _, conf)
|
||||||
@@ -900,9 +891,9 @@ private module Stage1 {
|
|||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
|
||||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
|
||||||
revFlow(n2, pragma[only_bind_into](config)) and
|
read(n1, c, n2, pragma[only_bind_into](config)) and
|
||||||
read(n1, c, n2, pragma[only_bind_into](config))
|
revFlow(n2, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -912,14 +903,17 @@ private module Stage1 {
|
|||||||
predicate revFlow(
|
predicate revFlow(
|
||||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
revFlow(node, toReturn, config) and exists(state) and exists(returnAp) and exists(ap)
|
revFlow(node, toReturn, pragma[only_bind_into](config)) and
|
||||||
|
exists(state) and
|
||||||
|
exists(returnAp) and
|
||||||
|
exists(ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
|
||||||
revFlow(node, true, config) and
|
revFlow(node, true, config) and
|
||||||
fwdFlow(node, true, config) and
|
fwdFlow(node, true, config) and
|
||||||
not fullInBarrier(node, config) and
|
not inBarrier(node, config) and
|
||||||
not fullOutBarrier(node, config)
|
not outBarrier(node, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if flow may return from `callable`. */
|
/** Holds if flow may return from `callable`. */
|
||||||
@@ -1014,8 +1008,8 @@ private predicate flowOutOfCallNodeCand1(
|
|||||||
) {
|
) {
|
||||||
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
|
||||||
Stage1::revFlow(ret, config) and
|
Stage1::revFlow(ret, config) and
|
||||||
not fullOutBarrier(ret, config) and
|
not outBarrier(ret, config) and
|
||||||
not fullInBarrier(out, config)
|
not inBarrier(out, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -1036,8 +1030,8 @@ private predicate flowIntoCallNodeCand1(
|
|||||||
) {
|
) {
|
||||||
viableParamArgNodeCand1(call, p, arg, config) and
|
viableParamArgNodeCand1(call, p, arg, config) and
|
||||||
Stage1::revFlow(p, config) and
|
Stage1::revFlow(p, config) and
|
||||||
not fullOutBarrier(arg, config) and
|
not outBarrier(arg, config) and
|
||||||
not fullInBarrier(p, config)
|
not inBarrier(p, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1189,7 +1183,7 @@ private module Stage2 {
|
|||||||
|
|
||||||
bindingset[node, state, ap, config]
|
bindingset[node, state, ap, config]
|
||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
PrevStage::revFlowState(state, config) and
|
PrevStage::revFlowState(state, pragma[only_bind_into](config)) and
|
||||||
exists(ap) and
|
exists(ap) and
|
||||||
not stateBarrier(node, state, config)
|
not stateBarrier(node, state, config)
|
||||||
}
|
}
|
||||||
@@ -1614,7 +1608,7 @@ private module Stage2 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -1769,9 +1763,9 @@ private module LocalFlowBigStep {
|
|||||||
or
|
or
|
||||||
node.asNode() instanceof OutNodeExt
|
node.asNode() instanceof OutNodeExt
|
||||||
or
|
or
|
||||||
store(_, _, node, _, config)
|
Stage2::storeStepCand(_, _, _, node, _, config)
|
||||||
or
|
or
|
||||||
read(_, _, node, config)
|
Stage2::readStepCand(_, _, node, config)
|
||||||
or
|
or
|
||||||
node instanceof FlowCheckNode
|
node instanceof FlowCheckNode
|
||||||
or
|
or
|
||||||
@@ -1792,8 +1786,8 @@ private module LocalFlowBigStep {
|
|||||||
additionalJumpStep(node, next, config) or
|
additionalJumpStep(node, next, config) or
|
||||||
flowIntoCallNodeCand1(_, node, next, config) or
|
flowIntoCallNodeCand1(_, node, next, config) or
|
||||||
flowOutOfCallNodeCand1(_, node, next, config) or
|
flowOutOfCallNodeCand1(_, node, next, config) or
|
||||||
store(node, _, next, _, config) or
|
Stage2::storeStepCand(node, _, _, next, _, config) or
|
||||||
read(node, _, next, config)
|
Stage2::readStepCand(node, _, next, config)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
|
||||||
@@ -1966,7 +1960,24 @@ private module Stage3 {
|
|||||||
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
|
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||||
|
PrevStage::revFlow(node, config) and
|
||||||
|
clearsContentCached(node.asNode(), c)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate clearContent(NodeEx node, Content c, Configuration config) {
|
||||||
|
exists(ContentSet cs |
|
||||||
|
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
|
||||||
|
c = cs.getAReadContent() and
|
||||||
|
clearSet(node, cs, pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate clear(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
clearContent(node, ap.getHead().getContent(), config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
@@ -1975,7 +1986,7 @@ private module Stage3 {
|
|||||||
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
exists(state) and
|
exists(state) and
|
||||||
exists(config) and
|
exists(config) and
|
||||||
not clear(node, ap) and
|
not clear(node, ap, config) and
|
||||||
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2403,7 +2414,7 @@ private module Stage3 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -3230,7 +3241,7 @@ private module Stage4 {
|
|||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap ap2, Content c |
|
exists(Ap ap2, Content c |
|
||||||
store(node1, tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
|
||||||
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
|
||||||
revFlowConsCand(ap2, c, ap1, config)
|
revFlowConsCand(ap2, c, ap1, config)
|
||||||
)
|
)
|
||||||
@@ -4242,7 +4253,7 @@ private module Subpaths {
|
|||||||
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
|
||||||
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
|
||||||
store(n1, _, n2, _, _) or
|
store(n1, _, n2, _, _) or
|
||||||
read(n1, _, n2, _)
|
readSet(n1, _, n2, _)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4597,7 +4608,7 @@ private module FlowExploration {
|
|||||||
or
|
or
|
||||||
exists(PartialPathNodeRev mid |
|
exists(PartialPathNodeRev mid |
|
||||||
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
|
||||||
not clearsContentCached(node.asNode(), ap.getHead()) and
|
not clearsContentEx(node, ap.getHead()) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||||
@@ -4613,7 +4624,7 @@ private module FlowExploration {
|
|||||||
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
|
||||||
not fullBarrier(node, config) and
|
not fullBarrier(node, config) and
|
||||||
not stateBarrier(node, state, config) and
|
not stateBarrier(node, state, config) and
|
||||||
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
|
not clearsContentEx(node, ap.getHead().getContent()) and
|
||||||
if node.asNode() instanceof CastingNode
|
if node.asNode() instanceof CastingNode
|
||||||
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
then compatibleTypes(node.getDataFlowType(), ap.getType())
|
||||||
else any()
|
else any()
|
||||||
@@ -5047,6 +5058,7 @@ private module FlowExploration {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
private predicate revPartialPathStep(
|
private predicate revPartialPathStep(
|
||||||
PartialPathNodeRev mid, NodeEx node, FlowState state, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
|
PartialPathNodeRev mid, NodeEx node, FlowState state, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2,
|
||||||
TRevSummaryCtx3 sc3, RevPartialAccessPath ap, Configuration config
|
TRevSummaryCtx3 sc3, RevPartialAccessPath ap, Configuration config
|
||||||
|
|||||||
@@ -326,7 +326,7 @@ private module Cached {
|
|||||||
predicate jumpStepCached(Node node1, Node node2) { jumpStep(node1, node2) }
|
predicate jumpStepCached(Node node1, Node node2) { jumpStep(node1, node2) }
|
||||||
|
|
||||||
cached
|
cached
|
||||||
predicate clearsContentCached(Node n, Content c) { clearsContent(n, c) }
|
predicate clearsContentCached(Node n, ContentSet c) { clearsContent(n, c) }
|
||||||
|
|
||||||
cached
|
cached
|
||||||
predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) }
|
predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) }
|
||||||
@@ -373,7 +373,7 @@ private module Cached {
|
|||||||
// For reads, `x.f`, we want to check that the tracked type after the read (which
|
// For reads, `x.f`, we want to check that the tracked type after the read (which
|
||||||
// is obtained by popping the head of the access path stack) is compatible with
|
// is obtained by popping the head of the access path stack) is compatible with
|
||||||
// the type of `x.f`.
|
// the type of `x.f`.
|
||||||
read(_, _, n)
|
readSet(_, _, n)
|
||||||
}
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
@@ -469,7 +469,7 @@ private module Cached {
|
|||||||
// read
|
// read
|
||||||
exists(Node mid |
|
exists(Node mid |
|
||||||
parameterValueFlowCand(p, mid, false) and
|
parameterValueFlowCand(p, mid, false) and
|
||||||
read(mid, _, node) and
|
readSet(mid, _, node) and
|
||||||
read = true
|
read = true
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
@@ -657,8 +657,10 @@ private module Cached {
|
|||||||
* Holds if `arg` flows to `out` through a call using only
|
* Holds if `arg` flows to `out` through a call using only
|
||||||
* value-preserving steps and a single read step, not taking call
|
* value-preserving steps and a single read step, not taking call
|
||||||
* contexts into account, thus representing a getter-step.
|
* contexts into account, thus representing a getter-step.
|
||||||
|
*
|
||||||
|
* This predicate is exposed for testing only.
|
||||||
*/
|
*/
|
||||||
predicate getterStep(ArgNode arg, Content c, Node out) {
|
predicate getterStep(ArgNode arg, ContentSet c, Node out) {
|
||||||
argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out)
|
argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -781,28 +783,30 @@ private module Cached {
|
|||||||
parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone())
|
parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cached
|
||||||
|
predicate readSet(Node node1, ContentSet c, Node node2) { readStep(node1, c, node2) }
|
||||||
|
|
||||||
private predicate store(
|
private predicate store(
|
||||||
Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType
|
Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType
|
||||||
) {
|
) {
|
||||||
storeStep(node1, c, node2) and
|
exists(ContentSet cs | c = cs.getAStoreContent() |
|
||||||
contentType = getNodeDataFlowType(node1) and
|
storeStep(node1, cs, node2) and
|
||||||
containerType = getNodeDataFlowType(node2)
|
contentType = getNodeDataFlowType(node1) and
|
||||||
or
|
containerType = getNodeDataFlowType(node2)
|
||||||
exists(Node n1, Node n2 |
|
|
||||||
n1 = node1.(PostUpdateNode).getPreUpdateNode() and
|
|
||||||
n2 = node2.(PostUpdateNode).getPreUpdateNode()
|
|
||||||
|
|
|
||||||
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1)
|
|
||||||
or
|
or
|
||||||
read(n2, c, n1) and
|
exists(Node n1, Node n2 |
|
||||||
contentType = getNodeDataFlowType(n1) and
|
n1 = node1.(PostUpdateNode).getPreUpdateNode() and
|
||||||
containerType = getNodeDataFlowType(n2)
|
n2 = node2.(PostUpdateNode).getPreUpdateNode()
|
||||||
|
|
|
||||||
|
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, cs, contentType), n1)
|
||||||
|
or
|
||||||
|
readSet(n2, cs, n1) and
|
||||||
|
contentType = getNodeDataFlowType(n1) and
|
||||||
|
containerType = getNodeDataFlowType(n2)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
cached
|
|
||||||
predicate read(Node node1, Content c, Node node2) { readStep(node1, c, node2) }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if data can flow from `node1` to `node2` via a direct assignment to
|
* Holds if data can flow from `node1` to `node2` via a direct assignment to
|
||||||
* `f`.
|
* `f`.
|
||||||
@@ -932,16 +936,16 @@ class CastingNode extends Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private predicate readStepWithTypes(
|
private predicate readStepWithTypes(
|
||||||
Node n1, DataFlowType container, Content c, Node n2, DataFlowType content
|
Node n1, DataFlowType container, ContentSet c, Node n2, DataFlowType content
|
||||||
) {
|
) {
|
||||||
read(n1, c, n2) and
|
readSet(n1, c, n2) and
|
||||||
container = getNodeDataFlowType(n1) and
|
container = getNodeDataFlowType(n1) and
|
||||||
content = getNodeDataFlowType(n2)
|
content = getNodeDataFlowType(n2)
|
||||||
}
|
}
|
||||||
|
|
||||||
private newtype TReadStepTypesOption =
|
private newtype TReadStepTypesOption =
|
||||||
TReadStepTypesNone() or
|
TReadStepTypesNone() or
|
||||||
TReadStepTypesSome(DataFlowType container, Content c, DataFlowType content) {
|
TReadStepTypesSome(DataFlowType container, ContentSet c, DataFlowType content) {
|
||||||
readStepWithTypes(_, container, c, _, content)
|
readStepWithTypes(_, container, c, _, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -950,7 +954,7 @@ private class ReadStepTypesOption extends TReadStepTypesOption {
|
|||||||
|
|
||||||
DataFlowType getContainerType() { this = TReadStepTypesSome(result, _, _) }
|
DataFlowType getContainerType() { this = TReadStepTypesSome(result, _, _) }
|
||||||
|
|
||||||
Content getContent() { this = TReadStepTypesSome(_, result, _) }
|
ContentSet getContent() { this = TReadStepTypesSome(_, result, _) }
|
||||||
|
|
||||||
DataFlowType getContentType() { this = TReadStepTypesSome(_, _, result) }
|
DataFlowType getContentType() { this = TReadStepTypesSome(_, _, result) }
|
||||||
|
|
||||||
@@ -1325,8 +1329,6 @@ abstract class AccessPathFront extends TAccessPathFront {
|
|||||||
abstract boolean toBoolNonEmpty();
|
abstract boolean toBoolNonEmpty();
|
||||||
|
|
||||||
TypedContent getHead() { this = TFrontHead(result) }
|
TypedContent getHead() { this = TFrontHead(result) }
|
||||||
|
|
||||||
predicate isClearedAt(Node n) { clearsContentCached(n, this.getHead().getContent()) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class AccessPathFrontNil extends AccessPathFront, TFrontNil {
|
class AccessPathFrontNil extends AccessPathFront, TFrontNil {
|
||||||
|
|||||||
@@ -1063,6 +1063,34 @@ private class CollectionContent extends Content, TCollectionContent {
|
|||||||
override string toString() { result = "<element>" }
|
override string toString() { result = "<element>" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An entity that represents a set of `Content`s.
|
||||||
|
*
|
||||||
|
* The set may be interpreted differently depending on whether it is
|
||||||
|
* stored into (`getAStoreContent`) or read from (`getAReadContent`).
|
||||||
|
*/
|
||||||
|
class ContentSet instanceof Content {
|
||||||
|
/** Gets a content that may be stored into when storing into this set. */
|
||||||
|
Content getAStoreContent() { result = this }
|
||||||
|
|
||||||
|
/** Gets a content that may be read from when reading from this set. */
|
||||||
|
Content getAReadContent() { result = this }
|
||||||
|
|
||||||
|
/** Gets a textual representation of this content set. */
|
||||||
|
string toString() { result = super.toString() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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/).
|
||||||
|
*/
|
||||||
|
predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
|
||||||
|
super.hasLocationInfo(path, sl, sc, el, ec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A guard that validates some instruction.
|
* A guard that validates some instruction.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -109,16 +109,6 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
/** Holds if taint propagation into `node` is prohibited. */
|
/** Holds if taint propagation into `node` is prohibited. */
|
||||||
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if taint propagation into `node` is prohibited when the flow state is
|
|
||||||
* `state`.
|
|
||||||
*/
|
|
||||||
predicate isSanitizerIn(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
|
||||||
|
|
||||||
final override predicate isBarrierIn(DataFlow::Node node, DataFlow::FlowState state) {
|
|
||||||
this.isSanitizerIn(node, state)
|
|
||||||
}
|
|
||||||
|
|
||||||
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
|
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
|
||||||
|
|
||||||
/** Holds if taint propagation out of `node` is prohibited. */
|
/** Holds if taint propagation out of `node` is prohibited. */
|
||||||
@@ -126,16 +116,6 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
|
|
||||||
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if taint propagation out of `node` is prohibited when the flow state is
|
|
||||||
* `state`.
|
|
||||||
*/
|
|
||||||
predicate isSanitizerOut(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
|
||||||
|
|
||||||
final override predicate isBarrierOut(DataFlow::Node node, DataFlow::FlowState state) {
|
|
||||||
this.isSanitizerOut(node, state)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
||||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||||
|
|
||||||
@@ -181,7 +161,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
|
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||||
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
||||||
defaultImplicitTaintRead(node, c)
|
defaultImplicitTaintRead(node, c)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,16 +109,6 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
/** Holds if taint propagation into `node` is prohibited. */
|
/** Holds if taint propagation into `node` is prohibited. */
|
||||||
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if taint propagation into `node` is prohibited when the flow state is
|
|
||||||
* `state`.
|
|
||||||
*/
|
|
||||||
predicate isSanitizerIn(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
|
||||||
|
|
||||||
final override predicate isBarrierIn(DataFlow::Node node, DataFlow::FlowState state) {
|
|
||||||
this.isSanitizerIn(node, state)
|
|
||||||
}
|
|
||||||
|
|
||||||
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
|
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
|
||||||
|
|
||||||
/** Holds if taint propagation out of `node` is prohibited. */
|
/** Holds if taint propagation out of `node` is prohibited. */
|
||||||
@@ -126,16 +116,6 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
|
|
||||||
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if taint propagation out of `node` is prohibited when the flow state is
|
|
||||||
* `state`.
|
|
||||||
*/
|
|
||||||
predicate isSanitizerOut(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
|
||||||
|
|
||||||
final override predicate isBarrierOut(DataFlow::Node node, DataFlow::FlowState state) {
|
|
||||||
this.isSanitizerOut(node, state)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
||||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||||
|
|
||||||
@@ -181,7 +161,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
|
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||||
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
||||||
defaultImplicitTaintRead(node, c)
|
defaultImplicitTaintRead(node, c)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,16 +109,6 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
/** Holds if taint propagation into `node` is prohibited. */
|
/** Holds if taint propagation into `node` is prohibited. */
|
||||||
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if taint propagation into `node` is prohibited when the flow state is
|
|
||||||
* `state`.
|
|
||||||
*/
|
|
||||||
predicate isSanitizerIn(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
|
||||||
|
|
||||||
final override predicate isBarrierIn(DataFlow::Node node, DataFlow::FlowState state) {
|
|
||||||
this.isSanitizerIn(node, state)
|
|
||||||
}
|
|
||||||
|
|
||||||
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
|
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
|
||||||
|
|
||||||
/** Holds if taint propagation out of `node` is prohibited. */
|
/** Holds if taint propagation out of `node` is prohibited. */
|
||||||
@@ -126,16 +116,6 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
|
|
||||||
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if taint propagation out of `node` is prohibited when the flow state is
|
|
||||||
* `state`.
|
|
||||||
*/
|
|
||||||
predicate isSanitizerOut(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
|
||||||
|
|
||||||
final override predicate isBarrierOut(DataFlow::Node node, DataFlow::FlowState state) {
|
|
||||||
this.isSanitizerOut(node, state)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
||||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||||
|
|
||||||
@@ -181,7 +161,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
|
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||||
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
||||||
defaultImplicitTaintRead(node, c)
|
defaultImplicitTaintRead(node, c)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ private import TranslatedDeclarationEntry
|
|||||||
private import TranslatedElement
|
private import TranslatedElement
|
||||||
private import TranslatedFunction
|
private import TranslatedFunction
|
||||||
private import TranslatedInitialization
|
private import TranslatedInitialization
|
||||||
private import TranslatedFunction
|
|
||||||
private import TranslatedStmt
|
private import TranslatedStmt
|
||||||
import TranslatedCall
|
import TranslatedCall
|
||||||
|
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ private predicate isOpaqueType(Type type) {
|
|||||||
* Holds if an `IROpaqueType` with the specified `tag` and `byteSize` should exist.
|
* Holds if an `IROpaqueType` with the specified `tag` and `byteSize` should exist.
|
||||||
*/
|
*/
|
||||||
predicate hasOpaqueType(Type tag, int byteSize) {
|
predicate hasOpaqueType(Type tag, int byteSize) {
|
||||||
isOpaqueType(tag) and byteSize = getTypeSize(tag)
|
isOpaqueType(tag) and byteSize = getTypeSize(tag.getUnspecifiedType())
|
||||||
or
|
or
|
||||||
tag instanceof UnknownType and Raw::needsUnknownOpaqueType(byteSize)
|
tag instanceof UnknownType and Raw::needsUnknownOpaqueType(byteSize)
|
||||||
}
|
}
|
||||||
@@ -153,17 +153,18 @@ private IRType getIRTypeForPRValue(Type type) {
|
|||||||
exists(Type unspecifiedType | unspecifiedType = type.getUnspecifiedType() |
|
exists(Type unspecifiedType | unspecifiedType = type.getUnspecifiedType() |
|
||||||
isOpaqueType(unspecifiedType) and
|
isOpaqueType(unspecifiedType) and
|
||||||
exists(IROpaqueType opaqueType | opaqueType = result |
|
exists(IROpaqueType opaqueType | opaqueType = result |
|
||||||
opaqueType.getByteSize() = getTypeSize(type) and
|
opaqueType.getByteSize() = getTypeSize(unspecifiedType) and
|
||||||
opaqueType.getTag() = unspecifiedType
|
opaqueType.getTag() = unspecifiedType
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
unspecifiedType instanceof BoolType and result.(IRBooleanType).getByteSize() = type.getSize()
|
unspecifiedType instanceof BoolType and
|
||||||
|
result.(IRBooleanType).getByteSize() = unspecifiedType.getSize()
|
||||||
or
|
or
|
||||||
isSignedIntegerType(unspecifiedType) and
|
isSignedIntegerType(unspecifiedType) and
|
||||||
result.(IRSignedIntegerType).getByteSize() = type.getSize()
|
result.(IRSignedIntegerType).getByteSize() = unspecifiedType.getSize()
|
||||||
or
|
or
|
||||||
isUnsignedIntegerType(unspecifiedType) and
|
isUnsignedIntegerType(unspecifiedType) and
|
||||||
result.(IRUnsignedIntegerType).getByteSize() = type.getSize()
|
result.(IRUnsignedIntegerType).getByteSize() = unspecifiedType.getSize()
|
||||||
or
|
or
|
||||||
exists(FloatingPointType floatType, IRFloatingPointType irFloatType |
|
exists(FloatingPointType floatType, IRFloatingPointType irFloatType |
|
||||||
floatType = unspecifiedType and
|
floatType = unspecifiedType and
|
||||||
@@ -173,7 +174,8 @@ private IRType getIRTypeForPRValue(Type type) {
|
|||||||
irFloatType.getDomain() = floatType.getDomain()
|
irFloatType.getDomain() = floatType.getDomain()
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
isPointerIshType(unspecifiedType) and result.(IRAddressType).getByteSize() = getTypeSize(type)
|
isPointerIshType(unspecifiedType) and
|
||||||
|
result.(IRAddressType).getByteSize() = getTypeSize(unspecifiedType)
|
||||||
or
|
or
|
||||||
unspecifiedType instanceof FunctionPointerIshType and
|
unspecifiedType instanceof FunctionPointerIshType and
|
||||||
result.(IRFunctionAddressType).getByteSize() = getTypeSize(type)
|
result.(IRFunctionAddressType).getByteSize() = getTypeSize(type)
|
||||||
|
|||||||
@@ -42,10 +42,13 @@ private class MallocAllocationFunction extends AllocationFunction {
|
|||||||
this.hasGlobalName([
|
this.hasGlobalName([
|
||||||
// --- Windows Memory Management for Windows Drivers
|
// --- Windows Memory Management for Windows Drivers
|
||||||
"ExAllocatePool", // ExAllocatePool(type, size)
|
"ExAllocatePool", // ExAllocatePool(type, size)
|
||||||
|
"ExAllocatePool2", // ExAllocatePool2(flags, size, tag)
|
||||||
|
"ExAllocatePool3", // ExAllocatePool3(flags, size, tag, extparams, extparamscount)
|
||||||
"ExAllocatePoolWithTag", // ExAllocatePool(type, size, tag)
|
"ExAllocatePoolWithTag", // ExAllocatePool(type, size, tag)
|
||||||
"ExAllocatePoolWithTagPriority", // ExAllocatePoolWithTagPriority(type, size, tag, priority)
|
"ExAllocatePoolWithTagPriority", // ExAllocatePoolWithTagPriority(type, size, tag, priority)
|
||||||
"ExAllocatePoolWithQuota", // ExAllocatePoolWithQuota(type, size)
|
"ExAllocatePoolWithQuota", // ExAllocatePoolWithQuota(type, size)
|
||||||
"ExAllocatePoolWithQuotaTag", // ExAllocatePoolWithQuotaTag(type, size, tag)
|
"ExAllocatePoolWithQuotaTag", // ExAllocatePoolWithQuotaTag(type, size, tag)
|
||||||
|
"ExAllocatePoolZero", // ExAllocatePoolZero(type, size, tag)
|
||||||
"IoAllocateMdl", // IoAllocateMdl(address, size, flag, flag, irp)
|
"IoAllocateMdl", // IoAllocateMdl(address, size, flag, flag, irp)
|
||||||
"IoAllocateErrorLogEntry", // IoAllocateErrorLogEntry(object, size)
|
"IoAllocateErrorLogEntry", // IoAllocateErrorLogEntry(object, size)
|
||||||
// --- Windows Global / Local legacy allocation
|
// --- Windows Global / Local legacy allocation
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
import semmle.code.cpp.Function
|
import semmle.code.cpp.Function
|
||||||
import semmle.code.cpp.models.interfaces.ArrayFunction
|
import semmle.code.cpp.models.interfaces.ArrayFunction
|
||||||
import semmle.code.cpp.models.interfaces.ArrayFunction
|
|
||||||
import semmle.code.cpp.models.interfaces.Alias
|
import semmle.code.cpp.models.interfaces.Alias
|
||||||
import semmle.code.cpp.models.interfaces.SideEffect
|
import semmle.code.cpp.models.interfaces.SideEffect
|
||||||
import semmle.code.cpp.models.interfaces.Taint
|
import semmle.code.cpp.models.interfaces.Taint
|
||||||
|
|||||||
@@ -1802,5 +1802,3 @@ module SimpleRangeAnalysisInternal {
|
|||||||
defMightOverflowNegatively(def, v) and result = varMaxVal(v)
|
defMightOverflowNegatively(def, v) and result = varMaxVal(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private import SimpleRangeAnalysisInternal
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import cpp
|
import cpp
|
||||||
import semmle.code.cpp.commons.Alloc
|
|
||||||
import semmle.code.cpp.commons.Buffer
|
import semmle.code.cpp.commons.Buffer
|
||||||
import semmle.code.cpp.commons.Scanf
|
import semmle.code.cpp.commons.Scanf
|
||||||
import semmle.code.cpp.models.implementations.Strcat
|
import semmle.code.cpp.models.implementations.Strcat
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ predicate guardedAbs(Operation e, Expr use) {
|
|||||||
* Holds if the value of `use` is guarded to be less than something, and `e`
|
* Holds if the value of `use` is guarded to be less than something, and `e`
|
||||||
* is in code controlled by that guard (where the guard condition held).
|
* is in code controlled by that guard (where the guard condition held).
|
||||||
*/
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
predicate guardedLesser(Operation e, Expr use) {
|
predicate guardedLesser(Operation e, Expr use) {
|
||||||
exists(GuardCondition c | c.ensuresLt(use, _, _, e.getBasicBlock(), true))
|
exists(GuardCondition c | c.ensuresLt(use, _, _, e.getBasicBlock(), true))
|
||||||
or
|
or
|
||||||
@@ -35,6 +36,7 @@ predicate guardedLesser(Operation e, Expr use) {
|
|||||||
* Holds if the value of `use` is guarded to be greater than something, and `e`
|
* Holds if the value of `use` is guarded to be greater than something, and `e`
|
||||||
* is in code controlled by that guard (where the guard condition held).
|
* is in code controlled by that guard (where the guard condition held).
|
||||||
*/
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
predicate guardedGreater(Operation e, Expr use) {
|
predicate guardedGreater(Operation e, Expr use) {
|
||||||
exists(GuardCondition c | c.ensuresLt(use, _, _, e.getBasicBlock(), false))
|
exists(GuardCondition c | c.ensuresLt(use, _, _, e.getBasicBlock(), false))
|
||||||
or
|
or
|
||||||
|
|||||||
@@ -1,3 +1,21 @@
|
|||||||
|
## 0.1.0
|
||||||
|
|
||||||
|
### Minor Analysis Improvements
|
||||||
|
|
||||||
|
* The `cpp/cleartext-transmission` query now recognizes additional sources, for sensitive private data such as e-mail addresses and credit card numbers.
|
||||||
|
* The `cpp/unused-local-variable` no longer ignores functions that include lambda expressions capturing trivially copyable objects.
|
||||||
|
* The `cpp/command-line-injection` query now takes into account calling contexts across string concatenations. This removes false positives due to mismatched calling contexts before and after string concatenations.
|
||||||
|
* A new query, "Potential exposure of sensitive system data to an unauthorized control sphere" (`cpp/potential-system-data-exposure`) has been added. This query is focused on exposure of information that is highly likely to be sensitive, whereas the similar query "Exposure of system data to an unauthorized control sphere" (`cpp/system-data-exposure`) is focused on exposure of information on a channel that is more likely to be intercepted by an attacker.
|
||||||
|
|
||||||
|
## 0.0.13
|
||||||
|
|
||||||
|
## 0.0.12
|
||||||
|
|
||||||
|
### Minor Analysis Improvements
|
||||||
|
|
||||||
|
* The `cpp/overflow-destination`, `cpp/unclear-array-index-validation`, and `cpp/uncontrolled-allocation-size` queries have been modernized and converted to `path-problem` queries and provide more true positive results.
|
||||||
|
* The `cpp/system-data-exposure` query has been increased from `medium` to `high` precision, following a number of improvements to the query logic.
|
||||||
|
|
||||||
## 0.0.11
|
## 0.0.11
|
||||||
|
|
||||||
### Breaking Changes
|
### Breaking Changes
|
||||||
|
|||||||
@@ -13,7 +13,6 @@
|
|||||||
|
|
||||||
import cpp
|
import cpp
|
||||||
import LeapYear
|
import LeapYear
|
||||||
import semmle.code.cpp.dataflow.DataFlow
|
|
||||||
|
|
||||||
from Expr source, Expr sink, PossibleYearArithmeticOperationCheckConfiguration config
|
from Expr source, Expr sink, PossibleYearArithmeticOperationCheckConfiguration config
|
||||||
where config.hasFlow(DataFlow::exprNode(source), DataFlow::exprNode(sink))
|
where config.hasFlow(DataFlow::exprNode(source), DataFlow::exprNode(sink))
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
|
|
||||||
import cpp
|
import cpp
|
||||||
import NtohlArrayNoBound
|
import NtohlArrayNoBound
|
||||||
import semmle.code.cpp.dataflow.DataFlow
|
|
||||||
|
|
||||||
from NetworkToBufferSizeConfiguration bufConfig, DataFlow::Node source, DataFlow::Node sink
|
from NetworkToBufferSizeConfiguration bufConfig, DataFlow::Node source, DataFlow::Node sink
|
||||||
where bufConfig.hasFlow(source, sink)
|
where bufConfig.hasFlow(source, sink)
|
||||||
|
|||||||
@@ -116,8 +116,8 @@ class ExecTaintConfiguration extends TaintTracking::Configuration {
|
|||||||
state instanceof ConcatState
|
state instanceof ConcatState
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSanitizerOut(DataFlow::Node node, DataFlow::FlowState state) {
|
override predicate isSanitizerOut(DataFlow::Node node) {
|
||||||
isSink(node, state) // Prevent duplicates along a call chain, since `shellCommand` will include wrappers
|
isSink(node, _) // Prevent duplicates along a call chain, since `shellCommand` will include wrappers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import semmle.code.cpp.security.BufferWrite
|
import semmle.code.cpp.security.BufferWrite
|
||||||
import semmle.code.cpp.commons.Alloc
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* See CWE-120/UnboundedWrite.ql for a summary of CWE-120 alert cases.
|
* See CWE-120/UnboundedWrite.ql for a summary of CWE-120 alert cases.
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import semmle.code.cpp.security.BufferWrite
|
import semmle.code.cpp.security.BufferWrite
|
||||||
import semmle.code.cpp.commons.Alloc
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* See CWE-120/UnboundedWrite.ql for a summary of CWE-120 alert cases.
|
* See CWE-120/UnboundedWrite.ql for a summary of CWE-120 alert cases.
|
||||||
|
|||||||
57
cpp/ql/src/Security/CWE/CWE-611/XXE.qhelp
Normal file
57
cpp/ql/src/Security/CWE/CWE-611/XXE.qhelp
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
|
||||||
|
<qhelp>
|
||||||
|
|
||||||
|
<overview>
|
||||||
|
<p>
|
||||||
|
Parsing untrusted XML files with a weakly configured XML parser may lead to an
|
||||||
|
XML external entity (XXE) attack. This type of attack uses external entity references
|
||||||
|
to access arbitrary files on a system, carry out denial-of-service (DoS) attacks, or server-side
|
||||||
|
request forgery. Even when the result of parsing is not returned to the user, DoS attacks are still possible
|
||||||
|
and out-of-band data retrieval techniques may allow attackers to steal sensitive data.
|
||||||
|
</p>
|
||||||
|
</overview>
|
||||||
|
|
||||||
|
<recommendation>
|
||||||
|
<p>
|
||||||
|
The easiest way to prevent XXE attacks is to disable external entity handling when
|
||||||
|
parsing untrusted data. How this is done depends on the library being used. Note that some
|
||||||
|
libraries, such as recent versions of <code>libxml</code>, disable entity expansion by default,
|
||||||
|
so unless you have explicitly enabled entity expansion, no further action needs to be taken.
|
||||||
|
</p>
|
||||||
|
</recommendation>
|
||||||
|
|
||||||
|
<example>
|
||||||
|
<p>
|
||||||
|
The following example uses the <code>Xerces-C++</code> XML parser to parse a string <code>data</code>.
|
||||||
|
If that string is from an untrusted source, this code may be vulnerable to an XXE attack, since
|
||||||
|
the parser is constructed in its default state with <code>setDisableDefaultEntityResolution</code>
|
||||||
|
set to <code>false</code>:
|
||||||
|
</p>
|
||||||
|
<sample src="XXEBad.cpp"/>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
To guard against XXE attacks, the <code>setDisableDefaultEntityResolution</code> option should be
|
||||||
|
set to <code>true</code>.
|
||||||
|
</p>
|
||||||
|
<sample src="XXEGood.cpp"/>
|
||||||
|
</example>
|
||||||
|
|
||||||
|
<references>
|
||||||
|
<li>
|
||||||
|
OWASP:
|
||||||
|
<a href="https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Processing">XML External Entity (XXE) Processing</a>.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
OWASP:
|
||||||
|
<a href="https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html">XML External Entity Prevention Cheat Sheet</a>.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Timothy Morgen:
|
||||||
|
<a href="https://research.nccgroup.com/2014/05/19/xml-schema-dtd-and-entity-attacks-a-compendium-of-known-techniques/">XML Schema, DTD, and Entity Attacks</a>.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Timur Yunusov, Alexey Osipov:
|
||||||
|
<a href="https://www.slideshare.net/qqlan/bh-ready-v4">XML Out-Of-Band Data Retrieval</a>.
|
||||||
|
</li>
|
||||||
|
</references>
|
||||||
|
</qhelp>
|
||||||
226
cpp/ql/src/Security/CWE/CWE-611/XXE.ql
Normal file
226
cpp/ql/src/Security/CWE/CWE-611/XXE.ql
Normal file
@@ -0,0 +1,226 @@
|
|||||||
|
/**
|
||||||
|
* @name XML external entity expansion
|
||||||
|
* @description Parsing user-controlled XML documents and allowing expansion of
|
||||||
|
* external entity references may lead to disclosure of
|
||||||
|
* confidential data or denial of service.
|
||||||
|
* @kind path-problem
|
||||||
|
* @id cpp/external-entity-expansion
|
||||||
|
* @problem.severity warning
|
||||||
|
* @security-severity 9.1
|
||||||
|
* @precision medium
|
||||||
|
* @tags security
|
||||||
|
* external/cwe/cwe-611
|
||||||
|
*/
|
||||||
|
|
||||||
|
import cpp
|
||||||
|
import semmle.code.cpp.ir.dataflow.DataFlow
|
||||||
|
import DataFlow::PathGraph
|
||||||
|
import semmle.code.cpp.ir.IR
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A flow state representing a possible configuration of an XML object.
|
||||||
|
*/
|
||||||
|
abstract class XXEFlowState extends DataFlow::FlowState {
|
||||||
|
bindingset[this]
|
||||||
|
XXEFlowState() { any() } // required characteristic predicate
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An `Expr` that changes the configuration of an XML object, transforming the
|
||||||
|
* `XXEFlowState` that flows through it.
|
||||||
|
*/
|
||||||
|
abstract class XXEFlowStateTranformer extends Expr {
|
||||||
|
/**
|
||||||
|
* Gets the flow state that `flowstate` is transformed into.
|
||||||
|
*
|
||||||
|
* Due to limitations of the implementation the transformation defined by this
|
||||||
|
* predicate must be idempotent, that is, for any input `x` it must be that:
|
||||||
|
* ```
|
||||||
|
* transform(tranform(x)) = tranform(x)
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
abstract XXEFlowState transform(XXEFlowState flowstate);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `AbstractDOMParser` class.
|
||||||
|
*/
|
||||||
|
class AbstractDOMParserClass extends Class {
|
||||||
|
AbstractDOMParserClass() { this.hasName("AbstractDOMParser") }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `XercesDOMParser` class.
|
||||||
|
*/
|
||||||
|
class XercesDOMParserClass extends Class {
|
||||||
|
XercesDOMParserClass() { this.hasName("XercesDOMParser") }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a valid flow state for `XercesDOMParser` flow.
|
||||||
|
*
|
||||||
|
* These flow states take the form `XercesDOM-A-B`, where:
|
||||||
|
* - A is 1 if `setDisableDefaultEntityResolution` is `true`, 0 otherwise.
|
||||||
|
* - B is 1 if `setCreateEntityReferenceNodes` is `true`, 0 otherwise.
|
||||||
|
*/
|
||||||
|
predicate encodeXercesDOMFlowState(
|
||||||
|
string flowstate, int disabledDefaultEntityResolution, int createEntityReferenceNodes
|
||||||
|
) {
|
||||||
|
flowstate = "XercesDOM-0-0" and
|
||||||
|
disabledDefaultEntityResolution = 0 and
|
||||||
|
createEntityReferenceNodes = 0
|
||||||
|
or
|
||||||
|
flowstate = "XercesDOM-0-1" and
|
||||||
|
disabledDefaultEntityResolution = 0 and
|
||||||
|
createEntityReferenceNodes = 1
|
||||||
|
or
|
||||||
|
flowstate = "XercesDOM-1-0" and
|
||||||
|
disabledDefaultEntityResolution = 1 and
|
||||||
|
createEntityReferenceNodes = 0
|
||||||
|
or
|
||||||
|
flowstate = "XercesDOM-1-1" and
|
||||||
|
disabledDefaultEntityResolution = 1 and
|
||||||
|
createEntityReferenceNodes = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A flow state representing the configuration of a `XercesDOMParser` object.
|
||||||
|
*/
|
||||||
|
class XercesDOMParserFlowState extends XXEFlowState {
|
||||||
|
XercesDOMParserFlowState() { encodeXercesDOMFlowState(this, _, _) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A flow state transformer for a call to
|
||||||
|
* `AbstractDOMParser.setDisableDefaultEntityResolution`. Transforms the flow
|
||||||
|
* state through the qualifier according to the setting in the parameter.
|
||||||
|
*/
|
||||||
|
class DisableDefaultEntityResolutionTranformer extends XXEFlowStateTranformer {
|
||||||
|
Expr newValue;
|
||||||
|
|
||||||
|
DisableDefaultEntityResolutionTranformer() {
|
||||||
|
exists(Call call, Function f |
|
||||||
|
call.getTarget() = f and
|
||||||
|
f.getDeclaringType() instanceof AbstractDOMParserClass and
|
||||||
|
f.hasName("setDisableDefaultEntityResolution") and
|
||||||
|
this = call.getQualifier() and
|
||||||
|
newValue = call.getArgument(0)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
final override XXEFlowState transform(XXEFlowState flowstate) {
|
||||||
|
exists(int createEntityReferenceNodes |
|
||||||
|
encodeXercesDOMFlowState(flowstate, _, createEntityReferenceNodes) and
|
||||||
|
(
|
||||||
|
newValue.getValue().toInt() = 1 and // true
|
||||||
|
encodeXercesDOMFlowState(result, 1, createEntityReferenceNodes)
|
||||||
|
or
|
||||||
|
not newValue.getValue().toInt() = 1 and // false or unknown
|
||||||
|
encodeXercesDOMFlowState(result, 0, createEntityReferenceNodes)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A flow state transformer for a call to
|
||||||
|
* `AbstractDOMParser.setCreateEntityReferenceNodes`. Transforms the flow
|
||||||
|
* state through the qualifier according to the setting in the parameter.
|
||||||
|
*/
|
||||||
|
class CreateEntityReferenceNodesTranformer extends XXEFlowStateTranformer {
|
||||||
|
Expr newValue;
|
||||||
|
|
||||||
|
CreateEntityReferenceNodesTranformer() {
|
||||||
|
exists(Call call, Function f |
|
||||||
|
call.getTarget() = f and
|
||||||
|
f.getDeclaringType() instanceof AbstractDOMParserClass and
|
||||||
|
f.hasName("setCreateEntityReferenceNodes") and
|
||||||
|
this = call.getQualifier() and
|
||||||
|
newValue = call.getArgument(0)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
final override XXEFlowState transform(XXEFlowState flowstate) {
|
||||||
|
exists(int disabledDefaultEntityResolution |
|
||||||
|
encodeXercesDOMFlowState(flowstate, disabledDefaultEntityResolution, _) and
|
||||||
|
(
|
||||||
|
newValue.getValue().toInt() = 1 and // true
|
||||||
|
encodeXercesDOMFlowState(result, disabledDefaultEntityResolution, 1)
|
||||||
|
or
|
||||||
|
not newValue.getValue().toInt() = 1 and // false or unknown
|
||||||
|
encodeXercesDOMFlowState(result, disabledDefaultEntityResolution, 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `AbstractDOMParser.parse` method.
|
||||||
|
*/
|
||||||
|
class ParseFunction extends Function {
|
||||||
|
ParseFunction() { this.getClassAndName("parse") instanceof AbstractDOMParserClass }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `createLSParser` function that returns a newly created `LSParser` object.
|
||||||
|
*/
|
||||||
|
class CreateLSParser extends Function {
|
||||||
|
CreateLSParser() {
|
||||||
|
this.hasName("createLSParser") and
|
||||||
|
this.getUnspecifiedType().(PointerType).getBaseType().getName() = "DOMLSParser" // returns a `DOMLSParser *`.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A configuration for tracking XML objects and their states.
|
||||||
|
*/
|
||||||
|
class XXEConfiguration extends DataFlow::Configuration {
|
||||||
|
XXEConfiguration() { this = "XXEConfiguration" }
|
||||||
|
|
||||||
|
override predicate isSource(DataFlow::Node node, string flowstate) {
|
||||||
|
// source is the write on `this` of a call to the `XercesDOMParser`
|
||||||
|
// constructor.
|
||||||
|
exists(CallInstruction call |
|
||||||
|
call.getStaticCallTarget() = any(XercesDOMParserClass c).getAConstructor() and
|
||||||
|
node.asInstruction().(WriteSideEffectInstruction).getDestinationAddress() =
|
||||||
|
call.getThisArgument() and
|
||||||
|
encodeXercesDOMFlowState(flowstate, 0, 1) // default configuration
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// source is the result of a call to `createLSParser`.
|
||||||
|
exists(Call call |
|
||||||
|
call.getTarget() instanceof CreateLSParser and
|
||||||
|
call = node.asExpr() and
|
||||||
|
encodeXercesDOMFlowState(flowstate, 0, 1) // default configuration
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate isSink(DataFlow::Node node, string flowstate) {
|
||||||
|
// sink is the read of the qualifier of a call to `parse`.
|
||||||
|
exists(Call call |
|
||||||
|
call.getTarget() instanceof ParseFunction and
|
||||||
|
call.getQualifier() = node.asConvertedExpr()
|
||||||
|
) and
|
||||||
|
flowstate instanceof XercesDOMParserFlowState and
|
||||||
|
not encodeXercesDOMFlowState(flowstate, 1, 1) // safe configuration
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate isAdditionalFlowStep(
|
||||||
|
DataFlow::Node node1, string state1, DataFlow::Node node2, string state2
|
||||||
|
) {
|
||||||
|
// create additional flow steps for `XXEFlowStateTranformer`s
|
||||||
|
state2 = node2.asConvertedExpr().(XXEFlowStateTranformer).transform(state1) and
|
||||||
|
DataFlow::simpleLocalFlowStep(node1, node2)
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate isBarrier(DataFlow::Node node, string flowstate) {
|
||||||
|
// when the flowstate is transformed at a call node, block the original
|
||||||
|
// flowstate value.
|
||||||
|
node.asConvertedExpr().(XXEFlowStateTranformer).transform(flowstate) != flowstate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
from XXEConfiguration conf, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||||
|
where conf.hasFlowPath(source, sink)
|
||||||
|
select sink, source, sink,
|
||||||
|
"This $@ is not configured to prevent an XML external entity (XXE) attack.", source, "XML parser"
|
||||||
4
cpp/ql/src/Security/CWE/CWE-611/XXEBad.cpp
Normal file
4
cpp/ql/src/Security/CWE/CWE-611/XXEBad.cpp
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
XercesDOMParser *parser = new XercesDOMParser();
|
||||||
|
|
||||||
|
parser->parse(data); // BAD (parser is not correctly configured, may expand external entity references)
|
||||||
5
cpp/ql/src/Security/CWE/CWE-611/XXEGood.cpp
Normal file
5
cpp/ql/src/Security/CWE/CWE-611/XXEGood.cpp
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
XercesDOMParser *parser = new XercesDOMParser();
|
||||||
|
|
||||||
|
parser->setDisableDefaultEntityResolution(true);
|
||||||
|
parser->parse(data);
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
---
|
|
||||||
category: minorAnalysis
|
|
||||||
---
|
|
||||||
* A new query, "Potential exposure of sensitive system data to an unauthorized control sphere" (`cpp/potential-system-data-exposure`) has been added. This query is focused on exposure of information that is highly likely to be sensitive, whereas the similar query "Exposure of system data to an unauthorized control sphere" (`cpp/system-data-exposure`) is focused on exposure of information on a channel that is more likely to be intercepted by an attacker.
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
---
|
|
||||||
category: minorAnalysis
|
|
||||||
---
|
|
||||||
* The `cpp/system-data-exposure` query has been increased from `medium` to `high` precision, following a number of improvements to the query logic.
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
---
|
|
||||||
category: minorAnalysis
|
|
||||||
---
|
|
||||||
* The `cpp/command-line-injection` query now takes into account calling contexts across string concatenations. This removes false positives due to mismatched calling contexts before and after string concatenations.
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user