mirror of
https://github.com/github/codeql.git
synced 2026-05-23 23:57:06 +02:00
Compare commits
2 Commits
yoff/pytho
...
redsun82/a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0d1d614b92 | ||
|
|
eb4430ef8b |
4
.bazelrc
4
.bazelrc
@@ -11,8 +11,6 @@ build --compilation_mode opt
|
||||
common --override_module=semmle_code=%workspace%/misc/bazel/semmle_code_stub
|
||||
|
||||
build --repo_env=CC=clang --repo_env=CXX=clang++
|
||||
# Disable Android SDK auto-detection (we don't use it, and rules_android has Bazel 9 compatibility issues)
|
||||
build --repo_env=ANDROID_HOME=
|
||||
|
||||
# print test output, like sembuild does.
|
||||
# Set to `errors` if this is too verbose.
|
||||
@@ -36,7 +34,7 @@ common --@rules_dotnet//dotnet/settings:strict_deps=false
|
||||
common --@rules_rust//rust/toolchain/channel=nightly
|
||||
|
||||
# Reduce this eventually to empty, once we've fixed all our usages of java, and https://github.com/bazel-contrib/rules_go/issues/4193 is fixed
|
||||
common --incompatible_autoload_externally="+@rules_cc,+@rules_java,+@rules_shell"
|
||||
common --incompatible_autoload_externally="+@rules_java,+@rules_shell"
|
||||
|
||||
build --java_language_version=17
|
||||
build --tool_java_language_version=17
|
||||
|
||||
@@ -1 +1 @@
|
||||
9.0.0
|
||||
8.4.2
|
||||
|
||||
2
.github/dependabot.yml
vendored
2
.github/dependabot.yml
vendored
@@ -45,5 +45,3 @@ updates:
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: weekly
|
||||
exclude-paths:
|
||||
- "misc/bazel/registry/**"
|
||||
|
||||
78
.github/workflows/compile-queries.yml
vendored
Normal file
78
.github/workflows/compile-queries.yml
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
name: "Compile all queries using the latest stable CodeQL CLI"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: # makes sure the cache gets populated - running on the branches people tend to merge into.
|
||||
- main
|
||||
- "rc/*"
|
||||
- "codeql-cli-*"
|
||||
pull_request:
|
||||
paths:
|
||||
- '**.ql'
|
||||
- '**.qll'
|
||||
- '**/qlpack.yml'
|
||||
- '**.dbscheme'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
detect-changes:
|
||||
if: github.repository_owner == 'github'
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
languages: ${{ steps.detect.outputs.languages }}
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- name: Detect changed languages
|
||||
id: detect
|
||||
run: |
|
||||
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
|
||||
# For PRs, detect which languages have changes
|
||||
changed_files=$(gh pr view ${{ github.event.pull_request.number }} --json files --jq '.files.[].path')
|
||||
languages=()
|
||||
for lang in actions cpp csharp go java javascript python ql ruby rust swift; do
|
||||
if echo "$changed_files" | grep -qE "^($lang/|shared/)" ; then
|
||||
languages+=("$lang")
|
||||
fi
|
||||
done
|
||||
echo "languages=$(jq -c -n '$ARGS.positional' --args "${languages[@]}")" >> $GITHUB_OUTPUT
|
||||
else
|
||||
# For pushes to main/rc branches, run all languages
|
||||
echo 'languages=["actions","cpp","csharp","go","java","javascript","python","ql","ruby","rust","swift"]' >> $GITHUB_OUTPUT
|
||||
fi
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
|
||||
compile-queries:
|
||||
needs: detect-changes
|
||||
if: github.repository_owner == 'github' && needs.detect-changes.outputs.languages != '[]'
|
||||
runs-on: ubuntu-latest-xl
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: ${{ fromJson(needs.detect-changes.outputs.languages) }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- name: Setup CodeQL
|
||||
uses: ./.github/actions/fetch-codeql
|
||||
with:
|
||||
channel: 'release'
|
||||
- name: Cache compilation cache
|
||||
id: query-cache
|
||||
uses: ./.github/actions/cache-query-compilation
|
||||
with:
|
||||
key: ${{ matrix.language }}-queries
|
||||
- name: check formatting
|
||||
run: find shared ${{ matrix.language }}/ql -type f \( -name "*.qll" -o -name "*.ql" \) -print0 | xargs -0 -n 3000 -P 10 codeql query format -q --check-only
|
||||
- name: compile queries - check-only
|
||||
# run with --check-only if running in a PR (github.sha != main)
|
||||
if : ${{ github.event_name == 'pull_request' }}
|
||||
shell: bash
|
||||
run: codeql query compile -q -j0 ${{ matrix.language }}/ql/{src,examples} --keep-going --warnings=error --check-only --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" --compilation-cache-size=500 --ram=56000
|
||||
- name: compile queries - full
|
||||
# do full compile if running on main - this populates the cache
|
||||
if : ${{ github.event_name != 'pull_request' }}
|
||||
shell: bash
|
||||
run: codeql query compile -q -j0 ${{ matrix.language }}/ql/{src,examples} --keep-going --warnings=error --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" --compilation-cache-size=500 --ram=56000
|
||||
236
.github/workflows/ruby-build.yml
vendored
Normal file
236
.github/workflows/ruby-build.yml
vendored
Normal file
@@ -0,0 +1,236 @@
|
||||
name: "Ruby: Build"
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- "ruby/**"
|
||||
- .github/workflows/ruby-build.yml
|
||||
- .github/actions/fetch-codeql/action.yml
|
||||
- codeql-workspace.yml
|
||||
- "shared/tree-sitter-extractor/**"
|
||||
branches:
|
||||
- main
|
||||
- "rc/*"
|
||||
pull_request:
|
||||
paths:
|
||||
- "ruby/**"
|
||||
- .github/workflows/ruby-build.yml
|
||||
- .github/actions/fetch-codeql/action.yml
|
||||
- codeql-workspace.yml
|
||||
- "shared/tree-sitter-extractor/**"
|
||||
branches:
|
||||
- main
|
||||
- "rc/*"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: "Version tag to create"
|
||||
required: false
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ruby
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- name: Install GNU tar
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
brew install gnu-tar
|
||||
echo "/usr/local/opt/gnu-tar/libexec/gnubin" >> $GITHUB_PATH
|
||||
- name: Prepare Windows
|
||||
if: runner.os == 'Windows'
|
||||
shell: powershell
|
||||
run: |
|
||||
git config --global core.longpaths true
|
||||
- uses: ./.github/actions/os-version
|
||||
id: os_version
|
||||
- name: Cache entire extractor
|
||||
uses: actions/cache@v3
|
||||
id: cache-extractor
|
||||
with:
|
||||
path: |
|
||||
target/release/codeql-extractor-ruby
|
||||
target/release/codeql-extractor-ruby.exe
|
||||
ruby/extractor/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll
|
||||
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-ruby-extractor-${{ hashFiles('ruby/extractor/rust-toolchain.toml', 'ruby/extractor/Cargo.lock') }}-${{ hashFiles('shared/tree-sitter-extractor') }}-${{ hashFiles('ruby/extractor/**/*.rs') }}
|
||||
- uses: actions/cache@v3
|
||||
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
target
|
||||
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-ruby-rust-cargo-${{ hashFiles('ruby/extractor/rust-toolchain.toml', 'ruby/extractor/**/Cargo.lock') }}
|
||||
- name: Check formatting
|
||||
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
||||
run: cd extractor && cargo fmt -- --check
|
||||
- name: Build
|
||||
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
||||
run: cd extractor && cargo build --verbose
|
||||
- name: Run tests
|
||||
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
||||
run: cd extractor && cargo test --verbose
|
||||
- name: Release build
|
||||
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
||||
run: cd extractor && cargo build --release
|
||||
- name: Generate dbscheme
|
||||
if: ${{ matrix.os == 'ubuntu-latest' && steps.cache-extractor.outputs.cache-hit != 'true'}}
|
||||
run: ../target/release/codeql-extractor-ruby generate --dbscheme ql/lib/ruby.dbscheme --library ql/lib/codeql/ruby/ast/internal/TreeSitter.qll
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||
with:
|
||||
name: ruby.dbscheme
|
||||
path: ruby/ql/lib/ruby.dbscheme
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||
with:
|
||||
name: TreeSitter.qll
|
||||
path: ruby/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: extractor-${{ matrix.os }}
|
||||
path: |
|
||||
target/release/codeql-extractor-ruby
|
||||
target/release/codeql-extractor-ruby.exe
|
||||
retention-days: 1
|
||||
compile-queries:
|
||||
if: github.repository_owner == 'github'
|
||||
runs-on: ubuntu-latest-xl
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- name: Fetch CodeQL
|
||||
uses: ./.github/actions/fetch-codeql
|
||||
- name: Cache compilation cache
|
||||
id: query-cache
|
||||
uses: ./.github/actions/cache-query-compilation
|
||||
with:
|
||||
key: ruby-build
|
||||
- name: Build Query Pack
|
||||
run: |
|
||||
PACKS=${{ runner.temp }}/query-packs
|
||||
rm -rf $PACKS
|
||||
codeql pack create ../misc/suite-helpers --output "$PACKS"
|
||||
codeql pack create ../shared/regex --output "$PACKS"
|
||||
codeql pack create ../shared/ssa --output "$PACKS"
|
||||
codeql pack create ../shared/tutorial --output "$PACKS"
|
||||
codeql pack create ql/lib --output "$PACKS"
|
||||
codeql pack create -j0 ql/src --output "$PACKS" --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
|
||||
PACK_FOLDER=$(readlink -f "$PACKS"/codeql/ruby-queries/*)
|
||||
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}/{}" \;)
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: codeql-ruby-queries
|
||||
path: |
|
||||
${{ runner.temp }}/query-packs/*
|
||||
retention-days: 1
|
||||
include-hidden-files: true
|
||||
|
||||
package:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build, compile-queries]
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: ruby.dbscheme
|
||||
path: ruby/ruby
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: extractor-ubuntu-latest
|
||||
path: ruby/linux64
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: extractor-windows-latest
|
||||
path: ruby/win64
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: extractor-macos-latest
|
||||
path: ruby/osx64
|
||||
- run: |
|
||||
mkdir -p ruby
|
||||
cp -r codeql-extractor.yml tools ql/lib/ruby.dbscheme.stats ruby/
|
||||
mkdir -p ruby/tools/{linux64,osx64,win64}
|
||||
cp linux64/codeql-extractor-ruby ruby/tools/linux64/extractor
|
||||
cp osx64/codeql-extractor-ruby ruby/tools/osx64/extractor
|
||||
cp win64/codeql-extractor-ruby.exe ruby/tools/win64/extractor.exe
|
||||
chmod +x ruby/tools/{linux64,osx64}/extractor
|
||||
zip -rq codeql-ruby.zip ruby
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: codeql-ruby-pack
|
||||
path: ruby/codeql-ruby.zip
|
||||
retention-days: 1
|
||||
include-hidden-files: true
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: codeql-ruby-queries
|
||||
path: ruby/qlpacks
|
||||
- run: |
|
||||
echo '{
|
||||
"provide": [
|
||||
"ruby/codeql-extractor.yml",
|
||||
"qlpacks/*/*/*/qlpack.yml"
|
||||
]
|
||||
}' > .codeqlmanifest.json
|
||||
zip -rq codeql-ruby-bundle.zip .codeqlmanifest.json ruby qlpacks
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: codeql-ruby-bundle
|
||||
path: ruby/codeql-ruby-bundle.zip
|
||||
retention-days: 1
|
||||
include-hidden-files: true
|
||||
|
||||
test:
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ${{ github.workspace }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
needs: [package]
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- name: Fetch CodeQL
|
||||
uses: ./.github/actions/fetch-codeql
|
||||
|
||||
- name: Download Ruby bundle
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: codeql-ruby-bundle
|
||||
path: ${{ runner.temp }}
|
||||
- name: Unzip Ruby bundle
|
||||
shell: bash
|
||||
run: unzip -q -d "${{ runner.temp }}/ruby-bundle" "${{ runner.temp }}/codeql-ruby-bundle.zip"
|
||||
|
||||
- name: Run QL test
|
||||
shell: bash
|
||||
run: |
|
||||
codeql test run --search-path "${{ runner.temp }}/ruby-bundle" --additional-packs "${{ runner.temp }}/ruby-bundle" ruby/ql/test/library-tests/ast/constants/
|
||||
- name: Create database
|
||||
shell: bash
|
||||
run: |
|
||||
codeql database create --search-path "${{ runner.temp }}/ruby-bundle" --language ruby --source-root ruby/ql/test/library-tests/ast/constants/ ../database
|
||||
- name: Analyze database
|
||||
shell: bash
|
||||
run: |
|
||||
codeql database analyze --search-path "${{ runner.temp }}/ruby-bundle" --format=sarifv2.1.0 --output=out.sarif ../database ruby-code-scanning.qls
|
||||
75
.github/workflows/ruby-dataset-measure.yml
vendored
Normal file
75
.github/workflows/ruby-dataset-measure.yml
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
name: "Ruby: Collect database stats"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- "rc/*"
|
||||
paths:
|
||||
- ruby/ql/lib/ruby.dbscheme
|
||||
- .github/workflows/ruby-dataset-measure.yml
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- "rc/*"
|
||||
paths:
|
||||
- ruby/ql/lib/ruby.dbscheme
|
||||
- .github/workflows/ruby-dataset-measure.yml
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
measure:
|
||||
env:
|
||||
CODEQL_THREADS: 4 # TODO: remove this once it's set by the CLI
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
repo: [rails/rails, discourse/discourse, spree/spree, ruby/ruby]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- uses: ./.github/actions/fetch-codeql
|
||||
|
||||
- uses: ./ruby/actions/create-extractor-pack
|
||||
|
||||
- name: Checkout ${{ matrix.repo }}
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
repository: ${{ matrix.repo }}
|
||||
path: ${{ github.workspace }}/repo
|
||||
- name: Create database
|
||||
run: |
|
||||
codeql database create \
|
||||
--search-path "${{ github.workspace }}" \
|
||||
--threads 4 \
|
||||
--language ruby --source-root "${{ github.workspace }}/repo" \
|
||||
"${{ runner.temp }}/database"
|
||||
- name: Measure database
|
||||
run: |
|
||||
mkdir -p "stats/${{ matrix.repo }}"
|
||||
codeql dataset measure --threads 4 --output "stats/${{ matrix.repo }}/stats.xml" "${{ runner.temp }}/database/db-ruby"
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: measurements-${{ hashFiles('stats/**') }}
|
||||
path: stats
|
||||
retention-days: 1
|
||||
|
||||
merge:
|
||||
runs-on: ubuntu-latest
|
||||
needs: measure
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: stats
|
||||
- run: |
|
||||
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
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ruby.dbscheme.stats
|
||||
path: ruby/ql/lib/ruby.dbscheme.stats
|
||||
40
.github/workflows/ruby-qltest-rtjo.yml
vendored
Normal file
40
.github/workflows/ruby-qltest-rtjo.yml
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
name: "Ruby: Run RTJO Language Tests"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
- reopened
|
||||
- labeled
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ruby
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
qltest-rtjo:
|
||||
if: "github.repository_owner == 'github' && github.event.label.name == 'Run: RTJO Language Tests'"
|
||||
runs-on: ubuntu-latest-xl
|
||||
strategy:
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/actions/fetch-codeql
|
||||
- uses: ./ruby/actions/create-extractor-pack
|
||||
- name: Cache compilation cache
|
||||
id: query-cache
|
||||
uses: ./.github/actions/cache-query-compilation
|
||||
with:
|
||||
key: ruby-qltest
|
||||
- name: Run QL tests
|
||||
run: |
|
||||
codeql test run --dynamic-join-order-mode=all --threads=0 --ram 50000 --search-path "${{ github.workspace }}" --check-databases --check-diff-informed --check-undefined-labels --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --consistency-queries ql/consistency-queries ql/test --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
73
.github/workflows/ruby-qltest.yml
vendored
Normal file
73
.github/workflows/ruby-qltest.yml
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
name: "Ruby: Run QL Tests"
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- "ruby/**"
|
||||
- "shared/**"
|
||||
- .github/workflows/ruby-build.yml
|
||||
- .github/actions/fetch-codeql/action.yml
|
||||
- codeql-workspace.yml
|
||||
branches:
|
||||
- main
|
||||
- "rc/*"
|
||||
pull_request:
|
||||
paths:
|
||||
- "ruby/**"
|
||||
- "shared/**"
|
||||
- .github/workflows/ruby-qltest.yml
|
||||
- .github/actions/fetch-codeql/action.yml
|
||||
- codeql-workspace.yml
|
||||
branches:
|
||||
- main
|
||||
- "rc/*"
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ruby
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
qlupgrade:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/actions/fetch-codeql
|
||||
- name: Check DB upgrade scripts
|
||||
run: |
|
||||
echo >empty.trap
|
||||
codeql dataset import -S ql/lib/upgrades/initial/ruby.dbscheme testdb empty.trap
|
||||
codeql dataset upgrade testdb --additional-packs ql/lib
|
||||
diff -q testdb/ruby.dbscheme ql/lib/ruby.dbscheme
|
||||
- name: Check DB downgrade scripts
|
||||
run: |
|
||||
echo >empty.trap
|
||||
rm -rf testdb; codeql dataset import -S ql/lib/ruby.dbscheme testdb empty.trap
|
||||
codeql resolve upgrades --format=lines --allow-downgrades --additional-packs downgrades \
|
||||
--dbscheme=ql/lib/ruby.dbscheme --target-dbscheme=downgrades/initial/ruby.dbscheme |
|
||||
xargs codeql execute upgrades testdb
|
||||
diff -q testdb/ruby.dbscheme downgrades/initial/ruby.dbscheme
|
||||
qltest:
|
||||
if: github.repository_owner == 'github'
|
||||
runs-on: ubuntu-latest-xl
|
||||
strategy:
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/actions/fetch-codeql
|
||||
- uses: ./ruby/actions/create-extractor-pack
|
||||
- name: Cache compilation cache
|
||||
id: query-cache
|
||||
uses: ./.github/actions/cache-query-compilation
|
||||
with:
|
||||
key: ruby-qltest
|
||||
- name: Run QL tests
|
||||
run: |
|
||||
codeql test run --threads=0 --ram 50000 --search-path "${{ github.workspace }}" --check-databases --check-diff-informed --check-undefined-labels --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --consistency-queries ql/consistency-queries ql/test --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
@@ -7,9 +7,9 @@ repos:
|
||||
rev: v3.2.0
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
exclude: /test([^/]*)/.*$(?<!\.qlref)|.*\.patch$|.*\.qll?$
|
||||
exclude: /test/.*$(?<!\.qlref)|.*\.patch$|.*\.qll?$
|
||||
- id: end-of-file-fixer
|
||||
exclude: Cargo.lock$|/test([^/]*)/.*$(?<!\.qlref)|.*\.patch$|.*\.qll?$
|
||||
exclude: Cargo.lock$|/test/.*$(?<!\.qlref)|.*\.patch$|.*\.qll?$
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||
rev: v17.0.6
|
||||
|
||||
84
MODULE.bazel
84
MODULE.bazel
@@ -15,23 +15,21 @@ local_path_override(
|
||||
# see https://registry.bazel.build/ for a list of available packages
|
||||
|
||||
bazel_dep(name = "platforms", version = "1.0.0")
|
||||
bazel_dep(name = "rules_cc", version = "0.2.17")
|
||||
bazel_dep(name = "rules_go", version = "0.60.0")
|
||||
bazel_dep(name = "rules_java", version = "9.6.1")
|
||||
bazel_dep(name = "rules_pkg", version = "1.2.0")
|
||||
bazel_dep(name = "rules_nodejs", version = "6.7.3")
|
||||
bazel_dep(name = "rules_python", version = "1.9.0")
|
||||
bazel_dep(name = "rules_shell", version = "0.7.1")
|
||||
bazel_dep(name = "bazel_skylib", version = "1.9.0")
|
||||
bazel_dep(name = "abseil-cpp", version = "20260107.1", repo_name = "absl")
|
||||
bazel_dep(name = "rules_go", version = "0.56.1")
|
||||
bazel_dep(name = "rules_pkg", version = "1.0.1")
|
||||
bazel_dep(name = "rules_nodejs", version = "6.2.0-codeql.1")
|
||||
bazel_dep(name = "rules_python", version = "0.40.0")
|
||||
bazel_dep(name = "rules_shell", version = "0.5.0")
|
||||
bazel_dep(name = "bazel_skylib", version = "1.8.1")
|
||||
bazel_dep(name = "abseil-cpp", version = "20240116.1", repo_name = "absl")
|
||||
bazel_dep(name = "nlohmann_json", version = "3.11.3", repo_name = "json")
|
||||
bazel_dep(name = "fmt", version = "12.1.0-codeql.1")
|
||||
bazel_dep(name = "rules_kotlin", version = "2.2.2-codeql.1")
|
||||
bazel_dep(name = "gazelle", version = "0.50.0")
|
||||
bazel_dep(name = "rules_kotlin", version = "2.2.0-codeql.1")
|
||||
bazel_dep(name = "gazelle", version = "0.40.0")
|
||||
bazel_dep(name = "rules_dotnet", version = "0.21.5-codeql.1")
|
||||
bazel_dep(name = "googletest", version = "1.17.0.bcr.2")
|
||||
bazel_dep(name = "rules_rust", version = "0.69.0")
|
||||
bazel_dep(name = "zstd", version = "1.5.7.bcr.1")
|
||||
bazel_dep(name = "googletest", version = "1.14.0.bcr.1")
|
||||
bazel_dep(name = "rules_rust", version = "0.66.0")
|
||||
bazel_dep(name = "zstd", version = "1.5.5.bcr.1")
|
||||
|
||||
bazel_dep(name = "buildifier_prebuilt", version = "6.4.0", dev_dependency = True)
|
||||
|
||||
@@ -43,7 +41,7 @@ RUST_EDITION = "2024"
|
||||
# a nightly toolchain is required to enable experimental_use_cc_common_link, which we require internally
|
||||
# we prefer to run the same version as internally, even if experimental_use_cc_common_link is not really
|
||||
# required in this repo
|
||||
RUST_VERSION = "nightly/2026-01-22"
|
||||
RUST_VERSION = "nightly/2025-08-01"
|
||||
|
||||
rust = use_extension("@rules_rust//rust:extensions.bzl", "rust")
|
||||
rust.toolchain(
|
||||
@@ -55,26 +53,26 @@ rust.toolchain(
|
||||
],
|
||||
# generated by buildutils-internal/scripts/fill-rust-sha256s.py (internal repo)
|
||||
sha256s = {
|
||||
"2026-01-22/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz": "88db619323cc1321630d124efa51ed02fabc5e020f08cfa0eda2c0ac1afbe69a",
|
||||
"2026-01-22/rustc-nightly-x86_64-apple-darwin.tar.xz": "08484da3fa38db56f93629aeabdc0ae9ff8ed9704c0792d35259cbc849b3f54c",
|
||||
"2026-01-22/rustc-nightly-aarch64-apple-darwin.tar.xz": "a39c0b21b7058e364ea1bd43144e42e4bf1efade036b2e82455f2afce194ee81",
|
||||
"2026-01-22/rustc-nightly-x86_64-pc-windows-msvc.tar.xz": "d00248ee9850dbb6932b2578e32ff74fc7c429854c1aa071066ca31b65385a3b",
|
||||
"2026-01-22/clippy-nightly-x86_64-unknown-linux-gnu.tar.xz": "70656a0ce994ffff16d5a35a7b170a0acd41e9bb54a589c96ed45bf97b094a4d",
|
||||
"2026-01-22/clippy-nightly-x86_64-apple-darwin.tar.xz": "fe242519fa961522734733009705aec3c2d9a20cc57291f2aa614e5e6262c88f",
|
||||
"2026-01-22/clippy-nightly-aarch64-apple-darwin.tar.xz": "38bb226363ec97c9722edf966cd58774a683e19fd2ff2a6030094445d51e06f9",
|
||||
"2026-01-22/clippy-nightly-x86_64-pc-windows-msvc.tar.xz": "6da9b4470beea67abfebf046f141eee0d2a8db7c7a9e4e2294478734fd477228",
|
||||
"2026-01-22/cargo-nightly-x86_64-unknown-linux-gnu.tar.xz": "99004e9d10c43a01499642f53bb3184d41137a95d65bfb217098840a9e79e892",
|
||||
"2026-01-22/cargo-nightly-x86_64-apple-darwin.tar.xz": "6e021394cf8d8400ac6cfdfcef24e4d74f988e91eb8028b36de3a64ce3502990",
|
||||
"2026-01-22/cargo-nightly-aarch64-apple-darwin.tar.xz": "4b2494cb69ab64132cddbc411a38ea9f1105e54d6f986e43168d54f79510c673",
|
||||
"2026-01-22/cargo-nightly-x86_64-pc-windows-msvc.tar.xz": "c36613cf57407212d10d37b76e49a60ff42336e953cdff9e177283f530a83fc1",
|
||||
"2026-01-22/llvm-tools-nightly-x86_64-unknown-linux-gnu.tar.xz": "0b123c5027dbd833aae6845ffe9bd07d309bf798746a7176aadaea68fbcbd05d",
|
||||
"2026-01-22/llvm-tools-nightly-x86_64-apple-darwin.tar.xz": "a47864491ad5619158c950ab7570fb6e487d5117338585c27334d45824b406d8",
|
||||
"2026-01-22/llvm-tools-nightly-aarch64-apple-darwin.tar.xz": "db9bc826d6e2e7e914505d50157682e516ceb90357e83d77abddc32c2d962f41",
|
||||
"2026-01-22/llvm-tools-nightly-x86_64-pc-windows-msvc.tar.xz": "ffaa406932b2fe62e01dad61cf4ed34860a5d2a6f9306ca340d79e630d930039",
|
||||
"2026-01-22/rust-std-nightly-x86_64-unknown-linux-gnu.tar.xz": "e9c0d5e06e18a4b509391b3088f29293e310cdc8ccc865be8fa3f09733326925",
|
||||
"2026-01-22/rust-std-nightly-x86_64-apple-darwin.tar.xz": "25d75995cee679a4828ca9fe48c5a31a67c3b0846018440ef912e5a6208f53f6",
|
||||
"2026-01-22/rust-std-nightly-aarch64-apple-darwin.tar.xz": "e4132bf3f2eed4684c86756a02315bcf481c23e675e3e25630fc604c9cb4594c",
|
||||
"2026-01-22/rust-std-nightly-x86_64-pc-windows-msvc.tar.xz": "961bb535ef95ae8a5fa4e224cb94aff190f155c45a9bcf7a53e184b024aa41b1",
|
||||
"2025-08-01/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz": "9bbeaf5d3fc7247d31463a9083aa251c995cc50662c8219e7a2254d76a72a9a4",
|
||||
"2025-08-01/rustc-nightly-x86_64-apple-darwin.tar.xz": "c9ea539a8eff0d5d162701f99f9e1aabe14dd0dfb420d62362817a5d09219de7",
|
||||
"2025-08-01/rustc-nightly-aarch64-apple-darwin.tar.xz": "ae83feebbc39cfd982e4ecc8297731fe79c185173aee138467b334c5404b3773",
|
||||
"2025-08-01/rustc-nightly-x86_64-pc-windows-msvc.tar.xz": "9f170c30d802a349be60cf52ec46260802093cb1013ad667fc0d528b7b10152f",
|
||||
"2025-08-01/clippy-nightly-x86_64-unknown-linux-gnu.tar.xz": "9ae5f3cd8f557c4f6df522597c69d14398cf604cfaed2b83e767c4b77a7eaaf6",
|
||||
"2025-08-01/clippy-nightly-x86_64-apple-darwin.tar.xz": "983cb9ee0b6b968188e04ab2d33743d54764b2681ce565e1b3f2b9135c696a3e",
|
||||
"2025-08-01/clippy-nightly-aarch64-apple-darwin.tar.xz": "ed2219dbc49d088225e1b7c5c4390fa295066e071fddaa2714018f6bb39ddbf0",
|
||||
"2025-08-01/clippy-nightly-x86_64-pc-windows-msvc.tar.xz": "911f40ab5cbdd686f40e00965271fe47c4805513a308ed01f30eafb25b448a50",
|
||||
"2025-08-01/cargo-nightly-x86_64-unknown-linux-gnu.tar.xz": "106463c284e48e4904c717471eeec2be5cc83a9d2cae8d6e948b52438cad2e69",
|
||||
"2025-08-01/cargo-nightly-x86_64-apple-darwin.tar.xz": "6ad35c40efc41a8c531ea43235058347b6902d98a9693bf0aed7fc16d5590cef",
|
||||
"2025-08-01/cargo-nightly-aarch64-apple-darwin.tar.xz": "dd28c365e9d298abc3154c797720ad36a0058f131265c9978b4c8e4e37012c8a",
|
||||
"2025-08-01/cargo-nightly-x86_64-pc-windows-msvc.tar.xz": "7b431286e12d6b3834b038f078389a00cac73f351e8c3152b2504a3c06420b3b",
|
||||
"2025-08-01/llvm-tools-nightly-x86_64-unknown-linux-gnu.tar.xz": "e342e305d7927cc288d386983b2bc253cfad3776b113386e903d0b302648ef47",
|
||||
"2025-08-01/llvm-tools-nightly-x86_64-apple-darwin.tar.xz": "e44dd3506524d85c37b3a54bcc91d01378fd2c590b2db5c5974d12f05c1b84d1",
|
||||
"2025-08-01/llvm-tools-nightly-aarch64-apple-darwin.tar.xz": "0c1b5f46dd81be4a9227b10283a0fcaa39c14fea7e81aea6fd6d9887ff6cdc41",
|
||||
"2025-08-01/llvm-tools-nightly-x86_64-pc-windows-msvc.tar.xz": "423e5fd11406adccbc31b8456ceb7375ce055cdf45e90d2c3babeb2d7f58383f",
|
||||
"2025-08-01/rust-std-nightly-x86_64-unknown-linux-gnu.tar.xz": "3c0ceb46a252647a1d4c7116d9ccae684fa5e42aaf3296419febd2c962c3b41d",
|
||||
"2025-08-01/rust-std-nightly-x86_64-apple-darwin.tar.xz": "3be416003cab10f767390a753d1d16ae4d26c7421c03c98992cf1943e5b0efe8",
|
||||
"2025-08-01/rust-std-nightly-aarch64-apple-darwin.tar.xz": "4046ac0ef951cb056b5028a399124f60999fa37792eab69d008d8d7965f389b4",
|
||||
"2025-08-01/rust-std-nightly-x86_64-pc-windows-msvc.tar.xz": "191ed9d8603c3a4fe5a7bbbc2feb72049078dae2df3d3b7d5dedf3abbf823e6e",
|
||||
},
|
||||
versions = [RUST_VERSION],
|
||||
)
|
||||
@@ -190,15 +188,6 @@ pip.parse(
|
||||
)
|
||||
use_repo(pip, "codegen_deps")
|
||||
|
||||
python = use_extension("@rules_python//python/extensions:python.bzl", "python")
|
||||
python.toolchain(
|
||||
is_default = True,
|
||||
python_version = "3.12",
|
||||
)
|
||||
use_repo(python, "python_3_12", "python_versions")
|
||||
|
||||
register_toolchains("@python_versions//3.12:all")
|
||||
|
||||
swift_deps = use_extension("//swift/third_party:load.bzl", "swift_deps")
|
||||
|
||||
# following list can be kept in sync with `bazel mod tidy`
|
||||
@@ -242,7 +231,6 @@ use_repo(
|
||||
"kotlin-compiler-2.2.0-Beta1",
|
||||
"kotlin-compiler-2.2.20-Beta2",
|
||||
"kotlin-compiler-2.3.0",
|
||||
"kotlin-compiler-2.3.20",
|
||||
"kotlin-compiler-embeddable-1.8.0",
|
||||
"kotlin-compiler-embeddable-1.9.0-Beta",
|
||||
"kotlin-compiler-embeddable-1.9.20-Beta",
|
||||
@@ -253,7 +241,6 @@ use_repo(
|
||||
"kotlin-compiler-embeddable-2.2.0-Beta1",
|
||||
"kotlin-compiler-embeddable-2.2.20-Beta2",
|
||||
"kotlin-compiler-embeddable-2.3.0",
|
||||
"kotlin-compiler-embeddable-2.3.20",
|
||||
"kotlin-stdlib-1.8.0",
|
||||
"kotlin-stdlib-1.9.0-Beta",
|
||||
"kotlin-stdlib-1.9.20-Beta",
|
||||
@@ -264,15 +251,14 @@ use_repo(
|
||||
"kotlin-stdlib-2.2.0-Beta1",
|
||||
"kotlin-stdlib-2.2.20-Beta2",
|
||||
"kotlin-stdlib-2.3.0",
|
||||
"kotlin-stdlib-2.3.20",
|
||||
)
|
||||
|
||||
go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk")
|
||||
go_sdk.download(version = "1.26.0")
|
||||
go_sdk.download(version = "1.25.0")
|
||||
|
||||
go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps")
|
||||
go_deps.from_file(go_mod = "//go/extractor:go.mod")
|
||||
use_repo(go_deps, "com_github_stretchr_testify", "org_golang_x_mod", "org_golang_x_tools")
|
||||
use_repo(go_deps, "org_golang_x_mod", "org_golang_x_tools")
|
||||
|
||||
ripunzip_archive = use_repo_rule("//misc/ripunzip:ripunzip.bzl", "ripunzip_archive")
|
||||
|
||||
|
||||
@@ -1,33 +1,3 @@
|
||||
## 0.4.34
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Removed false positive injection sink models for the `context` input of `docker/build-push-action` and the `allowed-endpoints` input of `step-security/harden-runner`.
|
||||
|
||||
## 0.4.33
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.4.32
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.4.31
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.4.30
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.4.29
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.4.28
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.4.27
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.4.28
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.4.29
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.4.30
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.4.31
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.4.32
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.4.33
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,5 +0,0 @@
|
||||
## 0.4.34
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Removed false positive injection sink models for the `context` input of `docker/build-push-action` and the `allowed-endpoints` input of `step-security/harden-runner`.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.4.34
|
||||
lastReleaseVersion: 0.4.27
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/actions-all
|
||||
extensible: actionsSinkModel
|
||||
data:
|
||||
- ["docker/build-push-action", "*", "input.context", "code-injection", "manual"]
|
||||
@@ -0,0 +1,6 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/actions-all
|
||||
extensible: actionsSinkModel
|
||||
data:
|
||||
- ["step-security/harden-runner", "*", "input.allowed-endpoints", "command-injection", "manual"]
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/actions-all
|
||||
version: 0.4.35-dev
|
||||
version: 0.4.27
|
||||
library: true
|
||||
warnOnImplicitThis: true
|
||||
dependencies:
|
||||
|
||||
@@ -1,37 +1,3 @@
|
||||
## 0.6.26
|
||||
|
||||
### Major Analysis Improvements
|
||||
|
||||
* Fixed alert messages in `actions/artifact-poisoning/critical` and `actions/artifact-poisoning/medium` as they previously included a redundant placeholder in the alert message that would on occasion contain a long block of yml that makes the alert difficult to understand. Also improved the wording to make it clearer that it is not the artifact that is being poisoned, but instead a potentially untrusted artifact that is consumed. Finally, changed the alert location to be the source, to align more with other queries reporting an artifact (e.g. zipslip) which is more useful.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The query `actions/missing-workflow-permissions` no longer produces false positive results on reusable workflows where all callers set permissions.
|
||||
|
||||
## 0.6.25
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.6.24
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.6.23
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.6.22
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.6.21
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.6.20
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.6.19
|
||||
|
||||
No user-facing changes.
|
||||
@@ -173,7 +139,7 @@ No user-facing changes.
|
||||
* `actions/if-expression-always-true/critical`
|
||||
* `actions/if-expression-always-true/high`
|
||||
* `actions/unnecessary-use-of-advanced-config`
|
||||
|
||||
|
||||
* The following query has been moved from the `code-scanning` suite to the `security-extended`
|
||||
suite. Any existing alerts for this query will be closed automatically unless the analysis is
|
||||
configured to use the `security-extended` suite.
|
||||
|
||||
@@ -26,23 +26,10 @@ string permissionsForJob(Job job) {
|
||||
"{" + concat(string permission | permission = jobNeedsPermission(job) | permission, ", ") + "}"
|
||||
}
|
||||
|
||||
predicate jobHasPermissions(Job job) {
|
||||
exists(job.getPermissions())
|
||||
or
|
||||
exists(job.getEnclosingWorkflow().getPermissions())
|
||||
or
|
||||
// The workflow is reusable and cannot be triggered in any other way; check callers
|
||||
exists(ReusableWorkflow r | r = job.getEnclosingWorkflow() |
|
||||
not exists(Event e | e = r.getOn().getAnEvent() | e.getName() != "workflow_call") and
|
||||
forall(Job caller | caller = job.getEnclosingWorkflow().(ReusableWorkflow).getACaller() |
|
||||
jobHasPermissions(caller)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
from Job job, string permissions
|
||||
where
|
||||
not jobHasPermissions(job) and
|
||||
not exists(job.getPermissions()) and
|
||||
not exists(job.getEnclosingWorkflow().getPermissions()) and
|
||||
// exists a trigger event that is not a workflow_call
|
||||
exists(Event e |
|
||||
e = job.getATriggerEvent() and
|
||||
|
||||
@@ -20,6 +20,6 @@ from ArtifactPoisoningFlow::PathNode source, ArtifactPoisoningFlow::PathNode sin
|
||||
where
|
||||
ArtifactPoisoningFlow::flowPath(source, sink) and
|
||||
event = getRelevantEventInPrivilegedContext(sink.getNode())
|
||||
select source.getNode(), source, sink,
|
||||
"Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@).",
|
||||
event, event.getName()
|
||||
select sink.getNode(), source, sink,
|
||||
"Potential artifact poisoning in $@, which may be controlled by an external user ($@).", sink,
|
||||
sink.getNode().toString(), event, event.getName()
|
||||
|
||||
@@ -20,5 +20,6 @@ from ArtifactPoisoningFlow::PathNode source, ArtifactPoisoningFlow::PathNode sin
|
||||
where
|
||||
ArtifactPoisoningFlow::flowPath(source, sink) and
|
||||
inNonPrivilegedContext(sink.getNode().asExpr())
|
||||
select source.getNode(), source, sink,
|
||||
"Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user."
|
||||
select sink.getNode(), source, sink,
|
||||
"Potential artifact poisoning in $@, which may be controlled by an external user.", sink,
|
||||
sink.getNode().toString()
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.6.20
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.6.21
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.6.22
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.6.23
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.6.24
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.6.25
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,9 +0,0 @@
|
||||
## 0.6.26
|
||||
|
||||
### Major Analysis Improvements
|
||||
|
||||
* Fixed alert messages in `actions/artifact-poisoning/critical` and `actions/artifact-poisoning/medium` as they previously included a redundant placeholder in the alert message that would on occasion contain a long block of yml that makes the alert difficult to understand. Also improved the wording to make it clearer that it is not the artifact that is being poisoned, but instead a potentially untrusted artifact that is consumed. Finally, changed the alert location to be the source, to align more with other queries reporting an artifact (e.g. zipslip) which is more useful.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The query `actions/missing-workflow-permissions` no longer produces false positive results on reusable workflows where all callers set permissions.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.6.26
|
||||
lastReleaseVersion: 0.6.19
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/actions-queries
|
||||
version: 0.6.27-dev
|
||||
version: 0.6.19
|
||||
library: false
|
||||
warnOnImplicitThis: true
|
||||
groups: [actions, queries]
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build and test
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/deploy-pages
|
||||
@@ -1,11 +0,0 @@
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
pages: write
|
||||
|
||||
jobs:
|
||||
call-workflow:
|
||||
uses: ./.github/workflows/perms11.yml
|
||||
@@ -55,21 +55,21 @@ nodes
|
||||
| .github/workflows/test25.yml:39:14:40:45 | ./gradlew buildScanPublishPrevious\n | semmle.label | ./gradlew buildScanPublishPrevious\n |
|
||||
subpaths
|
||||
#select
|
||||
| .github/actions/download-artifact-2/action.yaml:6:7:25:4 | Uses Step | .github/actions/download-artifact-2/action.yaml:6:7:25:4 | Uses Step | .github/workflows/artifactpoisoning92.yml:28:9:29:6 | Uses Step | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning92.yml:3:3:3:14 | workflow_run | workflow_run |
|
||||
| .github/actions/download-artifact-2/action.yaml:6:7:25:4 | Uses Step | .github/actions/download-artifact-2/action.yaml:6:7:25:4 | Uses Step | .github/workflows/artifactpoisoning92.yml:29:14:29:26 | make snapshot | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning92.yml:3:3:3:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning11.yml:13:9:32:6 | Uses Step | .github/workflows/artifactpoisoning11.yml:13:9:32:6 | Uses Step | .github/workflows/artifactpoisoning11.yml:38:11:38:77 | ./sonarcloud-data/x.py build -j$(nproc) --compiler gcc --skip-build | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning11.yml:4:3:4:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning12.yml:13:9:32:6 | Uses Step | .github/workflows/artifactpoisoning12.yml:13:9:32:6 | Uses Step | .github/workflows/artifactpoisoning12.yml:38:11:38:25 | python foo/x.py | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning12.yml:4:3:4:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning21.yml:13:9:18:6 | Uses Step | .github/workflows/artifactpoisoning21.yml:13:9:18:6 | Uses Step | .github/workflows/artifactpoisoning21.yml:19:14:20:21 | sh foo/cmd\n | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning21.yml:4:3:4:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning22.yml:13:9:17:6 | Uses Step | .github/workflows/artifactpoisoning22.yml:13:9:17:6 | Uses Step | .github/workflows/artifactpoisoning22.yml:18:14:18:19 | sh cmd | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning22.yml:4:3:4:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning31.yml:13:9:15:6 | Run Step | .github/workflows/artifactpoisoning31.yml:13:9:15:6 | Run Step | .github/workflows/artifactpoisoning31.yml:19:14:19:22 | ./foo/cmd | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning31.yml:4:3:4:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning32.yml:13:9:16:6 | Run Step | .github/workflows/artifactpoisoning32.yml:13:9:16:6 | Run Step | .github/workflows/artifactpoisoning32.yml:17:14:18:20 | ./bar/cmd\n | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning32.yml:4:3:4:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning33.yml:13:9:16:6 | Run Step | .github/workflows/artifactpoisoning33.yml:13:9:16:6 | Run Step | .github/workflows/artifactpoisoning33.yml:17:14:18:20 | ./bar/cmd\n | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning33.yml:4:3:4:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning34.yml:13:9:16:6 | Run Step | .github/workflows/artifactpoisoning34.yml:13:9:16:6 | Run Step | .github/workflows/artifactpoisoning34.yml:20:14:22:23 | npm install\nnpm run lint\n | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning34.yml:4:3:4:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning41.yml:13:9:21:6 | Run Step | .github/workflows/artifactpoisoning41.yml:13:9:21:6 | Run Step | .github/workflows/artifactpoisoning41.yml:22:14:22:22 | ./foo/cmd | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning41.yml:4:3:4:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning42.yml:13:9:21:6 | Run Step | .github/workflows/artifactpoisoning42.yml:13:9:21:6 | Run Step | .github/workflows/artifactpoisoning42.yml:22:14:22:18 | ./cmd | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning42.yml:4:3:4:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning71.yml:9:9:16:6 | Uses Step | .github/workflows/artifactpoisoning71.yml:9:9:16:6 | Uses Step | .github/workflows/artifactpoisoning71.yml:17:14:18:40 | sed -f config foo.md > bar.md\n | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning71.yml:4:5:4:16 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning81.yml:28:9:31:6 | Uses Step | .github/workflows/artifactpoisoning81.yml:28:9:31:6 | Uses Step | .github/workflows/artifactpoisoning81.yml:31:14:31:27 | python test.py | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning81.yml:3:5:3:23 | pull_request_target | pull_request_target |
|
||||
| .github/workflows/artifactpoisoning96.yml:13:9:18:6 | Uses Step | .github/workflows/artifactpoisoning96.yml:13:9:18:6 | Uses Step | .github/workflows/artifactpoisoning96.yml:18:14:18:24 | npm install | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning96.yml:2:3:2:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning101.yml:10:9:16:6 | Uses Step | .github/workflows/artifactpoisoning101.yml:10:9:16:6 | Uses Step | .github/workflows/artifactpoisoning101.yml:17:14:19:59 | PR_NUMBER=$(./get_pull_request_number.sh pr_number.txt)\necho "PR_NUMBER=$PR_NUMBER" >> $GITHUB_OUTPUT \n | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/artifactpoisoning101.yml:4:3:4:21 | pull_request_target | pull_request_target |
|
||||
| .github/workflows/test18.yml:12:15:33:12 | Uses Step | .github/workflows/test18.yml:12:15:33:12 | Uses Step | .github/workflows/test18.yml:36:15:40:58 | Uses Step | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/test18.yml:3:5:3:16 | workflow_run | workflow_run |
|
||||
| .github/workflows/test25.yml:22:9:32:6 | Uses Step: downloadBuildScan | .github/workflows/test25.yml:22:9:32:6 | Uses Step: downloadBuildScan | .github/workflows/test25.yml:39:14:40:45 | ./gradlew buildScanPublishPrevious\n | Potential artifact poisoning; the artifact being consumed has contents that may be controlled by an external user ($@). | .github/workflows/test25.yml:2:3:2:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning11.yml:38:11:38:77 | ./sonarcloud-data/x.py build -j$(nproc) --compiler gcc --skip-build | .github/workflows/artifactpoisoning11.yml:13:9:32:6 | Uses Step | .github/workflows/artifactpoisoning11.yml:38:11:38:77 | ./sonarcloud-data/x.py build -j$(nproc) --compiler gcc --skip-build | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/artifactpoisoning11.yml:38:11:38:77 | ./sonarcloud-data/x.py build -j$(nproc) --compiler gcc --skip-build | ./sonarcloud-data/x.py build -j$(nproc) --compiler gcc --skip-build | .github/workflows/artifactpoisoning11.yml:4:3:4:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning12.yml:38:11:38:25 | python foo/x.py | .github/workflows/artifactpoisoning12.yml:13:9:32:6 | Uses Step | .github/workflows/artifactpoisoning12.yml:38:11:38:25 | python foo/x.py | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/artifactpoisoning12.yml:38:11:38:25 | python foo/x.py | python foo/x.py | .github/workflows/artifactpoisoning12.yml:4:3:4:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning21.yml:19:14:20:21 | sh foo/cmd\n | .github/workflows/artifactpoisoning21.yml:13:9:18:6 | Uses Step | .github/workflows/artifactpoisoning21.yml:19:14:20:21 | sh foo/cmd\n | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/artifactpoisoning21.yml:19:14:20:21 | sh foo/cmd\n | sh foo/cmd\n | .github/workflows/artifactpoisoning21.yml:4:3:4:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning22.yml:18:14:18:19 | sh cmd | .github/workflows/artifactpoisoning22.yml:13:9:17:6 | Uses Step | .github/workflows/artifactpoisoning22.yml:18:14:18:19 | sh cmd | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/artifactpoisoning22.yml:18:14:18:19 | sh cmd | sh cmd | .github/workflows/artifactpoisoning22.yml:4:3:4:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning31.yml:19:14:19:22 | ./foo/cmd | .github/workflows/artifactpoisoning31.yml:13:9:15:6 | Run Step | .github/workflows/artifactpoisoning31.yml:19:14:19:22 | ./foo/cmd | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/artifactpoisoning31.yml:19:14:19:22 | ./foo/cmd | ./foo/cmd | .github/workflows/artifactpoisoning31.yml:4:3:4:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning32.yml:17:14:18:20 | ./bar/cmd\n | .github/workflows/artifactpoisoning32.yml:13:9:16:6 | Run Step | .github/workflows/artifactpoisoning32.yml:17:14:18:20 | ./bar/cmd\n | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/artifactpoisoning32.yml:17:14:18:20 | ./bar/cmd\n | ./bar/cmd\n | .github/workflows/artifactpoisoning32.yml:4:3:4:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning33.yml:17:14:18:20 | ./bar/cmd\n | .github/workflows/artifactpoisoning33.yml:13:9:16:6 | Run Step | .github/workflows/artifactpoisoning33.yml:17:14:18:20 | ./bar/cmd\n | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/artifactpoisoning33.yml:17:14:18:20 | ./bar/cmd\n | ./bar/cmd\n | .github/workflows/artifactpoisoning33.yml:4:3:4:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning34.yml:20:14:22:23 | npm install\nnpm run lint\n | .github/workflows/artifactpoisoning34.yml:13:9:16:6 | Run Step | .github/workflows/artifactpoisoning34.yml:20:14:22:23 | npm install\nnpm run lint\n | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/artifactpoisoning34.yml:20:14:22:23 | npm install\nnpm run lint\n | npm install\nnpm run lint\n | .github/workflows/artifactpoisoning34.yml:4:3:4:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning41.yml:22:14:22:22 | ./foo/cmd | .github/workflows/artifactpoisoning41.yml:13:9:21:6 | Run Step | .github/workflows/artifactpoisoning41.yml:22:14:22:22 | ./foo/cmd | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/artifactpoisoning41.yml:22:14:22:22 | ./foo/cmd | ./foo/cmd | .github/workflows/artifactpoisoning41.yml:4:3:4:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning42.yml:22:14:22:18 | ./cmd | .github/workflows/artifactpoisoning42.yml:13:9:21:6 | Run Step | .github/workflows/artifactpoisoning42.yml:22:14:22:18 | ./cmd | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/artifactpoisoning42.yml:22:14:22:18 | ./cmd | ./cmd | .github/workflows/artifactpoisoning42.yml:4:3:4:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning71.yml:17:14:18:40 | sed -f config foo.md > bar.md\n | .github/workflows/artifactpoisoning71.yml:9:9:16:6 | Uses Step | .github/workflows/artifactpoisoning71.yml:17:14:18:40 | sed -f config foo.md > bar.md\n | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/artifactpoisoning71.yml:17:14:18:40 | sed -f config foo.md > bar.md\n | sed -f config foo.md > bar.md\n | .github/workflows/artifactpoisoning71.yml:4:5:4:16 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning81.yml:31:14:31:27 | python test.py | .github/workflows/artifactpoisoning81.yml:28:9:31:6 | Uses Step | .github/workflows/artifactpoisoning81.yml:31:14:31:27 | python test.py | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/artifactpoisoning81.yml:31:14:31:27 | python test.py | python test.py | .github/workflows/artifactpoisoning81.yml:3:5:3:23 | pull_request_target | pull_request_target |
|
||||
| .github/workflows/artifactpoisoning92.yml:28:9:29:6 | Uses Step | .github/actions/download-artifact-2/action.yaml:6:7:25:4 | Uses Step | .github/workflows/artifactpoisoning92.yml:28:9:29:6 | Uses Step | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/artifactpoisoning92.yml:28:9:29:6 | Uses Step | Uses Step | .github/workflows/artifactpoisoning92.yml:3:3:3:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning92.yml:29:14:29:26 | make snapshot | .github/actions/download-artifact-2/action.yaml:6:7:25:4 | Uses Step | .github/workflows/artifactpoisoning92.yml:29:14:29:26 | make snapshot | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/artifactpoisoning92.yml:29:14:29:26 | make snapshot | make snapshot | .github/workflows/artifactpoisoning92.yml:3:3:3:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning96.yml:18:14:18:24 | npm install | .github/workflows/artifactpoisoning96.yml:13:9:18:6 | Uses Step | .github/workflows/artifactpoisoning96.yml:18:14:18:24 | npm install | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/artifactpoisoning96.yml:18:14:18:24 | npm install | npm install | .github/workflows/artifactpoisoning96.yml:2:3:2:14 | workflow_run | workflow_run |
|
||||
| .github/workflows/artifactpoisoning101.yml:17:14:19:59 | PR_NUMBER=$(./get_pull_request_number.sh pr_number.txt)\necho "PR_NUMBER=$PR_NUMBER" >> $GITHUB_OUTPUT \n | .github/workflows/artifactpoisoning101.yml:10:9:16:6 | Uses Step | .github/workflows/artifactpoisoning101.yml:17:14:19:59 | PR_NUMBER=$(./get_pull_request_number.sh pr_number.txt)\necho "PR_NUMBER=$PR_NUMBER" >> $GITHUB_OUTPUT \n | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/artifactpoisoning101.yml:17:14:19:59 | PR_NUMBER=$(./get_pull_request_number.sh pr_number.txt)\necho "PR_NUMBER=$PR_NUMBER" >> $GITHUB_OUTPUT \n | PR_NUMBER=$(./get_pull_request_number.sh pr_number.txt)\necho "PR_NUMBER=$PR_NUMBER" >> $GITHUB_OUTPUT \n | .github/workflows/artifactpoisoning101.yml:4:3:4:21 | pull_request_target | pull_request_target |
|
||||
| .github/workflows/test18.yml:36:15:40:58 | Uses Step | .github/workflows/test18.yml:12:15:33:12 | Uses Step | .github/workflows/test18.yml:36:15:40:58 | Uses Step | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/test18.yml:36:15:40:58 | Uses Step | Uses Step | .github/workflows/test18.yml:3:5:3:16 | workflow_run | workflow_run |
|
||||
| .github/workflows/test25.yml:39:14:40:45 | ./gradlew buildScanPublishPrevious\n | .github/workflows/test25.yml:22:9:32:6 | Uses Step: downloadBuildScan | .github/workflows/test25.yml:39:14:40:45 | ./gradlew buildScanPublishPrevious\n | Potential artifact poisoning in $@, which may be controlled by an external user ($@). | .github/workflows/test25.yml:39:14:40:45 | ./gradlew buildScanPublishPrevious\n | ./gradlew buildScanPublishPrevious\n | .github/workflows/test25.yml:2:3:2:14 | workflow_run | workflow_run |
|
||||
|
||||
@@ -199,7 +199,6 @@ def annotate_as_appropriate(filename, lines):
|
||||
# as overlay[local?]. It is not clear that these heuristics are exactly what we want,
|
||||
# but they seem to work well enough for now (as determined by speed and accuracy numbers).
|
||||
if (filename.endswith("Test.qll") or
|
||||
re.search(r"go/ql/lib/semmle/go/security/[^/]+[.]qll$", filename.replace(os.sep, "/")) or
|
||||
((filename.endswith("Query.qll") or filename.endswith("Config.qll")) and
|
||||
any("implements DataFlow::ConfigSig" in line for line in lines))):
|
||||
return None
|
||||
|
||||
@@ -172,6 +172,10 @@
|
||||
"cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/reachability/PrintDominance.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/reachability/PrintDominance.qll"
|
||||
],
|
||||
"C# ControlFlowReachability": [
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/ControlFlowReachability.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/ControlFlowReachability.qll"
|
||||
],
|
||||
"C++ ExternalAPIs": [
|
||||
"cpp/ql/src/Security/CWE/CWE-020/ExternalAPIs.qll",
|
||||
"cpp/ql/src/Security/CWE/CWE-020/ir/ExternalAPIs.qll"
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
class Element extends @element {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Trap extends @trap {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Tag extends @tag {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
from Element e, Trap trap
|
||||
where
|
||||
in_trap_or_tag(e, trap)
|
||||
or
|
||||
exists(Tag tag |
|
||||
in_trap_or_tag(e, tag) and
|
||||
trap_uses_tag(trap, tag)
|
||||
)
|
||||
select e, trap
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,13 +0,0 @@
|
||||
class SourceFile extends @source_file {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Trap extends @trap {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
from SourceFile source_file, string name, Trap trap
|
||||
where
|
||||
source_file_uses_trap(source_file, trap) and
|
||||
source_file_name(source_file, name)
|
||||
select name, trap
|
||||
@@ -1,8 +0,0 @@
|
||||
description: Add source_file_name
|
||||
compatibility: backwards
|
||||
source_file_uses_trap.rel: run source_file_uses_trap.ql
|
||||
source_file_name.rel: delete
|
||||
tag_name.rel: delete
|
||||
trap_uses_tag.rel: delete
|
||||
in_trap.rel: run in_trap.ql
|
||||
in_trap_or_tag.rel: delete
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,5 +0,0 @@
|
||||
description: Add trap_filename, source_file_uses_trap and in_trap relations
|
||||
compatibility: full
|
||||
trap_filename.rel: delete
|
||||
source_file_uses_trap.rel: delete
|
||||
in_trap.rel: delete
|
||||
@@ -7,12 +7,10 @@ ql/cpp/ql/src/Diagnostics/ExtractedFiles.ql
|
||||
ql/cpp/ql/src/Diagnostics/ExtractionWarnings.ql
|
||||
ql/cpp/ql/src/Diagnostics/FailedExtractorInvocations.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Arithmetic/BadAdditionOverflowCheck.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Arithmetic/IntMultToLong.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Arithmetic/SignedOverflowCheck.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Conversion/CastArrayPointerArithmetic.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Format/SnprintfOverflow.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Format/WrongNumberOfFormatArguments.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArguments.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Memory Management/AllocaInLoop.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Memory Management/PointerOverflow.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Memory Management/ReturnStackAllocatedMemory.ql
|
||||
@@ -30,7 +28,6 @@ ql/cpp/ql/src/Security/CWE/CWE-120/VeryLikelyOverrunWrite.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-190/ArithmeticUncontrolled.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-253/HResultBooleanConversion.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-311/CleartextFileWrite.ql
|
||||
@@ -43,7 +40,6 @@ ql/cpp/ql/src/Security/CWE/CWE-367/TOCTOUFilesystemRace.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-416/IteratorToExpiredContainer.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-416/UseOfStringAfterLifetimeEnds.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-416/UseOfUniquePointerAfterLifetimeEnds.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-468/SuspiciousAddWithSizeof.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-497/ExposedSystemData.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-611/XXE.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-676/DangerousFunctionOverflow.ql
|
||||
@@ -56,6 +52,5 @@ ql/cpp/ql/src/Summary/LinesOfUserCode.ql
|
||||
ql/cpp/ql/src/Telemetry/CompilerErrors.ql
|
||||
ql/cpp/ql/src/Telemetry/DatabaseQuality.ql
|
||||
ql/cpp/ql/src/Telemetry/ExtractionMetrics.ql
|
||||
ql/cpp/ql/src/Telemetry/ExtractorInformation.ql
|
||||
ql/cpp/ql/src/Telemetry/MissingIncludes.ql
|
||||
ql/cpp/ql/src/Telemetry/SucceededIncludes.ql
|
||||
|
||||
@@ -160,7 +160,6 @@ ql/cpp/ql/src/Summary/LinesOfUserCode.ql
|
||||
ql/cpp/ql/src/Telemetry/CompilerErrors.ql
|
||||
ql/cpp/ql/src/Telemetry/DatabaseQuality.ql
|
||||
ql/cpp/ql/src/Telemetry/ExtractionMetrics.ql
|
||||
ql/cpp/ql/src/Telemetry/ExtractorInformation.ql
|
||||
ql/cpp/ql/src/Telemetry/MissingIncludes.ql
|
||||
ql/cpp/ql/src/Telemetry/SucceededIncludes.ql
|
||||
ql/cpp/ql/src/jsf/4.06 Pre-Processing Directives/AV Rule 32.ql
|
||||
|
||||
@@ -93,6 +93,5 @@ ql/cpp/ql/src/Summary/LinesOfUserCode.ql
|
||||
ql/cpp/ql/src/Telemetry/CompilerErrors.ql
|
||||
ql/cpp/ql/src/Telemetry/DatabaseQuality.ql
|
||||
ql/cpp/ql/src/Telemetry/ExtractionMetrics.ql
|
||||
ql/cpp/ql/src/Telemetry/ExtractorInformation.ql
|
||||
ql/cpp/ql/src/Telemetry/MissingIncludes.ql
|
||||
ql/cpp/ql/src/Telemetry/SucceededIncludes.ql
|
||||
|
||||
@@ -1,69 +1,3 @@
|
||||
## 10.0.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* The deprecated `NonThrowingFunction` class has been removed, use `NonCppThrowingFunction` instead.
|
||||
* The deprecated `ThrowingFunction` class has been removed, use `AlwaysSehThrowingFunction` instead.
|
||||
|
||||
### New Features
|
||||
|
||||
* Added a subclass `AutoconfConfigureTestFile` of `ConfigurationTestFile` that represents files created by GNU autoconf configure scripts to test the build configuration.
|
||||
|
||||
## 9.0.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* The `SourceModelCsv`, `SinkModelCsv`, and `SummaryModelCsv` classes and the associated CSV parsing infrastructure have been removed from `ExternalFlow.qll`. New models should be added as `.model.yml` files in the `ext/` directory.
|
||||
|
||||
### New Features
|
||||
|
||||
* Added a subclass `MesonPrivateTestFile` of `ConfigurationTestFile` that represents files created by Meson to test the build configuration.
|
||||
* Added a class `ConstructorDirectFieldInit` to represent field initializations that occur in member initializer lists.
|
||||
* Added a class `ConstructorDefaultFieldInit` to represent default field initializations.
|
||||
* Added a class `DataFlow::IndirectParameterNode` to represent the indirection of a parameter as a dataflow node.
|
||||
* Added a predicate `Node::asIndirectInstruction` which returns the `Instruction` that defines the indirect dataflow node, if any.
|
||||
* Added a class `IndirectUninitializedNode` to represent the indirection of an uninitialized local variable as a dataflow node.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Added `HttpReceiveHttpRequest`, `HttpReceiveRequestEntityBody`, and `HttpReceiveClientCertificate` from Win32's `http.h` as remote flow sources.
|
||||
* Added dataflow through members initialized via non-static data member initialization (NSDMI).
|
||||
|
||||
## 8.0.3
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 8.0.2
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 8.0.1
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Inline expectations test comments, which are of the form `// $ tag` or `// $ tag=value`, are now parsed more strictly and will not be recognized if there isn't a space after the `$` symbol.
|
||||
|
||||
## 8.0.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* CodeQL version 2.24.2 accidentally introduced a syntactical breaking change to `BarrierGuard<...>::getAnIndirectBarrierNode` and `InstructionBarrierGuard<...>::getAnIndirectBarrierNode`. These breaking changes have now been reverted so that the original code compiles again.
|
||||
* `MustFlow`, the inter-procedural must-flow data flow analysis library, has been re-worked to use parameterized modules. Like in the case of data flow and taint tracking, instead of extending the `MustFlowConfiguration` class, the user should now implement a module with the `MustFlow::ConfigSig` signature, and instantiate the `MustFlow::Global` parameterized module with the implemented module.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Refactored the "Year field changed using an arithmetic operation without checking for leap year" query (`cpp/leap-year/unchecked-after-arithmetic-year-modification`) to address large numbers of false positive results.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* The `allowInterproceduralFlow` predicate of must-flow data flow configurations now correctly handles direct recursion.
|
||||
|
||||
## 7.1.1
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Added remote flow source models for the `winhttp.h` windows header and the Azure SDK core library for C/C++.
|
||||
|
||||
## 7.1.0
|
||||
|
||||
### New Features
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* Data flow barriers and barrier guards can now be added using data extensions. For more information see [Customizing library models for C and C++](https://codeql.github.com/docs/codeql-language-guides/customizing-library-models-for-cpp/).
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* A new predicate `getSwitchCase` was added to the `SwitchStmt` class, which yields the `n`th `case` statement from a `switch` statement.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Added taint flow models for the `Strsafe.h` header from the Windows SDK.
|
||||
@@ -1,10 +0,0 @@
|
||||
## 10.0.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* The deprecated `NonThrowingFunction` class has been removed, use `NonCppThrowingFunction` instead.
|
||||
* The deprecated `ThrowingFunction` class has been removed, use `AlwaysSehThrowingFunction` instead.
|
||||
|
||||
### New Features
|
||||
|
||||
* Added a subclass `AutoconfConfigureTestFile` of `ConfigurationTestFile` that represents files created by GNU autoconf configure scripts to test the build configuration.
|
||||
@@ -1,5 +0,0 @@
|
||||
## 7.1.1
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Added remote flow source models for the `winhttp.h` windows header and the Azure SDK core library for C/C++.
|
||||
@@ -1,14 +0,0 @@
|
||||
## 8.0.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* CodeQL version 2.24.2 accidentally introduced a syntactical breaking change to `BarrierGuard<...>::getAnIndirectBarrierNode` and `InstructionBarrierGuard<...>::getAnIndirectBarrierNode`. These breaking changes have now been reverted so that the original code compiles again.
|
||||
* `MustFlow`, the inter-procedural must-flow data flow analysis library, has been re-worked to use parameterized modules. Like in the case of data flow and taint tracking, instead of extending the `MustFlowConfiguration` class, the user should now implement a module with the `MustFlow::ConfigSig` signature, and instantiate the `MustFlow::Global` parameterized module with the implemented module.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Refactored the "Year field changed using an arithmetic operation without checking for leap year" query (`cpp/leap-year/unchecked-after-arithmetic-year-modification`) to address large numbers of false positive results.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* The `allowInterproceduralFlow` predicate of must-flow data flow configurations now correctly handles direct recursion.
|
||||
@@ -1,5 +0,0 @@
|
||||
## 8.0.1
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Inline expectations test comments, which are of the form `// $ tag` or `// $ tag=value`, are now parsed more strictly and will not be recognized if there isn't a space after the `$` symbol.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 8.0.2
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,3 +0,0 @@
|
||||
## 8.0.3
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,19 +0,0 @@
|
||||
## 9.0.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* The `SourceModelCsv`, `SinkModelCsv`, and `SummaryModelCsv` classes and the associated CSV parsing infrastructure have been removed from `ExternalFlow.qll`. New models should be added as `.model.yml` files in the `ext/` directory.
|
||||
|
||||
### New Features
|
||||
|
||||
* Added a subclass `MesonPrivateTestFile` of `ConfigurationTestFile` that represents files created by Meson to test the build configuration.
|
||||
* Added a class `ConstructorDirectFieldInit` to represent field initializations that occur in member initializer lists.
|
||||
* Added a class `ConstructorDefaultFieldInit` to represent default field initializations.
|
||||
* Added a class `DataFlow::IndirectParameterNode` to represent the indirection of a parameter as a dataflow node.
|
||||
* Added a predicate `Node::asIndirectInstruction` which returns the `Instruction` that defines the indirect dataflow node, if any.
|
||||
* Added a class `IndirectUninitializedNode` to represent the indirection of an uninitialized local variable as a dataflow node.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Added `HttpReceiveHttpRequest`, `HttpReceiveRequestEntityBody`, and `HttpReceiveClientCertificate` from Win32's `http.h` as remote flow sources.
|
||||
* Added dataflow through members initialized via non-static data member initialization (NSDMI).
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 10.0.0
|
||||
lastReleaseVersion: 7.1.0
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
# Models for strsafe.h safe string functions
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: sourceModel
|
||||
data: # namespace, type, subtypes, name, signature, ext, output, kind, provenance
|
||||
# StringCchGets: (pszDest, cchDest)
|
||||
- ["", "", False, "StringCchGetsA", "", "", "Argument[*0]", "local", "manual"]
|
||||
- ["", "", False, "StringCchGetsW", "", "", "Argument[*0]", "local", "manual"]
|
||||
# StringCbGets: (pszDest, cbDest)
|
||||
- ["", "", False, "StringCbGetsA", "", "", "Argument[*0]", "local", "manual"]
|
||||
- ["", "", False, "StringCbGetsW", "", "", "Argument[*0]", "local", "manual"]
|
||||
# StringCchGetsEx: (pszDest, cchDest, ppszDestEnd, pcchRemaining, dwFlags)
|
||||
- ["", "", False, "StringCchGetsExA", "", "", "Argument[*0]", "local", "manual"]
|
||||
- ["", "", False, "StringCchGetsExW", "", "", "Argument[*0]", "local", "manual"]
|
||||
# StringCbGetsEx: (pszDest, cbDest, ppszDestEnd, pcbRemaining, dwFlags)
|
||||
- ["", "", False, "StringCbGetsExA", "", "", "Argument[*0]", "local", "manual"]
|
||||
- ["", "", False, "StringCbGetsExW", "", "", "Argument[*0]", "local", "manual"]
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: summaryModel
|
||||
data: # namespace, type, subtypes, name, signature, ext, input, output, kind, provenance
|
||||
# StringCchCopy: (pszDest, cchDest, pszSrc)
|
||||
- ["", "", False, "StringCchCopyA", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
|
||||
- ["", "", False, "StringCchCopyW", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
|
||||
# StringCbCopy: (pszDest, cbDest, pszSrc)
|
||||
- ["", "", False, "StringCbCopyA", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
|
||||
- ["", "", False, "StringCbCopyW", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
|
||||
# StringCchCopyEx: (pszDest, cchDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags)
|
||||
- ["", "", False, "StringCchCopyExA", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
|
||||
- ["", "", False, "StringCchCopyExW", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
|
||||
# StringCbCopyEx: (pszDest, cbDest, pszSrc, ppszDestEnd, pcbRemaining, dwFlags)
|
||||
- ["", "", False, "StringCbCopyExA", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
|
||||
- ["", "", False, "StringCbCopyExW", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
|
||||
# StringCchCopyN: (pszDest, cchDest, pszSrc, cchToCopy)
|
||||
- ["", "", False, "StringCchCopyNA", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
|
||||
- ["", "", False, "StringCchCopyNW", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
|
||||
# StringCbCopyN: (pszDest, cbDest, pszSrc, cbToCopy)
|
||||
- ["", "", False, "StringCbCopyNA", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
|
||||
- ["", "", False, "StringCbCopyNW", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
|
||||
# StringCchCopyNEx: (pszDest, cchDest, pszSrc, cchToCopy, ppszDestEnd, pcchRemaining, dwFlags)
|
||||
- ["", "", False, "StringCchCopyNExA", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
|
||||
- ["", "", False, "StringCchCopyNExW", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
|
||||
# StringCbCopyNEx: (pszDest, cbDest, pszSrc, cbToCopy, ppszDestEnd, pcbRemaining, dwFlags)
|
||||
- ["", "", False, "StringCbCopyNExA", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
|
||||
- ["", "", False, "StringCbCopyNExW", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
|
||||
# StringCchCat: (pszDest, cchDest, pszSrc)
|
||||
- ["", "", False, "StringCchCatA", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
|
||||
- ["", "", False, "StringCchCatW", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
|
||||
# StringCbCat: (pszDest, cbDest, pszSrc)
|
||||
- ["", "", False, "StringCbCatA", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
|
||||
- ["", "", False, "StringCbCatW", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
|
||||
# StringCchCatEx: (pszDest, cchDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags)
|
||||
- ["", "", False, "StringCchCatExA", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
|
||||
- ["", "", False, "StringCchCatExW", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
|
||||
# StringCbCatEx: (pszDest, cbDest, pszSrc, ppszDestEnd, pcbRemaining, dwFlags)
|
||||
- ["", "", False, "StringCbCatExA", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
|
||||
- ["", "", False, "StringCbCatExW", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
|
||||
# StringCchCatN: (pszDest, cchDest, pszSrc, cchToAppend)
|
||||
- ["", "", False, "StringCchCatNA", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
|
||||
- ["", "", False, "StringCchCatNW", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
|
||||
# StringCbCatN: (pszDest, cbDest, pszSrc, cbToAppend)
|
||||
- ["", "", False, "StringCbCatNA", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
|
||||
- ["", "", False, "StringCbCatNW", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
|
||||
# StringCchCatNEx: (pszDest, cchDest, pszSrc, cchToAppend, ppszDestEnd, pcchRemaining, dwFlags)
|
||||
- ["", "", False, "StringCchCatNExA", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
|
||||
- ["", "", False, "StringCchCatNExW", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
|
||||
# StringCbCatNEx: (pszDest, cbDest, pszSrc, cbToAppend, ppszDestEnd, pcbRemaining, dwFlags)
|
||||
- ["", "", False, "StringCbCatNExA", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
|
||||
- ["", "", False, "StringCbCatNExW", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
|
||||
# StringCchPrintf: (pszDest, cchDest, pszFormat, ...)
|
||||
- ["", "", False, "StringCchPrintfA", "", "", "Argument[*2..8]", "Argument[*0]", "taint", "manual"]
|
||||
- ["", "", False, "StringCchPrintfW", "", "", "Argument[*2..8]", "Argument[*0]", "taint", "manual"]
|
||||
# StringCbPrintf: (pszDest, cbDest, pszFormat, ...)
|
||||
- ["", "", False, "StringCbPrintfA", "", "", "Argument[*2..8]", "Argument[*0]", "taint", "manual"]
|
||||
- ["", "", False, "StringCbPrintfW", "", "", "Argument[*2..8]", "Argument[*0]", "taint", "manual"]
|
||||
# StringCchPrintfEx: (pszDest, cchDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, ...)
|
||||
- ["", "", False, "StringCchPrintfExA", "", "", "Argument[*5..11]", "Argument[*0]", "taint", "manual"]
|
||||
- ["", "", False, "StringCchPrintfExW", "", "", "Argument[*5..11]", "Argument[*0]", "taint", "manual"]
|
||||
# StringCbPrintfEx: (pszDest, cbDest, ppszDestEnd, pcbRemaining, dwFlags, pszFormat, ...)
|
||||
- ["", "", False, "StringCbPrintfExA", "", "", "Argument[*5..11]", "Argument[*0]", "taint", "manual"]
|
||||
- ["", "", False, "StringCbPrintfExW", "", "", "Argument[*5..11]", "Argument[*0]", "taint", "manual"]
|
||||
# StringCchVPrintf: (pszDest, cchDest, pszFormat, argList)
|
||||
- ["", "", False, "StringCchVPrintfA", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
|
||||
- ["", "", False, "StringCchVPrintfW", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
|
||||
# StringCbVPrintf: (pszDest, cbDest, pszFormat, argList)
|
||||
- ["", "", False, "StringCbVPrintfA", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
|
||||
- ["", "", False, "StringCbVPrintfW", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"]
|
||||
# StringCchVPrintfEx: (pszDest, cchDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, argList)
|
||||
- ["", "", False, "StringCchVPrintfExA", "", "", "Argument[*5]", "Argument[*0]", "taint", "manual"]
|
||||
- ["", "", False, "StringCchVPrintfExW", "", "", "Argument[*5]", "Argument[*0]", "taint", "manual"]
|
||||
# StringCbVPrintfEx: (pszDest, cbDest, ppszDestEnd, pcbRemaining, dwFlags, pszFormat, argList)
|
||||
- ["", "", False, "StringCbVPrintfExA", "", "", "Argument[*5]", "Argument[*0]", "taint", "manual"]
|
||||
- ["", "", False, "StringCbVPrintfExW", "", "", "Argument[*5]", "Argument[*0]", "taint", "manual"]
|
||||
@@ -24,16 +24,6 @@ extensions:
|
||||
- ["", "", False, "MapViewOfFileNuma2", "", "", "ReturnValue[*]", "local", "manual"]
|
||||
# ntifs.h
|
||||
- ["", "", False, "NtReadFile", "", "", "Argument[*5]", "local", "manual"]
|
||||
# winhttp.h
|
||||
- ["", "", False, "WinHttpReadData", "", "", "Argument[*1]", "remote", "manual"]
|
||||
- ["", "", False, "WinHttpReadDataEx", "", "", "Argument[*1]", "remote", "manual"]
|
||||
- ["", "", False, "WinHttpQueryHeaders", "", "", "Argument[*3]", "remote", "manual"]
|
||||
- ["", "", False, "WinHttpQueryHeadersEx", "", "", "Argument[*5]", "remote", "manual"]
|
||||
- ["", "", False, "WinHttpQueryHeadersEx", "", "", "Argument[*6]", "remote", "manual"]
|
||||
- ["", "", False, "WinHttpQueryHeadersEx", "", "", "Argument[**8]", "remote", "manual"]
|
||||
- ["", "", False, "HttpReceiveHttpRequest", "", "", "Argument[*3]", "remote", "manual"]
|
||||
- ["", "", False, "HttpReceiveRequestEntityBody", "", "", "Argument[*3]", "remote", "manual"]
|
||||
- ["", "", False, "HttpReceiveClientCertificate", "", "", "Argument[*3]", "remote", "manual"]
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: summaryModel
|
||||
@@ -56,6 +46,4 @@ extensions:
|
||||
- ["", "", False, "RtlMoveMemory", "", "", "Argument[*@1]", "Argument[*@0]", "value", "manual"]
|
||||
- ["", "", False, "RtlMoveVolatileMemory", "", "", "Argument[*@1]", "Argument[*@0]", "value", "manual"]
|
||||
# winternl.h
|
||||
- ["", "", False, "RtlInitUnicodeString", "", "", "Argument[*1]", "Argument[*0].Field[*Buffer]", "value", "manual"]
|
||||
# winhttp.h
|
||||
- ["", "", False, "WinHttpCrackUrl", "", "", "Argument[*0]", "Argument[*3]", "taint", "manual"]
|
||||
- ["", "", False, "RtlInitUnicodeString", "", "", "Argument[*1]", "Argument[*0].Field[*Buffer]", "value", "manual"]
|
||||
@@ -1,22 +0,0 @@
|
||||
# ZeroMQ networking library models
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: sourceModel
|
||||
data: # namespace, type, subtypes, name, signature, ext, output, kind, provenance
|
||||
- ["", "", False, "zmq_recv", "", "", "Argument[*1]", "remote", "manual"]
|
||||
- ["", "", False, "zmq_recvmsg", "", "", "Argument[*1]", "remote", "manual"]
|
||||
- ["", "", False, "zmq_msg_recv", "", "", "Argument[*0]", "remote", "manual"]
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: sinkModel
|
||||
data: # namespace, type, subtypes, name, signature, ext, input, kind, provenance
|
||||
- ["", "", False, "zmq_send", "", "", "Argument[*1]", "remote-sink", "manual"]
|
||||
- ["", "", False, "zmq_sendmsg", "", "", "Argument[*1]", "remote-sink", "manual"]
|
||||
- ["", "", False, "zmq_msg_send", "", "", "Argument[*0]", "remote-sink", "manual"]
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: summaryModel
|
||||
data: # namespace, type, subtypes, name, signature, ext, input, output, kind, provenance
|
||||
- ["", "", False, "zmq_msg_init_data", "", "", "Argument[*1]", "Argument[*0]", "taint", "manual"]
|
||||
- ["", "", False, "zmq_msg_data", "", "", "Argument[*0]", "ReturnValue[*]", "taint", "manual"]
|
||||
@@ -12,7 +12,4 @@ extensions:
|
||||
- ["", "", False, "_malloca", "0", "", "", False]
|
||||
- ["", "", False, "calloc", "1", "0", "", True]
|
||||
- ["std", "", False, "calloc", "1", "0", "", True]
|
||||
- ["bsl", "", False, "calloc", "1", "0", "", True]
|
||||
- ["", "", False, "aligned_alloc", "1", "", "", True]
|
||||
- ["std", "", False, "aligned_alloc", "1", "", "", True]
|
||||
- ["bsl", "", False, "aligned_alloc", "1", "", "", True]
|
||||
- ["bsl", "", False, "calloc", "1", "0", "", True]
|
||||
@@ -1,41 +0,0 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: sourceModel
|
||||
data: # namespace, type, subtypes, name, signature, ext, output, kind, provenance
|
||||
- ["Azure::Core::Http", "RawResponse", True, "GetHeaders", "", "", "ReturnValue[*]", "remote", "manual"]
|
||||
- ["Azure::Core::Http", "RawResponse", True, "GetBody", "", "", "ReturnValue[*]", "remote", "manual"]
|
||||
- ["Azure::Core::Http", "RawResponse", True, "ExtractBodyStream", "", "", "ReturnValue[*]", "remote", "manual"]
|
||||
- ["Azure::Core::Http", "Request", True, "GetHeaders", "", "", "ReturnValue", "remote", "manual"]
|
||||
- ["Azure::Core::Http", "Request", True, "GetHeader", "", "", "ReturnValue", "remote", "manual"]
|
||||
- ["Azure::Core::Http", "Request", True, "GetBodyStream", "", "", "ReturnValue[*]", "remote", "manual"]
|
||||
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: summaryModel
|
||||
data: # namespace, type, subtypes, name, signature, ext, input, output, kind, provenance
|
||||
- ["Azure::Core", "Url", True, "Url", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"]
|
||||
- ["Azure::Core", "Url", True, "SetScheme", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"]
|
||||
- ["Azure::Core", "Url", True, "SetHost", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"]
|
||||
- ["Azure::Core", "Url", True, "SetPort", "", "", "Argument[0]", "Argument[-1]", "taint", "manual"]
|
||||
- ["Azure::Core", "Url", True, "SetPath", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"]
|
||||
- ["Azure::Core", "Url", True, "SetQueryParameters", "", "", "Argument[0]", "Argument[-1]", "taint", "manual"]
|
||||
- ["Azure::Core", "Url", True, "AppendPath", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"]
|
||||
- ["Azure::Core", "Url", True, "AppendQueryParameter", "", "", "Argument[*1]", "Argument[-1]", "taint", "manual"]
|
||||
- ["Azure::Core", "Url", True, "GetHost", "", "", "Argument[-1]", "ReturnValue[*]", "taint", "manual"]
|
||||
- ["Azure::Core", "Url", True, "GetPath", "", "", "Argument[-1]", "ReturnValue[*]", "taint", "manual"]
|
||||
- ["Azure::Core", "Url", True, "GetPort", "", "", "Argument[-1]", "ReturnValue", "taint", "manual"]
|
||||
- ["Azure::Core", "Url", True, "GetQueryParameters", "", "", "Argument[-1]", "ReturnValue", "taint", "manual"]
|
||||
- ["Azure::Core", "Url", True, "GetScheme", "", "", "Argument[-1]", "ReturnValue[*]", "taint", "manual"]
|
||||
- ["Azure::Core", "Url", True, "GetRelativeUrl", "", "", "Argument[-1]", "ReturnValue", "taint", "manual"]
|
||||
- ["Azure::Core", "Url", True, "GetAbsoluteUrl", "", "", "Argument[-1]", "ReturnValue", "taint", "manual"]
|
||||
- ["Azure::Core", "Url", True, "Decode", "", "", "Argument[*0]", "ReturnValue", "taint", "manual"]
|
||||
- ["Azure::Core", "Url", True, "Encode", "", "", "Argument[*0]", "ReturnValue", "taint", "manual"]
|
||||
- ["Azure::Core::IO", "BodyStream", True, "Read", "", "", "Argument[-1]", "Argument[*0]", "taint", "manual"]
|
||||
- ["Azure::Core::IO", "BodyStream", True, "ReadToCount", "", "", "Argument[-1]", "Argument[*0]", "taint", "manual"]
|
||||
- ["Azure::Core::IO", "BodyStream", True, "ReadToEnd", "", "", "Argument[-1]", "ReturnValue.Element", "taint", "manual"]
|
||||
- ["Azure", "Nullable", True, "Nullable", "", "", "Argument[0]", "Argument[-1]", "taint", "manual"]
|
||||
- ["Azure", "Nullable", True, "operator=", "", "", "Argument[*0]", "Argument[-1]", "value", "manual"]
|
||||
- ["Azure", "Nullable", True, "Value", "", "", "Argument[-1]", "ReturnValue[*]", "taint", "manual"]
|
||||
- ["Azure", "Nullable", True, "operator->", "", "", "Argument[-1]", "ReturnValue[*]", "taint", "manual"]
|
||||
- ["Azure", "Nullable", True, "operator*", "", "", "Argument[-1]", "ReturnValue[*]", "taint", "manual"]
|
||||
@@ -1,19 +0,0 @@
|
||||
# Models for getc and similar character-reading functions
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: sourceModel
|
||||
data: # namespace, type, subtypes, name, signature, ext, output, kind, provenance
|
||||
- ["", "", False, "getc", "", "", "ReturnValue", "remote", "manual"]
|
||||
- ["", "", False, "getwc", "", "", "ReturnValue", "remote", "manual"]
|
||||
- ["", "", False, "_getc_nolock", "", "", "ReturnValue", "remote", "manual"]
|
||||
- ["", "", False, "_getwc_nolock", "", "", "ReturnValue", "remote", "manual"]
|
||||
- ["", "", False, "getch", "", "", "ReturnValue", "local", "manual"]
|
||||
- ["", "", False, "_getch", "", "", "ReturnValue", "local", "manual"]
|
||||
- ["", "", False, "_getwch", "", "", "ReturnValue", "local", "manual"]
|
||||
- ["", "", False, "_getch_nolock", "", "", "ReturnValue", "local", "manual"]
|
||||
- ["", "", False, "_getwch_nolock", "", "", "ReturnValue", "local", "manual"]
|
||||
- ["", "", False, "getchar", "", "", "ReturnValue", "local", "manual"]
|
||||
- ["", "", False, "getwchar", "", "", "ReturnValue", "local", "manual"]
|
||||
- ["", "", False, "_getchar_nolock", "", "", "ReturnValue", "local", "manual"]
|
||||
- ["", "", False, "_getwchar_nolock", "", "", "ReturnValue", "local", "manual"]
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 10.0.1-dev
|
||||
version: 7.1.0
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -26,26 +26,3 @@ class CmakeTryCompileFile extends ConfigurationTestFile {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A file created by Meson to test the system configuration.
|
||||
*/
|
||||
class MesonPrivateTestFile extends ConfigurationTestFile {
|
||||
MesonPrivateTestFile() {
|
||||
this.getBaseName() = "testfile.c" and
|
||||
exists(Folder folder, Folder parent |
|
||||
folder = this.getParentContainer() and
|
||||
parent = folder.getParentContainer()
|
||||
|
|
||||
folder.getBaseName().matches("tmp%") and
|
||||
parent.getBaseName() = "meson-private"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A file created by a GNU autoconf configure script to test the system configuration.
|
||||
*/
|
||||
class AutoconfConfigureTestFile extends ConfigurationTestFile {
|
||||
AutoconfConfigureTestFile() { this.getBaseName().regexpMatch("conftest[0-9]*\\.c(pp)?") }
|
||||
}
|
||||
|
||||
@@ -524,12 +524,6 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
|
||||
not exists(NewOrNewArrayExpr new | e = new.getAllocatorCall().getArgument(0))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this function has an ambiguous return type, meaning that zero or multiple return
|
||||
* types for this function are present in the database (this can occur in `build-mode: none`).
|
||||
*/
|
||||
predicate hasAmbiguousReturnType() { count(this.getType()) != 1 }
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
|
||||
@@ -14,9 +14,7 @@ class PackedTimeType extends Type {
|
||||
}
|
||||
}
|
||||
|
||||
private predicate timeType(string typeName) {
|
||||
typeName = ["_SYSTEMTIME", "SYSTEMTIME", "tm", "TIME_FIELDS", "_TIME_FIELDS", "PTIME_FIELDS"]
|
||||
}
|
||||
private predicate timeType(string typeName) { typeName = ["_SYSTEMTIME", "SYSTEMTIME", "tm"] }
|
||||
|
||||
/**
|
||||
* A type that is used to represent times and dates in an 'unpacked' form, that is,
|
||||
@@ -97,24 +95,3 @@ class StructTmMonthFieldAccess extends MonthFieldAccess {
|
||||
class StructTmYearFieldAccess extends YearFieldAccess {
|
||||
StructTmYearFieldAccess() { this.getTarget().getName() = "tm_year" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A `DayFieldAccess` for the `TIME_FIELDS` struct.
|
||||
*/
|
||||
class TimeFieldsDayFieldAccess extends DayFieldAccess {
|
||||
TimeFieldsDayFieldAccess() { this.getTarget().getName() = "Day" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A `MonthFieldAccess` for the `TIME_FIELDS` struct.
|
||||
*/
|
||||
class TimeFieldsMonthFieldAccess extends MonthFieldAccess {
|
||||
TimeFieldsMonthFieldAccess() { this.getTarget().getName() = "Month" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A `YearFieldAccess` for the `TIME_FIELDS` struct.
|
||||
*/
|
||||
class TimeFieldsYearFieldAccess extends YearFieldAccess {
|
||||
TimeFieldsYearFieldAccess() { this.getTarget().getName() = "Year" }
|
||||
}
|
||||
|
||||
@@ -163,23 +163,12 @@ predicate primitiveVariadicFormatter(
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a function call whose target is a variadic formatter with the given
|
||||
* `type`, `format` parameter index and `output` parameter index.
|
||||
*
|
||||
* Join-order helper for `callsVariadicFormatter`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate callsVariadicFormatterCall(FunctionCall fc, string type, int format, int output) {
|
||||
variadicFormatter(fc.getTarget(), type, format, output)
|
||||
}
|
||||
|
||||
private predicate callsVariadicFormatter(
|
||||
Function f, string type, int formatParamIndex, int outputParamIndex
|
||||
) {
|
||||
// calls a variadic formatter with `formatParamIndex`, `outputParamIndex` linked
|
||||
exists(FunctionCall fc, int format, int output |
|
||||
callsVariadicFormatterCall(fc, type, format, output) and
|
||||
variadicFormatter(pragma[only_bind_into](fc.getTarget()), type, format, output) and
|
||||
fc.getEnclosingFunction() = f and
|
||||
fc.getArgument(format) = f.getParameter(formatParamIndex).getAnAccess() and
|
||||
fc.getArgument(output) = f.getParameter(outputParamIndex).getAnAccess()
|
||||
@@ -187,7 +176,7 @@ private predicate callsVariadicFormatter(
|
||||
or
|
||||
// calls a variadic formatter with only `formatParamIndex` linked
|
||||
exists(FunctionCall fc, string calledType, int format, int output |
|
||||
callsVariadicFormatterCall(fc, calledType, format, output) and
|
||||
variadicFormatter(pragma[only_bind_into](fc.getTarget()), calledType, format, output) and
|
||||
fc.getEnclosingFunction() = f and
|
||||
fc.getArgument(format) = f.getParameter(formatParamIndex).getAnAccess() and
|
||||
not fc.getArgument(output) = f.getParameter(_).getAnAccess() and
|
||||
@@ -459,13 +448,6 @@ class FormatLiteral extends Literal instanceof StringLiteral {
|
||||
*/
|
||||
int getConvSpecOffset(int n) { result = this.getFormat().indexOf("%", n, 0) }
|
||||
|
||||
/**
|
||||
* Gets the nth conversion specifier string.
|
||||
*/
|
||||
private string getConvSpecString(int n) {
|
||||
n >= 0 and result = "%" + this.getFormat().splitAt("%", n + 1)
|
||||
}
|
||||
|
||||
/*
|
||||
* Each of these predicates gets a regular expressions to match each individual
|
||||
* parts of a conversion specifier.
|
||||
@@ -531,20 +513,22 @@ class FormatLiteral extends Literal instanceof StringLiteral {
|
||||
int n, string spec, string params, string flags, string width, string prec, string len,
|
||||
string conv
|
||||
) {
|
||||
exists(string convSpec, string regexp |
|
||||
convSpec = this.getConvSpecString(n) and
|
||||
exists(int offset, string fmt, string rst, string regexp |
|
||||
offset = this.getConvSpecOffset(n) and
|
||||
fmt = this.getFormat() and
|
||||
rst = fmt.substring(offset, fmt.length()) and
|
||||
regexp = this.getConvSpecRegexp() and
|
||||
(
|
||||
spec = convSpec.regexpCapture(regexp, 1) and
|
||||
params = convSpec.regexpCapture(regexp, 2) and
|
||||
flags = convSpec.regexpCapture(regexp, 3) and
|
||||
width = convSpec.regexpCapture(regexp, 4) and
|
||||
prec = convSpec.regexpCapture(regexp, 5) and
|
||||
len = convSpec.regexpCapture(regexp, 6) and
|
||||
conv = convSpec.regexpCapture(regexp, 7)
|
||||
spec = rst.regexpCapture(regexp, 1) and
|
||||
params = rst.regexpCapture(regexp, 2) and
|
||||
flags = rst.regexpCapture(regexp, 3) and
|
||||
width = rst.regexpCapture(regexp, 4) and
|
||||
prec = rst.regexpCapture(regexp, 5) and
|
||||
len = rst.regexpCapture(regexp, 6) and
|
||||
conv = rst.regexpCapture(regexp, 7)
|
||||
or
|
||||
spec = convSpec.regexpCapture(regexp, 1) and
|
||||
not exists(convSpec.regexpCapture(regexp, 2)) and
|
||||
spec = rst.regexpCapture(regexp, 1) and
|
||||
not exists(rst.regexpCapture(regexp, 2)) and
|
||||
params = "" and
|
||||
flags = "" and
|
||||
width = "" and
|
||||
@@ -559,10 +543,12 @@ class FormatLiteral extends Literal instanceof StringLiteral {
|
||||
* Gets the nth conversion specifier (including the initial `%`).
|
||||
*/
|
||||
string getConvSpec(int n) {
|
||||
exists(string convSpec, string regexp |
|
||||
convSpec = this.getConvSpecString(n) and
|
||||
exists(int offset, string fmt, string rst, string regexp |
|
||||
offset = this.getConvSpecOffset(n) and
|
||||
fmt = this.getFormat() and
|
||||
rst = fmt.substring(offset, fmt.length()) and
|
||||
regexp = this.getConvSpecRegexp() and
|
||||
result = convSpec.regexpCapture(regexp, 1)
|
||||
result = rst.regexpCapture(regexp, 1)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -194,13 +194,6 @@ class ScanfFormatLiteral extends Expr {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the nth conversion specifier string.
|
||||
*/
|
||||
private string getConvSpecString(int n) {
|
||||
n >= 0 and result = "%" + this.getFormat().splitAt("%", n + 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the regular expression to match each individual part of a conversion specifier.
|
||||
*/
|
||||
@@ -234,14 +227,16 @@ class ScanfFormatLiteral extends Expr {
|
||||
* specifier.
|
||||
*/
|
||||
predicate parseConvSpec(int n, string spec, string width, string len, string conv) {
|
||||
exists(string convSpec, string regexp |
|
||||
convSpec = this.getConvSpecString(n) and
|
||||
exists(int offset, string fmt, string rst, string regexp |
|
||||
offset = this.getConvSpecOffset(n) and
|
||||
fmt = this.getFormat() and
|
||||
rst = fmt.substring(offset, fmt.length()) and
|
||||
regexp = this.getConvSpecRegexp() and
|
||||
(
|
||||
spec = convSpec.regexpCapture(regexp, 1) and
|
||||
width = convSpec.regexpCapture(regexp, 2) and
|
||||
len = convSpec.regexpCapture(regexp, 3) and
|
||||
conv = convSpec.regexpCapture(regexp, 4)
|
||||
spec = rst.regexpCapture(regexp, 1) and
|
||||
width = rst.regexpCapture(regexp, 2) and
|
||||
len = rst.regexpCapture(regexp, 3) and
|
||||
conv = rst.regexpCapture(regexp, 4)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1663,7 +1663,7 @@ private module Cached {
|
||||
private predicate compares_ge(
|
||||
ValueNumber test, Operand left, Operand right, int k, boolean isGe, GuardValue value
|
||||
) {
|
||||
compares_lt(test, right, left, 1 - k, isGe, value)
|
||||
exists(int onemk | k = 1 - onemk | compares_lt(test, right, left, onemk, isGe, value))
|
||||
}
|
||||
|
||||
/** Rearrange various simple comparisons into `left < right + k` form. */
|
||||
|
||||
@@ -1,20 +1,15 @@
|
||||
/**
|
||||
* INTERNAL use only. This is an experimental API subject to change without notice.
|
||||
*
|
||||
* Provides classes and predicates for dealing with flow models specified
|
||||
* in data extension files.
|
||||
* Provides classes and predicates for dealing with flow models specified in CSV format.
|
||||
*
|
||||
* The extensible relations have the following columns:
|
||||
* The CSV specification has the following columns:
|
||||
* - Sources:
|
||||
* `namespace; type; subtypes; name; signature; ext; output; kind; provenance`
|
||||
* `namespace; type; subtypes; name; signature; ext; output; kind`
|
||||
* - Sinks:
|
||||
* `namespace; type; subtypes; name; signature; ext; input; kind; provenance`
|
||||
* `namespace; type; subtypes; name; signature; ext; input; kind`
|
||||
* - Summaries:
|
||||
* `namespace; type; subtypes; name; signature; ext; input; output; kind; provenance`
|
||||
* - Barriers:
|
||||
* `namespace; type; subtypes; name; signature; ext; output; kind; provenance`
|
||||
* - BarrierGuards:
|
||||
* `namespace; type; subtypes; name; signature; ext; input; acceptingValue; kind; provenance`
|
||||
* `namespace; type; subtypes; name; signature; ext; input; output; kind`
|
||||
*
|
||||
* The interpretation of a row is similar to API-graphs with a left-to-right
|
||||
* reading.
|
||||
@@ -91,23 +86,11 @@
|
||||
* value, and
|
||||
* - flow from the _second_ indirection of the 0th argument to the first
|
||||
* indirection of the return value, etc.
|
||||
* 8. The `acceptingValue` column of barrier guard models specifies the condition
|
||||
* under which the guard blocks flow. It can be one of "true" or "false". In
|
||||
* the future "no-exception", "not-zero", "null", "not-null" may be supported.
|
||||
* 9. The `kind` column is a tag that can be referenced from QL to determine to
|
||||
* 8. The `kind` column is a tag that can be referenced from QL to determine to
|
||||
* which classes the interpreted elements should be added. For example, for
|
||||
* sources "remote" indicates a default remote flow source, and for summaries
|
||||
* "taint" indicates a default additional taint step and "value" indicates a
|
||||
* globally applicable value-preserving step.
|
||||
* 10. The `provenance` column is a tag to indicate the origin and verification of a model.
|
||||
* The format is {origin}-{verification} or just "manual" where the origin describes
|
||||
* the origin of the model and verification describes how the model has been verified.
|
||||
* Some examples are:
|
||||
* - "df-generated": The model has been generated by the model generator tool.
|
||||
* - "df-manual": The model has been generated by the model generator and verified by a human.
|
||||
* - "manual": The model has been written by hand.
|
||||
* This information is used in a heuristic for dataflow analysis to determine, if a
|
||||
* model or source code should be used for determining flow.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
@@ -121,9 +104,117 @@ private import internal.FlowSummaryImpl::Private
|
||||
private import internal.FlowSummaryImpl::Private::External
|
||||
private import internal.ExternalFlowExtensions::Extensions as Extensions
|
||||
private import codeql.mad.ModelValidation as SharedModelVal
|
||||
private import codeql.util.Unit
|
||||
private import codeql.mad.static.ModelsAsData as SharedMaD
|
||||
|
||||
/**
|
||||
* A unit class for adding additional source model rows.
|
||||
*
|
||||
* Extend this class to add additional source definitions.
|
||||
*/
|
||||
class SourceModelCsv extends Unit {
|
||||
/** Holds if `row` specifies a source definition. */
|
||||
abstract predicate row(string row);
|
||||
}
|
||||
|
||||
/**
|
||||
* A unit class for adding additional sink model rows.
|
||||
*
|
||||
* Extend this class to add additional sink definitions.
|
||||
*/
|
||||
class SinkModelCsv extends Unit {
|
||||
/** Holds if `row` specifies a sink definition. */
|
||||
abstract predicate row(string row);
|
||||
}
|
||||
|
||||
/**
|
||||
* A unit class for adding additional summary model rows.
|
||||
*
|
||||
* Extend this class to add additional flow summary definitions.
|
||||
*/
|
||||
class SummaryModelCsv extends Unit {
|
||||
/** Holds if `row` specifies a summary definition. */
|
||||
abstract predicate row(string row);
|
||||
}
|
||||
|
||||
/** Holds if `row` is a source model. */
|
||||
predicate sourceModel(string row) { any(SourceModelCsv s).row(row) }
|
||||
|
||||
/** Holds if `row` is a sink model. */
|
||||
predicate sinkModel(string row) { any(SinkModelCsv s).row(row) }
|
||||
|
||||
/** Holds if `row` is a summary model. */
|
||||
predicate summaryModel(string row) { any(SummaryModelCsv s).row(row) }
|
||||
|
||||
private module MadInput implements SharedMaD::InputSig {
|
||||
/** Holds if a source model exists for the given parameters. */
|
||||
predicate additionalSourceModel(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string output, string kind, string provenance, string model
|
||||
) {
|
||||
exists(string row |
|
||||
sourceModel(row) and
|
||||
row.splitAt(";", 0) = namespace and
|
||||
row.splitAt(";", 1) = type and
|
||||
row.splitAt(";", 2) = subtypes.toString() and
|
||||
subtypes = [true, false] and
|
||||
row.splitAt(";", 3) = name and
|
||||
row.splitAt(";", 4) = signature and
|
||||
row.splitAt(";", 5) = ext and
|
||||
row.splitAt(";", 6) = output and
|
||||
row.splitAt(";", 7) = kind
|
||||
) and
|
||||
provenance = "manual" and
|
||||
model = ""
|
||||
}
|
||||
|
||||
/** Holds if a sink model exists for the given parameters. */
|
||||
predicate additionalSinkModel(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string input, string kind, string provenance, string model
|
||||
) {
|
||||
exists(string row |
|
||||
sinkModel(row) and
|
||||
row.splitAt(";", 0) = namespace and
|
||||
row.splitAt(";", 1) = type and
|
||||
row.splitAt(";", 2) = subtypes.toString() and
|
||||
subtypes = [true, false] and
|
||||
row.splitAt(";", 3) = name and
|
||||
row.splitAt(";", 4) = signature and
|
||||
row.splitAt(";", 5) = ext and
|
||||
row.splitAt(";", 6) = input and
|
||||
row.splitAt(";", 7) = kind
|
||||
) and
|
||||
provenance = "manual" and
|
||||
model = ""
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a summary model exists for the given parameters.
|
||||
*
|
||||
* This predicate does not expand `@` to `*`s.
|
||||
*/
|
||||
predicate additionalSummaryModel(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string input, string output, string kind, string provenance, string model
|
||||
) {
|
||||
exists(string row |
|
||||
summaryModel(row) and
|
||||
row.splitAt(";", 0) = namespace and
|
||||
row.splitAt(";", 1) = type and
|
||||
row.splitAt(";", 2) = subtypes.toString() and
|
||||
subtypes = [true, false] and
|
||||
row.splitAt(";", 3) = name and
|
||||
row.splitAt(";", 4) = signature and
|
||||
row.splitAt(";", 5) = ext and
|
||||
row.splitAt(";", 6) = input and
|
||||
row.splitAt(";", 7) = output and
|
||||
row.splitAt(";", 8) = kind
|
||||
) and
|
||||
provenance = "manual" and
|
||||
model = ""
|
||||
}
|
||||
|
||||
string namespaceSegmentSeparator() { result = "::" }
|
||||
}
|
||||
|
||||
@@ -159,8 +250,8 @@ predicate summaryModel(
|
||||
)
|
||||
}
|
||||
|
||||
/** Provides a query predicate to check the data for validation errors. */
|
||||
module ModelValidation {
|
||||
/** Provides a query predicate to check the CSV data for validation errors. */
|
||||
module CsvValidation {
|
||||
private string getInvalidModelInput() {
|
||||
exists(string pred, AccessPath input, string part |
|
||||
sinkModel(_, _, _, _, _, _, input, _, _, _) and pred = "sink"
|
||||
@@ -203,6 +294,40 @@ module ModelValidation {
|
||||
|
||||
private module KindVal = SharedModelVal::KindValidation<KindValConfig>;
|
||||
|
||||
private string getInvalidModelSubtype() {
|
||||
exists(string pred, string row |
|
||||
sourceModel(row) and pred = "source"
|
||||
or
|
||||
sinkModel(row) and pred = "sink"
|
||||
or
|
||||
summaryModel(row) and pred = "summary"
|
||||
|
|
||||
exists(string b |
|
||||
b = row.splitAt(";", 2) and
|
||||
not b = ["true", "false"] and
|
||||
result = "Invalid boolean \"" + b + "\" in " + pred + " model."
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private string getInvalidModelColumnCount() {
|
||||
exists(string pred, string row, int expect |
|
||||
sourceModel(row) and expect = 8 and pred = "source"
|
||||
or
|
||||
sinkModel(row) and expect = 8 and pred = "sink"
|
||||
or
|
||||
summaryModel(row) and expect = 9 and pred = "summary"
|
||||
|
|
||||
exists(int cols |
|
||||
cols = 1 + max(int n | exists(row.splitAt(";", n))) and
|
||||
cols != expect and
|
||||
result =
|
||||
"Wrong number of columns in " + pred + " model row, expected " + expect + ", got " + cols +
|
||||
"."
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private string getInvalidModelSignature() {
|
||||
exists(string pred, string namespace, string type, string name, string signature, string ext |
|
||||
sourceModel(namespace, type, _, name, signature, ext, _, _, _, _) and pred = "source"
|
||||
@@ -228,25 +353,12 @@ module ModelValidation {
|
||||
)
|
||||
}
|
||||
|
||||
private string getIncorrectConstructorSummaryOutput() {
|
||||
exists(string namespace, string type, string name, string output |
|
||||
type = name or
|
||||
type = name + "<" + any(string s)
|
||||
|
|
||||
summaryModel(namespace, type, _, name, _, _, _, output, _, _, _) and
|
||||
output.matches("ReturnValue%") and
|
||||
result =
|
||||
"Constructor model for " + namespace + "." + type +
|
||||
" should use `Argument[this]` in the output, not `ReturnValue`."
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if some row in a MaD flow model appears to contain typos. */
|
||||
/** Holds if some row in a CSV-based flow model appears to contain typos. */
|
||||
query predicate invalidModelRow(string msg) {
|
||||
msg =
|
||||
[
|
||||
getInvalidModelSignature(), getInvalidModelInput(), getInvalidModelOutput(),
|
||||
KindVal::getInvalidModelKind(), getIncorrectConstructorSummaryOutput()
|
||||
getInvalidModelSubtype(), getInvalidModelColumnCount(), KindVal::getInvalidModelKind()
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -443,7 +555,6 @@ private Locatable getSupportedFunctionTemplateArgument(Function templateFunction
|
||||
* Normalize the `n`'th parameter of `f` by replacing template names
|
||||
* with `func:N` (where `N` is the index of the template).
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private string getTypeNameWithoutFunctionTemplates(Function f, int n, int remaining) {
|
||||
exists(Function templateFunction |
|
||||
templateFunction = getFullyTemplatedFunction(f) and
|
||||
@@ -900,7 +1011,7 @@ private module Cached {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is specified as a source with the given kind in a MaD flow
|
||||
* Holds if `node` is specified as a source with the given kind in a CSV flow
|
||||
* model.
|
||||
*/
|
||||
cached
|
||||
@@ -911,7 +1022,7 @@ private module Cached {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is specified as a sink with the given kind in a MaD flow
|
||||
* Holds if `node` is specified as a sink with the given kind in a CSV flow
|
||||
* model.
|
||||
*/
|
||||
cached
|
||||
@@ -947,13 +1058,13 @@ private module Cached {
|
||||
|
||||
private predicate barrierGuardChecks(IRGuardCondition g, Expr e, boolean gv, TKindModelPair kmp) {
|
||||
exists(
|
||||
SourceSinkInterpretationInput::InterpretNode n, Public::AcceptingValue acceptingValue,
|
||||
SourceSinkInterpretationInput::InterpretNode n, Public::AcceptingValue acceptingvalue,
|
||||
string kind, string model
|
||||
|
|
||||
isBarrierGuardNode(n, acceptingValue, kind, model) and
|
||||
isBarrierGuardNode(n, acceptingvalue, kind, model) and
|
||||
n.asNode().asExpr() = e and
|
||||
kmp = TMkPair(kind, model) and
|
||||
gv = convertAcceptingValue(acceptingValue).asBooleanValue() and
|
||||
gv = convertAcceptingValue(acceptingvalue).asBooleanValue() and
|
||||
n.asNode().(Private::ArgumentNode).getCall().asCallInstruction() = g
|
||||
)
|
||||
}
|
||||
@@ -970,14 +1081,14 @@ private module Cached {
|
||||
) {
|
||||
exists(
|
||||
SourceSinkInterpretationInput::InterpretNode interpretNode,
|
||||
Public::AcceptingValue acceptingValue, string kind, string model, int indirectionIndex,
|
||||
Public::AcceptingValue acceptingvalue, string kind, string model, int indirectionIndex,
|
||||
Private::ArgumentNode arg
|
||||
|
|
||||
isBarrierGuardNode(interpretNode, acceptingValue, kind, model) and
|
||||
isBarrierGuardNode(interpretNode, acceptingvalue, kind, model) and
|
||||
arg = interpretNode.asNode() and
|
||||
arg.asIndirectExpr(indirectionIndex) = e and
|
||||
kmp = MkKindModelPairIntPair(TMkPair(kind, model), indirectionIndex) and
|
||||
gv = convertAcceptingValue(acceptingValue).asBooleanValue() and
|
||||
gv = convertAcceptingValue(acceptingvalue).asBooleanValue() and
|
||||
arg.getCall().asCallInstruction() = g
|
||||
)
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ extensible predicate barrierModel(
|
||||
*/
|
||||
extensible predicate barrierGuardModel(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string input, string acceptingValue, string kind, string provenance, QlBuiltins::ExtensionId madId
|
||||
string input, string acceptingvalue, string kind, string provenance, QlBuiltins::ExtensionId madId
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
@@ -162,13 +162,13 @@ module SourceSinkInterpretationInput implements
|
||||
}
|
||||
|
||||
predicate barrierGuardElement(
|
||||
Element e, string input, Public::AcceptingValue acceptingValue, string kind,
|
||||
Element e, string input, Public::AcceptingValue acceptingvalue, string kind,
|
||||
Public::Provenance provenance, string model
|
||||
) {
|
||||
exists(
|
||||
string package, string type, boolean subtypes, string name, string signature, string ext
|
||||
|
|
||||
barrierGuardModel(package, type, subtypes, name, signature, ext, input, acceptingValue, kind,
|
||||
barrierGuardModel(package, type, subtypes, name, signature, ext, input, acceptingvalue, kind,
|
||||
provenance, model) and
|
||||
e = interpretElement(package, type, subtypes, name, signature, ext)
|
||||
)
|
||||
@@ -201,7 +201,7 @@ module SourceSinkInterpretationInput implements
|
||||
string toString() {
|
||||
result = this.asElement().toString()
|
||||
or
|
||||
result = this.asNode().toStringImpl()
|
||||
result = this.asNode().toString()
|
||||
or
|
||||
result = this.asCall().toString()
|
||||
}
|
||||
|
||||
@@ -585,15 +585,12 @@ class ConstructorDelegationInit extends ConstructorBaseInit, @ctordelegatinginit
|
||||
|
||||
/**
|
||||
* An initialization of a member variable performed as part of a
|
||||
* constructor's initializer list or by default initialization.
|
||||
*
|
||||
* constructor's explicit initializer list or implicit actions.
|
||||
* In the example below, member variable `b` is being initialized by
|
||||
* constructor parameter `a`, and `c` is initialized by default
|
||||
* initialization:
|
||||
* constructor parameter `a`:
|
||||
* ```
|
||||
* struct S {
|
||||
* int b;
|
||||
* int c = 3;
|
||||
* S(int a): b(a) {}
|
||||
* } s(2);
|
||||
* ```
|
||||
@@ -619,28 +616,6 @@ class ConstructorFieldInit extends ConstructorInit, @ctorfieldinit {
|
||||
override predicate mayBeGloballyImpure() { this.getExpr().mayBeGloballyImpure() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An initialization of a member variable performed as part of a
|
||||
* constructor's explicit initializer list.
|
||||
*/
|
||||
class ConstructorDirectFieldInit extends ConstructorFieldInit {
|
||||
ConstructorDirectFieldInit() { exists(this.getChild(0)) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ConstructorDirectFieldInit" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An initialization of a member variable performed by default
|
||||
* initialization.
|
||||
*/
|
||||
class ConstructorDefaultFieldInit extends ConstructorFieldInit {
|
||||
ConstructorDefaultFieldInit() {
|
||||
not exists(this.getChild(0)) and exists(this.getTarget().getInitializer())
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ConstructorDefaultFieldInit" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to a destructor of a base class or field as part of a destructor's
|
||||
* compiler-generated actions.
|
||||
|
||||
@@ -6,67 +6,75 @@ private import OverlayXml
|
||||
|
||||
/**
|
||||
* Holds always for the overlay variant and never for the base variant.
|
||||
* This local predicate is used to define local predicates that behave
|
||||
* differently for the base and overlay variant.
|
||||
*/
|
||||
overlay[local]
|
||||
predicate isOverlay() { databaseMetadata("isOverlay", "true") }
|
||||
|
||||
overlay[local]
|
||||
private string getLocationFilePath(@location_default loc) {
|
||||
exists(@file file | locations_default(loc, file, _, _, _, _) | files(file, result))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the TRAP file or tag `t` is reachable from source file `sourceFile`
|
||||
* in the base (isOverlayVariant=false) or overlay (isOverlayVariant=true) variant.
|
||||
* Gets the file path for an element with a single location.
|
||||
*/
|
||||
overlay[local]
|
||||
private predicate locallyReachableTrapOrTag(
|
||||
boolean isOverlayVariant, string sourceFile, @trap_or_tag t
|
||||
) {
|
||||
exists(@source_file sf, @trap trap |
|
||||
(if isOverlay() then isOverlayVariant = true else isOverlayVariant = false) and
|
||||
source_file_uses_trap(sf, trap) and
|
||||
source_file_name(sf, sourceFile) and
|
||||
(t = trap or trap_uses_tag(trap, t))
|
||||
private string getSingleLocationFilePath(@element e) {
|
||||
exists(@location_default loc |
|
||||
var_decls(e, _, _, _, loc)
|
||||
or
|
||||
fun_decls(e, _, _, _, loc)
|
||||
or
|
||||
type_decls(e, _, loc)
|
||||
or
|
||||
namespace_decls(e, _, loc, _)
|
||||
or
|
||||
macroinvocations(e, _, loc, _)
|
||||
or
|
||||
preprocdirects(e, _, loc)
|
||||
|
|
||||
result = getLocationFilePath(loc)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if element `e` is in TRAP file or tag `t`
|
||||
* in the base (isOverlayVariant=false) or overlay (isOverlayVariant=true) variant.
|
||||
* Gets the file path for an element with potentially multiple locations.
|
||||
*/
|
||||
overlay[local]
|
||||
private predicate locallyInTrapOrTag(boolean isOverlayVariant, @element e, @trap_or_tag t) {
|
||||
(if isOverlay() then isOverlayVariant = true else isOverlayVariant = false) and
|
||||
in_trap_or_tag(e, t)
|
||||
private string getMultiLocationFilePath(@element e) {
|
||||
exists(@location_default loc |
|
||||
var_decls(_, e, _, _, loc)
|
||||
or
|
||||
fun_decls(_, e, _, _, loc)
|
||||
or
|
||||
type_decls(_, e, loc)
|
||||
or
|
||||
namespace_decls(_, e, loc, _)
|
||||
|
|
||||
result = getLocationFilePath(loc)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A local helper predicate that holds in the base variant and never in the
|
||||
* overlay variant.
|
||||
*/
|
||||
overlay[local]
|
||||
private predicate isBase() { not isOverlay() }
|
||||
|
||||
/**
|
||||
* Discards an element from the base variant if:
|
||||
* - We have knowledge about what TRAP file or tag it is in (in the base).
|
||||
* - It is not in any overlay TRAP file or tag that is reachable from an overlay source file.
|
||||
* - For every base TRAP file or tag that contains it and is reachable from a base source file,
|
||||
* either the source file has changed, or the overlay has redefined the TRAP file or tag,
|
||||
* or the overlay runner has re-extracted the same source file.
|
||||
* - It has a single location in a changed file, or
|
||||
* - All of its locations are in changed files.
|
||||
*/
|
||||
overlay[discard_entity]
|
||||
private predicate discardElement(@element e) {
|
||||
// If we don't have any knowledge about what TRAP file something
|
||||
// is in, then we don't want to discard it, so we only consider
|
||||
// entities that are known to be in a base TRAP file or tag.
|
||||
locallyInTrapOrTag(false, e, _) and
|
||||
// Anything that is reachable from an overlay source file should
|
||||
// not be discarded.
|
||||
not exists(@trap_or_tag t | locallyInTrapOrTag(true, e, t) |
|
||||
locallyReachableTrapOrTag(true, _, t)
|
||||
) and
|
||||
// Finally, we have to make sure the base variant does not retain it.
|
||||
// If it is reachable from a base source file, then that is
|
||||
// sufficient unless either the base source file has changed (in
|
||||
// particular, been deleted), or the overlay has redefined the TRAP
|
||||
// file or tag it is in, or the overlay runner has re-extracted the same
|
||||
// source file (e.g. because a header it includes has changed).
|
||||
forall(@trap_or_tag t, string sourceFile |
|
||||
locallyInTrapOrTag(false, e, t) and
|
||||
locallyReachableTrapOrTag(false, sourceFile, t)
|
||||
|
|
||||
overlayChangedFiles(sourceFile) or
|
||||
locallyReachableTrapOrTag(true, _, t) or
|
||||
locallyReachableTrapOrTag(true, sourceFile, _)
|
||||
isBase() and
|
||||
(
|
||||
overlayChangedFiles(getSingleLocationFilePath(e))
|
||||
or
|
||||
forex(string path | path = getMultiLocationFilePath(e) | overlayChangedFiles(path))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ class Namespace extends @namespace {
|
||||
if namespacembrs(_, this)
|
||||
then
|
||||
exists(Namespace ns |
|
||||
namespacembrs(ns, pragma[only_bind_out](this)) and
|
||||
namespacembrs(ns, this) and
|
||||
result = ns.getQualifiedName() + "::" + this.getName()
|
||||
)
|
||||
else result = this.getName()
|
||||
@@ -37,7 +37,7 @@ class Namespace extends @namespace {
|
||||
string getAQualifierForMembers() {
|
||||
if namespacembrs(_, this)
|
||||
then
|
||||
exists(Namespace ns | namespacembrs(ns, pragma[only_bind_out](this)) |
|
||||
exists(Namespace ns | namespacembrs(ns, this) |
|
||||
result = ns.getAQualifierForMembers() + "::" + this.getName()
|
||||
or
|
||||
// If this is an inline namespace, its members are also visible in any
|
||||
|
||||
@@ -8,145 +8,83 @@ private import cpp
|
||||
private import semmle.code.cpp.ir.IR
|
||||
|
||||
/**
|
||||
* Provides an inter-procedural must-flow data flow analysis.
|
||||
* A configuration of a data flow analysis that performs must-flow analysis. This is different
|
||||
* from `DataFlow.qll` which performs may-flow analysis (i.e., it finds paths where the source _may_
|
||||
* flow to the sink).
|
||||
*
|
||||
* Like in `DataFlow.qll`, each use of the `MustFlow.qll` library must define its own unique extension
|
||||
* of this abstract class. To create a configuration, extend this class with a subclass whose
|
||||
* characteristic predicate is a unique singleton string and override `isSource`, `isSink` (and
|
||||
* `isAdditionalFlowStep` if additional steps are required).
|
||||
*/
|
||||
module MustFlow {
|
||||
/**
|
||||
* An input configuration of a data flow analysis that performs must-flow analysis. This is different
|
||||
* from `DataFlow.qll` which performs may-flow analysis (i.e., it finds paths where the source _may_
|
||||
* flow to the sink).
|
||||
*/
|
||||
signature module ConfigSig {
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source.
|
||||
*/
|
||||
predicate isSource(Instruction source);
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink.
|
||||
*/
|
||||
predicate isSink(Operand sink);
|
||||
|
||||
/**
|
||||
* Holds if data flow through `instr` is prohibited.
|
||||
*/
|
||||
default predicate isBarrier(Instruction instr) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis.
|
||||
*/
|
||||
default predicate isAdditionalFlowStep(Operand node1, Instruction node2) { none() }
|
||||
|
||||
/** Holds if this configuration allows flow from arguments to parameters. */
|
||||
default predicate allowInterproceduralFlow() { any() }
|
||||
}
|
||||
abstract class MustFlowConfiguration extends string {
|
||||
bindingset[this]
|
||||
MustFlowConfiguration() { any() }
|
||||
|
||||
/**
|
||||
* Constructs a global must-flow computation.
|
||||
* Holds if `source` is a relevant data flow source.
|
||||
*/
|
||||
module Global<ConfigSig Config> {
|
||||
import Config
|
||||
abstract predicate isSource(Instruction source);
|
||||
|
||||
/**
|
||||
* Holds if data must flow from `source` to `sink`.
|
||||
*
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate flowPath(PathNode source, PathSink sink) {
|
||||
isSource(source.getInstruction()) and
|
||||
source.getASuccessor*() = sink
|
||||
}
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink.
|
||||
*/
|
||||
abstract predicate isSink(Operand sink);
|
||||
|
||||
/** Holds if `node` flows from a source. */
|
||||
pragma[nomagic]
|
||||
private predicate flowsFromSource(Instruction node) {
|
||||
not isBarrier(node) and
|
||||
(
|
||||
isSource(node)
|
||||
or
|
||||
exists(Instruction mid |
|
||||
step(mid, node) and
|
||||
flowsFromSource(mid)
|
||||
)
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Holds if data flow through `instr` is prohibited.
|
||||
*/
|
||||
predicate isBarrier(Instruction instr) { none() }
|
||||
|
||||
/** Holds if `node` flows to a sink. */
|
||||
pragma[nomagic]
|
||||
private predicate flowsToSink(Instruction node) {
|
||||
flowsFromSource(node) and
|
||||
(
|
||||
isSink(node.getAUse())
|
||||
or
|
||||
exists(Instruction mid |
|
||||
step(node, mid) and
|
||||
flowsToSink(mid)
|
||||
)
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Operand node1, Instruction node2) { none() }
|
||||
|
||||
/** Holds if `nodeFrom` flows to `nodeTo`. */
|
||||
private predicate step(Instruction nodeFrom, Instruction nodeTo) {
|
||||
Cached::localStep(nodeFrom, nodeTo)
|
||||
or
|
||||
allowInterproceduralFlow() and
|
||||
Cached::flowThroughCallable(nodeFrom, nodeTo)
|
||||
or
|
||||
isAdditionalFlowStep(nodeFrom.getAUse(), nodeTo)
|
||||
}
|
||||
/** Holds if this configuration allows flow from arguments to parameters. */
|
||||
predicate allowInterproceduralFlow() { any() }
|
||||
|
||||
private newtype TLocalPathNode =
|
||||
MkLocalPathNode(Instruction n) {
|
||||
flowsToSink(n) and
|
||||
(
|
||||
isSource(n)
|
||||
or
|
||||
exists(PathNode mid | step(mid.getInstruction(), n))
|
||||
)
|
||||
}
|
||||
|
||||
/** A `Node` that is in a path from a source to a sink. */
|
||||
class PathNode extends TLocalPathNode {
|
||||
Instruction n;
|
||||
|
||||
PathNode() { this = MkLocalPathNode(n) }
|
||||
|
||||
/** Gets the underlying node. */
|
||||
Instruction getInstruction() { result = n }
|
||||
|
||||
/** Gets a textual representation of this node. */
|
||||
string toString() { result = n.getAst().toString() }
|
||||
|
||||
/** Gets the location of this element. */
|
||||
Location getLocation() { result = n.getLocation() }
|
||||
|
||||
/** Gets a successor node, if any. */
|
||||
PathNode getASuccessor() { step(this.getInstruction(), result.getInstruction()) }
|
||||
}
|
||||
|
||||
private class PathSink extends PathNode {
|
||||
PathSink() { isSink(this.getInstruction().getAUse()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the query predicates needed to include a graph in a path-problem query.
|
||||
*/
|
||||
module PathGraph {
|
||||
private predicate reach(PathNode n) { n instanceof PathSink or reach(n.getASuccessor()) }
|
||||
|
||||
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
|
||||
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b and reach(b) }
|
||||
|
||||
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
reach(n) and key = "semmle.label" and val = n.toString()
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Holds if data must flow from `source` to `sink` for this configuration.
|
||||
*
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
final predicate hasFlowPath(MustFlowPathNode source, MustFlowPathSink sink) {
|
||||
this.isSource(source.getInstruction()) and
|
||||
source.getASuccessor*() = sink
|
||||
}
|
||||
}
|
||||
|
||||
/** Holds if `node` flows from a source. */
|
||||
pragma[nomagic]
|
||||
private predicate flowsFromSource(Instruction node, MustFlowConfiguration config) {
|
||||
not config.isBarrier(node) and
|
||||
(
|
||||
config.isSource(node)
|
||||
or
|
||||
exists(Instruction mid |
|
||||
step(mid, node, config) and
|
||||
flowsFromSource(mid, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `node` flows to a sink. */
|
||||
pragma[nomagic]
|
||||
private predicate flowsToSink(Instruction node, MustFlowConfiguration config) {
|
||||
flowsFromSource(node, pragma[only_bind_into](config)) and
|
||||
(
|
||||
config.isSink(node.getAUse())
|
||||
or
|
||||
exists(Instruction mid |
|
||||
step(node, mid, config) and
|
||||
flowsToSink(mid, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
/** Holds if `p` is the `n`'th parameter of the non-virtual function `f`. */
|
||||
@@ -164,7 +102,7 @@ private module Cached {
|
||||
not f.isVirtual() and
|
||||
call.getPositionalArgument(n) = instr and
|
||||
f = call.getStaticCallTarget() and
|
||||
isEnclosingNonVirtualFunctionInitializeParameter(init, f) and
|
||||
getEnclosingNonVirtualFunctionInitializeParameter(init, f) and
|
||||
init.getParameter().getIndex() = pragma[only_bind_into](pragma[only_bind_out](n))
|
||||
}
|
||||
|
||||
@@ -173,7 +111,7 @@ private module Cached {
|
||||
* corresponding initialization instruction that receives the value of `instr` in `f`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate isPositionalArgumentInitParam(
|
||||
private predicate getPositionalArgumentInitParam(
|
||||
CallInstruction call, Instruction instr, InitializeParameterInstruction init, Function f
|
||||
) {
|
||||
exists(int n |
|
||||
@@ -188,18 +126,18 @@ private module Cached {
|
||||
* `instr` in `f`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate isThisArgumentInitParam(
|
||||
private predicate getThisArgumentInitParam(
|
||||
CallInstruction call, Instruction instr, InitializeParameterInstruction init, Function f
|
||||
) {
|
||||
not f.isVirtual() and
|
||||
call.getStaticCallTarget() = f and
|
||||
isEnclosingNonVirtualFunctionInitializeParameter(init, f) and
|
||||
getEnclosingNonVirtualFunctionInitializeParameter(init, f) and
|
||||
call.getThisArgument() = instr and
|
||||
init.getIRVariable() instanceof IRThisVariable
|
||||
}
|
||||
|
||||
/** Holds if `f` is the enclosing non-virtual function of `init`. */
|
||||
private predicate isEnclosingNonVirtualFunctionInitializeParameter(
|
||||
private predicate getEnclosingNonVirtualFunctionInitializeParameter(
|
||||
InitializeParameterInstruction init, Function f
|
||||
) {
|
||||
not f.isVirtual() and
|
||||
@@ -207,7 +145,7 @@ private module Cached {
|
||||
}
|
||||
|
||||
/** Holds if `f` is the enclosing non-virtual function of `init`. */
|
||||
private predicate isEnclosingNonVirtualFunctionInitializeIndirection(
|
||||
private predicate getEnclosingNonVirtualFunctionInitializeIndirection(
|
||||
InitializeIndirectionInstruction init, Function f
|
||||
) {
|
||||
not f.isVirtual() and
|
||||
@@ -215,16 +153,15 @@ private module Cached {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `argument` is an argument (or argument indirection) to a call, and
|
||||
* `parameter` is the corresponding initialization instruction in the call target.
|
||||
* Holds if `instr` is an argument (or argument indirection) to a call, and
|
||||
* `succ` is the corresponding initialization instruction in the call target.
|
||||
*/
|
||||
cached
|
||||
predicate flowThroughCallable(Instruction argument, Instruction parameter) {
|
||||
private predicate flowThroughCallable(Instruction argument, Instruction parameter) {
|
||||
// Flow from an argument to a parameter
|
||||
exists(CallInstruction call, InitializeParameterInstruction init | init = parameter |
|
||||
isPositionalArgumentInitParam(call, argument, init, call.getStaticCallTarget())
|
||||
getPositionalArgumentInitParam(call, argument, init, call.getStaticCallTarget())
|
||||
or
|
||||
isThisArgumentInitParam(call, argument, init, call.getStaticCallTarget())
|
||||
getThisArgumentInitParam(call, argument, init, call.getStaticCallTarget())
|
||||
)
|
||||
or
|
||||
// Flow from argument indirection to parameter indirection
|
||||
@@ -233,7 +170,7 @@ private module Cached {
|
||||
|
|
||||
init = parameter and
|
||||
read.getPrimaryInstruction() = call and
|
||||
isEnclosingNonVirtualFunctionInitializeIndirection(init, call.getStaticCallTarget())
|
||||
getEnclosingNonVirtualFunctionInitializeIndirection(init, call.getStaticCallTarget())
|
||||
|
|
||||
exists(int n |
|
||||
read.getSideEffectOperand().getAnyDef() = argument and
|
||||
@@ -268,10 +205,92 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
predicate localStep(Instruction nodeFrom, Instruction nodeTo) {
|
||||
predicate step(Instruction nodeFrom, Instruction nodeTo) {
|
||||
exists(Operand mid |
|
||||
instructionToOperandStep(nodeFrom, mid) and
|
||||
operandToInstructionStep(mid, nodeTo)
|
||||
)
|
||||
or
|
||||
flowThroughCallable(nodeFrom, nodeTo)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the enclosing callable of `n`. Unlike `n.getEnclosingCallable()`, this
|
||||
* predicate ensures that joins go from `n` to the result instead of the other
|
||||
* way around.
|
||||
*/
|
||||
pragma[inline]
|
||||
private IRFunction getEnclosingCallable(Instruction n) {
|
||||
pragma[only_bind_into](result) = pragma[only_bind_out](n).getEnclosingIRFunction()
|
||||
}
|
||||
|
||||
/** Holds if `nodeFrom` flows to `nodeTo`. */
|
||||
private predicate step(Instruction nodeFrom, Instruction nodeTo, MustFlowConfiguration config) {
|
||||
exists(config) and
|
||||
Cached::step(pragma[only_bind_into](nodeFrom), pragma[only_bind_into](nodeTo)) and
|
||||
(
|
||||
config.allowInterproceduralFlow()
|
||||
or
|
||||
getEnclosingCallable(nodeFrom) = getEnclosingCallable(nodeTo)
|
||||
)
|
||||
or
|
||||
config.isAdditionalFlowStep(nodeFrom.getAUse(), nodeTo)
|
||||
}
|
||||
|
||||
private newtype TLocalPathNode =
|
||||
MkLocalPathNode(Instruction n, MustFlowConfiguration config) {
|
||||
flowsToSink(n, config) and
|
||||
(
|
||||
config.isSource(n)
|
||||
or
|
||||
exists(MustFlowPathNode mid | step(mid.getInstruction(), n, config))
|
||||
)
|
||||
}
|
||||
|
||||
/** A `Node` that is in a path from a source to a sink. */
|
||||
class MustFlowPathNode extends TLocalPathNode {
|
||||
Instruction n;
|
||||
|
||||
MustFlowPathNode() { this = MkLocalPathNode(n, _) }
|
||||
|
||||
/** Gets the underlying node. */
|
||||
Instruction getInstruction() { result = n }
|
||||
|
||||
/** Gets a textual representation of this node. */
|
||||
string toString() { result = n.getAst().toString() }
|
||||
|
||||
/** Gets the location of this element. */
|
||||
Location getLocation() { result = n.getLocation() }
|
||||
|
||||
/** Gets a successor node, if any. */
|
||||
MustFlowPathNode getASuccessor() {
|
||||
step(this.getInstruction(), result.getInstruction(), this.getConfiguration())
|
||||
}
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
MustFlowConfiguration getConfiguration() { this = MkLocalPathNode(_, result) }
|
||||
}
|
||||
|
||||
private class MustFlowPathSink extends MustFlowPathNode {
|
||||
MustFlowPathSink() { this.getConfiguration().isSink(this.getInstruction().getAUse()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the query predicates needed to include a graph in a path-problem query.
|
||||
*/
|
||||
module PathGraph {
|
||||
private predicate reach(MustFlowPathNode n) {
|
||||
n instanceof MustFlowPathSink or reach(n.getASuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
|
||||
query predicate edges(MustFlowPathNode a, MustFlowPathNode b) {
|
||||
a.getASuccessor() = b and reach(b)
|
||||
}
|
||||
|
||||
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||
query predicate nodes(MustFlowPathNode n, string key, string val) {
|
||||
reach(n) and key = "semmle.label" and val = n.toString()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,12 +238,7 @@ private module TrackVirtualDispatch<methodDispatchSig/1 virtualDispatch0> {
|
||||
|
||||
private import TypeTracking<Location, TtInput>::TypeTrack<qualifierSource/1>::Graph<qualifierOfVirtualCall/1>
|
||||
|
||||
private predicate isSource(PathNode n) { n.isSource() }
|
||||
|
||||
private predicate isSink(PathNode n) { n.isSink() }
|
||||
|
||||
private predicate edgePlus(PathNode n1, PathNode n2) =
|
||||
doublyBoundedFastTC(edges/2, isSource/1, isSink/1)(n1, n2)
|
||||
private predicate edgePlus(PathNode n1, PathNode n2) = fastTC(edges/2)(n1, n2)
|
||||
|
||||
/**
|
||||
* Gets the most specific implementation of `mf` that may be called when the
|
||||
@@ -260,15 +255,6 @@ private module TrackVirtualDispatch<methodDispatchSig/1 virtualDispatch0> {
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private MemberFunction mostSpecificForSource(PathNode p1, MemberFunction mf) {
|
||||
p1.isSource() and
|
||||
exists(Class derived |
|
||||
qualifierSourceImpl(p1.getNode(), derived) and
|
||||
result = mostSpecific(mf, derived)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a possible pair of end-points `(p1, p2)` where:
|
||||
* - `p1` is a derived-to-base conversion that converts from some
|
||||
@@ -278,16 +264,16 @@ private module TrackVirtualDispatch<methodDispatchSig/1 virtualDispatch0> {
|
||||
* - `callable` is the most specific implementation that may be called when
|
||||
* the qualifier has type `derived`.
|
||||
*/
|
||||
bindingset[p1, p2]
|
||||
pragma[inline_late]
|
||||
private predicate pairCand(
|
||||
PathNode p1, PathNode p2, DataFlowPrivate::DataFlowCallable callable,
|
||||
DataFlowPrivate::DataFlowCall call
|
||||
) {
|
||||
p2.isSink() and
|
||||
exists(MemberFunction mf |
|
||||
exists(Class derived, MemberFunction mf |
|
||||
qualifierSourceImpl(p1.getNode(), derived) and
|
||||
qualifierOfVirtualCallImpl(p2.getNode(), call.asCallInstruction(), mf) and
|
||||
callable.asSourceCallable() = mostSpecificForSource(p1, mf)
|
||||
p1.isSource() and
|
||||
p2.isSink() and
|
||||
callable.asSourceCallable() = mostSpecific(mf, derived)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,5 @@
|
||||
private import cpp as Cpp
|
||||
private import DataFlowUtil
|
||||
private import DataFlowNodes
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import DataFlowDispatch
|
||||
private import semmle.code.cpp.ir.internal.IRCppLanguage
|
||||
@@ -17,42 +16,28 @@ private import semmle.code.cpp.dataflow.ExternalFlow as External
|
||||
cached
|
||||
private module Cached {
|
||||
cached
|
||||
newtype TIRDataFlowNode0 =
|
||||
TInstructionNode0(Instruction i) {
|
||||
not Ssa::ignoreInstruction(i) and
|
||||
not exists(Operand op |
|
||||
not Ssa::ignoreOperand(op) and i = Ssa::getIRRepresentationOfOperand(op)
|
||||
) and
|
||||
// We exclude `void`-typed instructions because they cannot contain data.
|
||||
// However, if the instruction is a glvalue, and their type is `void`, then the result
|
||||
// type of the instruction is really `void*`, and thus we still want to have a dataflow
|
||||
// node for it.
|
||||
(not i.getResultType() instanceof VoidType or i.isGLValue())
|
||||
} or
|
||||
TMultipleUseOperandNode0(Operand op) {
|
||||
not Ssa::ignoreOperand(op) and not exists(Ssa::getIRRepresentationOfOperand(op))
|
||||
} or
|
||||
TSingleUseOperandNode0(Operand op) {
|
||||
not Ssa::ignoreOperand(op) and exists(Ssa::getIRRepresentationOfOperand(op))
|
||||
}
|
||||
|
||||
cached
|
||||
string toStringCached(Node n) {
|
||||
result = toExprString(n)
|
||||
or
|
||||
not exists(toExprString(n)) and
|
||||
result = n.toStringImpl()
|
||||
module Nodes0 {
|
||||
cached
|
||||
newtype TIRDataFlowNode0 =
|
||||
TInstructionNode0(Instruction i) {
|
||||
not Ssa::ignoreInstruction(i) and
|
||||
not exists(Operand op |
|
||||
not Ssa::ignoreOperand(op) and i = Ssa::getIRRepresentationOfOperand(op)
|
||||
) and
|
||||
// We exclude `void`-typed instructions because they cannot contain data.
|
||||
// However, if the instruction is a glvalue, and their type is `void`, then the result
|
||||
// type of the instruction is really `void*`, and thus we still want to have a dataflow
|
||||
// node for it.
|
||||
(not i.getResultType() instanceof VoidType or i.isGLValue())
|
||||
} or
|
||||
TMultipleUseOperandNode0(Operand op) {
|
||||
not Ssa::ignoreOperand(op) and not exists(Ssa::getIRRepresentationOfOperand(op))
|
||||
} or
|
||||
TSingleUseOperandNode0(Operand op) {
|
||||
not Ssa::ignoreOperand(op) and exists(Ssa::getIRRepresentationOfOperand(op))
|
||||
}
|
||||
}
|
||||
|
||||
cached
|
||||
Location getLocationCached(Node n) { result = n.getLocationImpl() }
|
||||
|
||||
cached
|
||||
newtype TContentApprox =
|
||||
TFieldApproxContent(string s) { fieldHasApproxName(_, s) } or
|
||||
TUnionApproxContent(string s) { unionHasApproxName(_, s) } or
|
||||
TElementApproxContent()
|
||||
|
||||
/**
|
||||
* Gets an additional term that is added to the `join` and `branch` computations to reflect
|
||||
* an additional forward or backwards branching factor that is not taken into account
|
||||
@@ -74,174 +59,38 @@ private module Cached {
|
||||
result = countNumberOfBranchesUsingParameter(switch, p)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
newtype TDataFlowCallable =
|
||||
TSourceCallable(Cpp::Declaration decl) or
|
||||
TSummarizedCallable(FlowSummaryImpl::Public::SummarizedCallable c)
|
||||
|
||||
cached
|
||||
newtype TDataFlowCall =
|
||||
TNormalCall(CallInstruction call) or
|
||||
TSummaryCall(
|
||||
FlowSummaryImpl::Public::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver
|
||||
) {
|
||||
FlowSummaryImpl::Private::summaryCallbackRange(c, receiver)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` in a way that loses the
|
||||
* calling context. For example, this would happen with flow through a
|
||||
* global or static variable.
|
||||
*/
|
||||
cached
|
||||
predicate jumpStep(Node n1, Node n2) {
|
||||
exists(GlobalLikeVariable v |
|
||||
exists(Ssa::GlobalUse globalUse |
|
||||
v = globalUse.getVariable() and
|
||||
n1.(FinalGlobalValue).getGlobalUse() = globalUse
|
||||
|
|
||||
globalUse.getIndirection() = getMinIndirectionForGlobalUse(globalUse) and
|
||||
v = n2.asVariable()
|
||||
or
|
||||
v = n2.asIndirectVariable(globalUse.getIndirection())
|
||||
)
|
||||
or
|
||||
exists(Ssa::GlobalDef globalDef |
|
||||
v = globalDef.getVariable() and
|
||||
n2.(InitialGlobalValue).getGlobalDef() = globalDef
|
||||
|
|
||||
globalDef.getIndirection() = getMinIndirectionForGlobalDef(globalDef) and
|
||||
v = n1.asVariable()
|
||||
or
|
||||
v = n1.asIndirectVariable(globalDef.getIndirection())
|
||||
)
|
||||
)
|
||||
or
|
||||
// models-as-data summarized flow
|
||||
FlowSummaryImpl::Private::Steps::summaryJumpStep(n1.(FlowSummaryNode).getSummaryNode(),
|
||||
n2.(FlowSummaryNode).getSummaryNode())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` via an assignment to `f`.
|
||||
* Thus, `node2` references an object with a field `f` that contains the
|
||||
* value of `node1`.
|
||||
*
|
||||
* The boolean `certain` is true if the destination address does not involve
|
||||
* any pointer arithmetic, and false otherwise.
|
||||
*/
|
||||
cached
|
||||
predicate storeStepImpl(Node node1, Content c, Node node2, boolean certain) {
|
||||
exists(
|
||||
PostFieldUpdateNode postFieldUpdate, int indirectionIndex1, int numberOfLoads,
|
||||
StoreInstruction store, FieldContent fc
|
||||
|
|
||||
postFieldUpdate = node2 and
|
||||
fc = c and
|
||||
nodeHasInstruction(node1, pragma[only_bind_into](store),
|
||||
pragma[only_bind_into](indirectionIndex1)) and
|
||||
postFieldUpdate.getIndirectionIndex() = 1 and
|
||||
numberOfLoadsFromOperand(postFieldUpdate.getFieldAddress(),
|
||||
store.getDestinationAddressOperand(), numberOfLoads, certain) and
|
||||
fc.getAField() = postFieldUpdate.getUpdatedField() and
|
||||
getIndirectionIndexLate(fc) = 1 + indirectionIndex1 + numberOfLoads
|
||||
)
|
||||
or
|
||||
// models-as-data summarized flow
|
||||
FlowSummaryImpl::Private::Steps::summaryStoreStep(node1.(FlowSummaryNode).getSummaryNode(), c,
|
||||
node2.(FlowSummaryNode).getSummaryNode()) and
|
||||
certain = true
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` via an assignment to `f`.
|
||||
* Thus, `node2` references an object with a field `f` that contains the
|
||||
* value of `node1`.
|
||||
*/
|
||||
cached
|
||||
predicate storeStep(Node node1, ContentSet c, Node node2) { storeStepImpl(node1, c, node2, _) }
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` via a read of `f`.
|
||||
* Thus, `node1` references an object with a field `f` whose value ends up in
|
||||
* `node2`.
|
||||
*/
|
||||
cached
|
||||
predicate readStep(Node node1, ContentSet c, Node node2) {
|
||||
exists(
|
||||
FieldAddress fa1, Operand operand, int numberOfLoads, int indirectionIndex2, FieldContent fc
|
||||
|
|
||||
fc = c and
|
||||
nodeHasOperand(node2, operand, indirectionIndex2) and
|
||||
// The `1` here matches the `node2.getIndirectionIndex() = 1` conjunct
|
||||
// in `storeStep`.
|
||||
nodeHasOperand(node1, fa1.getObjectAddressOperand(), 1) and
|
||||
numberOfLoadsFromOperand(fa1, operand, numberOfLoads, _) and
|
||||
fc.getAField() = fa1.getField() and
|
||||
getIndirectionIndexLate(fc) = indirectionIndex2 + numberOfLoads
|
||||
)
|
||||
or
|
||||
// models-as-data summarized flow
|
||||
FlowSummaryImpl::Private::Steps::summaryReadStep(node1.(FlowSummaryNode).getSummaryNode(), c,
|
||||
node2.(FlowSummaryNode).getSummaryNode())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if values stored inside content `c` are cleared at node `n`.
|
||||
*/
|
||||
cached
|
||||
predicate clearsContent(Node n, ContentSet c) {
|
||||
n =
|
||||
any(PostUpdateNode pun, Content d |
|
||||
d.impliesClearOf(c) and storeStepImpl(_, d, pun, true)
|
||||
|
|
||||
pun
|
||||
).getPreUpdateNode() and
|
||||
(
|
||||
not exists(Operand op, Cpp::Operation p |
|
||||
n.(IndirectOperand).hasOperandAndIndirectionIndex(op, _) and
|
||||
(
|
||||
p instanceof Cpp::AssignPointerAddExpr or
|
||||
p instanceof Cpp::AssignPointerSubExpr or
|
||||
p instanceof Cpp::CrementOperation
|
||||
)
|
||||
|
|
||||
p.getAnOperand() = op.getUse().getAst()
|
||||
)
|
||||
or
|
||||
forex(PostUpdateNode pun, Content d |
|
||||
pragma[only_bind_into](d).impliesClearOf(pragma[only_bind_into](c)) and
|
||||
storeStepImpl(_, d, pun, true) and
|
||||
pun.getPreUpdateNode() = n
|
||||
|
|
||||
c.(Content).getIndirectionIndex() = d.getIndirectionIndex()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import Cached
|
||||
|
||||
private int getNumberOfIndirections(Node n) {
|
||||
result = n.(RawIndirectOperand).getIndirectionIndex()
|
||||
or
|
||||
result = n.(RawIndirectInstruction).getIndirectionIndex()
|
||||
or
|
||||
result = n.(VariableNode).getIndirectionIndex()
|
||||
or
|
||||
result = n.(PostUpdateNodeImpl).getIndirectionIndex()
|
||||
or
|
||||
result = n.(FinalParameterNode).getIndirectionIndex()
|
||||
or
|
||||
result = n.(BodyLessParameterNodeImpl).getIndirectionIndex()
|
||||
}
|
||||
private import Nodes0
|
||||
|
||||
/**
|
||||
* Gets the number of stars (i.e., `*`s) needed to produce the `toString`
|
||||
* output for `n`.
|
||||
* A module for calculating the number of stars (i.e., `*`s) needed for various
|
||||
* dataflow node `toString` predicates.
|
||||
*/
|
||||
string stars(Node n) { result = repeatStars(getNumberOfIndirections(n)) }
|
||||
module NodeStars {
|
||||
private int getNumberOfIndirections(Node n) {
|
||||
result = n.(RawIndirectOperand).getIndirectionIndex()
|
||||
or
|
||||
result = n.(RawIndirectInstruction).getIndirectionIndex()
|
||||
or
|
||||
result = n.(VariableNode).getIndirectionIndex()
|
||||
or
|
||||
result = n.(PostUpdateNodeImpl).getIndirectionIndex()
|
||||
or
|
||||
result = n.(FinalParameterNode).getIndirectionIndex()
|
||||
or
|
||||
result = n.(BodyLessParameterNodeImpl).getIndirectionIndex()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of stars (i.e., `*`s) needed to produce the `toString`
|
||||
* output for `n`.
|
||||
*/
|
||||
string stars(Node n) { result = repeatStars(getNumberOfIndirections(n)) }
|
||||
}
|
||||
|
||||
import NodeStars
|
||||
|
||||
/**
|
||||
* A cut-down `DataFlow::Node` class that does not depend on the output of SSA.
|
||||
@@ -979,10 +828,85 @@ private int getMinIndirectionForGlobalDef(Ssa::GlobalDef def) {
|
||||
result = getMinIndirectionsForType(def.getUnspecifiedType())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` in a way that loses the
|
||||
* calling context. For example, this would happen with flow through a
|
||||
* global or static variable.
|
||||
*/
|
||||
predicate jumpStep(Node n1, Node n2) {
|
||||
exists(GlobalLikeVariable v |
|
||||
exists(Ssa::GlobalUse globalUse |
|
||||
v = globalUse.getVariable() and
|
||||
n1.(FinalGlobalValue).getGlobalUse() = globalUse
|
||||
|
|
||||
globalUse.getIndirection() = getMinIndirectionForGlobalUse(globalUse) and
|
||||
v = n2.asVariable()
|
||||
or
|
||||
v = n2.asIndirectVariable(globalUse.getIndirection())
|
||||
)
|
||||
or
|
||||
exists(Ssa::GlobalDef globalDef |
|
||||
v = globalDef.getVariable() and
|
||||
n2.(InitialGlobalValue).getGlobalDef() = globalDef
|
||||
|
|
||||
globalDef.getIndirection() = getMinIndirectionForGlobalDef(globalDef) and
|
||||
v = n1.asVariable()
|
||||
or
|
||||
v = n1.asIndirectVariable(globalDef.getIndirection())
|
||||
)
|
||||
)
|
||||
or
|
||||
// models-as-data summarized flow
|
||||
FlowSummaryImpl::Private::Steps::summaryJumpStep(n1.(FlowSummaryNode).getSummaryNode(),
|
||||
n2.(FlowSummaryNode).getSummaryNode())
|
||||
}
|
||||
|
||||
bindingset[c]
|
||||
pragma[inline_late]
|
||||
private int getIndirectionIndexLate(Content c) { result = c.getIndirectionIndex() }
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` via an assignment to `f`.
|
||||
* Thus, `node2` references an object with a field `f` that contains the
|
||||
* value of `node1`.
|
||||
*
|
||||
* The boolean `certain` is true if the destination address does not involve
|
||||
* any pointer arithmetic, and false otherwise. This has to do with whether a
|
||||
* store step can be used to clear a field (see `clearsContent`).
|
||||
*/
|
||||
predicate storeStepImpl(Node node1, Content c, Node node2, boolean certain) {
|
||||
exists(
|
||||
PostFieldUpdateNode postFieldUpdate, int indirectionIndex1, int numberOfLoads,
|
||||
StoreInstruction store, FieldContent fc
|
||||
|
|
||||
postFieldUpdate = node2 and
|
||||
fc = c and
|
||||
nodeHasInstruction(node1, pragma[only_bind_into](store),
|
||||
pragma[only_bind_into](indirectionIndex1)) and
|
||||
postFieldUpdate.getIndirectionIndex() = 1 and
|
||||
numberOfLoadsFromOperand(postFieldUpdate.getFieldAddress(),
|
||||
store.getDestinationAddressOperand(), numberOfLoads, certain) and
|
||||
fc.getAField() = postFieldUpdate.getUpdatedField() and
|
||||
getIndirectionIndexLate(fc) = 1 + indirectionIndex1 + numberOfLoads
|
||||
)
|
||||
or
|
||||
// models-as-data summarized flow
|
||||
FlowSummaryImpl::Private::Steps::summaryStoreStep(node1.(FlowSummaryNode).getSummaryNode(), c,
|
||||
node2.(FlowSummaryNode).getSummaryNode()) and
|
||||
certain = true
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` via an assignment to `f`.
|
||||
* Thus, `node2` references an object with a field `f` that contains the
|
||||
* value of `node1`.
|
||||
*/
|
||||
predicate storeStep(Node node1, ContentSet c, Node node2) { storeStepImpl(node1, c, node2, _) }
|
||||
|
||||
/**
|
||||
* Holds if `operandFrom` flows to `operandTo` using a sequence of conversion-like
|
||||
* operations and exactly `n` `LoadInstruction` operations.
|
||||
*/
|
||||
private predicate numberOfLoadsFromOperandRec(
|
||||
Operand operandFrom, Operand operandTo, int ind, boolean certain
|
||||
) {
|
||||
@@ -1033,6 +957,63 @@ predicate nodeHasInstruction(Node node, Instruction instr, int indirectionIndex)
|
||||
hasInstructionAndIndex(node, instr, indirectionIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` via a read of `f`.
|
||||
* Thus, `node1` references an object with a field `f` whose value ends up in
|
||||
* `node2`.
|
||||
*/
|
||||
predicate readStep(Node node1, ContentSet c, Node node2) {
|
||||
exists(
|
||||
FieldAddress fa1, Operand operand, int numberOfLoads, int indirectionIndex2, FieldContent fc
|
||||
|
|
||||
fc = c and
|
||||
nodeHasOperand(node2, operand, indirectionIndex2) and
|
||||
// The `1` here matches the `node2.getIndirectionIndex() = 1` conjunct
|
||||
// in `storeStep`.
|
||||
nodeHasOperand(node1, fa1.getObjectAddressOperand(), 1) and
|
||||
numberOfLoadsFromOperand(fa1, operand, numberOfLoads, _) and
|
||||
fc.getAField() = fa1.getField() and
|
||||
getIndirectionIndexLate(fc) = indirectionIndex2 + numberOfLoads
|
||||
)
|
||||
or
|
||||
// models-as-data summarized flow
|
||||
FlowSummaryImpl::Private::Steps::summaryReadStep(node1.(FlowSummaryNode).getSummaryNode(), c,
|
||||
node2.(FlowSummaryNode).getSummaryNode())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if values stored inside content `c` are cleared at node `n`.
|
||||
*/
|
||||
predicate clearsContent(Node n, ContentSet c) {
|
||||
n =
|
||||
any(PostUpdateNode pun, Content d | d.impliesClearOf(c) and storeStepImpl(_, d, pun, true) | pun)
|
||||
.getPreUpdateNode() and
|
||||
(
|
||||
// The crement operations and pointer addition and subtraction self-assign. We do not
|
||||
// want to clear the contents if it is indirectly pointed at by any of these operations,
|
||||
// as part of the contents might still be accessible afterwards. If there is no such
|
||||
// indirection clearing the contents is safe.
|
||||
not exists(Operand op, Cpp::Operation p |
|
||||
n.(IndirectOperand).hasOperandAndIndirectionIndex(op, _) and
|
||||
(
|
||||
p instanceof Cpp::AssignPointerAddExpr or
|
||||
p instanceof Cpp::AssignPointerSubExpr or
|
||||
p instanceof Cpp::CrementOperation
|
||||
)
|
||||
|
|
||||
p.getAnOperand() = op.getUse().getAst()
|
||||
)
|
||||
or
|
||||
forex(PostUpdateNode pun, Content d |
|
||||
pragma[only_bind_into](d).impliesClearOf(pragma[only_bind_into](c)) and
|
||||
storeStepImpl(_, d, pun, true) and
|
||||
pun.getPreUpdateNode() = n
|
||||
|
|
||||
c.(Content).getIndirectionIndex() = d.getIndirectionIndex()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the value that is being tracked is expected to be stored inside content `c`
|
||||
* at node `n`.
|
||||
@@ -1065,6 +1046,11 @@ class CastNode extends Node {
|
||||
CastNode() { none() } // stub implementation
|
||||
}
|
||||
|
||||
cached
|
||||
private newtype TDataFlowCallable =
|
||||
TSourceCallable(Cpp::Declaration decl) or
|
||||
TSummarizedCallable(FlowSummaryImpl::Public::SummarizedCallable c)
|
||||
|
||||
/**
|
||||
* A callable, which may be:
|
||||
* - a function (that may contain code)
|
||||
@@ -1148,6 +1134,15 @@ class DataFlowType extends TypeFinal {
|
||||
string toString() { result = "" }
|
||||
}
|
||||
|
||||
cached
|
||||
private newtype TDataFlowCall =
|
||||
TNormalCall(CallInstruction call) or
|
||||
TSummaryCall(
|
||||
FlowSummaryImpl::Public::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver
|
||||
) {
|
||||
FlowSummaryImpl::Private::summaryCallbackRange(c, receiver)
|
||||
}
|
||||
|
||||
private predicate summarizedCallableIsManual(SummarizedCallable sc) {
|
||||
sc.asSummarizedCallable().hasManualModel()
|
||||
}
|
||||
@@ -1170,7 +1165,7 @@ class DataFlowCall extends TDataFlowCall {
|
||||
/**
|
||||
* Gets the `Function` that the call targets, if this is statically known.
|
||||
*/
|
||||
Declaration getStaticCallSourceTarget() { none() }
|
||||
Function getStaticCallSourceTarget() { none() }
|
||||
|
||||
/**
|
||||
* Gets the target of this call. We use the following strategy for deciding
|
||||
@@ -1182,7 +1177,7 @@ class DataFlowCall extends TDataFlowCall {
|
||||
* whether is it manual or generated.
|
||||
*/
|
||||
final DataFlowCallable getStaticCallTarget() {
|
||||
exists(Declaration target | target = this.getStaticCallSourceTarget() |
|
||||
exists(Function target | target = this.getStaticCallSourceTarget() |
|
||||
// Don't use the source callable if there is a manual model for the
|
||||
// target
|
||||
not exists(SummarizedCallable sc |
|
||||
@@ -1242,7 +1237,7 @@ private class NormalCall extends DataFlowCall, TNormalCall {
|
||||
|
||||
override CallTargetOperand getCallTargetOperand() { result = call.getCallTargetOperand() }
|
||||
|
||||
override Declaration getStaticCallSourceTarget() { result = call.getStaticCallTarget() }
|
||||
override Function getStaticCallSourceTarget() { result = call.getStaticCallTarget() }
|
||||
|
||||
override ArgumentOperand getArgumentOperand(int index) { result = call.getArgumentOperand(index) }
|
||||
|
||||
@@ -1528,6 +1523,12 @@ private predicate fieldHasApproxName(Field f, string s) {
|
||||
|
||||
private predicate unionHasApproxName(Cpp::Union u, string s) { s = u.getName().charAt(0) }
|
||||
|
||||
cached
|
||||
private newtype TContentApprox =
|
||||
TFieldApproxContent(string s) { fieldHasApproxName(_, s) } or
|
||||
TUnionApproxContent(string s) { unionHasApproxName(_, s) } or
|
||||
TElementApproxContent()
|
||||
|
||||
/** An approximated `Content`. */
|
||||
class ContentApprox extends TContentApprox {
|
||||
string toString() { none() } // overridden in subclasses
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,8 +6,8 @@ private import cpp
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import DataFlowUtil
|
||||
private import DataFlowPrivate
|
||||
private import DataFlowNodes
|
||||
private import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction
|
||||
private import semmle.code.cpp.ir.implementation.raw.internal.TranslatedExpr
|
||||
private import semmle.code.cpp.ir.implementation.raw.internal.InstructionTag
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
@@ -73,9 +73,17 @@ private module Cached {
|
||||
// a result for `getConvertedResultExpression`. We remap this here so that
|
||||
// this `ConvertInstruction` maps to the result of the expression that
|
||||
// represents the extent.
|
||||
result = IRConstruction::Raw::getAllocationExtentConvertExpr(instr)
|
||||
exists(TranslatedNonConstantAllocationSize tas |
|
||||
result = tas.getExtent().getExpr() and
|
||||
instr = tas.getInstruction(AllocationExtentConvertTag())
|
||||
)
|
||||
or
|
||||
result = IRConstruction::Raw::getTransparentConversionParenthesisExpr(instr)
|
||||
// There's no instruction that returns `ParenthesisExpr`, but some queries
|
||||
// expect this
|
||||
exists(TranslatedTransparentConversion ttc |
|
||||
result = ttc.getExpr().(ParenthesisExpr) and
|
||||
instr = ttc.getResult()
|
||||
)
|
||||
or
|
||||
// Certain expressions generate `CopyValueInstruction`s only when they
|
||||
// are needed. Examples of this include crement operations and compound
|
||||
@@ -104,10 +112,10 @@ private module Cached {
|
||||
// needed, and in that case the only value that will propagate forward in
|
||||
// the program is the value that's been updated. So in those cases we just
|
||||
// use the result of `node.asDefinition()` as the result of `node.asExpr()`.
|
||||
exists(StoreInstruction store |
|
||||
store = instr and
|
||||
IRConstruction::Raw::instructionProducesExprResult(store) and
|
||||
result = asDefinitionImpl0(store)
|
||||
exists(TranslatedCoreExpr tco |
|
||||
tco.getInstruction(_) = instr and
|
||||
tco.producesExprResult() and
|
||||
result = asDefinitionImpl0(instr)
|
||||
)
|
||||
or
|
||||
// IR construction breaks an array aggregate literal `{1, 2, 3}` into a
|
||||
@@ -137,9 +145,18 @@ private module Cached {
|
||||
// For an expression such as `i += 2` we pretend that the generated
|
||||
// `StoreInstruction` contains the result of the expression even though
|
||||
// this isn't totally aligned with the C/C++ standard.
|
||||
result = IRConstruction::Raw::getAssignOperationStoreExpr(store)
|
||||
exists(TranslatedAssignOperation tao |
|
||||
store = tao.getInstruction(AssignmentStoreTag()) and
|
||||
result = tao.getExpr()
|
||||
)
|
||||
or
|
||||
result = IRConstruction::Raw::getCrementOperationStoreExpr(store)
|
||||
// Similarly for `i++` and `++i` we pretend that the generated
|
||||
// `StoreInstruction` contains the result of the expression even though
|
||||
// this isn't totally aligned with the C/C++ standard.
|
||||
exists(TranslatedCrementOperation tco |
|
||||
store = tco.getInstruction(CrementStoreTag()) and
|
||||
result = tco.getExpr()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -149,7 +166,11 @@ private module Cached {
|
||||
*/
|
||||
private predicate excludeAsDefinitionResult(StoreInstruction store) {
|
||||
// Exclude the store to the temporary generated by a ternary expression.
|
||||
IRConstruction::Raw::isConditionalExprTempStore(store)
|
||||
exists(TranslatedConditionalExpr tce |
|
||||
store = tce.getInstruction(ConditionValueFalseStoreTag())
|
||||
or
|
||||
store = tce.getInstruction(ConditionValueTrueStoreTag())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs
|
||||
private import DataFlowUtil
|
||||
private import DataFlowNodes
|
||||
private import DataFlowPrivate
|
||||
private import SsaImpl as Ssa
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ private import cpp
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowNodes
|
||||
private import PrintIRUtilities
|
||||
|
||||
/** A property provider for local IR dataflow store steps. */
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user