Compare commits

..

1 Commits

Author SHA1 Message Date
github-actions[bot]
824caaee07 use ATM model from training run classification_1659313637_335f5d4e_foo_10 2022-09-14 20:16:22 +00:00
189 changed files with 1331 additions and 10465 deletions

View File

@@ -56,7 +56,7 @@ jobs:
# uses a compiled language
- run: |
dotnet build csharp
dotnet build csharp /p:UseSharedCompilation=false
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@main

View File

@@ -55,7 +55,7 @@ jobs:
DATABASE="${{ runner.temp }}/csharp-database"
PROJECT="${{ runner.temp }}/csharp-project"
dotnet new classlib --language=C# --output="$PROJECT"
codeql database create "$DATABASE" --language=csharp --source-root="$PROJECT" --command 'dotnet build /t:rebuild csharp-project.csproj'
codeql database create "$DATABASE" --language=csharp --source-root="$PROJECT" --command 'dotnet build /t:rebuild csharp-project.csproj /p:UseSharedCompilation=false'
- name: Capture coverage information
run: |
DATABASE="${{ runner.temp }}/csharp-database"

View File

@@ -5,13 +5,6 @@ on:
branches: [main]
pull_request:
branches: [main]
paths:
- "ql/**"
- "**.qll"
- "**.ql"
- "**.dbscheme"
- "**/qlpack.yml"
- ".github/workflows/ql-for-ql-build.yml"
env:
CARGO_TERM_COLOR: always
@@ -61,7 +54,7 @@ jobs:
cp -r ${{ runner.temp }}/queries ${{ runner.temp }}/pack
env:
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
### Build the extractor ###
- name: Cache entire extractor
if: steps.cache-pack.outputs.cache-hit != 'true'
@@ -115,7 +108,7 @@ jobs:
### Run the analysis ###
- name: Hack codeql-action options
run: |
JSON=$(jq -nc --arg pack "${PACK}" '.database."run-queries"=["--search-path", $pack] | .resolve.queries=["--search-path", $pack] | .resolve.extractor=["--search-path", $pack] | .resolve.languages=["--search-path", $pack] | .database.init=["--search-path", $pack]')
JSON=$(jq -nc --arg pack "${PACK}" '.database."run-queries"=["--search-path", $pack] | .resolve.queries=["--search-path", $pack] | .resolve.extractor=["--search-path", $pack] | .database.init=["--search-path", $pack]')
echo "CODEQL_ACTION_EXTRA_OPTIONS=${JSON}" >> ${GITHUB_ENV}
env:
PACK: ${{ runner.temp }}/pack
@@ -123,14 +116,14 @@ jobs:
- name: Create CodeQL config file
run: |
echo "paths-ignore:" >> ${CONF}
echo " - ql/ql/test" >> ${CONF}
echo " - \"*/ql/lib/upgrades/\"" >> ${CONF}
echo " - ql/ql/test" >> ${CONF}
echo " - \"*/ql/lib/upgrades/\"" >> ${CONF}
echo "disable-default-queries: true" >> ${CONF}
echo "queries:" >> ${CONF}
echo " - uses: ./ql/ql/src/codeql-suites/ql-code-scanning.qls" >> ${CONF}
echo "Config file: "
cat ${CONF}
env:
env:
CONF: ./ql-for-ql-config.yml
- name: Initialize CodeQL
uses: github/codeql-action/init@71a8b35ff4c80fcfcd05bc1cd932fe3c08f943ca
@@ -146,13 +139,13 @@ jobs:
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@71a8b35ff4c80fcfcd05bc1cd932fe3c08f943ca
with:
with:
category: "ql-for-ql"
- name: Copy sarif file to CWD
run: cp ../results/ql.sarif ./ql-for-ql.sarif
- name: Fixup the $scema in sarif # Until https://github.com/microsoft/sarif-vscode-extension/pull/436/ is part in a stable release
run: |
sed -i 's/\$schema.*/\$schema": "https:\/\/raw.githubusercontent.com\/oasis-tcs\/sarif-spec\/master\/Schemata\/sarif-schema-2.1.0",/' ql-for-ql.sarif
sed -i 's/\$schema.*/\$schema": "https:\/\/raw.githubusercontent.com\/oasis-tcs\/sarif-spec\/master\/Schemata\/sarif-schema-2.1.0",/' ql-for-ql.sarif
- name: Sarif as artifact
uses: actions/upload-artifact@v3
with:

View File

@@ -299,7 +299,7 @@ namespace Semmle.Autobuild.Cpp.Tests
{
Actions.RunProcess[@"cmd.exe /C nuget restore C:\Project\test.sln -DisableParallelProcessing"] = 1;
Actions.RunProcess[@"cmd.exe /C C:\Project\.nuget\nuget.exe restore C:\Project\test.sln -DisableParallelProcessing"] = 0;
Actions.RunProcess[@"cmd.exe /C CALL ^""C:\Program Files ^(x86^)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat^"" && set Platform=&& type NUL && C:\odasa\tools\odasa index --auto msbuild C:\Project\test.sln /t:rebuild /p:Platform=""x86"" /p:Configuration=""Release"" /p:MvcBuildViews=true"] = 0;
Actions.RunProcess[@"cmd.exe /C CALL ^""C:\Program Files ^(x86^)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat^"" && set Platform=&& type NUL && C:\odasa\tools\odasa index --auto msbuild C:\Project\test.sln /p:UseSharedCompilation=false /t:rebuild /p:Platform=""x86"" /p:Configuration=""Release"" /p:MvcBuildViews=true"] = 0;
Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = "";
Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = 1;
Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationVersion"] = 0;

View File

@@ -162,7 +162,7 @@ module SemanticExprConfig {
predicate phi(SsaVariable v) { v.asInstruction() instanceof IR::PhiInstruction }
SsaVariable getAPhiInput(SsaVariable v) {
exists(IR::PhiInstruction instr | v.asInstruction() = instr |
exists(IR::PhiInstruction instr |
result.asInstruction() = instr.getAnInput()
or
result.asOperand() = instr.getAnInputOperand()

View File

@@ -1 +0,0 @@
Console.WriteLine(args[0]);

View File

@@ -1,10 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@@ -1,3 +0,0 @@
from create_database_utils import *
run_codeql_database_create(['dotnet build'], test_db="default-db", db=None, lang="csharp")

View File

@@ -1,2 +0,0 @@
libraryPathDependencies:
- codeql-csharp

View File

@@ -18,10 +18,9 @@ function RegisterExtractorPack(id)
-- For now, parse the command line as follows:
-- Everything that starts with `-` (or `/`) will be ignored.
-- The first non-option argument is treated as the command.
-- if that's `build`, we append `-p:UseSharedCompilation=false` to the command line,
-- if that's `build`, we append `/p:UseSharedCompilation=false` to the command line,
-- otherwise we do nothing.
local match = false
local needsSeparator = false;
local argv = compilerArguments.argv
if OperatingSystem == 'windows' then
-- let's hope that this split matches the escaping rules `dotnet` applies to command line arguments
@@ -34,30 +33,18 @@ function RegisterExtractorPack(id)
local firstCharacter = string.sub(arg, 1, 1)
if not (firstCharacter == '-') and not (firstCharacter == '/') then
Log(1, 'Dotnet subcommand detected: %s', arg)
if arg == 'build' or arg == 'msbuild' or arg == 'publish' or arg == 'pack' or arg == 'test' then
match = true
break
end
if arg == 'run' then
-- for `dotnet run`, we need to make sure that `-p:UseSharedCompilation=false` is
-- not passed in as an argument to the program that is run
match = true
needsSeparator = true
end
end
if arg == '--' then
needsSeparator = false
if arg == 'build' or arg == 'msbuild' then match = true end
break
end
end
if match then
local injections = { '-p:UseSharedCompilation=false' }
if needsSeparator then
table.insert(injections, '--')
end
return {
order = ORDER_REPLACE,
invocation = BuildExtractorInvocation(id, compilerPath, compilerPath, compilerArguments, nil, injections)
invocation = BuildExtractorInvocation(id, compilerPath,
compilerPath,
compilerArguments, nil, {
'/p:UseSharedCompilation=false'
})
}
end
return nil

View File

@@ -14,18 +14,11 @@ There are two types of CodeQL packs: query packs and library packs.
You can use the package management commands in the CodeQL CLI to create CodeQL packs, add dependencies to packs, and install or update dependencies. For more information, see ":ref:`Creating and working with CodeQL packs <creating-and-working-with-codeql-packs>`." You can also publish and download CodeQL packs using the CodeQL CLI. For more information, see ":doc:`Publishing and using CodeQL packs <publishing-and-using-codeql-packs>`."
The standard CodeQL packages for all supported languages are published in the `GitHub Container registry <https://github.com/orgs/codeql/packages>`__.
The `CodeQL repository <https://github.com/github/codeql>`__ contains source files for the standard CodeQL packs for all supported languages.
.. _codeql-pack-structure:
CodeQL pack structure
---------------------
A CodeQL pack must contain a file called ``qlpack.yml`` in its root directory. In the ``qlpack.yml`` file, the ``name:`` field must have a value that follows the format of ``<scope>/<pack>``, where ``<scope>`` is the GitHub organization or user account that the pack will be published to and ``<pack>`` is the name of the pack. Additionally, query packs and library packs with CodeQL tests contain a ``codeql-pack.lock.yml`` file that contains the resolved dependencies of the pack. This file is generated during a call to the ``codeql pack install`` command, is not meant to be edited by hand, and should be added to your version control system.
The other files and directories within the pack should be logically organized. For example, typically:
A CodeQL pack must contain a file called ``qlpack.yml`` in its root directory. In the ``qlpack.yml`` file, the ``name:`` field must have a value that follows the format of ``<scope>/<pack>``, where ``<scope>`` is the GitHub organization or user account that the pack will be published to and ``<pack>`` is the name of the pack. The other
files and directories within the pack should be logically organized. For example, typically:
- Queries are organized into directories for specific categories.
- Queries for specific products, libraries, and frameworks are organized into
@@ -34,17 +27,21 @@ The other files and directories within the pack should be logically organized. F
About ``qlpack.yml`` files
--------------------------
When executing query-related commands, CodeQL first looks in siblings of the installation directory (and their subdirectories) for ``qlpack.yml`` files.
Then it checks the package cache for CodeQL packs which have been downloaded. This means that when you are developing queries locally, the local packages
When executing query-related commands, CodeQL first looks in siblings of the installation directory (and their subdirectories) for ``qlpack.yml`` files.
Then it checks the package cache for CodeQL packs which have been downloaded. This means that when you are developing queries locally, the local packages
in the installation directory override packages of the same name in the package cache, so that you can test your local changes.
The metadata in each ``qlpack.yml`` file tells
The metadata in each `qlpack.yml`` file tells
CodeQL how to compile any queries in the pack, what libraries the pack depends on, and where to
find query suite definitions.
The contents of the CodeQL pack (queries or libraries used in CodeQL analysis) is included in the same directory as ``qlpack.yml``, or its subdirectories.
The contents of the CodeQL pack (queries or libraries used in CodeQL analysis) is
included in the same directory as ``qlpack.yml``, or its subdirectories.
The directory containing the ``qlpack.yml`` file serves as the root directory for the content of the CodeQL pack. That is, for all ``.ql`` and ``.qll`` files in the pack, CodeQL will resolve all import statements relative to the directory containing the ``qlpack.yml`` file at the pack's root.
The location of ``qlpack.yml`` defines the library path for the content
of the CodeQL pack. That is, for all ``.ql`` and ``.qll`` files in the pack,
CodeQL will resolve all import statements relative to the ``qlpack.yml`` at the
pack's root.
.. _codeqlpack-yml-properties:
@@ -59,282 +56,49 @@ The following properties are supported in ``qlpack.yml`` files.
* - Property
- Example
- Required by
- Required
- Purpose
* - ``name``
- .. code-block:: yaml
name: octo-org/security-queries
- ``octo-org/security-queries``
- All packs
- The scope, where the CodeQL pack is published, and the name of the pack defined using alphanumeric characters and hyphens. It must be unique as CodeQL cannot differentiate between CodeQL packs with identical names. Use the pack name to specify queries to run using ``database analyze`` and to define dependencies between CodeQL packs (see examples below).
- The scope, where the CodeQL pack is published, and the name of the pack defined using alphanumeric characters and hyphens. It must be unique as CodeQL cannot differentiate between CodeQL packs with identical names. Name components cannot start or end with a hyphen. Additionally, a period is not allowed in pack names at all. Use the pack name to specify queries to run using ``database analyze`` and to define dependencies between QL packs (see examples below).
* - ``version``
- .. code-block:: yaml
version: 0.0.0
- ``0.0.0``
- All packs
- A semantic version for this CodeQL pack that must adhere to the `SemVer v2.0.0 specification <https://semver.org/spec/v2.0.0.html>`__.
- A version range for this CodeQL pack. This must be a valid semantic version that meets the `SemVer v2.0.0 specification <https://semver.org/spec/v2.0.0.html>`__.
* - ``dependencies``
- .. code-block:: yaml
dependencies:
codeql/cpp-all: ^0.0.2
- Packs that define CodeQL package dependencies on other packs
- A map from pack references to the semantic version range that is compatible with this pack. Supported for CLI versions v2.6.0 and later.
* - ``defaultSuiteFile``
- .. code-block:: yaml
defaultSuiteFile: cpp-code-scanning.qls
- Packs that export a set of default queries to run
- The path to a query suite file relative to the package root, containing all of the queries that are run by default when this pack is passed to the ``codeql database analyze`` command. Supported from CLI version v2.6.0 and onwards. Only one of ``defaultSuiteFile`` or ``defaultSuite`` can be defined.
* - ``defaultSuite``
- .. code-block:: yaml
defaultSuite:
queries: .
exclude:
precision: medium
- Packs that export a set of default queries to run
- An inlined query suite containing all of the queries that are run by default when this pack is passed to the ``codeql database analyze`` command. Supported from CLI version v2.6.0 and onwards. Only one of ``defaultSuiteFile`` or ``defaultSuite`` can be defined.
* - ``library``
- .. code-block:: yaml
library: true
- Library packs
- A boolean value that indicates whether this pack is a library pack. Library packs do not contain queries and are not compiled. Query packs can ignore this field or explicitly set it to ``false``.
* - ``suites``
- .. code-block:: yaml
suites: octo-org-query-suites
- ``codeql/javascript-all: ^1.2.3``
- Optional
- The path to a directory in the pack that contains the query suites you want to make known to the CLI, defined relative to the pack directory. CodeQL pack users can run "well-known" suites stored in this directory by specifying the pack name, without providing their full path. This is not supported for CodeQL packs downloaded from the Container registry. For more information about query suites, see ":doc:`Creating CodeQL query suites <creating-codeql-query-suites>`."
- The names and version ranges of any CodeQL packs that this pack depends on, as a mapping. This gives the pack access to any libraries, database schema, and query suites defined in the dependency. For more information, see `SemVer ranges <https://docs.npmjs.com/cli/v6/using-npm/semver#ranges>`__ in the NPM documentation.
* - ``suites``
- ``octo-org-query-suites``
- Optional
- The path to a directory in the pack that contains the query suites you want to make known to the CLI, defined relative to the pack directory. QL pack users can run "well-known" suites stored in this directory by specifying the pack name, without providing their full path. This is not supported for CodeQL packs downloaded from a package registry. For more information about query suites, see ":doc:`Creating CodeQL query suites <creating-codeql-query-suites>`."
* - ``extractor``
- .. code-block:: yaml
extractor: javascript
- All packs containing CodeQL tests
- The CodeQL language extractor to use when running the CodeQL tests in the pack. For more information about testing queries, see ":doc:`Testing custom queries <testing-custom-queries>`."
- ``javascript``
- All test packs
- The CodeQL language extractor to use when the CLI creates a database in the pack. For more information about testing queries, see ":doc:`Testing custom queries <testing-custom-queries>`."
* - ``tests``
- .. code-block:: yaml
tests: .
- Optional for packs containing CodeQL tests. Ignored for packs without tests.
- The path to a directory within the pack that contains tests, defined relative to the pack directory. Use ``.`` to specify the whole pack. Any queries in this directory are run as tests when ``test run`` is run with the ``--strict-test-discovery`` option. These queries are ignored by query suite definitions that use ``queries`` or ``qlpack`` instructions to ask for all queries in a particular pack. If this property is missing, then ``.`` is assumed.
- ``.``
- Optional for test packs
- The path to a directory within the pack that contains tests, defined relative to the pack directory. Use ``.`` to specify the whole pack. Any queries in this directory are run as tests when ``test run`` is run with the ``--strict-test-discovery`` option. These queries are ignored by query suite definitions that use ``queries`` or ``qlpack`` instructions to ask for all queries in a particular pack.
* - ``dbscheme``
- .. code-block:: yaml
dbscheme: semmlecode.python.dbscheme
- ``semmlecode.python.dbscheme``
- Core language packs only
- The path to the :ref:`database schema <codeql-database-schema>` for all libraries and queries written for this CodeQL language (see example below).
* - ``upgrades``
- .. code-block:: yaml
upgrades: .
- ``.``
- Core language packs only
- The path to a directory within the pack that contains database upgrade scripts, defined relative to the pack directory. Database upgrades are used internally to ensure that a database created with a different version of the CodeQL CLI is compatible with the current version of the CLI.
- The path to a directory within the pack that contains upgrade scripts, defined relative to the pack directory. The ``database upgrade`` action uses these scripts to update databases that were created by an older version of an extractor so they're compatible with the current extractor (see `Upgrade scripts for a language <#upgrade-scripts-for-a-language>`__ below.)
* - ``authors``
- .. code-block:: yaml
authors: author1@github.com,author2@github.com
- ``example@github.com``
- All packs
- Metadata that will be displayed on the packaging search page in the packages section of the account that the CodeQL pack is published to.
* - ``license``
- .. code-block:: yaml
license: MIT
* - ``licenses``
- ``(LGPL-2.1 AND MIT)``
- All packs
- Metadata that will be displayed on the packaging search page in the packages section of the account that the CodeQL pack is published to. For a list of allowed licenses, see `SPDX License List <https://spdx.org/licenses/>`__ in the SPDX Specification.
- Metadata that will be displayed on the packaging search page in the packages section of the account that the CodeQL pack is published to. For a list of allowed licenses, see `SPDX License List <https://spdx.org/licenses/>`__ in the SPDX Specification.
* - ``description``
- .. code-block:: yaml
description: Human-readable description of the contents of the CodeQL pack.
- ``Human-readable description of the contents of the CodeQL pack.``
- All packs
- Metadata that will be displayed on the packaging search page in the packages section of the account that the CodeQL pack is published to.
* - ``libraryPathDependencies``
- .. code-block:: yaml
libraryPathDependencies: codeql/javascript-all
- Optional, deprecated
- Use the ``dependencies`` property instead. The names of any CodeQL packs that this CodeQL pack depends on, as an array. This gives the pack access to any libraries, database schema, and query suites defined in the dependency.
.. _about-codeql-pack-lock:
About ``codeql-pack.lock.yml`` files
------------------------------------
``codeql-pack.lock.yml`` files store the versions of the resolved transitive dependencies of a CodeQL pack. This file is created by the ``codeql pack install`` command if it does not already exist and should be added to your version control system. The ``dependencies`` section of the ``qlpack.yml`` file contains version ranges that are compatible with the pack. The ``codeql-pack.lock.yml`` file locks the versions to precise dependencies. This ensures that running ``codeql pack install`` on this the pack will always retrieve the same versions of dependencies even if newer compatible versions exist.
For example, if a ``qlpack.yml`` file contains the following dependencies:
.. code-block:: yaml
dependencies:
codeql/cpp-all: ^0.1.2
my-user/my-lib: ^0.2.3
other-dependency/from-source: "*"
The ``codeql-pack.lock.yml`` file will contain something like the following:
.. code-block:: yaml
dependencies:
codeql/cpp-all:
version: 0.1.4
my-user/my-lib:
version: 0.2.4
my-user/transitive-dependency:
version: 1.2.4
The ``codeql/cpp-all`` dependency is locked to version 0.1.4. The ``my-user/my-lib`` dependency is locked to version 0.2.4. The ``my-user/transitive-dependency``, which is a transitive dependency and is not specified in the ``qlpack.yml`` file, is locked to version 1.2.4. The ``other-dependency/from-source`` is absent from the lock file since it is resolved from source. This dependency must be available in the same CodeQL workspace as the pack. For more information about CodeQL workspaces and resolving dependencies from source, see ":doc:`About CodeQL Workspaces <about-codeql-workspaces>`."
In most cases, the ``codeql-pack.lock.yml`` file is only relevant for query packs since library packs are non-executable and usually do not need their transitive dependencies to be fixed. The exception to this is for library packs that contain tests. In this case, the ``codeql-pack.lock.yml`` file is used to ensure that the tests are always run with the same versions of dependencies to avoid spurious failures when there are mismatched dependencies.
.. _custom-codeql-packs:
Examples of custom CodeQL packs
-------------------------------
When you write custom queries or tests, you should save them in custom CodeQL packs. For simplicity, try to organize each pack logically. For more information, see "`CodeQL pack structure <#codeql-pack-structure>`__." Save files for queries and tests in separate packs and, where possible, organize custom packs into specific folders for each target language. This is particuarly useful if you intend to publish your CodeQL packs so they can be shared with others or used in GitHub `Code scanning <https://docs.github.com/en/code-security/secure-coding/automatically-scanning-your-code-for-vulnerabilities-and-errors/about-code-scanning>`__.
CodeQL packs for custom libraries
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A custom CodeQL pack containing custom C++ libraries, with no queries or tests, may have a ``qlpack.yml`` file containing:
.. code-block:: yaml
name: my-github-user/my-custom-libraries
version: 1.2.3
library: true
dependencies:
codeql/cpp-all: ^0.1.2
where ``codeql/cpp-all`` is the name of the CodeQL pack for C/C++ analysis included in the CodeQL repository. The version range ``^0.1.2`` indicates that this pack is compatible with all versions of ``codeql/cpp-all`` that are greater than or equal to ``0.1.2`` and less than ``0.2.0``. Any CodeQL library file (a file with a ``.qll`` extension) defined in this pack will be available to queries defined in any query pack that includes this pack in its dependencies block.
The ``library`` property indicates that this pack is a library pack and does not contain any queries.
CodeQL packs for custom queries
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A custom CodeQL pack containing custom C++ queries and libraries may have a ``qlpack.yml`` file containing:
.. code-block:: yaml
name: my-github-user/my-custom-queries
version: 1.2.3
dependencies:
codeql/cpp-all: ^0.1.2
my-github-user/my-custom-libraries: ^1.2.3
suites: my-custom-suites
where ``codeql/cpp-all`` is the name of the CodeQL pack for C/C++ analysis included in the CodeQL repository. The version range ``^0.1.2`` indicates that this pack is compatible with all versions of ``codeql/cpp-all`` that are greater than or equal to ``0.1.2`` and less than ``0.2.0``. ``my-github-user/my-custom-libraries`` is the name of a CodeQL pack containing custom CodeQL libraries for C++. Any CodeQL library file (a file with a ``.qll`` extension) defined in this pack will be available to queries in the ``my-github-user/my-custom-queries`` pack.
The ``suites`` property indicates a directory where "well-known" query suites can be found. These suites can be used on the command line by referring to their name only, rather than their full path. For more information about query suites, see ":doc:`Creating CodeQL query suites <creating-codeql-query-suites>`."
CodeQL packs for custom tests
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
For custom CodeQL packs containing test files, you also need to include an
``extractor`` property so that the ``test run`` command knows how to create test
databases. You may also wish to specify the ``tests`` property.
.. include:: ../reusables/test-qlpack.rst
For more information about running tests, see ":doc:`Testing custom queries
<testing-custom-queries>`."
.. _standard-codeql-packs:
Examples of CodeQL packs in the CodeQL repository
-------------------------------------------------
Each of the languages in the CodeQL repository has four main CodeQL packs:
- Core library pack for the language, with the :ref:`database schema <codeql-database-schema>`
used by the language, and CodeQL libraries, and queries at ``<language>/ql/lib``
- Core query pack for the language that includes the default queries for the language, along
with their query suites at ``<language>/ql/src``
- Tests for the core language libraries and queries at ``<language>/ql/test``
- Example queries for the language at ``<language>/ql/examples``
Core library pack
~~~~~~~~~~~~~~~~~
Here is an example ``qlpack.yml`` file for the `C/C++ analysis libraries
<https://github.com/github/codeql/blob/main/cpp/ql/lib/qlpack.yml>`__
core language pack:
.. code-block:: yaml
name: codeql/cpp-all
version: x.y.z-dev
dbscheme: semmlecode.cpp.dbscheme
library: true
upgrades: upgrades
Some extra notes on the following properties:
- ``library``: Indicates that this is a library pack with no executable queries. It is only meant to be used as a dependency for other packs.
- ``dbscheme`` and ``upgrades``: These properties are internal to the CodeQL CLI and should only be defined in the core QL pack for a language.
.. _standard-codeql-query-packs:
Core query pack
~~~~~~~~~~~~~~~
Here is an example ``qlpack.yml`` file for `C/C++ analysis queries
<https://github.com/github/codeql/blob/main/cpp/ql/src/qlpack.yml>`__
core query pack:
.. code-block:: yaml
name: codeql/cpp-queries
version: x.y.z-dev
dependencies:
codeql/cpp-all: "*"
codeql/suite-helpers: "*"
suites: codeql-suites
defaultSuiteFile: codeql-suites/cpp-code-scanning.qls
Some extra notes on the following properties:
- ``dependencies``: This query pack depends on ``codeql/cpp-all`` and ``codeql/suite-helpers``. Since these dependencies are resolved from source, it does not matter what version of the CodeQL pack they are compatible with. For more information about resolving dependencies from source, see ":ref:`Source Dependencies <source-dependencies>`."
- ``suites``: Indicates the directory containing "well-known" query suites.
- ``defaultSuiteFile``: The name of the default query suite file that is used when no query suite is specified.
Tests for the core CodeQL pack
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Here is an example ``qlpack.yml`` file for `C/C++ analysis tests
<https://github.com/github/codeql/blob/main/cpp/ql/src/qlpack.yml>`__
core test pack:
.. code-block:: yaml
name: codeql/cpp-tests
dependencies:
codeql/cpp-all: "*"
codeql/cpp-queries: "*"
extractor: cpp
tests: .
Some extra notes on the following properties:
- ``dependencies``: This pack depends on the core CodeQL query and library packs for C++.
- ``extractor``: This specifies that all the tests will use the same C++ extractor to create the database for the tests.
- ``tests``: This specifies the location of the tests. In this case, the tests are in the root folder (and all sub-folders) of the pack.
- ``version``: There is no ``version`` property for the tests pack. This prevents test packs from accidentally being published.

View File

@@ -1,94 +0,0 @@
.. _about-codeql-workspaces:
About CodeQL Workspaces
=======================
.. include:: ../reusables/beta-note-package-management.rst
CodeQL workspaces are used to group multiple CodeQL packs together. A typical use case for a CodeQL workspace is to develop a set of CodeQL library and query packs that are mutually dependent. For more information on CodeQL packs, see ":doc:`About CodeQL packs <about-codeql-packs>`."
The main benefit of a CodeQL workspace is that it makes it easier for you to develop and maintain multiple CodeQL packs. When you use a CodeQL workspace, all the CodeQL packs in the workspace are available as *source dependencies* for each other when you run a CodeQL command that resolves queries. This makes it easier to develop, maintain, and publish multiple, related CodeQL packs.
In most cases, you should store the CodeQL workspace and the CodeQL packs contained in it in one git repository. This makes it easier to share your CodeQL development environment.
The ``codeql-workspace.yml`` file
----------------------------------
A CodeQL workspace is defined by a ``codeql-workspace.yml`` yaml file. This file contains a ``provide`` block, and optionally an ``ignore`` block.
* The ``provide`` block contains a list of glob patterns that define the CodeQL packs that are available in the workspace.
* The ``ignore`` block contains a list of glob patterns that define CodeQL packs that are not available in the workspace.
Each entry in the ``provide`` or ``ignore`` section must map to the location of a ``qlpack.yml`` file. All glob patterns are defined relative to the directory that contains the workspace file. For a list of patterns accepted in this file, see "`@actions/glob <https://github.com/actions/toolkit/tree/main/packages/glob#patterns>`__ ."
For example, the following ``codeql-workspace.yml`` file defines a workspace that contains all the CodeQL packs recursively found in the ``codeql-packs`` directory, except for the packs in the ``experimental`` directory:
.. code-block:: yaml
provide:
- "*/codeql-packs/**/qlpack.yml"
ignore:
- "*/codeql-packs/**/experimental/**/qlpack.yml"
To verify that your ``codeql-workspace.yml`` file includes the CodeQL packs that you expect, run the ``codeql pack ls`` command in the same directory as your workspace. The result of the command is a list of all CodeQL packs in the workspace.
.. _source-dependencies:
Source Dependencies
-------------------
Source dependencies are CodeQL packs that are resolved from the local file system outside of the CodeQL package cache. These dependencies can be in the same CodeQL workspace, or specified as a path option using the ``--additional-packs`` argument. When you compile and run queries locally, source dependencies override any dependencies found in the CodeQL package cache as well as version constraints defined in the ``qlpack.yml``. All references to CodeQL packs in the same workspace are resolved as source dependencies.
This is particularly useful in the following situations:
- One of the dependencies of the query pack you are running is not yet published. Resolving from source is the only way to reference that pack.
- You are making changes to multiple packs at the same time and want to test them together. Resolving from source ensures that you are using the version of the pack with your changes in it.
CodeQL workspaces and query resolution
--------------------------------------
All CodeQL packs in a workspace are available as source dependencies for each other when you run any CodeQL command that resolves queries or packs. For example, when you run ``codeql pack install`` in a pack directory in a workspace, any dependency that can be found in the workspace will be used instead of downloading that dependency to the package cache and adding it to the ``codeql-pack.lock.yml`` file. For more information, see ":ref:`Adding and Installing Dependencies <adding-and-installing-dependencies>`."
Similarly, when you publish a CodeQL query pack to the GitHub container registry using ``codeql pack publish`` the command will always use the dependencies from the workspace instead of using dependencies found in the local package cache.
This ensures that any local changes you make to a query library in a dependency are automatically reflected in any query packs you publish from that workspace.
Example
~~~~~~~
Consider the following ``codeql-workspace.yml`` file:
.. code-block:: yaml
provide:
- "**/qlpack.yml"
And the following CodeQL library pack ``qlpack.yml`` file in the workspace:
.. code-block:: yaml
name: my-company/my-library
library: true
version: 1.0.0
And the following CodeQL query pack ``qlpack.yml`` file in the workspace:
.. code-block:: yaml
name: my-company/my-queries
version: 1.0.0
dependencies:
my-company/my-library: "*"
codeql/cpp-all: ~0.2.0
Notice that the ``dependencies`` block for the CodeQL query pack, ``my-company/my-queries``, specifies ``"*"`` as the version of the library pack. Since the library pack is already defined as a source dependency in ``codeql-workspace.yml``, the library pack's content is always resolved from inside the workspace. Any version constraint you define will be ignored in this case. We recommend that you use ``"*"`` for source dependencies to make it clear that the version is inherited from the workspace.
When you execute ``codeql pack install`` from the query pack directory, an appropriate version of ``codeql/cpp-all`` is downloaded to the local package cache. Also, a ``codeql-pack.lock.yml`` file is created that contains the resolved version of ``codeql/cpp-all``. The lock file won't contain an entry for ``my-company/my-library`` since it is resolved from source dependencies. The ``codeql-pack.lock.yml`` file will look something like this:
.. code-block:: yaml
dependencies:
codeql/cpp-all:
version: 0.2.2
When you execute ``codeql pack publish`` from the query pack directory, the ``codeql/cpp-all`` dependency from the package cache and the ``my-company/my-library`` from the workspace are bundled with ``my-company/my-queries`` and published to the GitHub container registry.

View File

@@ -0,0 +1,245 @@
.. _about-ql-packs:
About QL packs
==============
QL packs are used to organize the files used in CodeQL analysis. They
contain queries, library files, query suites, and important metadata.
The `CodeQL repository <https://github.com/github/codeql>`__ contains standard QL packs for all supported languages.
You can also make custom QL packs to contain your own queries and libraries.
QL pack structure
-----------------
A QL pack must contain a file called ``qlpack.yml`` in its root directory. The other
files and directories within the pack should be logically organized. For example, typically:
- Queries are organized into directories for specific categories.
- Queries for specific products, libraries, and frameworks are organized into
their own top-level directories.
- There is a top-level directory named ``<owner>/<language>`` for query library
(``.qll``) files. Within this directory, ``.qll`` files should be organized into
subdirectories for specific categories.
About ``qlpack.yml`` files
--------------------------
When executing commands, CodeQL scans siblings of the installation directory (and
their subdirectories) for ``qlpack.yml`` files. The metadata in the file tells
CodeQL how to compile queries, what libraries the pack depends on, and where to
find query suite definitions.
The content of the QL pack (queries and libraries used in CodeQL analysis) is
included in the same directory as ``qlpack.yml``, or its subdirectories.
The location of ``qlpack.yml`` defines the library path for the content
of the QL pack. That is, for all ``.ql`` and ``.qll`` files in the QL pack,
CodeQL will resolve all import statements relative to the ``qlpack.yml`` at the
pack's root.
For example, in a QL pack with the following contents, you can import ``CustomSinks.qll``
from any location in the pack by declaring ``import mycompany.java.CustomSinks``.
.. code-block:: none
qlpack.yml
mycompany/
java/
security/
CustomSinks.qll
Security/
CustomQuery.ql
For more information, see ":ref:`Importing modules <importing-modules>`"
in the QL language reference.
.. _qlpack-yml-properties:
``qlpack.yml`` properties
~~~~~~~~~~~~~~~~~~~~~~~~~
The following properties are supported in ``qlpack.yml`` files.
.. list-table::
:header-rows: 1
:widths: auto
* - Property
- Example
- Required
- Purpose
* - ``name``
- ``org-queries``
- All packs
- The name of the QL pack defined using alphanumeric characters, hyphens, and periods. It must be unique as CodeQL cannot differentiate between QL packs with identical names. If you intend to distribute the pack, prefix the name with your (or your organization's) name followed by a hyphen. Use the pack name to specify queries to run using ``database analyze`` and to define dependencies between QL packs (see examples below).
* - ``version``
- ``0.0.0``
- All packs
- A version number for this QL pack. This must be a valid semantic version that meets the `SemVer v2.0.0 specification <https://semver.org/spec/v2.0.0.html>`__.
* - ``libraryPathDependencies``
- ``codeql/javascript-all``
- Optional
- The names of any QL packs that this QL pack depends on, as a sequence. This gives the pack access to any libraries, database schema, and query suites defined in the dependency.
* - ``suites``
- ``suites``
- Optional
- The path to a directory in the pack that contains the query suites you want to make known to the CLI, defined relative to the pack directory. QL pack users can run "well-known" suites stored in this directory by specifying the pack name, without providing their full path. For more information about query suites, see ":doc:`Creating CodeQL query suites <creating-codeql-query-suites>`."
* - ``extractor``
- ``javascript``
- All test packs
- The CodeQL language extractor to use when the CLI creates a database from test files in the pack. For more information about testing queries, see ":doc:`Testing custom queries <testing-custom-queries>`."
* - ``tests``
- ``.``
- Optional for test packs
- Supported from release 2.1.0 onwards. The path to a directory within the pack that contains tests, defined relative to the pack directory. Use ``.`` to specify the whole pack. Any queries in this directory are run as tests when ``test run`` is run with the ``--strict-test-discovery`` option. These queries are ignored by query suite definitions that use ``queries`` or ``qlpack`` instructions to ask for all queries in a particular pack.
* - ``dbscheme``
- ``semmlecode.python.dbscheme``
- Core language pack only
- The path to the :ref:`database schema <codeql-database-schema>` for all libraries and queries written for this CodeQL language (see example below).
* - ``upgrades``
- ``.``
- Packs with upgrades
- The path to a directory within the pack that contains upgrade scripts, defined relative to the pack directory. The ``database upgrade`` action uses these scripts to update databases that were created by an older version of an extractor so they're compatible with the current extractor (see `Upgrade scripts for a language <#upgrade-scripts-for-a-language>`__ below.)
* - ``dependencies``
- .. code-block:: yaml
dependencies:
codeql/cpp-all: ^0.0.2
- Packs that define CodeQL package dependencies on other packs
- A map from pack references to the semantic version range that is compatible with this pack. Supported from CLI version v2.6.0 and onwards.
* - ``defaultSuiteFile``
- ``defaultSuiteFile: cpp-code-scanning.qls``
- Packs that export a set of default queries to run
- The path to a query suite file containing all of the queries that are run by default when this pack is passed to the ``codeql database analyze`` command. Supported from CLI version v2.6.0 and onwards.
.. _custom-ql-packs:
Examples of custom QL packs
---------------------------
When you write custom queries or tests, you should save them in
custom QL packs. For simplicity, try to organize each pack logically. For more
information, see `QL pack structure <#ql-pack-structure>`__. Save files for queries
and tests in separate packs and, where possible, organize custom packs into specific
folders for each target language.
QL packs for custom queries
~~~~~~~~~~~~~~~~~~~~~~~~~~~
A custom QL pack for queries must include a ``qlpack.yml`` file at
the pack root, containing ``name``, ``version``,
and ``libraryPathDependencies`` properties. If the pack contains query suites, you can
use the ``suites`` property to define their location. Query suites defined
here are called "well-known" suites, and can be used on the command line by referring to
their name only, rather than their full path.
For more information about query suites, see ":doc:`Creating CodeQL query suites <creating-codeql-query-suites>`."
For example, a ``qlpack.yml`` file for a QL pack featuring custom C++ queries
and libraries may contain:
.. code-block:: yaml
name: my-custom-queries
version: 0.0.0
libraryPathDependencies: codeql/cpp-all
suites: my-custom-suites
where ``codeql/cpp-all`` is the name of the QL pack for C/C++ analysis included in
the CodeQL repository.
.. pull-quote::
Note
When you create a custom QL pack, it's usually a good idea to add it to the search path in your CodeQL configuration.
This will ensure that any libraries the pack contains are available to the CodeQL CLI.
For more information, see ":ref:`Specifying command options in a CodeQL configuration file <specifying-command-options-in-a-codeql-configuration-file>`."
QL packs for custom test files
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
For custom QL packs containing test files, you also need to include an
``extractor`` property so that the ``test run`` command knows how to create test
databases. You may also wish to specify the ``tests`` property.
.. include:: ../reusables/test-qlpack.rst
For more information about running tests, see ":doc:`Testing custom queries
<testing-custom-queries>`."
.. _standard-ql-packs:
Examples of QL packs in the CodeQL repository
---------------------------------------------
Each of the languages in the CodeQL repository has four main QL packs:
- Core library pack for the language, with the :ref:`database schema <codeql-database-schema>`
used by the language, and CodeQL libraries, and queries at ``ql/<language>/ql/lib``
- Core query pack for the language that includes the default queries for the language, along
with their query suites at ``ql/<language>/ql/src``
- Tests for the core language libraries and queries at ``ql/<language>/ql/test``
- Upgrade scripts for the language at ``ql/<language>/upgrades``
Core library pack
~~~~~~~~~~~~~~~~~
The ``qlpack.yml`` file for a core library pack uses the following properties:
``name``, ``version``, ``dbscheme``.
The ``dbscheme`` property should only be defined in the core QL
pack for a language.
For example, the ``qlpack.yml`` file for `C/C++ analysis libraries
<https://github.com/github/codeql/blob/main/cpp/ql/lib/qlpack.yml>`__
contains:
.. code-block:: yaml
name: codeql/cpp-all
version: 0.0.0
dbscheme: semmlecode.cpp.dbscheme
upgrades: upgrades
Core query pack
~~~~~~~~~~~~~~~
The ``qlpack.yml`` file for a core query pack uses the following properties:
``name``, ``version``, ``suites``, ``defaultSuiteFile``, ``dependencies`` .
For example, the ``qlpack.yml`` file for `C/C++ analysis queries
<https://github.com/github/codeql/blob/main/cpp/ql/lib/qlpack.yml>`__
contains:
.. code-block:: yaml
name: codeql/cpp-queries
version: 0.0.0
suites: codeql-suites
defaultSuiteFile: codeql-suites/cpp-code-scanning.qls
dependencies:
codeql/cpp-all: "*"
codeql/suite-helpers: "*"
Tests for the core QL pack
~~~~~~~~~~~~~~~~~~~~~~~~~~
The ``qlpack.yml`` file for the tests for the core QL packs use the following
properties: ``name``, ``version``, and ``dependencies``.
The ``dependencies`` always specifies the core QL pack.
For example, the ``qlpack.yml`` file for `C/C++ analysis tests
<https://github.com/github/codeql/blob/main/cpp/ql/test/qlpack.yml>`__
contains:
.. code-block:: yaml
name: codeql/cpp-tests
version: 0.0.0
dependencies:
codeql/cpp-all: "*"
codeql/cpp-queries: "*"
.. _upgrade-ql-packs:

View File

@@ -36,7 +36,6 @@ You can analyze a database by running the following command::
codeql database analyze <database> --format=<format> --output=<output> <queries>
You must specify:
- ``<database>``: the path to the CodeQL database you want to analyze.
@@ -59,10 +58,9 @@ You can also specify:
- a path to a directory containing query files
- a path to a query suite file
- the name of a CodeQL query pack
- with an optional version range
- with an optional path to a query, directory, or query suite inside the pack
If omitted, the default query suite for the language of the database being analyzed will be used. For more information, see the :ref:`examples <database-analyze-examples>` below.
If omitted, the default query suite for the language
of the database being analyzed will be used. For more information, see the
:ref:`examples <database-analyze-examples>` below.
- ``--sarif-category``: an identifying category for the results. Used when
you want to upload more than one set of results for a commit.
@@ -80,17 +78,17 @@ You can also specify:
- .. include:: ../reusables/threads-query-execution.rst
.. pull-quote::
Upgrading databases
For databases that were created by CodeQL CLI v2.3.3 or earlier, you will need
to explicitly upgrade the database before you can run an analysis with a newer
version of the CodeQL CLI. If this step is necessary, then you will see a message telling you
If the CodeQL queries you want to use are newer than the
extractor used to create the database, then you may see a message telling you
that your database needs to be upgraded when you run ``database analyze``.
For databases that were created by CodeQL CLI v2.3.4 or later, the CLI will implicitly run any
required upgrades. Explicitly running the upgrade command is not necessary.
You can quickly upgrade a database by running the ``database upgrade``
command. For more information, see ":doc:`Upgrading CodeQL databases
<upgrading-codeql-databases>`."
For full details of all the options you can use when analyzing databases, see
the `database analyze reference documentation <../manual/database-analyze>`__.
@@ -124,14 +122,6 @@ You can also run your own custom queries with the ``database analyze`` command.
For more information about preparing your queries to use with the CodeQL CLI,
see ":doc:`Using custom queries with the CodeQL CLI <using-custom-queries-with-the-codeql-cli>`."
If you do not have the CodeQL repository checked out, you can execute the same queries by specifying the query pack name and the path to the queries::
codeql database analyze --download <javascript-database> codeql/javascript-queries:Declarations/UnusedVariable.ql --format=csv --output=js-analysis/js-results.csv
Use the ``--download`` flag to download the query pack if it isn't yet available locally.
.. _run-query-pack:
Running a CodeQL pack
~~~~~~~~~~~~~~~~~~~~~
@@ -145,34 +135,6 @@ pack names and use the ``--download`` flag::
The ``analyze`` command above runs the default suite from ``microsoft/coding-standards v1.0.0`` and the latest version of ``github/security-queries`` on the specified database.
For further information about default suites, see ":ref:`Publishing and using CodeQL packs <publishing-and-using-codeql-packs>`".
Running all queries in a directory
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can run all the queries located in a directory by providing the directory
path, rather than listing all the individual query files. Paths are searched
recursively, so any queries contained in subfolders will also be executed.
.. pull-quote::
Important
You should avoid specifying the root of a :ref:`core CodeQL query pack
<standard-codeql-query-packs>` when executing ``database analyze``
as it might contain some special queries that aren't designed to be used with
the command. Rather, :ref:`run the query pack <run-query-pack>` to include the
pack's default queries in the analysis, or run one of the
code scanning query suites.
For example, to execute all Python queries contained in the ``Functions`` directory you would run::
codeql database analyze <python-database> ../ql/python/ql/src/Functions/ --format=sarif-latest --output=python-analysis/python-results.sarif
When the analysis has finished, a SARIF results file is generated. Specifying ``--format=sarif-latest`` ensures
that the results are formatted according to the most recent SARIF specification
supported by CodeQL.
.. _including-query-help-for-custom-codeql-queries-in-sarif-files:
Running a subset of queries in a CodeQL pack
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -230,10 +192,10 @@ For more information, see `Analyzing a CodeQL database <https://docs.github.com/
or `Code scanning API <https://docs.github.com/en/rest/reference/code-scanning>`__ in the GitHub documentation.
CodeQL query suites are ``.qls`` files that use directives to select queries to run
based on certain metadata properties. The standard CodeQL packs have metadata that specify
based on certain metadata properties. The standard QL packs have metadata that specify
the location of the query suites used by code scanning, so the CodeQL CLI knows where to find these
suite files automatically, and you don't have to specify the full path on the command line.
For more information, see ":ref:`About CodeQL packs <standard-codeql-packs>`."
For more information, see ":ref:`About QL packs <standard-ql-packs>`."
The standard query suites are stored at the following paths in
the CodeQL repository::
@@ -265,6 +227,35 @@ Integrating a CodeQL pack into a code scanning workflow in GitHub
You can use CodeQL query packs in your code scanning setup. This allows you to select query packs published by various sources and use them to analyze your code.
For more information, see "`Using CodeQL query packs in the CodeQL action <https://docs.github.com/en/code-security/secure-coding/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-codeql-query-packs/>`_" or "`Downloading and using CodeQL query packs in your CI system <https://docs.github.com/en/code-security/secure-coding/using-codeql-code-scanning-with-your-existing-ci-system/configuring-codeql-cli-in-your-ci-system#downloading-and-using-codeql-query-packs>`_."
Running all queries in a directory
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can run all the queries located in a directory by providing the directory
path, rather than listing all the individual query files. Paths are searched
recursively, so any queries contained in subfolders will also be executed.
.. pull-quote::
Important
You shouldn't specify the root of a :doc:`QL pack
<about-ql-packs>` when executing ``database analyze``
as it contains some special queries that aren't designed to be used with
the command. Rather, to run a wide range of useful queries, run one of the
LGTM.com query suites.
For example, to execute all Python queries contained in the ``Functions``
directory you would run::
codeql database analyze <python-database> ../ql/python/ql/src/Functions/ --format=sarif-latest --output=python-analysis/python-results.sarif
A SARIF results file is generated. Specifying ``--format=sarif-latest`` ensures
that the results are formatted according to the most recent SARIF specification
supported by CodeQL.
.. _including-query-help-for-custom-codeql-queries-in-sarif-files:
Including query help for custom CodeQL queries in SARIF files
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@@ -3,21 +3,22 @@
CodeQL CLI reference
====================
Learn more about the files you can use when running CodeQL processes and the results format and exit codes that CodeQL generates.
Learn more about the files you can use when running CodeQL processes and the results format and exit codes that CodeQL generates.
.. toctree::
:titlesonly:
:hidden:
about-codeql-packs
about-codeql-workspaces
about-ql-packs
query-reference-files
sarif-output
exit-codes
extractor-options
- :doc:`About CodeQL packs <about-codeql-packs>`: CodeQL packs are created with the CodeQL CLI and are used to create, depend on, publish, and run CodeQL queries, libraries, and query suites.
- :doc:`About CodeQL workspaces <about-codeql-workspaces>`: CodeQL workspaces are used to group multiple CodeQL packs together.
- :doc:`About CodeQL packs <about-codeql-packs>`: CodeQL packs are created with the CodeQL CLI and are used to create, depend on, publish, and run CodeQL queries and libraries.
- :doc:`About QL packs <about-ql-packs>`: QL packs are used to organize the files used in CodeQL analysis. They
contain queries, library files, query suites, and important metadata.
- :doc:`Query reference files <query-reference-files>`: A query reference file is text file that defines the location of one query to test.
- :doc:`SARIF output <sarif-output>`: CodeQL supports SARIF as an output format for sharing static analysis results.
- :doc:`Exit codes <exit-codes>`: The CodeQL CLI reports the status of each command it runs as an exit code.

View File

@@ -34,28 +34,24 @@ You must specify:
The ``codeql pack init`` command creates the directory structure and configuration files for a CodeQL pack. By default, the command creates a query pack. If you want to create a library pack, you must edit the ``qlpack.yml`` file to explicitly declare the file as a library pack by including the ``library:true`` property.
Modifying an existing legacy QL pack to create a CodeQL pack
------------------------------------------------------------
Modifying an existing QL pack to create a CodeQL pack
-----------------------------------------------------
If you already have a ``qlpack.yml`` file, you can edit it manually to convert it into a CodeQL pack.
#. Edit the ``name`` property so that it matches the format ``<scope>/<name>``, where ``<scope>`` is the name of the GitHub organization or user account that you will publish to.
#. In the ``qlpack.yml`` file, include a ``version`` property with a semver identifier, as well as an optional ``dependencies`` block.
#. Migrate the list of dependencies in ``libraryPathDependencies`` to the ``dependencies`` block. Specify the version range for each dependency. If the range is unimportant, or you are unsure of compatibility, you can specify ``"*"``, which indicates that any version is acceptable and will default to the latest version when you run ``codeql pack install``.
For more information about the properties, see ":ref:`About CodeQL packs <about-codeql-packs>`."
.. _adding-and-installing-dependencies:
Adding and installing dependencies to a CodeQL pack
---------------------------------------------------
You can add dependencies on CodeQL packs using the command ``codeql pack add``. You must specify the scope, name, and (optionally) a compatible version range.
You can add dependencies on CodeQL packs using the command ``codeql pack add``. You must specify the scope, name, and version range.
::
codeql pack add <scope>/<name>@x.x.x <scope>/<other-name>
If you don't specify a version range, the latest version will be added. Otherwise, the latest version that satisfies the requested range will be added.
The version range is optional. If you leave off the version range, the latest version will be added. Otherwise, the latest version that satisfies the requested range will be added.
This command updates the ``qlpack.yml`` file with the requested dependencies and downloads them into the package cache. Please note that this command will reformat the file and remove all comments.
@@ -71,8 +67,7 @@ This command downloads all dependencies to the shared cache on the local disk.
Note
Running the ``codeql pack add`` and ``codeql pack install`` commands will generate or update the ``codeql-pack.lock.yml`` file. This file should be checked-in to version control. The ``codeql-pack.lock.yml`` file contains the precise version numbers used by the pack.
For more information, see ":ref:`About codeql-pack.lock.yml files <about-codeql-pack-lock>`."
Running the ``codeql pack add`` and ``codeql pack install`` commands will generate or update the ``qlpack.lock.yml`` file. This file should be checked-in to version control. The ``qlpack.lock.yml`` file contains the precise version numbers used by the pack.
.. pull-quote::

View File

@@ -7,8 +7,8 @@ Before you analyze your code using CodeQL, you need to create a CodeQL
database containing all the data required to run queries on your code.
CodeQL analysis relies on extracting relational data from your code, and
using it to build a :ref:`CodeQL database <codeql-database>`. CodeQL
databases contain all of the important information about a codebase, which can
using it to build a :ref:`CodeQL database <codeql-database>`. CodeQL
databases contain all of the important information about a codebase, which can
be analyzed by executing CodeQL queries against it.
Before you generate a CodeQL database, you need to:
@@ -18,9 +18,9 @@ Before you generate a CodeQL database, you need to:
should be ready to build, with all dependencies already installed.
For information about using the CodeQL CLI in a third-party CI system to create results
to display in GitHub as code scanning alerts, see `Configuring CodeQL CLI in your CI system <https://docs.github.com/en/code-security/secure-coding/using-codeql-code-scanning-with-your-existing-ci-system/configuring-codeql-cli-in-your-ci-system>`__
to display in GitHub as code scanning alerts, see `Configuring CodeQL CLI in your CI system <https://docs.github.com/en/code-security/secure-coding/using-codeql-code-scanning-with-your-existing-ci-system/configuring-codeql-cli-in-your-ci-system>`__
in the GitHub documentation. For information about enabling CodeQL code scanning using GitHub Actions,
see `Setting up code scanning for a repository <https://docs.github.com/en/code-security/secure-coding/automatically-scanning-your-code-for-vulnerabilities-and-errors/setting-up-code-scanning-for-a-repository>`__
see `Setting up code scanning for a repository <https://docs.github.com/en/code-security/secure-coding/automatically-scanning-your-code-for-vulnerabilities-and-errors/setting-up-code-scanning-for-a-repository>`__
in the GitHub documentation.
Running ``codeql database create``
@@ -37,38 +37,38 @@ You must specify:
- ``<database>``: a path to the new database to be created. This directory will
be created when you execute the command---you cannot specify an existing
directory.
directory.
- ``--language``: the identifier for the language to create a database for.
When used with ``--db-cluster``, the option accepts a comma-separated list,
When used with ``--db-cluster``, the option accepts a comma-separated list,
or can be specified more than once.
CodeQL supports creating databases for the following languages:
.. include:: ../reusables/extractors.rst
You can specify additional options depending on the location of your source file,
if the code needs to be compiled, and if you want to create CodeQL databases for
You can specify additional options depending on the location of your source file,
if the code needs to be compiled, and if you want to create CodeQL databases for
more than one language:
- ``--source-root``: the root folder for the primary source files used in
database creation. By default, the command assumes that the current
directory is the source root---use this option to specify a different location.
- ``--db-cluster``: use for multi-language codebases when you want to create
databases for more than one language.
databases for more than one language.
- ``--command``: used when you create a database for one or more compiled languages,
omit if the only languages requested are Python and JavaScript.
This specifies the build commands needed to invoke the compiler.
omit if the only languages requested are Python and JavaScript.
This specifies the build commands needed to invoke the compiler.
Commands are run from the current folder, or ``--source-root``
if specified. If you don't include a ``--command``, CodeQL will attempt to
detect the build system automatically, using a built-in autobuilder.
- ``--no-run-unnecessary-builds``: used with ``--db-cluster`` to suppress the build
command for languages where the CodeQL CLI does not need to monitor the build
detect the build system automatically, using a built-in autobuilder.
- ``--no-run-unnecessary-builds``: used with ``--db-cluster`` to suppress the build
command for languages where the CodeQL CLI does not need to monitor the build
(for example, Python and JavaScript/TypeScript).
You can specify extractor options to customize the behavior of extractors that create CodeQL databases. For more information, see
":doc:`Extractor options <extractor-options>`."
For full details of all the options you can use when creating databases,
see the `database create reference documentation <../manual/database-create>`__.
see the `database create reference documentation <../manual/database-create>`__.
Progress and results
--------------------
@@ -117,7 +117,7 @@ extract both JavaScript and TypeScript files::
Here, we have specified a ``--source-root`` path, which is the location where
database creation is executed, but is not necessarily the checkout root of the
codebase.
codebase.
By default, files in ``node_modules`` and ``bower_components`` directories are not extracted.
@@ -127,7 +127,7 @@ Python
When creating databases for Python you must ensure:
- You have the all of the required versions of Python installed.
- You have access to the `pip <https://pypi.org/project/pip/>`__
- You have access to the `pip <https://pypi.org/project/pip/>`__
packaging management system and can install any
packages that the codebase depends on.
- You have installed the `virtualenv <https://pypi.org/project/virtualenv/>`__ pip module.
@@ -143,14 +143,14 @@ generating a new Python database at ``<output-folder>/python-database``.
Ruby
~~~~
Creating databases for Ruby requires no additional dependencies.
Creating databases for Ruby requires no additional dependencies.
In the command line you must specify ``--language=ruby``. For example::
codeql database create --language=ruby --source-root <folder-to-extract> <output-folder>/ruby-database
Here, we have specified a ``--source-root`` path, which is the location where
database creation is executed, but is not necessarily the checkout root of the
codebase.
codebase.
Creating databases for compiled languages
-----------------------------------------
@@ -179,11 +179,11 @@ build steps, you may need to explicitly define each step in the command line.
.. pull-quote:: Creating databases for Go
For Go, install the Go toolchain (version 1.11 or later) and, if there
are dependencies, the appropriate dependency manager (such as `dep
<https://golang.github.io/dep/>`__).
The Go autobuilder attempts to automatically detect code written in Go in a repository,
and only runs build scripts in an attempt to fetch dependencies. To force
CodeQL to limit extraction to the files compiled by your build script, set the environment variable
@@ -194,7 +194,7 @@ Specifying build commands
~~~~~~~~~~~~~~~~~~~~~~~~~
The following examples are designed to give you an idea of some of the build
commands that you can specify for compiled languages.
commands that you can specify for compiled languages.
.. pull-quote:: Important
@@ -210,10 +210,11 @@ commands that you can specify for compiled languages.
- C# project built using ``dotnet build``::
It is a good idea to add `/t:rebuild` to ensure that all code will be built, or do a
prior `dotnet clean` (code that is not built will not be included in the CodeQL database):
For C# projects using either `dotnet build` or `msbuild`, you should specify `/p:UseSharedCompilation=false`
in the build command. It is also a good idea to add `/t:rebuild` to ensure that all code will be built (code
that is not built will not be included in the CodeQL database):
codeql database create csharp-database --language=csharp --command='dotnet build /t:rebuild'
codeql database create csharp-database --language=csharp --command='dotnet build /p:UseSharedCompilation=false /t:rebuild'
- Go project built using the ``CODEQL_EXTRACTOR_GO_BUILD_TRACING=on`` environment variable::
@@ -259,7 +260,7 @@ commands that you can specify for compiled languages.
- Project built using a custom build script::
codeql database create new-database --language=<language> --command='./scripts/build.sh'
This command runs a custom script that contains all of the commands required
to build the project.
@@ -278,7 +279,7 @@ You must specify:
- ``<database>``: a path to the new database to be created. This directory will
be created when you execute the command---you cannot specify an existing
directory.
directory.
- ``--begin-tracing``: creates scripts that can be used to set up an environment in which build commands will be traced.
You may specify other options for the ``codeql database init`` command as normal.
@@ -348,7 +349,8 @@ The following example shows how you could use indirect build tracing in an Azure
- task: VSBuild@1
inputs:
solution: '**/*.sln'
msbuildArgs: /p:OutDir=$(Build.ArtifactStagingDirectory)
# Disable MSBuild shared compilation for C# builds.
msbuildArgs: /p:OutDir=$(Build.ArtifactStagingDirectory) /p:UseSharedCompilation=false
platform: Any CPU
configuration: Release
# Execute a clean build, in order to remove any existing build artifacts prior to the build.
@@ -386,10 +388,14 @@ Obtaining databases from LGTM.com
CodeQL. For each project on LGTM.com, you can download an archived CodeQL
database corresponding to the most recently analyzed revision of the code. These
databases can also be analyzed using the CodeQL CLI or used with the CodeQL
extension for Visual Studio Code.
extension for Visual Studio Code.
.. include:: ../reusables/download-lgtm-database.rst
Before running an analysis, unzip the databases and try :doc:`upgrading <upgrading-codeql-databases>` the
unzipped databases to ensure they are compatible with your local copy of the
CodeQL queries and libraries.
.. pull-quote::
Note

View File

@@ -4,7 +4,7 @@ Creating CodeQL query suites
============================
CodeQL query suites provide a way of selecting queries, based on their
filename, location on disk or in a CodeQL pack, or metadata properties.
filename, location on disk or in a QL pack, or metadata properties.
Create query suites for the queries that you want to frequently use in
your CodeQL analyses.
@@ -18,8 +18,8 @@ suite definition have been executed, the result is a set of selected queries.
.. pull-quote:: Note
Any custom queries that you want to add to a query suite must be in a :doc:`CodeQL
pack <about-codeql-packs>` and contain the correct query metadata.
Any custom queries that you want to add to a query suite must be in a :doc:`QL
pack <about-ql-packs>` and contain the correct query metadata.
For more information, see
":doc:`Using custom queries with the CodeQL CLI <using-custom-queries-with-the-codeql-cli>`."
@@ -35,7 +35,7 @@ queries using:
- query: <path-to-query>
The argument must be one or more file paths, relative to the CodeQL pack containing
The argument must be one or more file paths, relative to the QL pack containing
the suite definition.
- A ``queries`` instruction---tells CodeQL to recursively scan a directory
@@ -43,30 +43,22 @@ queries using:
- queries: <path-to-subdirectory>
The path of the directory must be relative to the root of the CodeQL pack that
The path of the directory must be relative to the root of the QL pack that
contains the suite definition file. To find the queries relative to a
different CodeQL pack, add a ``from`` field::
different QL pack, add a ``from`` field::
- queries: <path-to-subdirectory>
from: <ql-pack-name>
version: ^x.y.z
The ``version`` field is optional and specifies a range of compatible versions of this CodeQL pack.
If you don't specify a version, then the most recent version of the pack is used.
- A ``qlpack`` instruction---tells CodeQL to resolve queries in the default suite of the
named CodeQL pack::
named QL pack::
- qlpack: <qlpack-name>
version: ^x.y.z
The default suite of a query pack includes a recommended set of queries
inside of that query pack. Not all query packs have a default suite. If the given query pack does not
define a default suite, the `qlpack` instruction will resolve to all of the queries within the pack.
The ``version`` field is optional and specifies a range of compatible versions of this CodeQL pack.
If you don't specify a version, then the most recent version of the pack is used.
.. pull-quote:: Note
When pathnames appear in query suite definitions, they must always
@@ -76,7 +68,7 @@ queries using:
You must add at least one ``query``, ``queries``, or ``qlpack`` instruction to
your suite definition, otherwise no queries will be selected. If the suite
contains no further instructions, all the queries found from the list of files,
in the given directory, or in the named CodeQL pack are selected. If there are further
in the given directory, or in the named QL pack are selected. If there are further
filtering instructions, only queries that match the constraints imposed by those
instructions will be selected.
@@ -125,7 +117,7 @@ In addition to metadata tags, the keys in the constraint block can also be:
- ``query filename``---matches on the last path component of the query file name.
- ``query path``---matches on the path to the query file relative to its
enclosing CodeQL pack.
enclosing QL pack.
- ``tags contain``---one of the given match strings must match
one of the space-separated components of the value of the ``@tags`` metadata property.
- ``tags contain all``---each of the given match strings must match one of the
@@ -135,7 +127,7 @@ Examples
~~~~~~~~
To define a suite that selects all queries in the default suite of the
``codeql/cpp-queries`` CodeQL pack, and then refines them to only include
``codeql/cpp-queries`` QL pack, and then refines them to only include
security queries, use::
- qlpack: codeql/cpp-queries
@@ -161,7 +153,7 @@ recommendation``, use::
problem.severity: recommendation
To create a suite that selects all queries with ``@tag security`` and
``@problem.severity high`` or ``very-high`` from the ``codeql/cpp-queries`` CodeQL pack,
``@problem.severity high`` or ``very-high`` from the ``codeql/cpp-queries`` QL pack,
use::
- queries: .
@@ -182,16 +174,12 @@ Existing query suite definitions can be reused by specifying:
- import: <path-to-query-suite>
The path to the imported suite must be relative to the CodeQL pack containing the
The path to the imported suite must be relative to the QL pack containing the
current suite definition. If the imported query suite is in a different QL
pack you can use::
- import: <path-to-query-suite>
from: <ql-pack>
version: ^x.y.z
The ``version`` field is optional and specifies a range of compatible versions of this CodeQL pack.
If you don't specify a version, then the most recent version of the pack is used.
Queries added using an ``import`` instruction can be filtered using subsequent
``exclude`` instructions.
@@ -212,8 +200,6 @@ Existing query suite definitions can be reused by specifying:
instruction, but takes a full suite definition as the argument, rather than the
path to a ``.qls`` file on disk.
To see what queries are included in a query suite, you can run the ``codeql resolve queries my-suite.qls`` command.
Example
~~~~~~~
@@ -230,27 +216,28 @@ following in a file called ``reusable-instructions.yml``::
- high
- very-high
Add ``reusable-instructions.yml`` to the same CodeQL pack as your current query
suite. Then, in one or more query suites, use the ``apply`` instruction to apply
the reusable instructions to the current suite. For example::
Add ``reusable-instructions.yml`` to the same QL pack as your current query
suite (for example, ``my-custom-queries``). Apply the reusable instructions
to the queries in your current suite using::
- qlpack: my-custom-queries
- apply: reusable-instructions.yml
To apply the same conditions to a different suite or directory within the same
QL pack, create a new definition and change (or replace) the ``qlpack``
instruction. For example::
- queries: queries/cpp/custom
- apply: reusable-instructions.yml
This will filter the queries in ``queries/cpp/custom`` to only include those that match the reusable conditions.
You can also create a suite definition using ``reusable-instructions.yml`` on
queries in a different CodeQL pack. If the ``.qls`` file is in the same CodeQL pack as
queries in a different QL pack. If the ``.qls`` file is in the same QL pack as
the queries, you can add a ``from`` field immediately after the ``apply``
instruction::
# load queries from the default suite of my-org/my-other-custom-queries
- qlpack: my-org/my-other-custom-queries
# apply the reusable instructions from the my-org/my-custom-instructions CodeQL pack
- qlpack: my-other-custom-queries
- apply: reusable-instructions.yml
from: my-org/my-custom-instructions
version: ^1.2.3 # optional
from: <name-of-ql-pack>
Naming a query suite
--------------------
@@ -268,20 +255,20 @@ directory. For more information, see "`Specifying well-known query suites
Saving a query suite
--------------------
Save your query suite in a file with a ``.qls`` extension and add it to a CodeQL
pack. For more information, see ":ref:`About CodeQL packs <custom-codeql-packs>`."
Save your query suite in a file with a ``.qls`` extension and add it to a QL
pack. For more information, see ":ref:`About QL packs <custom-ql-packs>`."
Specifying well-known query suites
----------------------------------
You can use CodeQL packs to declare directories that contain "well-known" query
You can use QL packs to declare directories that contain "well-known" query
suites. You can use "well-known" query suites on the command line by referring
to their file name,
without providing their full path. This gives you a simple way of specifying a
set of queries, without needing to search inside CodeQL packs and distributions.
set of queries, without needing to search inside QL packs and distributions.
To declare a directory that contains "well-known" query suites, add the directory
to the ``suites`` property in the ``qlpack.yml`` file at the root of your CodeQL pack.
For more information, see ":ref:`About CodeQL packs <codeqlpack-yml-properties>`."
to the ``suites`` property in the ``qlpack.yml`` file at the root of your QL pack.
For more information, see ":ref:`About QL packs <qlpack-yml-properties>`."
Using query suites with CodeQL
------------------------------
@@ -301,7 +288,7 @@ JavaScript, visit
https://github.com/github/codeql/tree/main/javascript/ql/src/codeql-suites.
These suite definitions apply reusable filter patterns to the queries
located in the standard CodeQL packs for each supported language. For more
located in the standard QL packs for each supported language. For more
information, see the `suite-helpers
<https://github.com/github/codeql/tree/main/misc/suite-helpers>`__ in the CodeQL
repository.

View File

@@ -23,11 +23,11 @@ and 4 are slightly different---for further details, see the sections labeled
**Information for macOS "Catalina" (or newer) users**. If you are using macOS
on Apple Silicon (e.g. Apple M1), ensure that the `Xcode command-line developer
tools <https://developer.apple.com/downloads/index.action>`__ and `Rosetta 2
<https://support.apple.com/en-us/HT211861>`__ are installed.
<https://support.apple.com/en-us/HT211861>`__ are installed.
.. pull-quote:: Note
The CodeQL CLI is currently not compatible with non-glibc Linux
The CodeQL CLI is currently not compatible with non-glibc Linux
distributions such as (muslc-based) Alpine Linux.
For information about installing the CodeQL CLI in a CI system to create results
@@ -47,7 +47,7 @@ Conditions <https://securitylab.github.com/tools/codeql/license>`__.
.. pull-quote:: Important
There are different versions of the CLI available to download, depending
There are several different versions of the CLI available to download, depending
on your use case:
- If you want to use the most up to date CodeQL tools and features, download the
@@ -202,6 +202,8 @@ CLI that you will extract in step 4. If you use git on the command line, you can
clone and rename the repository in a single step by running
``git clone git@github.com:github/codeql.git codeql-repo`` in the ``codeql-home`` folder.
For Go analysis, run ``codeql-repo/go/scripts/install-deps.sh`` to install its dependencies.
.. pull-quote:: Note
The CodeQL libraries and queries for Go analysis used to live in a
@@ -211,10 +213,10 @@ clone and rename the repository in a single step by running
For more information, see the `Relocation announcement <https://github.com/github/codeql-go/issues/741>`__.
Within this repository, the queries and libraries are organized into CodeQL
packs. Along with the queries themselves, CodeQL packs contain important metadata
Within this repository, the queries and libraries are organized into QL
packs. Along with the queries themselves, QL packs contain important metadata
that tells the CodeQL CLI how to process the query files. For more information,
see ":doc:`About CodeQL packs <about-codeql-packs>`."
see ":doc:`About QL packs <about-ql-packs>`."
.. pull-quote:: Important
@@ -230,7 +232,10 @@ see ":doc:`About CodeQL packs <about-codeql-packs>`."
may need to be upgraded before you can analyze them.
- For the most up to date CodeQL queries, check out the ``main`` branch.
This branch represents the very latest version of CodeQL's analysis.
This branch represents the very latest version of CodeQL's analysis. Even
databases created using the most recent version of the CLI may have to be
upgraded before you can analyze them. For more information, see
":doc:`Upgrading CodeQL databases <upgrading-codeql-databases>`."
- For the queries used in a particular LGTM Enterprise release, check out the
branch tagged with the relevant release number. For example, the branch
@@ -240,7 +245,7 @@ see ":doc:`About CodeQL packs <about-codeql-packs>`."
<https://help.semmle.com/lgtm-enterprise/admin/help/prepare-database-upload.html>`__
in the LGTM admin help.
1. Extract the zip archive
4. Extract the zip archive
~~~~~~~~~~~~~~~~~~~~~~~~~~
For Linux, Windows, and macOS users (version 10.14 "Mojave", and earlier)
@@ -266,8 +271,8 @@ up to create and analyze databases:
- Run ``codeql resolve languages`` to show which languages are
available for database creation. This will list the languages supported by
default in your CodeQL CLI package.
- Run ``codeql resolve qlpacks`` to show which CodeQL packs the CLI can find. This
will display the names of all the CodeQL packs directly available to the CodeQL CLI.
- Run ``codeql resolve qlpacks`` to show which QL packs the CLI can find. This
will display the names of all the QL packs directly available to the CodeQL CLI.
This should include:
- Query packs for each supported language, for example, ``codeql/{language}-queries``.

View File

@@ -60,13 +60,12 @@ To analyze a CodeQL database with a CodeQL pack, run the following command:
::
codeql database analyze <database> <scope>/<pack>@x.x.x:<path>
codeql database analyze <database> <scope>/<pack>@x.x.x
- ``<database>``: the CodeQL database to be analyzed.
- ``<scope>``: the name of the GitHub organization that the pack is published to.
- ``<pack>``: the name for the pack that you are using.
- ``@x.x.x``: an optional version number. If omitted, the latest version will be used.
- ``:<path>``: an optional path to a query, directory, or query suite. If omitted, the pack's default query suite will be used.
The ``analyze`` command will run the default suite of any specified CodeQL packs. You can specify multiple CodeQL packs to be used for analyzing a CodeQL database. For example:

View File

@@ -10,10 +10,10 @@ to run a query that's not part of a test directory.
There are two ways to specify queries that you want to run as tests:
#. Use a query reference file to specify the location of a query to test.
This is useful when you create tests for alert and path queries that
are intended to identify problems in real codebases. You might create
This is useful when you create tests for alert and path queries that
are intended to identify problems in real codebases. You might create
several directories of test code, each focusing on different
aspects of the query. Then you would add a query reference file to
aspects of the query. Then you would add a query reference file to
each directory of test code, to specify the query to test.
#. Add the query directly to a directory of tests.
These is typically useful when you're writing queries explicitly to test the behavior
@@ -25,24 +25,22 @@ Defining a query reference file
Each query reference file, ``.qlref``, contains a single line that defines
where to find one query. The location must be defined relative
to the root of the CodeQL pack that contains the query.
Usually, this is either the CodeQL pack that contains the ``.qlref``, a CodeQL pack
specified in the ``dependencies`` block for the test pack, or a transitive dependency of
the CodeQL pack.
to the root of the QL pack that contains the query.
Usually, this is a QL pack specified by the ``libraryPathDependencies`` for the test pack.
You should use forward slashes in the path on all operating
systems to ensure compatibility between systems.
systems to ensure compatibility between systems.
Example
^^^^^^^
^^^^^^^^
A query reference file to test a JavaScript alert query:
`DeadAngularJSEventListener.qlref <https://github.com/github/codeql/blob/main/javascript/ql/test/query-tests/AngularJS/DeadAngularJSEventListener/DeadAngularJSEventListener.qlref>`__
The ```qlpack.yml`` file <https://github.com/github/codeql/blob/main/javascript/ql/test/qlpack.yml>`__
for the CodeQL pack at ``javascript/ql/test`` defines ``codeql/javascript-queries`` as
The `QL pack <https://github.com/github/codeql/blob/main/javascript/ql/test/qlpack.yml>`__
for the ``javascript/ql/test`` directory defines the ``codeql-javascript`` queries as
a dependency. So the query reference file defines the location of the query relative
to the ``codeql/javascript-queries`` CodeQL pack::
to the ``codeql-javascript`` QL pack::
AngularJS/DeadAngularJSEventListener.ql

View File

@@ -8,15 +8,15 @@ configuration file.
You can specify CodeQL CLI command options in two ways:
- Directly in the command line, using the appropriate flag.
- Directly in the command line, using the appropriate flag.
- In a configuration (or ``config``) file that CodeQL scans for relevant
options each time a command is executed.
For options that are likely to change each time you execute a command,
specifying the value on the command line is the most convenient way of passing
the information to CodeQL. Saving options in a ``config`` file is a good way to
specify options you use frequently.
It's also a good way to add custom CodeQL packs that you use regularly to your search path.
specify options you use frequently.
It's also a good way to add custom QL packs that you use regularly to your search path.
Using a CodeQL configuration file
---------------------------------
@@ -39,7 +39,7 @@ To apply the same options to more than one command you can:
.. pull-quote::
Note
- ``config`` files only accept spaces between between option flags and
values---CodeQL will throw an error if you use ``=`` to specify an option value.
- If you specify an option in the command line, this overrides the ``config``
@@ -66,7 +66,7 @@ Examples
--ram 4096
--threads 4
- To globally specify a directory for CodeQL to scan for CodeQL packs (which is not a
- To globally specify a directory for CodeQL to scan for QL packs (which is not a
sibling of the installation directory), use::
--search-path <path-to-directory>

View File

@@ -13,10 +13,10 @@ on the query and the expected results until the actual results and the expected
results exactly match. This topic shows you how to create test files and execute
tests on them using the ``test run`` subcommand.
Setting up a test CodeQL pack for custom queries
------------------------------------------------
Setting up a test QL pack for custom queries
--------------------------------------------
All CodeQL tests must be stored in a special "test" CodeQL pack.
All CodeQL tests must be stored in a special "test" QL pack.
That is, a directory for test files with a ``qlpack.yml``
file that defines:
@@ -24,25 +24,22 @@ file that defines:
name: <name-of-test-pack>
version: 0.0.0
dependencies:
<codeql-libraries-and-queries-to-test>: "*"
libraryPathDependencies: <codeql-libraries-and-queries-to-test>
extractor: <language-of-code-to-test>
The ``dependencies`` value specifies the CodeQL packs containing queries to test.
Typically, these packs will be resolved from source, and so it is not necessary
to specify a fixed version of the pack.
The ``extractor`` defines which language the CLI will use
to create test databases from the code files stored in this CodeQL pack.
For more information, see ":doc:`About CodeQL packs <about-codeql-packs>`."
The ``libraryPathDependencies`` value specifies the CodeQL queries to test.
The ``extractor`` defines which language the CLI will use
to create test databases from the code files stored in this QL pack.
For more information, see ":doc:`About QL packs <about-ql-packs>`."
You may find it useful to look at the way query tests are organized in the
`CodeQL repository <https://github.com/github/codeql>`__.
Each language has a ``src`` directory, ``ql/<language>/ql/src``,
that contains libraries and queries for analyzing codebases.
Alongside the ``src`` directory, there is a ``test`` directory with tests for
these libraries and queries.
You may find it useful to look at the way query tests are organized in the
`CodeQL repository <https://github.com/github/codeql>`__.
Each language has a ``src`` directory, ``ql/<language>/ql/src``,
that contains libraries and queries for analyzing codebases.
Alongside the ``src`` directory,
there's a ``test`` directory with tests for these libraries and queries.
Each ``test`` directory is configured as a test CodeQL pack with two subdirectories:
Each ``test`` directory is configured as a test QL pack with two subdirectories:
- ``query-tests`` a series of subdirectories with tests for queries stored in the ``src`` directory.
Each subdirectory contains test code and a QL reference file that specifies the query to test.
@@ -52,18 +49,18 @@ Each ``test`` directory is configured as a test CodeQL pack with two subdirector
Setting up the test files for a query
-------------------------------------
For each query you want to test, you should create a sub-directory in the test CodeQL pack.
For each query you want to test, you should create a sub-directory in the test QL pack.
Then add the following files to the subdirectory before you run the test command:
- A query reference file (``.qlref`` file) defining the location of the query to test.
The location is defined relative to the root of the CodeQL pack that contains the
query. Usually, this is a CodeQL pack specified in the
``dependencies`` block of the test pack.
The location is defined relative to the root of the QL pack that contains the
query. Usually, this is a QL pack specified by the
``libraryPathDependencies`` for the test pack.
For more information, see ":doc:`Query reference files <query-reference-files>`."
You do not need to add a query reference file if the query you want to
You don't need to add a query reference file if the query you want to
test is stored in the test directory,
but it is generally good practice to store queries separately from tests.
but it's generally good practice to store queries separately from tests.
The only exception is unit tests for QL libraries, which tend to be
stored in test packs, separate from queries that generate alerts or paths.
@@ -71,13 +68,15 @@ Then add the following files to the subdirectory before you run the test command
should consist of one or more files containing examples of the code the
query is designed to identify.
You can also define the results you expect to see when you run the query against
You can also define the results you expect to see when you run the query against
the example code, by creating a file with the extension ``.expected``.
Alternatively, you can leave the test command to create the ``.expected`` file
for you.
for you. (If you're using CodeQL CLI 2.0.2--2.0.6, you need to create an
``.expected`` file otherwise the command will fail to find your test query.
You can create an empty ``.expected`` file to workaround this limitation.)
For an example showing how to create and test a query, see the `example
<#example>`__ below.
<#example>`__ below.
.. pull-quote:: Important
@@ -87,14 +86,14 @@ For an example showing how to create and test a query, see the `example
it must have the same base name as the corresponding ``.expected`` file. For
example, if the query is ``MyJavaQuery.ql``, the expected results file must
be ``MyJavaQuery.expected``.
If you want to specify a ``.qlref`` file in the command, it must have the same base
name as the corresponding ``.expected`` file, but the query itself
may have a different name.
may have a different name.
The names of the example code files don't have to be consistent with the
other test files. All example code files found next to the ``.qlref`` (or ``.ql``)
file and in any subdirectories will be used to create a test database.
file and in any subdirectories will be used to create a test database.
Therefore, for simplicity, we recommend you don't save test files in
directories that are ancestors of each other.
@@ -109,10 +108,10 @@ The ``<test|dir>`` argument can be one or more of the following:
- Path to a ``.ql`` file.
- Path to a ``.qlref`` file that references a ``.ql`` file.
- Path to a directory that will be searched recursively for ``.ql`` and
- Path to a directory that will be searched recursively for ``.ql`` and
``.qlref`` files.
You can also specify:
You can also specify:
- .. include:: ../reusables/threads-query-execution.rst
@@ -124,7 +123,7 @@ Example
The following example shows you how to set up a test for a query that searches
Java code for ``if`` statements that have empty ``then`` blocks. It includes
steps to add the custom query and corresponding test files to separate CodeQL packs
steps to add the custom query and corresponding test files to separate QL packs
outside your checkout of the CodeQL repository. This ensures when you update the
CodeQL libraries, or check out a different branch, you won't overwrite your
custom queries and tests.
@@ -145,36 +144,36 @@ Prepare a query and test files
#. Save the query to a file named ``EmptyThen.ql`` in a directory with your
other custom queries. For example,
``custom-queries/java/queries/EmptyThen.ql``.
#. If you haven't already added your custom queries to a CodeQL pack,
create a CodeQL pack now. For example, if your custom Java queries
``custom-queries/java/queries/EmptyThen.ql``.
#. If you haven't already added your custom queries to a QL pack,
create a QL pack now. For example, if your custom Java queries
are stored in ``custom-queries/java/queries``, add a ``qlpack.yml`` file with the
following contents to ``custom-queries/java/queries``:
.. code-block:: yaml
name: my-custom-queries
dependencies:
codeql/java-queries: "*"
version: 0.0.0
libraryPathDependencies: codeql-java
For more information about CodeQL packs, see ":doc:`About CodeQL packs
<about-codeql-packs>`."
For more information about QL packs, see ":doc:`About QL packs
<about-ql-packs>`."
#. Create a CodeQL pack for your Java tests by adding a ``qlpack.yml`` file
#. Create a QL pack for your Java tests by adding a ``qlpack.yml`` file
with the following contents to ``custom-queries/java/tests``,
updating the ``dependencies`` to match the name of your CodeQL pack of custom queries:
updating ``libraryPathDependencies`` to match the name of your QL pack of custom queries:
.. include:: ../reusables/test-qlpack.rst
#. Within the Java test pack, create a directory to contain the test files
associated with ``EmptyThen.ql``.
For example, ``custom-queries/java/tests/EmptyThen``.
For example, ``custom-queries/java/tests/EmptyThen``.
#. In the new directory, create ``EmptyThen.qlref`` to define the location of ``EmptyThen.ql``.
#. In the new directory, create ``EmptyThen.qlref`` to define the location of ``EmptyThen.ql``.
The path to the query must be specified relative to the root of
the CodeQL pack that contains the query. In this case, the query is in the
top level directory of the CodeQL pack named ``my-custom-queries``,
the QL pack that contains the query. In this case, the query is in the
top level directory of the QL pack named ``my-custom-queries``,
which is declared as a dependency for ``my-query-tests``.
Therefore, ``EmptyThen.qlref`` should simply contain ``EmptyThen.ql``.
@@ -192,7 +191,7 @@ Prepare a query and test files
System.out.println("Empty argument");
}
}
public void good(String arg) {
if (arg.isEmpty()) {
System.out.println("Empty argument");
@@ -212,8 +211,8 @@ When the test runs it:
#. Extracts a CodeQL database from the ``.java`` files stored in the ``EmptyThen`` directory.
#. Compiles the query referenced by the ``EmptyThen.qlref`` file.
If this step fails, it's because the CLI can't find your custom CodeQL pack.
Re-run the command and specify the location of your custom CodeQL pack, for example:
If this step fails, it's because the CLI can't find your custom QL pack.
Re-run the command and specify the location of your custom QL pack, for example:
``codeql test run --search-path=java java/tests/EmptyThen``
@@ -235,14 +234,14 @@ CodeQL generates the following files in the ``EmptyThen`` directory:
When tests complete successfully, this database is deleted in a housekeeping step.
You can override this step by running ``test run`` with the ``--keep-databases`` option.
In this case, the failure was expected and is easy to fix.
In this case, the failure was expected and is easy to fix.
If you open the ``EmptyThen.actual`` file, you can see the results of the test:
.. code-block:: none
| Test.java:3:5:3:22 | stmt | This if statement has an empty then. |
This file contains a table, with a column for the location of the result,
This file contains a table, with a column for the location of the result,
along with separate columns for each part of the ``select`` clause the query outputs.
Since the results are what we expected, we can update the file extension to define
this as the expected result for this test (``EmptyThen.expected``).
@@ -253,17 +252,17 @@ If you rerun the test now, the output will be similar but it will finish by repo
If the results of the query change, for example, if you revise the ``select`` statement for the query,
the test will fail. For failed results, the CLI output includes a unified diff of the
``EmptyThen.expected`` and ``EmptyThen.actual`` files.
This information may be sufficient to debug trivial test failures.
This information may be sufficient to debug trivial test failures.
For failures that are harder to debug, you can import ``EmptyThen.testproj``
into CodeQL for VS Code, execute ``EmptyThen.ql``, and view the results in the
``Test.java`` example code. For more information, see ":ref:`Analyzing your projects
<analyzing-your-projects>`" in the CodeQL for VS Code
help.
help.
Further reading
---------------
- ":ref:`CodeQL queries
<codeql-queries>`"
- ":ref:`Testing CodeQL queries in Visual Studio Code <testing-codeql-queries-in-visual-studio-code>`"
- ":ref:`Testing CodeQL queries in Visual Studio Code <testing-codeql-queries-in-visual-studio-code>`"

View File

@@ -3,7 +3,7 @@
Testing query help files
========================
Test query help files by rendering them as markdown to ensure they are valid
Test query help files by rendering them as markdown to ensure they are valid
before uploading them to the CodeQL repository or using them in code scanning.
Query help is documentation that accompanies a query to explain how the query works,
@@ -12,46 +12,46 @@ It is good practice to write query help for all new queries. For more informatio
see `Contributing to CodeQL <https://github.com/github/codeql/blob/main/CONTRIBUTING.md>`__
in the CodeQL repository.
The CodeQL CLI includes a command to test query help and render the content as
markdown, so that you can easily preview the content in your IDE. Use the command to validate
query help files before uploading them to the CodeQL repository or sharing them with other users.
From CodeQL CLI 2.7.1 onwards, you can also include the markdown-rendered query help in SARIF files
generated during CodeQL analyses so that the query help can be displayed in the code scanning UI.
For more information, see
The CodeQL CLI includes a command to test query help and render the content as
markdown, so that you can easily preview the content in your IDE. Use the command to validate
query help files before uploading them to the CodeQL repository or sharing them with other users.
From CodeQL CLI 2.7.1 onwards, you can also include the markdown-rendered query help in SARIF files
generated during CodeQL analyses so that the query help can be displayed in the code scanning UI.
For more information, see
":ref:`Analyzing databases with the CodeQL CLI <including-query-help-for-custom-codeql-queries-in-sarif-files>`."
Prerequisites
-------------
- The query help (``.qhelp``) file must have an accompanying query (``.ql``) file with
- The query help (``.qhelp``) file must have an accompanying query (``.ql``) file with
an identical base name.
- The query help file should follow the standard structure and style for query help documentation.
For more information, see the `Query help style guide <https://github.com/github/codeql/blob/main/docs/query-help-style-guide.md>`__
in the CodeQL repository.
For more information, see the `Query help style guide <https://github.com/github/codeql/blob/main/docs/query-help-style-guide.md>`__
in the CodeQL repository.
Running ``codeql generate query-help``
--------------------------------------
You can test query help files by running the following command::
codeql generate query-help <qhelp|query|dir|suite> --format=<format> [--output=<dir|file>]
codeql generate query-help <qhelp|query|dir|suite> --format=<format> [--output=<dir|file>]
where ``<qhelp|query|dir|suite>`` is one of:
- the path to a ``.qhelp`` file.
- the path to a ``.ql`` file.
- the path to a directory containing queries and query help files.
- the path to a query suite, or the name of a well-known query suite for a CodeQL pack.
- the path to a query suite, or the name of a well-known query suite for a QL pack.
For more information, see "`Creating CodeQL query suites <https://codeql.github.com/docs/codeql-cli/creating-codeql-query-suites#specifying-well-known-query-suites>`__."
You must specify a ``--format`` option, which defines how the query help is rendered.
Currently, you must specify ``markdown`` to render the query help as markdown.
You must specify a ``--format`` option, which defines how the query help is rendered.
Currently, you must specify ``markdown`` to render the query help as markdown.
The ``--output`` option defines a file path where the rendered query help will be saved.
- For directories containing ``.qhelp`` files or a query suites
defining one or more ``.qhelp`` files, you must specify an ``--output`` directory.
Filenames within the output directory will be derived from the ``.qhelp`` file names.
- For directories containing ``.qhelp`` files or a query suites
defining one or more ``.qhelp`` files, you must specify an ``--output`` directory.
Filenames within the output directory will be derived from the ``.qhelp`` file names.
- For single ``.qhelp`` or ``.ql`` files, you may specify an ``--output`` option.
If you don't specify an output path, the rendered query help is written to ``stdout``.
@@ -63,15 +63,15 @@ see the `generate query-help reference documentation
Results
-------
When you run the command, CodeQL attempts to render
When you run the command, CodeQL attempts to render
each ``.qhelp`` file that has an accompanying ``.ql`` file. For single files, the rendered
content will be printed to ``stdout`` if you don't specify an ``--output`` option. For all other
use cases, the rendered content is saved to the specified output path.
content will be printed to ``stdout`` if you don't specify an ``--output`` option. For all other
use cases, the rendered content is saved to the specified output path.
By default, the CodeQL CLI will print a warning message if:
- Any of the query help is invalid, along with a description of the invalid query help elements
- Any ``.qhelp`` files specified in the command don't have the same base name
- Any ``.qhelp`` files specified in the command don't have the same base name
as an accompanying ``.ql`` file
- Any ``.ql`` files specified in the command don't have the same base name
as an accompanying ``.qhelp`` file

View File

@@ -0,0 +1,55 @@
.. _upgrading-codeql-databases:
Upgrading CodeQL databases
==========================
As the CodeQL CLI tools and queries evolve, you may find that some of your
CodeQL databases become out of date. You must upgrade out-of-date databases
before you can analyze them.
Databases become out of date when:
- For databases created using the CodeQL CLI, the version of CLI tools used to
create them is older than your copy of the CodeQL queries.
- For databases downloaded from LGTM.com, the CodeQL tools used by LGTM.com to create
that revision of the code are older than your copy of the CodeQL queries.
If you have a local checkout of the ``github/codeql`` repository, please note that
the ``main`` branch of the CodeQL queries is updated more often than both the
CLI and LGTM.com, so databases are most likely to become out of date if you use
the queries on this branch. For more information about the different versions of
the CodeQL queries, see ":ref:`Getting started with the CodeQL CLI <local-copy-codeql-queries>`."
Out-of-date databases must be upgraded before they can be analyzed. This topic
shows you how to upgrade a CodeQL database using the ``database upgrade``
subcommand.
Prerequisites
-------------
Archived databases downloaded from LGTM.com must be unzipped before they are
upgraded.
Running ``codeql database upgrade``
-----------------------------------
CodeQL databases are upgraded by running the following command::
codeql database upgrade <database>
where ``<database>``, the path to the CodeQL database you
want to upgrade, must be specified.
For full details of all the options you can use when upgrading databases,
see the "`database upgrade <../manual/database-upgrade>`__" reference documentation.
Progress and results
--------------------
When you execute the ``database upgrade`` command, CodeQL identifies the version
of the :ref:`schema <codeql-database-schema>` associated with the database. From
there, it works out what (if anything) is required to make the database work
with your queries and libraries. It will rewrite the database, if necessary, or
make no changes if the database is already compatible (or if it finds no
information about how to perform an upgrade). Once a database has been upgraded
it cannot be downgraded for use with older versions of the CodeQL products.

View File

@@ -54,20 +54,23 @@ Packaging custom QL queries
.. include:: ../reusables/beta-note-package-management.rst
When you write your own queries with the intention to share them with others, you should
save them in a custom CodeQL pack. You can publish the pack as a CodeQL pack to GitHub
Packages - the GitHub Container registry. For further information see
":ref:`About CodeQL packs <about-codeql-packs>`."
When you write your own queries, you should save them in a custom QL pack
directory. When you are ready to share your queries with other users, you can publish the pack as a CodeQL pack to GitHub Packages - the GitHub Container registry.
CodeQL packs organize the files used in CodeQL analysis and can store queries,
QL packs organize the files used in CodeQL analysis and can store queries,
library files, query suites, and important metadata. Their root directory must
contain a file named ``qlpack.yml``. Your custom queries should be saved in the
CodeQL pack root, or its subdirectories.
QL pack root, or its subdirectories.
For each CodeQL pack, the ``qlpack.yml`` file includes information that tells the CodeQL CLI
For each QL pack, the ``qlpack.yml`` file includes information that tells CodeQL
how to compile the queries, which other CodeQL packs and libraries the pack
depends on, and where to find query suite definitions. For more information
about what to include in this file, see ":ref:`About CodeQL packs <codeqlpack-yml-properties>`."
about what to include in this file, see ":ref:`About QL packs <about-ql-packs>`."
CodeQL packages are used to create, share, depend on, and run CodeQL queries and
libraries. You can publish your own CodeQL packages and download ones created by
others via the the Container registry. For further information see
":ref:`About CodeQL packs <about-codeql-packs>`."
Contributing to the CodeQL repository
-------------------------------------

View File

@@ -7,7 +7,7 @@ Using the CodeQL CLI
See the following links to learn how to get set up and run CodeQL commands:
- :doc:`About the CodeQL CLI <about-the-codeql-cli>`: Software
- :doc:`About the CodeQL CLI <about-the-codeql-cli>`: Software
developers and security researchers can secure their code using the CodeQL CLI.
- :doc:`Getting started with the CodeQL CLI
@@ -17,15 +17,19 @@ See the following links to learn how to get set up and run CodeQL commands:
- :doc:`Creating CodeQL databases
<creating-codeql-databases>`: Create relational
representations of source code that can be queried like any other database.
- :doc:`Extractor options
<extractor-options>`: Set options for the
<extractor-options>`: Set options for the
behavior of extractors that create CodeQL databases.
- :doc:`Analyzing CodeQL databases with the CodeQL CLI
<analyzing-databases-with-the-codeql-cli>`: Analyze your code using queries
written in a specially-designed, object-oriented query language.
- :doc:`Upgrading CodeQL databases
<upgrading-codeql-databases>`: Upgrade your databases so
that they can be analyzed using the most up to date CodeQL products.
- :doc:`Using custom queries with the CodeQL CLI
<using-custom-queries-with-the-codeql-cli>`: Use custom queries to extend your
analysis or highlight errors that are specific to a particular codebase.
@@ -38,7 +42,7 @@ See the following links to learn how to get set up and run CodeQL commands:
your analysis.
- :doc:`Testing query help files <testing-query-help-files>`:
Test query help files by rendering them as markdown to ensure they are valid
Test query help files by rendering them as markdown to ensure they are valid
before adding them to the CodeQL repository or using them in code scanning.
- :doc:`Creating and working with CodeQL packs <creating-and-working-with-codeql-packs>`:
@@ -47,7 +51,7 @@ See the following links to learn how to get set up and run CodeQL commands:
- :doc:`Publishing and using CodeQL packs <publishing-and-using-codeql-packs>`:
Publish your own or use others CodeQL packs for code scanning.
- :doc:`Specifying command options in a CodeQL configuration file <specifying-command-options-in-a-codeql-configuration-file>`:
- :doc:`Specifying command options in a CodeQL configuration file <specifying-command-options-in-a-codeql-configuration-file>`:
You can save default or frequently used options for your commands in a per-user configuration file.
.. toctree::
@@ -59,6 +63,7 @@ See the following links to learn how to get set up and run CodeQL commands:
creating-codeql-databases
extractor-options
analyzing-databases-with-the-codeql-cli
upgrading-codeql-databases
using-custom-queries-with-the-codeql-cli
creating-codeql-query-suites
testing-custom-queries

View File

@@ -19,7 +19,7 @@ To analyze a project, you need to add a :ref:`CodeQL database <codeql-database>`
.. image:: ../images/codeql-for-visual-studio-code/choose-database.png
:width: 350
:alt: Choose a database to analyze
For more information about obtaining a local database, see below.
#. Once you've chosen a database, it is displayed in the Databases view. To see the menu options for interacting with a database, right-click an entry in the list. You can select multiple databases using **Ctrl/Cmd+click**.
@@ -27,7 +27,7 @@ To analyze a project, you need to add a :ref:`CodeQL database <codeql-database>`
Obtaining a local database
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you have a CodeQL database saved locally, as an unarchived folder or as a ZIP file, you can add it to Visual Studio Code. There are several ways to obtain a local CodeQL database.
If you have a CodeQL database saved locally, as an unarchived folder or as a ZIP file, you can add it to Visual Studio Code. There are several ways to obtain a local CodeQL database.
- To create a database with the CodeQL CLI, see ":ref:`Creating CodeQL databases <creating-codeql-databases>`."
@@ -36,14 +36,14 @@ If you have a CodeQL database saved locally, as an unarchived folder or as a ZIP
- To analyze a test database, add a ``.testproj`` folder to the Databases view.
Test databases (that is, folders with a ``.testproj`` extension) are generated when you run regression tests on custom queries using the :ref:`CodeQL CLI <codeql-cli>`.
If a query fails a regression test, you may want to analyze the test database in Visual Studio Code to debug the failure.
For more information about running query tests, see ":ref:`Testing custom queries <testing-custom-queries>`" in the CodeQL CLI help.
For more information about running query tests, see ":ref:`Testing custom queries <testing-custom-queries>`" in the CodeQL CLI help.
Running a query
------------------------
The `CodeQL repository <https://github.com/github/codeql>`__ on GitHub contains lots of example queries.
If you have that folder (or a different CodeQL pack) available in your workspace, you can access existing queries under ``<language>/ql/src/<category>``, for example ``java/ql/src/Likely Bugs``.
If you have that folder (or a different QL pack) available in your workspace, you can access existing queries under ``<language>/ql/src/<category>``, for example ``java/ql/src/Likely Bugs``.
#. Open a query (``.ql``) file. It is displayed in the editor, with IntelliSense features such as syntax highlighting and autocomplete suggestions.
#. Right-click in the query window and select **CodeQL: Run Query**. (Alternatively, run the command from the Command Palette.)
@@ -77,7 +77,7 @@ To run the query, use **CodeQL: Run Query**.
You can see all quick queries that you've run in the current session in the Query History view. Click an entry to see the exact text of the quick query that produced the results.
Once you're happy with your quick query, you should save it in a CodeQL pack so you can access it later. For more information, see ":ref:`About CodeQL packs <about-codeql-packs>`."
Once you're happy with your quick query, you should save it in a QL pack so you can access it later. For more information, see ":ref:`About QL packs <about-ql-packs>`."
.. _running-a-specific-part-of-a-query-or-library:
@@ -87,7 +87,7 @@ Running a specific part of a query or library
This is helpful if you're debugging a query or library and you want to locate the part that is wrong.
Instead of using **CodeQL: Run Query** to run the whole query (the :ref:`select clause <select-clauses>` and any :ref:`query predicates <query-predicates>`), you can use **CodeQL: Quick Evaluation** to run a specific part of a ``.ql`` or ``.qll`` file.
**CodeQL: Quick Evaluation** evaluates a code snippet (instead of the whole query) and displays results of that selection in the Results view.
**CodeQL: Quick Evaluation** evaluates a code snippet (instead of the whole query) and displays results of that selection in the Results view.
Possible targets for quick evaluation include:
- Selecting the name of a CodeQL entity (such as a :ref:`class <classes>` or :ref:`predicate <predicates>`) to evaluate that entity.

View File

@@ -110,7 +110,7 @@ For example, to make a custom CodeQL folder called ``my-custom-cpp-pack`` depend
version: 0.0.0
libraryPathDependencies: codeql/cpp-all
For more information about why you need to add a ``qlpack.yml`` file, see ":ref:`About CodeQL packs <about-codeql-packs>`."
For more information about why you need to add a ``qlpack.yml`` file, see ":ref:`About QL packs <about-ql-packs>`."
Further reading
----------------

View File

@@ -5,7 +5,7 @@
CodeQL glossary
===============
An overview of the technical terms and concepts in CodeQL.
An overview of the technical terms and concepts in CodeQL.
.. _bqrs-file:
@@ -26,11 +26,11 @@ exported as a variety of different formats, including SARIF.
CodeQL database
---------------
A database (or CodeQL database) is a directory containing:
A database (or CodeQL database) is a directory containing:
- queryable data, extracted from the code.
- a source reference, for displaying query results directly in the code.
- query results.
- query results.
- log files generated during database creation, query
execution, and other operations.
@@ -39,15 +39,15 @@ A database (or CodeQL database) is a directory containing:
DIL
---
DIL stands for Datalog Intermediary Language. It is an intermediate
representation between QL and relation algebra (RA) that is generated
during query compilation. DIL is useful for advanced users as an aid
for debugging query performance.
DIL stands for Datalog Intermediary Language. It is an intermediate
representation between QL and relation algebra (RA) that is generated
during query compilation. DIL is useful for advanced users as an aid
for debugging query performance.
The DIL format may change without warning between CLI releases.
When you specify the ``--dump-dil`` option for ``codeql query compile``, CodeQL
prints DIL to standard output for the queries it compiles. You can also
view results in DIL format when you run queries in VS Code.
When you specify the ``--dump-dil`` option for ``codeql query compile``, CodeQL
prints DIL to standard output for the queries it compiles. You can also
view results in DIL format when you run queries in VS Code.
For more information, see ":ref:`Analyzing your projects <viewing-query-results>`" in the CodeQL for VS Code help.
.. _extractor:
@@ -56,7 +56,7 @@ Extractor
---------
An extractor is a tool that produces the relational data and source
reference for each input file, from which a CodeQL database can be built.
reference for each input file, from which a CodeQL database can be built.
.. _codeql-database-schema:
@@ -67,7 +67,7 @@ A QL database schema is a file describing the column types and
extensional relations that make up a raw QL dataset. It is a text file
with the ``.dbscheme`` extension.
The extractor and core CodeQL pack for a language each declare the database
The extractor and core QL pack for a language each declare the database
schema that they use. This defines the database layout they create or
expect. When you create a CodeQL database, the extractor copies
its schema into the database. The CLI uses this to check whether the
@@ -83,16 +83,16 @@ There is currently no public-facing specification for the syntax of schemas.
--------------
``.qlo`` files are optionally generated during query compilation.
If you specify the ``--dump-qlo`` option for ``codeql query compile``,
If you specify the ``--dump-qlo`` option for ``codeql query compile``,
CodeQL writes ``.qlo`` files for the queries it compiles. They can be used
as an aid for debugging and performance tuning for advanced users.
as an aid for debugging and performance tuning for advanced users.
``.qlo`` is a binary format that represents a compiled
and optimized query in terms of relational algebra (RA) or the
intermediate :ref:`DIL <dil>` format. ``.qlo`` files can be expanded to
readable text using ``codeql query decompile``.
``.qlo`` is a binary format that represents a compiled
and optimized query in terms of relational algebra (RA) or the
intermediate :ref:`DIL <dil>` format. ``.qlo`` files can be expanded to
readable text using ``codeql query decompile``.
The exact details of the ``.qlo`` format may change without warning between CLI releases.
The exact details of the ``.qlo`` format may change without warning between CLI releases.
.. _sarif-file:
@@ -101,22 +101,22 @@ SARIF file
Static analysis results interchange format (SARIF) is an output format used for
sharing static analysis results. For more information, see ":ref:`SARIF
output <sarif-output>`."
output <sarif-output>`."
.. _source-reference:
Source reference
----------------
A source reference is a mechanism that allows the retrieval of the
contents of a source file, given an absolute filename at which that file
A source reference is a mechanism that allows the retrieval of the
contents of a source file, given an absolute filename at which that file
resided during extraction. Specific examples include:
- A source archive directory, within which the requested absolute
- A source archive directory, within which the requested absolute
filename maps to a UTF8-encoded file.
- A source archive, typically in ZIP format, which contains the UTF8-encoded
- A source archive, typically in ZIP format, which contains the UTF8-encoded
content of all source files.
- A source archive repository, typically in ``git`` format, typically bare,
- A source archive repository, typically in ``git`` format, typically bare,
which contains the UTF8-encoded content of all source files.
Source references are typically included in CodeQL databases.
@@ -126,7 +126,7 @@ Source references are typically included in CodeQL databases.
TRAP file
---------
A TRAP file is a UTF-8 encoded file generated by a CodeQL extractor
A TRAP file is a UTF-8 encoded file generated by a CodeQL extractor
with the extension ``.trap``. To save space, they are usually archived. They
contain the information that, when interpreted relative to a QL database
schema, is used to create a QL dataset.

View File

@@ -15,8 +15,6 @@ Learn all about QL, the powerful query language that underlies the code scanning
- :doc:`Modules <modules>`: Modules provide a way of organizing QL code by grouping together related types, predicates, and other modules.
- :doc:`Signatures <signatures>`: Signatures provide a typing mechanism to parameters of parameterized modules.
- :doc:`Aliases <aliases>`: An alias is an alternative name for an existing QL entity.
- :doc:`Variables <variables>`: Variables in QL are used in a similar way to variables in algebra or logic. They represent sets of values, and those values are usually restricted by a formula.
@@ -46,7 +44,6 @@ Learn all about QL, the powerful query language that underlies the code scanning
queries
types
modules
signatures
aliases
variables
expressions

View File

@@ -133,92 +133,6 @@ defined :ref:`above <library-modules>`:
This defines an explicit module named ``M``. The body of this module defines
the class ``OneTwo``.
.. _parameterized-modules:
Parameterized modules
=====================
Parameterized modules are QL's approach to generic programming.
Similar to explicit modules, parameterized modules are defined within other modules using the keywork ``module``.
In addition to the module name, parameterized modules declare one or more parameters between the name and the module body.
For example, consider the module ``M``, which takes two predicate parameters and defines a new predicate
that applies them one after the other:
.. code-block:: ql
module M<transformer/1 first, transformer/1 second> {
bindingset[x]
int applyBoth(int x) {
result = second(first(x))
}
}
Parameterized modules cannot be directly referenced.
Instead, you instantiate a parameterized module by passing arguments enclosed in angle brackets (``<`` and ``>``) to the module.
Instantiated parameterized modules can be used as a :ref:`module expression <name-resolution>`, identical to explicit module references.
For example, we can instantiate ``M`` with two identical arguments ``increment``, creating a module
containing a predicate that adds 2:
.. code-block:: ql
bindingset[result] bindingset[x]
int increment(int x) { result = x + 1 }
module IncrementTwice = M<increment/1, increment/1>;
select IncrementTwice::applyBoth(40) // 42
The parameters of a parameterized module are (meta-)typed with :ref:`signatures <signatures>`.
For example, in the previous two snippets, we relied on the predicate signature ``transformer``:
.. code-block:: ql
bindingset[x]
signature int transformer(int x);
The instantiation of parameterized modules is applicative.
That is, if you instantiate a parameterized module twice with identical arguments, the resulting object is the same.
This is particularly relevant for type definitions inside parameterized modules as :ref:`classes <classes>`
or via :ref:`newtype <algebraic-datatypes>`, because the duplication of such type definitions would result in
incompatible types.
The following example instantiates module ``M`` inside calls to predicate ``foo`` twice.
The first call is valid but the second call generates an error.
.. code-block:: ql
bindingset[this]
signature class TSig;
module M<TSig T> {
newtype A = B() or C()
}
string foo(M<int>::A a) { ... }
select foo(M<int>::B()), // valid: repeated identical instantiation of M does not duplicate A, B, C
foo(M<float>::B()) // ERROR: M<float>::B is not compatible with M<int>::A
Module parameters are dependently typed, meaning that signature expressions in parameter definitions can reference
preceding parameters.
For example, we can declare the signature for ``T2`` dependent on ``T1``, enforcing a subtyping relationship
between the two parameters:
.. code-block:: ql
signature class TSig;
module Extends<TSig T> { signature class Type extends T; }
module ParameterizedModule<TSig T1, Extends<T1>::Type T2> { ... }
Dependently typed parameters are particularly useful in combination with
:ref:`parameterized module signatures <parameterized-module-signatures>`.
.. _module-bodies:
Module bodies

View File

@@ -21,7 +21,7 @@ In summary, the kinds of expressions are:
- **Module expressions**
- These refer to modules.
- They can be simple :ref:`names <names>`, :ref:`qualified references <qualified-references>`
(in import statements), :ref:`selections <selections>`, or :ref:`instantiations <parameterized-modules>`.
(in import statements), or :ref:`selections <selections>`.
- **Type expressions**
- These refer to types.
- They can be simple :ref:`names <names>` or :ref:`selections <selections>`.

View File

@@ -68,7 +68,7 @@ contain a single top-level tag named
of the active database schema (for example, ``<queries
language="java"/>``).
A ``qlpack.yml`` file defines a :ref:`CodeQL pack <about-codeql-packs>`.
A ``qlpack.yml`` file defines a :ref:`QL pack <about-ql-packs>`.
The content of a ``qlpack.yml`` file is described in the CodeQL CLI documentation.
If both a ``queries.xml`` and a ``qlpack.yml`` exist in the same
@@ -77,16 +77,16 @@ exist for compatibility with older tooling).
The CodeQL CLI and newer tools based on it (such as,
GitHub code scanning and the CodeQL extension for Visual Studio Code)
construct a library path using CodeQL packs. For each CodeQL pack
added to the library path, the CodeQL packs named in its
construct a library path using QL packs. For each QL pack
added to the library path, the QL packs named in its
``libraryPathDependencies`` will be subsequently added to the library
path, and the process continues until all packs have been
resolved. The actual library path consists of the root directories of
the selected CodeQL packs. This process depends on a mechanism for finding
CodeQL packs by pack name, as described in the :ref:`CodeQL CLI documentation <codeql-cli>`.
the selected QL packs. This process depends on a mechanism for finding
QL packs by pack name, as described in the :ref:`CodeQL CLI documentation <codeql-cli>`.
When the query directory contains a ``queries.xml`` file but no
``qlpack.yml``, the CodeQL pack resolution behaves as if it defines a QL
``qlpack.yml``, the QL pack resolution behaves as if it defines a QL
pack with no name and a single library path dependency named
``legacy-libraries-LANGUAGE`` where ``LANGUAGE`` is taken from
``queries.xml``. The ``github/codeql`` repository provides packs with
@@ -94,7 +94,7 @@ names following this pattern, which themselves depend on the actual
CodeQL libraries for each language.
When the query directory contains neither a ``queries.xml`` nor
``qlpack.yml`` file, it is considered to be a CodeQL pack with no name and
``qlpack.yml`` file, it is considered to be a QL pack with no name and
no library dependencies. This causes the library path to consist of
*only* the query directory itself. This is not generally useful,
but it suffices for running toy examples of QL code that don't

View File

@@ -1,120 +0,0 @@
:tocdepth: 1
.. index:: signature
.. _signatures:
Signatures
##########
Parameterized modules use signatures as a type system for their parameters.
There are three categories of signatures: **predicate signatures**, **type signatures**, and **module signatures**.
Predicate signatures
====================
Predicate signatures declare module parameters that will be substituted with predicates when the module is instantiated.
The substitution of predicate signatures relies on structural typing. That is, predicates do not have to be explicitly
defined as implementing a predicate signature - they just have to match the return and argument types.
Predicate signatures are defined much like predicates themselves, but they do not have a body.
In detail, a predicate signature definition consists of:
#. The keyword ``signature``.
#. The keyword ``predicate`` (allows subsitution with a :ref:`predicate without result <predicates-without-result>`),
or the type of the result (allows subsitution with a :ref:`predicate with result <predicates-with-result>`).
#. The name of the predicate signature. This is an `identifier <https://codeql.github.com/docs/ql-language-reference/ql-language-specification/#identifiers>`_
starting with a lowercase letter.
#. The arguments to the predicate signature, if any, separated by commas.
For each argument, specify the argument type and an identifier for the argument variable.
#. A semicolon ``;``.
For example:
.. code-block:: ql
signature int operator(int lhs, int rhs);
Type signatures
===============
Type signatures declare module parameters that will be substituted with types when the module is instantiated.
Type signatures are used to specify supertypes and are the simplest category of signatures.
The substitution of type signatures relies on structural typing. That is, types do not have to be explicitly defined as
implementing a type signature - they just need to have the specified (transitive) supertypes.
In detail, a type signature definition consists of:
#. The keyword ``signature``.
#. The keyword ``class``.
#. The name of the type signature. This is an `identifier <https://codeql.github.com/docs/ql-language-reference/ql-language-specification/#identifiers>`_
starting with a uppercase letter.
#. Optionally, the keyword ``extends`` followed by a list of types, separated by commas.
#. A semicolon ``;``.
For example:
.. code-block:: ql
signature class ExtendsInt extends int;
Module signatures
=================
Module signatures declare module parameters that will be substituted with modules when the module is instantiated.
Module signatures specify a collection of types and predicates that a module needs to contain under given names and
matching given signatures.
Unlike type signatures and predicate signatures, the substitution of type signatures relies on nominal typing.
That is, the definition of a module must declare the module signatures it implements.
In detail, a type signature definition consists of:
#. The keyword ``signature``.
#. The keyword ``module``.
#. The name of the module signature. This is an `identifier <https://codeql.github.com/docs/ql-language-reference/ql-language-specification/#identifiers>`_
starting with a uppercase letter.
#. Optionally, a list of parameters for :ref:`parameterized module signatures <parameterized-module-signatures>`.
#. The module signature body, consisting of type signatures and predicate signatures enclosed in braces.
The ``signature`` keyword is omitted for these contained signatures.
For example:
.. code-block:: ql
signature module MSig {
class T;
predicate restriction(T t);
}
module Module implements MSig {
newtype T = A() or B();
predicate restriction(T t) { t = A() }
}
.. _parameterized-module-signatures:
Parameterized module signatures
-------------------------------
Module signatures can themselves be parameterized in exactly the same way as parameterized modules.
This is particularly useful in combination with the dependent typing of module parameters.
For example:
.. code-block:: ql
signature class NodeSig;
signature module EdgeSig<NodeSig Node> {
predicate apply(Node src, Node dst);
}
module Reachability<NodeSig Node, EdgeSig<Node> Edge> {
Node reachableFrom(Node src) {
Edge::apply+(src, result)
}
}

View File

@@ -1,9 +1,15 @@
.. code-block:: yaml
name: my-github-user/my-query-tests
dependencies:
my-github-user/my-custom-queries: ^1.2.3
name: my-query-tests
version: 0.0.0
libraryPathDependencies: my-custom-queries
extractor: java
tests: .
This ``qlpack.yml`` file states that ``my-github-user/my-query-tests`` depends on ``my-github-user/my-custom-queries`` at a version greater than or equal to 1.2.3 and less than 2.0.0. It also declares that the CLI should use the Java ``extractor`` when creating test databases. The ``tests: .`` line declares that all ``.ql`` files in the pack should be run as tests when ``codeql test run`` is run with the ``--strict-test-discovery`` option. Typically, test packs do not contain a ``version`` property. This prevents you from accidentally publishing them.
This ``qlpack.yml`` file states that ``my-query-tests`` depends on
``my-custom-queries``. It also declares that the CLI should use the
Java ``extractor`` when creating test databases.
Supported from CLI 2.1.0 onward, the ``tests: .`` line declares
that all ``.ql`` files in the pack should be
run as tests when ``codeql test run`` is run with the
``--strict-test-discovery`` option.

View File

@@ -3,7 +3,7 @@
About CodeQL queries
####################
CodeQL queries are used to analyze code for issues related to security, correctness, maintainability, and readability.
CodeQL queries are used to analyze code for issues related to security, correctness, maintainability, and readability.
Overview
********
@@ -13,7 +13,7 @@ CodeQL includes queries to find the most relevant and interesting problems for e
- **Alert queries**: queries that highlight issues in specific locations in your code.
- **Path queries**: queries that describe the flow of information between a source and a sink in your code.
You can add custom queries to :doc:`CodeQL packs <../codeql-cli/about-codeql-packs>` to analyze your projects with "`Code scanning <https://docs.github.com/en/code-security/secure-coding/automatically-scanning-your-code-for-vulnerabilities-and-errors/about-code-scanning>`__", use them to analyze a database with the ":ref:`CodeQL CLI <codeql-cli>`," or you can contribute to the standard CodeQL queries in our `open source repository on GitHub <https://github.com/github/codeql>`__.
You can add custom queries to :doc:`QL packs <../codeql-cli/about-ql-packs>` to analyze your projects with "`Code scanning <https://docs.github.com/en/code-security/secure-coding/automatically-scanning-your-code-for-vulnerabilities-and-errors/about-code-scanning>`__", use them to analyze a database with the ":ref:`CodeQL CLI <codeql-cli>`," or you can contribute to the standard CodeQL queries in our `open source repository on GitHub <https://github.com/github/codeql>`__.
This topic is a basic introduction to query files. You can find more information on writing queries for specific programming languages in the ":ref:`CodeQL language guides <codeql-language-guides>`," and detailed technical information about QL in the ":ref:`QL language reference <ql-language-reference>`."
For more information on how to format your code when contributing queries to the GitHub repository, see the `CodeQL style guide <https://github.com/github/codeql/blob/main/docs/ql-style-guide.md>`__.

View File

@@ -1,7 +1,7 @@
package,sink,source,summary,sink:bean-validation,sink:create-file,sink:groovy,sink:header-splitting,sink:information-leak,sink:intent-start,sink:jdbc-url,sink:jexl,sink:jndi-injection,sink:ldap,sink:logging,sink:mvel,sink:ognl-injection,sink:open-url,sink:pending-intent-sent,sink:regex-use[-1],sink:regex-use[0],sink:regex-use[],sink:regex-use[f-1],sink:regex-use[f1],sink:regex-use[f],sink:set-hostname-verifier,sink:sql,sink:url-open-stream,sink:url-redirect,sink:write-file,sink:xpath,sink:xslt,sink:xss,source:android-external-storage-dir,source:android-widget,source:contentprovider,source:remote,summary:taint,summary:value
android.app,24,,103,,,,,,7,,,,,,,,,17,,,,,,,,,,,,,,,,,,,18,85
android.content,24,31,154,,,,,,16,,,,,,,,,,,,,,,,,8,,,,,,,4,,27,,63,91
android.database,59,,39,,,,,,,,,,,,,,,,,,,,,,,59,,,,,,,,,,,39,
android.app,16,,103,,,,,,7,,,,,,,,,9,,,,,,,,,,,,,,,,,,,18,85
android.content,24,31,108,,,,,,16,,,,,,,,,,,,,,,,,8,,,,,,,4,,27,,31,77
android.database,59,,30,,,,,,,,,,,,,,,,,,,,,,,59,,,,,,,,,,,30,
android.net,,,60,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,45,15
android.os,,2,122,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,41,81
android.util,6,16,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,,,16,,
1 package sink source summary sink:bean-validation sink:create-file sink:groovy sink:header-splitting sink:information-leak sink:intent-start sink:jdbc-url sink:jexl sink:jndi-injection sink:ldap sink:logging sink:mvel sink:ognl-injection sink:open-url sink:pending-intent-sent sink:regex-use[-1] sink:regex-use[0] sink:regex-use[] sink:regex-use[f-1] sink:regex-use[f1] sink:regex-use[f] sink:set-hostname-verifier sink:sql sink:url-open-stream sink:url-redirect sink:write-file sink:xpath sink:xslt sink:xss source:android-external-storage-dir source:android-widget source:contentprovider source:remote summary:taint summary:value
2 android.app 24 16 103 7 17 9 18 85
3 android.content 24 31 154 108 16 8 4 27 63 31 91 77
4 android.database 59 39 30 59 39 30
5 android.net 60 45 15
6 android.os 2 122 2 41 81
7 android.util 6 16 6 16

View File

@@ -7,7 +7,7 @@ Java framework & library support
:widths: auto
Framework / library,Package,Flow sources,Taint & value steps,Sinks (total),`CWE022` :sub:`Path injection`,`CWE036` :sub:`Path traversal`,`CWE079` :sub:`Cross-site scripting`,`CWE089` :sub:`SQL injection`,`CWE090` :sub:`LDAP injection`,`CWE094` :sub:`Code injection`,`CWE319` :sub:`Cleartext transmission`
Android,``android.*``,52,479,116,,,3,67,,,
Android,``android.*``,52,424,108,,,3,67,,,
`Apache Commons Collections <https://commons.apache.org/proper/commons-collections/>`_,"``org.apache.commons.collections``, ``org.apache.commons.collections4``",,1600,,,,,,,,
`Apache Commons IO <https://commons.apache.org/proper/commons-io/>`_,``org.apache.commons.io``,,556,106,91,,,,,,15
`Apache Commons Lang <https://commons.apache.org/proper/commons-lang/>`_,``org.apache.commons.lang3``,,424,,,,,,,,
@@ -19,5 +19,5 @@ Java framework & library support
Java extensions,"``javax.*``, ``jakarta.*``",63,609,32,,,4,,1,1,2
`Spring <https://spring.io/>`_,``org.springframework.*``,29,477,101,,,,19,14,,29
Others,"``androidx.slice``, ``cn.hutool.core.codec``, ``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.fasterxml.jackson.core``, ``com.fasterxml.jackson.databind``, ``com.opensymphony.xwork2.ognl``, ``com.rabbitmq.client``, ``com.unboundid.ldap.sdk``, ``com.zaxxer.hikari``, ``flexjson``, ``groovy.lang``, ``groovy.util``, ``jodd.json``, ``kotlin.jvm.internal``, ``net.sf.saxon.s9api``, ``ognl``, ``okhttp3``, ``org.apache.commons.codec``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.commons.logging``, ``org.apache.commons.ognl``, ``org.apache.directory.ldap.client.api``, ``org.apache.ibatis.jdbc``, ``org.apache.log4j``, ``org.apache.logging.log4j``, ``org.apache.shiro.codec``, ``org.apache.shiro.jndi``, ``org.codehaus.groovy.control``, ``org.dom4j``, ``org.hibernate``, ``org.jboss.logging``, ``org.jdbi.v3.core``, ``org.jooq``, ``org.mvel2``, ``org.scijava.log``, ``org.slf4j``, ``org.xml.sax``, ``org.xmlpull.v1``, ``play.mvc``, ``ratpack.core.form``, ``ratpack.core.handling``, ``ratpack.core.http``, ``ratpack.exec``, ``ratpack.form``, ``ratpack.func``, ``ratpack.handling``, ``ratpack.http``, ``ratpack.util``, ``retrofit2``",65,395,932,,,,14,18,,3
Totals,,217,6497,1484,119,6,10,107,33,1,84
Totals,,217,6442,1476,119,6,10,107,33,1,84

View File

@@ -389,7 +389,11 @@ open class KotlinFileExtractor(
with("class source", c) {
DeclarationStackAdjuster(c).use {
val id = useClassSource(c)
val id = if (c.isAnonymousObject) {
useAnonymousClass(c).javaResult.id.cast<DbClass>()
} else {
useClassSource(c)
}
val pkg = c.packageFqName?.asString() ?: ""
val cls = if (c.isAnonymousObject) "" else c.name.asString()
val pkgId = extractPackage(pkg)
@@ -1338,7 +1342,7 @@ open class KotlinFileExtractor(
} else {
var subbedType: IrSimpleType = receiverType
ancestorTypes.forEach {
val thisClass = subbedType.classifier.owner
val thisClass = subbedType.classifier.owner as IrClass
if (thisClass !is IrClass) {
logger.errorElement("Found ancestor with unexpected type ${thisClass.javaClass}", callTarget)
return listOf()
@@ -2204,7 +2208,7 @@ open class KotlinFileExtractor(
tw.writeExprsKotlinType(id, type.kotlinResult.id)
binopDisp(id)
}
isFunction(target, "kotlin", "(some array type)", { isArrayType(it) }, "set") && c.origin == IrStatementOrigin.EQ && c.dispatchReceiver != null -> {
isFunction(target, "kotlin", "(some array type)", { isArrayType(it) }, "set") && c.origin == IrStatementOrigin.EQ -> {
val array = c.dispatchReceiver
val arrayIdx = c.getValueArgument(0)
val assignedValue = c.getValueArgument(1)
@@ -2394,11 +2398,7 @@ open class KotlinFileExtractor(
if (e.typeArgumentsCount > 0) {
logger.warnElement("Unexpected type arguments (${e.typeArgumentsCount}) for anonymous class constructor call", e)
}
val c = eType.classifier.owner
if (c !is IrClass) {
logger.errorElement("Anonymous constructor call type not a class (${c.javaClass})", e)
return
}
val c = eType.classifier.owner as IrClass
useAnonymousClass(c)
} else {
useType(eType)
@@ -2418,11 +2418,8 @@ open class KotlinFileExtractor(
}
val typeAccessType = if (isAnonymous) {
val c = eType.classifier.owner
if (c !is IrClass) {
logger.warnElement("Anonymous type not a class (${c.javaClass})", e)
}
if ((c as? IrClass)?.superTypes?.size == 1) {
val c = eType.classifier.owner as IrClass
if (c.superTypes.size == 1) {
useType(c.superTypes.first())
} else {
useType(pluginContext.irBuiltIns.anyType)
@@ -3681,11 +3678,6 @@ open class KotlinFileExtractor(
logger.errorElement("Cannot find class for kPropertyType. ${kPropertyType.classFqName?.asString()}", propertyReferenceExpr)
return
}
val parameterTypes = kPropertyType.arguments.map { it as? IrType }.requireNoNullsOrNull()
if (parameterTypes == null) {
logger.errorElement("Unexpected: Non-IrType parameter.", propertyReferenceExpr)
return
}
val locId = tw.getLocation(propertyReferenceExpr)
@@ -3706,6 +3698,7 @@ open class KotlinFileExtractor(
val classId = extractGeneratedClass(ids, listOf(baseClass, kPropertyType), locId, currentDeclaration)
val helper = PropertyReferenceHelper(propertyReferenceExpr, locId, ids)
val parameterTypes = kPropertyType.arguments.map { it as IrType }
helper.extractReceiverField()
@@ -3852,11 +3845,7 @@ open class KotlinFileExtractor(
return
}
val parameterTypes = type.arguments.map { it as? IrType }.requireNoNullsOrNull()
if (parameterTypes == null) {
logger.errorElement("Unexpected: Non-IrType parameter.", functionReferenceExpr)
return
}
val parameterTypes = type.arguments.map { it as IrType }
val dispatchReceiverIdx: Int
val expressionTypeArguments: List<IrType>
@@ -4264,8 +4253,6 @@ open class KotlinFileExtractor(
* Extracts a type access expression and its child type access expressions in case of a generic type. Nested generics are also handled.
*/
private fun extractTypeAccessRecursive(t: IrType, location: Label<DbLocation>, parent: Label<out DbExprparent>, idx: Int, enclosingCallable: Label<out DbCallable>, enclosingStmt: Label<out DbStmt>, typeContext: TypeContext = TypeContext.OTHER): Label<out DbExpr> {
// TODO: `useType` substitutes types to their java equivalent, and sometimes that also means changing the number of type arguments. The below logic doesn't take this into account.
// For example `KFunction2<Int,Double,String>` becomes `KFunction<String>` with three child type access expressions: `Int`, `Double`, `String`.
val typeAccessId = extractTypeAccess(useType(t, typeContext), location, parent, idx, enclosingCallable, enclosingStmt)
if (t is IrSimpleType) {
extractTypeArguments(t.arguments.filterIsInstance<IrType>(), location, typeAccessId, enclosingCallable, enclosingStmt)
@@ -4682,18 +4669,14 @@ open class KotlinFileExtractor(
if (baseClass == null) {
logger.warnElement("Cannot find base class", currentDeclaration)
} else {
val superCallId = tw.getFreshIdLabel<DbSuperconstructorinvocationstmt>()
tw.writeStmts_superconstructorinvocationstmt(superCallId, constructorBlockId, 0, ids.constructor)
val baseConstructor = baseClass.owner.declarations.findSubType<IrFunction> { it.symbol is IrConstructorSymbol }
if (baseConstructor == null) {
logger.warnElement("Cannot find base constructor", currentDeclaration)
} else {
val superCallId = tw.getFreshIdLabel<DbSuperconstructorinvocationstmt>()
tw.writeStmts_superconstructorinvocationstmt(superCallId, constructorBlockId, 0, ids.constructor)
val baseConstructorId = useFunction<DbConstructor>(baseConstructor as IrFunction)
val baseConstructorId = useFunction<DbConstructor>(baseConstructor)
tw.writeHasLocation(superCallId, locId)
tw.writeCallableBinding(superCallId.cast<DbCaller>(), baseConstructorId)
}
tw.writeHasLocation(superCallId, locId)
tw.writeCallableBinding(superCallId.cast<DbCaller>(), baseConstructorId)
}
addModifiers(id, "final")

View File

@@ -539,52 +539,21 @@ open class KotlinUsesExtractor(
)
}
data class ArrayInfo(val elementTypeResults: TypeResults,
val componentTypeResults: TypeResults,
val dimensions: Int)
private fun useArrayType(arrayType: IrSimpleType, componentType: IrType, elementType: IrType, dimensions: Int, isPrimitiveArray: Boolean): TypeResults {
/**
* `t` is somewhere in a stack of array types, or possibly the
* element type of the innermost array. For example, in
* `Array<Array<Int>>`, we will be called with `t` being
* `Array<Array<Int>>`, then `Array<Int>`, then `Int`.
* `isPrimitiveArray` is true if we are immediately nested
* inside a primitive array.
*/
private fun useArrayType(t: IrType, isPrimitiveArray: Boolean): ArrayInfo {
if (!t.isBoxedArray && !t.isPrimitiveArray()) {
val nullableT = if (t.isPrimitiveType() && !isPrimitiveArray) t.makeNullable() else t
val typeResults = useType(nullableT)
return ArrayInfo(typeResults, typeResults, 0)
}
if (t !is IrSimpleType) {
logger.error("Unexpected non-simple array type: ${t.javaClass}")
return ArrayInfo(extractErrorType(), extractErrorType(), 0)
}
val arrayClass = t.classifier.owner
val arrayClass = arrayType.classifier.owner
if (arrayClass !is IrClass) {
logger.error("Unexpected owner type for array type: ${arrayClass.javaClass}")
return ArrayInfo(extractErrorType(), extractErrorType(), 0)
error("Unexpected owner type for array type: ${arrayClass.javaClass}")
return extractErrorType()
}
// Because Java's arrays are covariant, Kotlin will render
// Array<in X> as Object[], Array<Array<in X>> as Object[][] etc.
val elementType = if ((t.arguments.singleOrNull() as? IrTypeProjection)?.variance == Variance.IN_VARIANCE) {
pluginContext.irBuiltIns.anyType
} else {
t.getArrayElementType(pluginContext.irBuiltIns)
}
// Ensure we extract Array<Int> as Integer[], not int[], for example:
fun nullableIfNotPrimitive(type: IrType) = if (type.isPrimitiveType() && !isPrimitiveArray) type.makeNullable() else type
val recInfo = useArrayType(elementType, t.isPrimitiveArray())
val componentTypeResults = useType(nullableIfNotPrimitive(componentType))
val elementTypeLabel = useType(nullableIfNotPrimitive(elementType)).javaResult.id
val javaShortName = recInfo.componentTypeResults.javaResult.shortName + "[]"
val kotlinShortName = recInfo.componentTypeResults.kotlinResult.shortName + "[]"
val elementTypeLabel = recInfo.elementTypeResults.javaResult.id
val componentTypeLabel = recInfo.componentTypeResults.javaResult.id
val dimensions = recInfo.dimensions + 1
val javaShortName = componentTypeResults.javaResult.shortName + "[]"
val id = tw.getLabelFor<DbArray>("@\"array;$dimensions;{${elementTypeLabel}}\"") {
tw.writeArrays(
@@ -592,9 +561,9 @@ open class KotlinUsesExtractor(
javaShortName,
elementTypeLabel,
dimensions,
componentTypeLabel)
componentTypeResults.javaResult.id)
extractClassSupertypes(arrayClass, it, ExtractSupertypesMode.Specialised(t.arguments))
extractClassSupertypes(arrayClass, it, ExtractSupertypesMode.Specialised(arrayType.arguments))
// array.length
val length = tw.getLabelFor<DbField>("@\"field;{$it};length\"")
@@ -605,7 +574,7 @@ open class KotlinUsesExtractor(
// Note we will only emit one `clone()` method per Java array type, so we choose `Array<C?>` as its Kotlin
// return type, where C is the component type with any nested arrays themselves invariant and nullable.
val kotlinCloneReturnType = getInvariantNullableArrayType(t).makeNullable()
val kotlinCloneReturnType = getInvariantNullableArrayType(arrayType).makeNullable()
val kotlinCloneReturnTypeLabel = useType(kotlinCloneReturnType).kotlinResult.id
val clone = tw.getLabelFor<DbMethod>("@\"callable;{$it}.clone(){$it}\"")
@@ -616,15 +585,11 @@ open class KotlinUsesExtractor(
val javaResult = TypeResult(
id,
recInfo.componentTypeResults.javaResult.signature + "[]",
componentTypeResults.javaResult.signature + "[]",
javaShortName)
val kotlinResult = TypeResult(
fakeKotlinType(),
recInfo.componentTypeResults.kotlinResult.signature + "[]",
kotlinShortName)
val typeResults = TypeResults(javaResult, kotlinResult)
return ArrayInfo(recInfo.elementTypeResults, typeResults, dimensions)
val arrayClassResult = useSimpleTypeClass(arrayClass, arrayType.arguments, arrayType.hasQuestionMark)
return TypeResults(javaResult, arrayClassResult.kotlinResult)
}
enum class TypeContext {
@@ -697,8 +662,45 @@ open class KotlinUsesExtractor(
}
(s.isBoxedArray && s.arguments.isNotEmpty()) || s.isPrimitiveArray() -> {
val arrayInfo = useArrayType(s, false)
return arrayInfo.componentTypeResults
fun replaceComponentTypeWithAny(t: IrSimpleType, dimensions: Int): IrType =
if (dimensions == 0)
pluginContext.irBuiltIns.anyType
else
t.toBuilder().also { it.arguments = (it.arguments[0] as IrTypeProjection)
.let { oldArg ->
listOf(makeTypeProjection(replaceComponentTypeWithAny(oldArg.type as IrSimpleType, dimensions - 1), oldArg.variance))
}
}.buildSimpleType()
var componentType: IrType = s.getArrayElementType(pluginContext.irBuiltIns)
var isPrimitiveArray = false
var dimensions = 0
var elementType: IrType = s
while (elementType.isBoxedArray || elementType.isPrimitiveArray()) {
dimensions++
if (elementType.isPrimitiveArray())
isPrimitiveArray = true
if (elementType is IrSimpleType) {
if ((elementType.arguments.singleOrNull() as? IrTypeProjection)?.variance == Variance.IN_VARIANCE) {
// Because Java's arrays are covariant, Kotlin will render Array<in X> as Object[], Array<Array<in X>> as Object[][] etc.
componentType = replaceComponentTypeWithAny(s, dimensions - 1)
elementType = pluginContext.irBuiltIns.anyType
break
}
} else {
logger.warn("Unexpected element type representation ${elementType.javaClass} for ${s.render()}")
}
elementType = elementType.getArrayElementType(pluginContext.irBuiltIns)
}
return useArrayType(
s,
componentType,
elementType,
dimensions,
isPrimitiveArray
)
}
owner is IrClass -> {
@@ -707,7 +709,7 @@ open class KotlinUsesExtractor(
return useSimpleTypeClass(owner, args, s.hasQuestionMark)
}
owner is IrTypeParameter -> {
val javaResult = useTypeParameter(owner)
val javaResult = useTypeParameter(owner as IrTypeParameter)
val aClassId = makeClass("kotlin", "TypeParam") // TODO: Wrong
val kotlinResult = if (true) TypeResult(fakeKotlinType(), "TODO", "TODO") else
if (s.hasQuestionMark) {
@@ -919,17 +921,10 @@ open class KotlinUsesExtractor(
}
private fun extendsAdditionAllowed(t: IrType) =
if (t.isBoxedArray) {
if (t is IrSimpleType) {
arrayExtendsAdditionAllowed(t)
} else {
logger.warn("Boxed array of unexpected kind ${t.javaClass}")
// Return false, for no particular reason
false
}
} else {
if (t.isBoxedArray)
arrayExtendsAdditionAllowed(t as IrSimpleType)
else
((t as? IrSimpleType)?.classOrNull?.owner?.isFinalClass) != true
}
private fun wildcardAdditionAllowed(v: Variance, t: IrType, addByDefault: Boolean) =
when {
@@ -1138,6 +1133,10 @@ open class KotlinUsesExtractor(
// Note not using `parentsWithSelf` as that only works if `d` is an IrDeclarationParent
d.parents.any { (it as? IrAnnotationContainer)?.hasAnnotation(jvmWildcardSuppressionAnnotaton) == true }
protected fun IrFunction.isLocalFunction(): Boolean {
return this.visibility == DescriptorVisibilities.LOCAL
}
/**
* Class to hold labels for generated classes around local functions, lambdas, function references, and property references.
*/
@@ -1179,14 +1178,6 @@ open class KotlinUsesExtractor(
return res
}
fun getExistingLocallyVisibleFunctionLabel(f: IrFunction): Label<DbMethod>? {
if (!f.isLocalFunction()){
return null
}
return tw.lm.locallyVisibleFunctionLabelMapping[f]?.function
}
// These are classes with Java equivalents, but whose methods don't all exist on those Java equivalents--
// for example, the numeric classes define arithmetic functions (Int.plus, Long.or and so on) that lower to
// primitive arithmetic on the JVM, but which we extract as calls to reflect the source syntax more closely.
@@ -1200,11 +1191,10 @@ open class KotlinUsesExtractor(
else
f.parentClassOrNull?.let { parentClass ->
getJavaEquivalentClass(parentClass)?.let { javaClass ->
if (javaClass != parentClass) {
val jvmName = getJvmName(f) ?: f.name.asString()
if (javaClass != parentClass)
// Look for an exact type match...
javaClass.declarations.findSubType<IrFunction> { decl ->
decl.name.asString() == jvmName &&
decl.name == f.name &&
decl.valueParameters.size == f.valueParameters.size &&
// Note matching by classifier not the whole type so that generic arguments are allowed to differ,
// as they always will for method type parameters occurring in parameter types (e.g. <T> toArray(T[] array)
@@ -1213,7 +1203,7 @@ open class KotlinUsesExtractor(
} ?:
// Or if there is none, look for the only viable overload
javaClass.declarations.singleOrNullSubType<IrFunction> { decl ->
decl.name.asString() == jvmName &&
decl.name == f.name &&
decl.valueParameters.size == f.valueParameters.size
} ?:
// Or check property accessors:
@@ -1233,7 +1223,6 @@ open class KotlinUsesExtractor(
}
null
}
}
else
null
}

View File

@@ -2,7 +2,6 @@ package com.github.codeql.comments
import com.github.codeql.*
import com.github.codeql.utils.IrVisitorLookup
import com.github.codeql.utils.isLocalFunction
import com.github.codeql.utils.versions.Psi2Ir
import com.intellij.psi.PsiComment
import com.intellij.psi.PsiElement
@@ -93,10 +92,29 @@ class CommentExtractor(private val fileExtractor: KotlinFileExtractor, private v
file.accept(IrVisitorLookup(psi2Ir, ownerPsi, file), owners)
for (ownerIr in owners) {
val ownerLabel = getLabel(ownerIr)
if (ownerLabel != null) {
tw.writeKtCommentOwners(commentLabel, ownerLabel)
}
val ownerLabel =
if (ownerIr == file)
fileLabel
else {
if (ownerIr is IrValueParameter && ownerIr.index == -1) {
// Don't attribute comments to the implicit `this` parameter of a function.
continue
}
val label: String
val existingLabel = if (ownerIr is IrVariable) {
label = "variable ${ownerIr.name.asString()}"
tw.getExistingVariableLabelFor(ownerIr)
} else {
label = getLabel(ownerIr) ?: continue
tw.getExistingLabelFor<DbTop>(label)
}
if (existingLabel == null) {
logger.warn("Couldn't get existing label for $label")
continue
}
existingLabel
}
tw.writeKtCommentOwners(commentLabel, ownerLabel)
}
}
@@ -108,47 +126,11 @@ class CommentExtractor(private val fileExtractor: KotlinFileExtractor, private v
return owner
}
private fun getLabel(element: IrElement): Label<out DbTop>? {
if (element == file)
return fileLabel
if (element is IrValueParameter && element.index == -1) {
// Don't attribute comments to the implicit `this` parameter of a function.
return null
}
val label: String
val existingLabel = if (element is IrVariable) {
// local variables are not named globally, so we need to get them from the variable label cache
label = "variable ${element.name.asString()}"
tw.getExistingVariableLabelFor(element)
} else if (element is IrFunction && element.isLocalFunction()) {
// local functions are not named globally, so we need to get them from the local function label cache
label = "local function ${element.name.asString()}"
fileExtractor.getExistingLocallyVisibleFunctionLabel(element)
}
else {
label = getLabelForNamedElement(element) ?: return null
tw.getExistingLabelFor<DbTop>(label)
}
if (existingLabel == null) {
logger.warn("Couldn't get existing label for $label")
return null
}
return existingLabel
}
private fun getLabelForNamedElement(element: IrElement) : String? {
private fun getLabel(element: IrElement) : String? {
when (element) {
is IrClass -> return fileExtractor.getClassLabel(element, listOf()).classLabel
is IrTypeParameter -> return fileExtractor.getTypeParameterLabel(element)
is IrFunction -> {
return if (element.isLocalFunction()) {
null
} else {
fileExtractor.getFunctionLabel(element, null)
}
}
is IrFunction -> return fileExtractor.getFunctionLabel(element, null)
is IrValueParameter -> return fileExtractor.getValueParameterLabel(element, null)
is IrProperty -> return fileExtractor.getPropertyLabel(element)
is IrField -> return fileExtractor.getFieldLabel(element)
@@ -162,10 +144,10 @@ class CommentExtractor(private val fileExtractor: KotlinFileExtractor, private v
return null
}
// Assign the comment to the class. The content of the `init` blocks might be extracted in multiple constructors.
return getLabelForNamedElement(parentClass)
return getLabel(parentClass)
}
// Fresh entities, not named elements:
// Fresh entities:
is IrBody -> return null
is IrExpression -> return null

View File

@@ -1,8 +0,0 @@
package com.github.codeql.utils
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.ir.declarations.IrFunction
fun IrFunction.isLocalFunction(): Boolean {
return this.visibility == DescriptorVisibilities.LOCAL
}

View File

@@ -1,10 +0,0 @@
---
category: minorAnalysis
---
* Added new flow steps for the following Android classes:
* `android.content.ContentResolver`
* `android.content.ContentProviderClient`
* `android.content.ContentProviderOperation`
* `android.content.ContentProviderOperation$Builder`
* `android.content.ContentProviderResult`
* `android.database.Cursor`

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Added flow sinks, sources and summaries for the Kotlin standard library.

View File

@@ -153,7 +153,7 @@ private module Frameworks {
private import semmle.code.java.frameworks.JMS
private import semmle.code.java.frameworks.RabbitMQ
private import semmle.code.java.regex.RegexFlowModels
private import semmle.code.java.frameworks.kotlin.StdLib
private import semmle.code.java.frameworks.KotlinStdLib
}
/**

View File

@@ -53,16 +53,6 @@ private class TypeFlowNode extends TTypeFlowNode {
}
}
private int getNodeKind(TypeFlowNode n) {
result = 1 and n instanceof TField
or
result = 2 and n instanceof TSsa
or
result = 3 and n instanceof TExpr
or
result = 4 and n instanceof TMethod
}
/** Gets `t` if it is a `RefType` or the boxed type if `t` is a primitive type. */
private RefType boxIfNeeded(Type t) {
t.(PrimitiveType).getBoxedType() = result or
@@ -156,181 +146,27 @@ private predicate joinStep(TypeFlowNode n1, TypeFlowNode n2) {
joinStep0(n1, n2) and not isNull(n1)
}
private predicate anyStep(TypeFlowNode n1, TypeFlowNode n2) { joinStep(n1, n2) or step(n1, n2) }
private import SccReduction
/**
* SCC reduction.
*
* This ought to be as easy as `equivalenceRelation(sccEdge/2)(n, scc)`, but
* this HOP is not currently supported for newtypes.
*
* A straightforward implementation would be:
* ```ql
* predicate sccRepr(TypeFlowNode n, TypeFlowNode scc) {
* scc =
* max(TypeFlowNode n2 |
* sccEdge+(n, n2)
* |
* n2
* order by
* n2.getLocation().getStartLine(), n2.getLocation().getStartColumn(), getNodeKind(n2)
* )
* }
*
* ```
* but this is quadratic in the size of the SCCs.
*
* Instead we find local maxima by following SCC edges and determine the SCC
* representatives from those.
* (This is still worst-case quadratic in the size of the SCCs, but generally
* performs better.)
*/
private module SccReduction {
private predicate sccEdge(TypeFlowNode n1, TypeFlowNode n2) {
anyStep(n1, n2) and anyStep+(n2, n1)
}
private predicate sccEdgeWithMax(TypeFlowNode n1, TypeFlowNode n2, TypeFlowNode m) {
sccEdge(n1, n2) and
m =
max(TypeFlowNode n |
n = [n1, n2]
|
n order by n.getLocation().getStartLine(), n.getLocation().getStartColumn(), getNodeKind(n)
)
}
private predicate hasLargerNeighbor(TypeFlowNode n) {
exists(TypeFlowNode n2 |
sccEdgeWithMax(n, n2, n2) and
not sccEdgeWithMax(n, n2, n)
or
sccEdgeWithMax(n2, n, n2) and
not sccEdgeWithMax(n2, n, n)
private predicate joinStepRank1(int r, TypeFlowNode n1, TypeFlowNode n2) {
n1 =
rank[r](TypeFlowNode n |
joinStep(n, n2)
|
n order by n.getLocation().getStartLine(), n.getLocation().getStartColumn()
)
}
private predicate localMax(TypeFlowNode m) {
sccEdgeWithMax(_, _, m) and
not hasLargerNeighbor(m)
}
private predicate sccReprFromLocalMax(TypeFlowNode scc) {
exists(TypeFlowNode m |
localMax(m) and
scc =
max(TypeFlowNode n2 |
sccEdge+(m, n2) and localMax(n2)
|
n2
order by
n2.getLocation().getStartLine(), n2.getLocation().getStartColumn(), getNodeKind(n2)
)
)
}
/** Holds if `n` is part of an SCC of size 2 or more represented by `scc`. */
predicate sccRepr(TypeFlowNode n, TypeFlowNode scc) {
sccEdge+(n, scc) and sccReprFromLocalMax(scc)
}
predicate sccJoinStep(TypeFlowNode n, TypeFlowNode scc) {
exists(TypeFlowNode mid |
joinStep(n, mid) and
sccRepr(mid, scc) and
not sccRepr(n, scc)
)
}
}
private signature predicate edgeSig(TypeFlowNode n1, TypeFlowNode n2);
private signature module RankedEdge {
predicate edgeRank(int r, TypeFlowNode n1, TypeFlowNode n2);
int lastRank(TypeFlowNode n);
private predicate joinStepRank2(int r2, int r1, TypeFlowNode n) {
r1 = rank[r2](int r | joinStepRank1(r, _, n) | r)
}
private module RankEdge<edgeSig/2 edge> implements RankedEdge {
/**
* Holds if `r` is a ranking of the incoming edges `(n1,n2)` to `n2`. The used
* ordering is not necessarily total, so the ranking may have gaps.
*/
private predicate edgeRank1(int r, TypeFlowNode n1, TypeFlowNode n2) {
n1 =
rank[r](TypeFlowNode n |
edge(n, n2)
|
n order by n.getLocation().getStartLine(), n.getLocation().getStartColumn()
)
}
/**
* Holds if `r2` is a ranking of the ranks from `edgeRank1`. This removes the
* gaps from the ranking.
*/
private predicate edgeRank2(int r2, int r1, TypeFlowNode n) {
r1 = rank[r2](int r | edgeRank1(r, _, n) | r)
}
/** Holds if `r` is a ranking of the incoming edges `(n1,n2)` to `n2`. */
predicate edgeRank(int r, TypeFlowNode n1, TypeFlowNode n2) {
exists(int r1 |
edgeRank1(r1, n1, n2) and
edgeRank2(r, r1, n2)
)
}
int lastRank(TypeFlowNode n) { result = max(int r | edgeRank(r, _, n)) }
private predicate joinStepRank(int r, TypeFlowNode n1, TypeFlowNode n2) {
exists(int r1 |
joinStepRank1(r1, n1, n2) and
joinStepRank2(r, r1, n2)
)
}
private signature module TypePropagation {
predicate candType(TypeFlowNode n, RefType t);
bindingset[t]
predicate supportsType(TypeFlowNode n, RefType t);
}
/** Implements recursion through `forall` by way of edge ranking. */
private module ForAll<RankedEdge Edge, TypePropagation T> {
/**
* Holds if `t` is a bound that holds on one of the incoming edges to `n` and
* thus is a candidate bound for `n`.
*/
pragma[nomagic]
private predicate candJoinType(TypeFlowNode n, RefType t) {
exists(TypeFlowNode mid |
T::candType(mid, t) and
Edge::edgeRank(_, mid, n)
)
}
/**
* Holds if `t` is a candidate bound for `n` that is also valid for data coming
* through the edges into `n` ranked from `1` to `r`.
*/
private predicate flowJoin(int r, TypeFlowNode n, RefType t) {
(
r = 1 and candJoinType(n, t)
or
flowJoin(r - 1, n, t) and Edge::edgeRank(r, _, n)
) and
forall(TypeFlowNode mid | Edge::edgeRank(r, mid, n) | T::supportsType(mid, t))
}
/**
* Holds if `t` is a candidate bound for `n` that is also valid for data
* coming through all the incoming edges, and therefore is a valid bound for
* `n`.
*/
predicate flowJoin(TypeFlowNode n, RefType t) { flowJoin(Edge::lastRank(n), n, t) }
}
module RankedJoinStep = RankEdge<joinStep/2>;
module RankedSccJoinStep = RankEdge<sccJoinStep/2>;
private int lastRank(TypeFlowNode n) { result = max(int r | joinStepRank(r, _, n)) }
private predicate exactTypeBase(TypeFlowNode n, RefType t) {
exists(ClassInstanceExpr e |
@@ -341,10 +177,15 @@ private predicate exactTypeBase(TypeFlowNode n, RefType t) {
)
}
private module ExactTypePropagation implements TypePropagation {
predicate candType = exactType/2;
private predicate exactTypeRank(int r, TypeFlowNode n, RefType t) {
forall(TypeFlowNode mid | joinStepRank(r, mid, n) | exactType(mid, t)) and
joinStepRank(r, _, n)
}
predicate supportsType = exactType/2;
private predicate exactTypeJoin(int r, TypeFlowNode n, RefType t) {
exactTypeRank(1, n, t) and r = 1
or
exactTypeJoin(r - 1, n, t) and exactTypeRank(r, n, t)
}
/**
@@ -358,14 +199,7 @@ private predicate exactType(TypeFlowNode n, RefType t) {
or
// The following is an optimized version of
// `forex(TypeFlowNode mid | joinStep(mid, n) | exactType(mid, t))`
ForAll<RankedJoinStep, ExactTypePropagation>::flowJoin(n, t)
or
exists(TypeFlowNode scc |
sccRepr(n, scc) and
// Optimized version of
// `forex(TypeFlowNode mid | sccJoinStep(mid, scc) | exactType(mid, t))`
ForAll<RankedSccJoinStep, ExactTypePropagation>::flowJoin(scc, t)
)
exactTypeJoin(lastRank(n), n, t)
}
/**
@@ -509,15 +343,30 @@ private predicate typeFlowBase(TypeFlowNode n, RefType t) {
)
}
private module TypeFlowPropagation implements TypePropagation {
predicate candType = typeFlow/2;
/**
* Holds if `t` is a bound that holds on one of the incoming edges to `n` and
* thus is a candidate bound for `n`.
*/
pragma[noinline]
private predicate typeFlowJoinCand(TypeFlowNode n, RefType t) {
exists(TypeFlowNode mid | joinStep(mid, n) | typeFlow(mid, t))
}
bindingset[t]
predicate supportsType(TypeFlowNode mid, RefType t) {
/**
* Holds if `t` is a candidate bound for `n` that is also valid for data coming
* through the edges into `n` ranked from `1` to `r`.
*/
private predicate typeFlowJoin(int r, TypeFlowNode n, RefType t) {
(
r = 1 and typeFlowJoinCand(n, t)
or
typeFlowJoin(r - 1, n, t) and joinStepRank(r, _, n)
) and
forall(TypeFlowNode mid | joinStepRank(r, mid, n) |
exists(RefType midtyp | exactType(mid, midtyp) or typeFlow(mid, midtyp) |
pragma[only_bind_out](midtyp).getAnAncestor() = t
)
}
)
}
/**
@@ -529,12 +378,7 @@ private predicate typeFlow(TypeFlowNode n, RefType t) {
or
exists(TypeFlowNode mid | typeFlow(mid, t) and step(mid, n))
or
ForAll<RankedJoinStep, TypeFlowPropagation>::flowJoin(n, t)
or
exists(TypeFlowNode scc |
sccRepr(n, scc) and
ForAll<RankedSccJoinStep, TypeFlowPropagation>::flowJoin(scc, t)
)
typeFlowJoin(lastRank(n), n, t)
}
pragma[nomagic]

View File

@@ -0,0 +1,11 @@
/** Definitions of taint steps in the KotlinStdLib framework */
import java
private import semmle.code.java.dataflow.ExternalFlow
private class KotlinStdLibSummaryCsv extends SummaryModelCsv {
override predicate row(string row) {
row =
"kotlin.jvm.internal;ArrayIteratorKt;false;iterator;(Object[]);;Argument[0].ArrayElement;ReturnValue.Element;value;manual"
}
}

View File

@@ -53,64 +53,7 @@ private class SummaryModels extends SummaryModelCsv {
"android.content;ContentValues;false;put;;;Argument[0];Argument[-1].MapKey;value;manual",
"android.content;ContentValues;false;put;;;Argument[1];Argument[-1].MapValue;value;manual",
"android.content;ContentValues;false;putAll;;;Argument[0].MapKey;Argument[-1].MapKey;value;manual",
"android.content;ContentValues;false;putAll;;;Argument[0].MapValue;Argument[-1].MapValue;value;manual",
"android.content;ContentResolver;true;acquireContentProviderClient;;;Argument[0];ReturnValue;taint;manual",
"android.content;ContentResolver;true;acquireUnstableContentProviderClient;;;Argument[0];ReturnValue;taint;manual",
"android.content;ContentResolver;true;acquireUnstableContentProviderClient;;;Argument[0];ReturnValue;taint;manual",
"android.content;ContentResolver;true;applyBatch;;;Argument[1];ReturnValue;taint;manual",
"android.content;ContentResolver;true;call;;;Argument[0];ReturnValue;taint;manual",
"android.content;ContentResolver;true;canonicalize;;;Argument[0];ReturnValue;taint;manual",
"android.content;ContentResolver;true;getStreamTypes;;;Argument[0];ReturnValue;taint;manual",
"android.content;ContentResolver;true;getType;;;Argument[0];ReturnValue;taint;manual",
"android.content;ContentResolver;true;insert;;;Argument[0];ReturnValue;taint;manual",
"android.content;ContentResolver;true;query;;;Argument[0];ReturnValue;taint;manual",
"android.content;ContentResolver;true;uncanonicalize;;;Argument[0];ReturnValue;taint;manual",
"android.content;ContentResolver;true;wrap;;;Argument[0];ReturnValue;taint;manual",
// ContentProviderClient is tainted at its creation, not by its arguments
"android.content;ContentProviderClient;true;applyBatch;;;Argument[-1];ReturnValue;taint;manual",
"android.content;ContentProviderClient;true;call;;;Argument[-1];ReturnValue;taint;manual",
"android.content;ContentProviderClient;true;canonicalize;;;Argument[-1];ReturnValue;taint;manual",
"android.content;ContentProviderClient;true;getLocalContentProvider;;;Argument[-1];ReturnValue;taint;manual",
"android.content;ContentProviderClient;true;getStreamTypes;;;Argument[-1];ReturnValue;taint;manual",
"android.content;ContentProviderClient;true;insert;;;Argument[-1];ReturnValue;taint;manual",
"android.content;ContentProviderClient;true;query;;;Argument[-1];ReturnValue;taint;manual",
"android.content;ContentProviderClient;true;uncanonicalize;;;Argument[-1];ReturnValue;taint;manual",
"android.content;ContentProviderOperation;false;apply;;;Argument[-1];ReturnValue;taint;manual",
"android.content;ContentProviderOperation;false;apply;;;Argument[0];ReturnValue;taint;manual",
"android.content;ContentProviderOperation;false;getUri;;;Argument[-1];ReturnValue;taint;manual",
"android.content;ContentProviderOperation;false;newAssertQuery;;;Argument[0];ReturnValue;taint;manual",
"android.content;ContentProviderOperation;false;newCall;;;Argument[0];ReturnValue;taint;manual",
"android.content;ContentProviderOperation;false;newDelete;;;Argument[0];ReturnValue;taint;manual",
"android.content;ContentProviderOperation;false;newInsert;;;Argument[0];ReturnValue;taint;manual",
"android.content;ContentProviderOperation;false;newUpdate;;;Argument[0];ReturnValue;taint;manual",
"android.content;ContentProviderOperation;false;resolveExtrasBackReferences;;;Argument[0];ReturnValue;taint;manual",
"android.content;ContentProviderOperation;false;resolveSelectionArgsBackReferences;;;Argument[0];ReturnValue;taint;manual",
"android.content;ContentProviderOperation;false;resolveValueBackReferences;;;Argument[0];ReturnValue;taint;manual",
"android.content;ContentProviderOperation$Builder;false;build;;;Argument[-1];ReturnValue;taint;manual",
"android.content;ContentProviderOperation$Builder;false;withExceptionAllowed;;;Argument[-1];ReturnValue;value;manual",
"android.content;ContentProviderOperation$Builder;false;withExpectedCount;;;Argument[-1];ReturnValue;value;manual",
"android.content;ContentProviderOperation$Builder;false;withExtra;;;Argument[-1];ReturnValue;value;manual",
"android.content;ContentProviderOperation$Builder;false;withExtraBackReference;;;Argument[-1];ReturnValue;value;manual",
"android.content;ContentProviderOperation$Builder;false;withExtras;;;Argument[-1];ReturnValue;value;manual",
"android.content;ContentProviderOperation$Builder;false;withSelection;;;Argument[-1];ReturnValue;value;manual",
"android.content;ContentProviderOperation$Builder;false;withSelectionBackReference;;;Argument[-1];ReturnValue;value;manual",
"android.content;ContentProviderOperation$Builder;false;withValue;;;Argument[-1];ReturnValue;value;manual",
"android.content;ContentProviderOperation$Builder;false;withValueBackReference;;;Argument[-1];ReturnValue;value;manual",
"android.content;ContentProviderOperation$Builder;false;withValues;;;Argument[-1];ReturnValue;value;manual",
"android.content;ContentProviderOperation$Builder;false;withYieldAllowed;;;Argument[-1];ReturnValue;value;manual",
"android.content;ContentProviderResult;false;ContentProviderResult;(Uri);;Argument[0];Argument[-1].Field[android.content.ContentProviderResult.uri];value;manual",
"android.content;ContentProviderResult;false;ContentProviderResult;(Bundle);;Argument[0];Argument[-1].Field[android.content.ContentProviderResult.extras];value;manual",
"android.content;ContentProviderResult;false;ContentProviderResult;(Throwable);;Argument[0];Argument[-1].Field[android.content.ContentProviderResult.exception];value;manual",
"android.content;ContentProviderResult;false;ContentProviderResult;(Parcel);;Argument[0];Argument[-1];taint;manual",
"android.database;Cursor;true;copyStringToBuffer;;;Argument[-1];Argument[1];taint;manual",
"android.database;Cursor;true;getBlob;;;Argument[-1];ReturnValue;taint;manual",
"android.database;Cursor;true;getColumnName;;;Argument[-1];ReturnValue;taint;manual",
"android.database;Cursor;true;getColumnNames;;;Argument[-1];ReturnValue;taint;manual",
"android.database;Cursor;true;getExtras;;;Argument[-1];ReturnValue;taint;manual",
"android.database;Cursor;true;getNotificationUri;;;Argument[-1];ReturnValue;taint;manual",
"android.database;Cursor;true;getNotificationUris;;;Argument[-1];ReturnValue;taint;manual",
"android.database;Cursor;true;getString;;;Argument[-1];ReturnValue;taint;manual",
"android.database;Cursor;true;respond;;;Argument[-1];ReturnValue;taint;manual"
"android.content;ContentValues;false;putAll;;;Argument[0].MapValue;Argument[-1].MapValue;value;manual"
]
}
}

View File

@@ -6,5 +6,4 @@ import java
private module GeneratedFrameworks {
private import apache.IOGenerated
private import kotlin.StdLibGenerated
}

View File

@@ -1,14 +0,0 @@
/** Definitions of taint steps in the KotlinStdLib framework */
import java
private import semmle.code.java.dataflow.ExternalFlow
private class KotlinStdLibSummaryCsv extends SummaryModelCsv {
override predicate row(string row) {
row =
[
"kotlin.jvm.internal;ArrayIteratorKt;false;iterator;(Object[]);;Argument[0].ArrayElement;ReturnValue.Element;value;manual",
"kotlin.collections;ArraysKt;false;withIndex;(Object[]);;Argument[0].ArrayElement;ReturnValue;taint;manual"
]
}
}

View File

@@ -106,15 +106,7 @@ private class PendingIntentSentSinkModels extends SinkModelCsv {
"android.app;PendingIntent;false;send;(Context,int,Intent,OnFinished,Handler,String);;Argument[2];pending-intent-sent;manual",
"android.app;PendingIntent;false;send;(Context,int,Intent,OnFinished,Handler);;Argument[2];pending-intent-sent;manual",
"android.app;PendingIntent;false;send;(Context,int,Intent);;Argument[2];pending-intent-sent;manual",
"android.app;Activity;true;setResult;(int,Intent);;Argument[1];pending-intent-sent;manual",
"android.app;AlarmManager;true;set;(int,long,PendingIntent);;Argument[2];pending-intent-sent;manual",
"android.app;AlarmManager;true;setAlarmClock;;;Argument[1];pending-intent-sent;manual",
"android.app;AlarmManager;true;setAndAllowWhileIdle;;;Argument[2];pending-intent-sent;manual",
"android.app;AlarmManager;true;setExact;(int,long,PendingIntent);;Argument[2];pending-intent-sent;manual",
"android.app;AlarmManager;true;setExactAndAllowWhileIdle;;;Argument[2];pending-intent-sent;manual",
"android.app;AlarmManager;true;setInexactRepeating;;;Argument[3];pending-intent-sent;manual",
"android.app;AlarmManager;true;setRepeating;;;Argument[3];pending-intent-sent;manual",
"android.app;AlarmManager;true;setWindow;(int,long,long,PendingIntent);;Argument[3];pending-intent-sent;manual",
"android.app;Activity;true;setResult;(int,Intent);;Argument[1];pending-intent-sent;manual"
]
}
}

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Added new sinks related to Android's `AlarmManager` to the query `java/android/implicit-pendingintents`.

View File

@@ -4,10 +4,10 @@
<qhelp>
<overview>
<p>By default, a "dot" (<code>.</code>) in a regular expression matches all characters except the newline characters <code>\n</code> and
<code>\r</code>. Regular expressions containing a dot can be bypassed with the characters <code>\r</code>(<code>%0a</code>) and
<code>\n</code>(<code>%0d</code>) when the default Java regular expression matching implementations are used. This becomes a security issue
if these regular expressions are used to decide whether to grant access to protected application resources.</p>
<p>By default, "dot" (<code>.</code>) in regular expressions matches all characters except newline characters <code>\n</code> and
<code>\r</code>. Regular expressions containing a dot can be bypassed with the characters \r(%0a) , \n(%0d) when the default regex
matching implementations of Java are used. When regular expressions serve to match protected resource patterns to grant access
to protected application resources, attackers can gain access to unauthorized paths.</p>
</overview>
<recommendation>
@@ -17,15 +17,18 @@ to address this vulnerability.</p>
</recommendation>
<example>
<p>The following snippets show a vulnerable example and a secure example respectively. The <code>bad</code> methods show a regex pattern allowing
a bypass by using line break characters. In the <code>good</code> methods, it is shown how to solve this problem by either specifying the regex
pattern correctly or using a Java API that properly matches new line characters.
<p>The following examples show the bad case and the good case respectively. The <code>bad</code> methods show a regex pattern allowing
bypass. In the <code>good</code> methods, it is shown how to solve this problem by either specifying the regex pattern correctly or
use the Java API that can detect new line characters.
</p>
<sample src="DotRegex.java" />
</example>
<references>
<li>Lay0us1:
<a href="https://github.com/Lay0us1/CVE-2022-32532">CVE 2022-22978: Authorization Bypass in RegexRequestMatcher</a>.
</li>
<li>Apache Shiro:
<a href="https://github.com/apache/shiro/commit/6bcb92e06fa588b9c7790dd01bc02135d58d3f5b">Address the RegexRequestMatcher issue in 1.9.1</a>.
</li>

View File

@@ -1,6 +1,6 @@
/**
* @name URL matched by permissive `.` in a regular expression
* @description URLs validated with a permissive `.` in regular expressions may be vulnerable
* @name URL matched by permissive `.` in the regular expression
* @description URL validated with permissive `.` in regex are possibly vulnerable
* to an authorization bypass.
* @kind path-problem
* @problem.severity warning

View File

@@ -9,7 +9,7 @@ import semmle.code.java.security.UrlRedirect
import Regex
/** A string that ends with `.*` not prefixed with `\`. */
private class PermissiveDotStr extends StringLiteral {
class PermissiveDotStr extends StringLiteral {
PermissiveDotStr() {
exists(string s, int i | this.getValue() = s |
s.indexOf(".*") = i and
@@ -19,7 +19,7 @@ private class PermissiveDotStr extends StringLiteral {
}
}
/** Remote flow sources obtained from the URI of a servlet request. */
/** Source model of remote flow source with servlets. */
private class GetServletUriSource extends SourceModelCsv {
override predicate row(string row) {
row =
@@ -33,7 +33,7 @@ private class GetServletUriSource extends SourceModelCsv {
}
}
/** The qualifier of a request dispatch method call. */
/** Sink of servlet dispatcher. */
private class UrlDispatchSink extends UrlRedirectSink {
UrlDispatchSink() {
exists(MethodAccess ma |
@@ -51,7 +51,7 @@ private class ServletFilterMethod extends Method {
}
}
/** The qualifier of a servlet filter method call. */
/** Sink of servlet filter. */
private class UrlFilterSink extends UrlRedirectSink {
UrlFilterSink() {
exists(MethodAccess ma |
@@ -61,8 +61,8 @@ private class UrlFilterSink extends UrlRedirectSink {
}
}
/** A Spring framework annotation indicating that a URI is user-provided. */
private class SpringUriInputAnnotation extends Annotation {
/** A Spring framework annotation indicating remote uri user input. */
class SpringUriInputAnnotation extends Annotation {
SpringUriInputAnnotation() {
this.getType()
.hasQualifiedName("org.springframework.web.bind.annotation",
@@ -70,8 +70,7 @@ private class SpringUriInputAnnotation extends Annotation {
}
}
/** A user-provided URI parameter of a request mapping method. */
private class SpringUriInputParameterSource extends DataFlow::Node {
class SpringUriInputParameterSource extends DataFlow::Node {
SpringUriInputParameterSource() {
this.asParameter() =
any(SpringRequestMappingParameter srmp |
@@ -83,7 +82,7 @@ private class SpringUriInputParameterSource extends DataFlow::Node {
/**
* A data flow sink to construct regular expressions.
*/
private class CompileRegexSink extends DataFlow::ExprNode {
class CompileRegexSink extends DataFlow::ExprNode {
CompileRegexSink() {
exists(MethodAccess ma, Method m | m = ma.getMethod() |
(
@@ -101,9 +100,9 @@ private class CompileRegexSink extends DataFlow::ExprNode {
}
/**
* A data flow configuration for regular expressions that include permissive dots.
* A flow configuration for permissive dot regex.
*/
private class PermissiveDotRegexConfig extends DataFlow2::Configuration {
class PermissiveDotRegexConfig extends DataFlow2::Configuration {
PermissiveDotRegexConfig() { this = "PermissiveDotRegex::PermissiveDotRegexConfig" }
override predicate isSource(DataFlow2::Node src) { src.asExpr() instanceof PermissiveDotStr }
@@ -124,8 +123,7 @@ private class PermissiveDotRegexConfig extends DataFlow2::Configuration {
}
/**
* A taint-tracking configuration for untrusted user input used to match regular expressions
* that include permissive dots.
* A taint-tracking configuration for untrusted user input used to match regular expressions.
*/
class MatchRegexConfiguration extends TaintTracking::Configuration {
MatchRegexConfiguration() { this = "PermissiveDotRegex::MatchRegexConfiguration" }
@@ -175,15 +173,12 @@ class MatchRegexConfiguration extends TaintTracking::Configuration {
}
}
/**
* A data flow sink representing a string being matched against a regular expression.
*/
abstract class MatchRegexSink extends DataFlow::ExprNode { }
/**
* A string being matched against a regular expression.
* A data flow sink to string match regular expressions.
*/
private class StringMatchRegexSink extends MatchRegexSink {
class StringMatchRegexSink extends MatchRegexSink {
StringMatchRegexSink() {
exists(MethodAccess ma, Method m | m = ma.getMethod() |
(
@@ -195,9 +190,9 @@ private class StringMatchRegexSink extends MatchRegexSink {
}
/**
* A string being matched against a regular expression using a pattern.
* A data flow sink to `pattern.matches` regular expressions.
*/
private class PatternMatchRegexSink extends MatchRegexSink {
class PatternMatchRegexSink extends MatchRegexSink {
PatternMatchRegexSink() {
exists(MethodAccess ma, Method m | m = ma.getMethod() |
(
@@ -209,9 +204,9 @@ private class PatternMatchRegexSink extends MatchRegexSink {
}
/**
* A string being used to create a pattern matcher.
* A data flow sink to `pattern.matcher` match regular expressions.
*/
private class PatternMatcherRegexSink extends MatchRegexSink {
class PatternMatcherRegexSink extends MatchRegexSink {
PatternMatcherRegexSink() {
exists(MethodAccess ma, Method m | m = ma.getMethod() |
(

View File

@@ -3,14 +3,14 @@
import java
/**
* The class `java.util.regex.Pattern`.
* The class `Pattern` for pattern match.
*/
class Pattern extends RefType {
Pattern() { this.hasQualifiedName("java.util.regex", "Pattern") }
}
/**
* The method `compile` of `java.util.regex.Pattern`.
* The method `compile` for `Pattern`.
*/
class PatternCompileMethod extends Method {
PatternCompileMethod() {
@@ -20,7 +20,7 @@ class PatternCompileMethod extends Method {
}
/**
* The method `matches` of `java.util.regex.Pattern`.
* The method `matches` for `Pattern`.
*/
class PatternMatchMethod extends Method {
PatternMatchMethod() {
@@ -30,7 +30,7 @@ class PatternMatchMethod extends Method {
}
/**
* The method `matcher` of `java.util.regex.Pattern`.
* The method `matcher` for `Pattern`.
*/
class PatternMatcherMethod extends Method {
PatternMatcherMethod() {
@@ -40,7 +40,7 @@ class PatternMatcherMethod extends Method {
}
/**
* The method `matches` of `java.lang.String`.
* The method `matches` for `String`.
*/
class StringMatchMethod extends Method {
StringMatchMethod() {

View File

@@ -7,13 +7,9 @@ comments
| comments.kt:28:5:30:6 | /*\n A block comment\n */ | /*\n A block comment\n */ |
| comments.kt:35:5:35:34 | /** Medium is in the middle */ | /** Medium is in the middle */ |
| comments.kt:37:5:37:23 | /** This is high */ | /** This is high */ |
| comments.kt:42:5:44:7 | /**\n * A variable.\n */ | /**\n * A variable.\n */ |
| comments.kt:42:5:44:6 | /**\n * A variable.\n */ | /**\n * A variable.\n */ |
| comments.kt:48:1:50:3 | /**\n * A type alias comment\n */ | /**\n * A type alias comment\n */ |
| comments.kt:54:5:56:7 | /**\n * An init block comment\n */ | /**\n * An init block comment\n */ |
| comments.kt:61:5:63:7 | /**\n * A prop comment\n */ | /**\n * A prop comment\n */ |
| comments.kt:65:9:67:11 | /**\n * An accessor comment\n */ | /**\n * An accessor comment\n */ |
| comments.kt:71:9:73:11 | /**\n * An anonymous function comment\n */ | /**\n * An anonymous function comment\n */ |
| comments.kt:79:9:81:11 | /**\n * A local function comment\n */ | /**\n * A local function comment\n */ |
commentOwners
| comments.kt:4:1:11:3 | /**\n * A group of *members*.\n *\n * This class has no useful logic; it's just a documentation example.\n *\n * @property name the name of this group.\n * @constructor Creates an empty group.\n */ | comments.kt:12:1:31:1 | Group |
| comments.kt:4:1:11:3 | /**\n * A group of *members*.\n *\n * This class has no useful logic; it's just a documentation example.\n *\n * @property name the name of this group.\n * @constructor Creates an empty group.\n */ | comments.kt:12:1:31:1 | Group |
@@ -23,19 +19,9 @@ commentOwners
| comments.kt:19:5:22:7 | /**\n * Adds a [member] to this group.\n * @return the new size of the group.\n */ | comments.kt:23:5:26:5 | add |
| comments.kt:35:5:35:34 | /** Medium is in the middle */ | comments.kt:36:5:36:14 | Medium |
| comments.kt:37:5:37:23 | /** This is high */ | comments.kt:38:5:38:11 | High |
| comments.kt:42:5:44:7 | /**\n * A variable.\n */ | comments.kt:45:5:45:13 | int a |
| comments.kt:42:5:44:6 | /**\n * A variable.\n */ | comments.kt:45:5:45:13 | int a |
| comments.kt:48:1:50:3 | /**\n * A type alias comment\n */ | comments.kt:51:1:51:24 | MyType |
| comments.kt:54:5:56:7 | /**\n * An init block comment\n */ | comments.kt:53:1:58:1 | InitBlock |
| comments.kt:61:5:63:7 | /**\n * A prop comment\n */ | comments.kt:64:5:68:17 | prop |
| comments.kt:65:9:67:11 | /**\n * An accessor comment\n */ | comments.kt:68:9:68:17 | getProp |
| comments.kt:71:9:73:11 | /**\n * An anonymous function comment\n */ | comments.kt:70:5:76:10 | getL |
| comments.kt:71:9:73:11 | /**\n * An anonymous function comment\n */ | comments.kt:70:5:76:10 | l |
| comments.kt:71:9:73:11 | /**\n * An anonymous function comment\n */ | comments.kt:70:5:76:10 | l |
| comments.kt:79:9:81:11 | /**\n * A local function comment\n */ | comments.kt:82:9:82:24 | localFn |
commentNoOwners
| comments.kt:1:1:1:25 | /** Kdoc with no owner */ |
| comments.kt:24:9:24:25 | // A line comment |
| comments.kt:28:5:30:6 | /*\n A block comment\n */ |
commentSections
| comments.kt:1:1:1:25 | /** Kdoc with no owner */ | Kdoc with no owner |
| comments.kt:4:1:11:3 | /**\n * A group of *members*.\n *\n * This class has no useful logic; it's just a documentation example.\n *\n * @property name the name of this group.\n * @constructor Creates an empty group.\n */ | A group of *members*.\n\nThis class has no useful logic; it's just a documentation example.\n\n |
@@ -45,22 +31,14 @@ commentSections
| comments.kt:19:5:22:7 | /**\n * Adds a [member] to this group.\n * @return the new size of the group.\n */ | Adds a [member] to this group.\n |
| comments.kt:35:5:35:34 | /** Medium is in the middle */ | Medium is in the middle |
| comments.kt:37:5:37:23 | /** This is high */ | This is high |
| comments.kt:42:5:44:7 | /**\n * A variable.\n */ | A variable. |
| comments.kt:42:5:44:6 | /**\n * A variable.\n */ | A variable. |
| comments.kt:48:1:50:3 | /**\n * A type alias comment\n */ | A type alias comment |
| comments.kt:54:5:56:7 | /**\n * An init block comment\n */ | An init block comment |
| comments.kt:61:5:63:7 | /**\n * A prop comment\n */ | A prop comment |
| comments.kt:65:9:67:11 | /**\n * An accessor comment\n */ | An accessor comment |
| comments.kt:71:9:73:11 | /**\n * An anonymous function comment\n */ | An anonymous function comment |
| comments.kt:79:9:81:11 | /**\n * A local function comment\n */ | A local function comment |
commentSectionContents
| A group of *members*.\n\nThis class has no useful logic; it's just a documentation example.\n\n | A group of *members*.\n\nThis class has no useful logic; it's just a documentation example.\n\n |
| A local function comment | A local function comment |
| A prop comment | A prop comment |
| A type alias comment | A type alias comment |
| A variable. | A variable. |
| Adds a [member] to this group.\n | Adds a [member] to this group.\n |
| An accessor comment | An accessor comment |
| An anonymous function comment | An anonymous function comment |
| An init block comment | An init block comment |
| Creates an empty group. | Creates an empty group. |
| Kdoc with no owner | Kdoc with no owner |

View File

@@ -41,7 +41,7 @@ enum class Severity(val sev: Int) {
fun fn1() {
/**
* A variable.
*/
*/
val a = 1
}
@@ -56,29 +56,3 @@ class InitBlock {
*/
init { }
}
class X {
/**
* A prop comment
*/
val prop: Int
/**
* An accessor comment
*/
get() = 5
val l: Lazy<Int> = lazy(
/**
* An anonymous function comment
*/
fun(): Int {
return 5
})
fun fn() {
/**
* A local function comment
*/
fun localFn() {}
}
}

View File

@@ -4,8 +4,6 @@ query predicate comments(KtComment c, string s) { c.getText() = s }
query predicate commentOwners(KtComment c, Top t) { c.getOwner() = t }
query predicate commentNoOwners(KtComment c) { not exists(c.getOwner()) }
query predicate commentSections(KtComment c, KtCommentSection s) { c.getSections() = s }
query predicate commentSectionContents(KtCommentSection s, string c) { s.getContent() = c }

View File

@@ -4,17 +4,17 @@ class ListFlowTest {
fun test(l: MutableList<String>) {
l[0] = taint("a")
sink(l) // $ hasTaintFlow=a
sink(l[0]) // $ hasValueFlow=a
sink(l)
sink(l[0])
for (s in l) {
sink(s) // $ hasValueFlow=a
sink(s)
}
val a = arrayOf(taint("b"), "c")
sink(a) // $ hasTaintFlow=b
sink(a[0]) // $ hasValueFlow=b
val a = arrayOf(taint("a"), "b")
sink(a)
sink(a[0])
for (s in a) {
sink(s) // $ hasValueFlow=b
sink(s)
}
}
}

View File

@@ -1,5 +1,6 @@
| test.kt:28:16:28:21 | getSecond(...) | Unexpected result: hasTaintFlow=a |
| test.kt:35:16:35:27 | component1(...) | Unexpected result: hasTaintFlow=d |
| test.kt:41:17:41:22 | getSecond(...) | Unexpected result: hasTaintFlow=e |
| test.kt:53:17:53:24 | getDuration(...) | Unexpected result: hasTaintFlow=f |
| test.kt:58:18:58:29 | component2(...) | Unexpected result: hasTaintFlow=g |
| list.kt:6:23:6:23 | a | list.kt:7:14:7:14 | l |
| list.kt:6:23:6:23 | a | list.kt:8:14:8:17 | get(...) |
| list.kt:6:23:6:23 | a | list.kt:10:18:10:18 | s |
| list.kt:13:32:13:32 | a | list.kt:14:14:14:14 | a |
| list.kt:13:32:13:32 | a | list.kt:15:14:15:17 | ...[...] |
| list.kt:13:32:13:32 | a | list.kt:17:18:17:18 | s |

View File

@@ -1,75 +0,0 @@
import kotlin.time.Duration
import kotlin.time.ExperimentalTime
import kotlin.time.TimedValue
class Test {
fun <T> taint(t: T) = t
fun sink(a: Any) {}
@OptIn(ExperimentalTime::class)
fun test(b: ByteArray,
f: kotlin.io.FileTreeWalk,
c1: CharArray,
c2: CharArray,
c3: CharArray,) {
sink(taint(b).copyOf()) // $ hasTaintFlow
sink(taint(f).maxDepth(1)) // $ hasTaintFlow
val sb = StringBuilder()
sink(sb.insertRange(0, taint(c1), 0, 0)) // $ hasTaintFlow
sink(sb) // $ hasTaintFlow
sink(taint(c2) + c3) // $ hasTaintFlow
val p = Pair(taint("a"), "")
sink(p) // $ hasTaintFlow=a
sink(p.component1()) // $ hasTaintFlow=a
sink(p.second)
sink(taint("b").capitalize()) // $ hasTaintFlow=b
sink(taint("c").replaceFirstChar { _ -> 'x' }) // $ hasTaintFlow=c
val t = Triple("", taint("d"), "")
sink(t) // $ hasTaintFlow=d
sink(t.component1())
sink(t.second) // $ hasTaintFlow=d
val p1 = taint("e") to ""
sink(p1) // $ hasTaintFlow=e
sink(p1.component1()) // $ hasTaintFlow=e
sink(p1.second)
val l = p.toList()
sink(l) // $ hasTaintFlow=a
sink(l[0]) // $ hasTaintFlow=a
for (s in l) {
sink(s) // $ hasTaintFlow=a
}
val tv = TimedValue(taint("f"), Duration.parse(""))
sink(tv) // $ hasTaintFlow=f
sink(tv.component1()) // $ hasTaintFlow=f
sink(tv.duration)
val mg0 = MatchGroup(taint("g"), IntRange(0, 10))
sink(mg0) // $ hasTaintFlow=g
sink(mg0.value) // $ hasTaintFlow=g
sink(mg0.component2())
val iv = IndexedValue<String>(5, taint("h"))
sink(iv) // $ hasTaintFlow=h
sink(iv.index)
sink(iv.component2()) // $ hasTaintFlow=h
val strings = arrayOf("", taint("i"))
sink(strings.withIndex()) // $ hasTaintFlow=i
sink(strings.withIndex().toList()) // $ hasTaintFlow=i
sink(strings.withIndex().toList()[0].value) // $ hasTaintFlow=i
sink(strings.withIndex().toList()[0].index)
for (x in strings.withIndex()) {
sink(x.value) // $ hasTaintFlow=i
sink(x.index)
}
}
}

View File

@@ -1,2 +1,19 @@
import java
import TestUtilities.InlineFlowTest
import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.dataflow.ExternalFlow
class Conf extends TaintTracking::Configuration {
Conf() { this = "qltest:mad-summaries" }
override predicate isSource(DataFlow::Node n) {
n.asExpr().(Argument).getCall().getCallee().hasName("taint")
}
override predicate isSink(DataFlow::Node n) {
n.asExpr().(Argument).getCall().getCallee().hasName("sink")
}
}
from DataFlow::Node src, DataFlow::Node sink, Conf conf
where conf.hasFlow(src, sink)
select src, sink

View File

@@ -30,74 +30,30 @@ test.kt:
# 4| -1: [VarAccess] mt
# 4| 0: [IntegerLiteral] 1
# 4| 1: [IntegerLiteral] 2
# 6| 3: [ExprStmt] <Expr>;
# 6| 0: [ImplicitCoercionToUnitExpr] <implicit coercion to unit>
# 6| 0: [TypeAccess] Unit
# 6| 1: [MethodAccess] set(...)
# 6| -1: [TypeAccess] TestKt
# 6| 0: [VarAccess] arr
# 6| 1: [IntegerLiteral] 1
# 6| 2: [IntegerLiteral] 2
# 6| 3: [IntegerLiteral] 3
# 7| 4: [ExprStmt] <Expr>;
# 7| 0: [ImplicitCoercionToUnitExpr] <implicit coercion to unit>
# 7| 0: [TypeAccess] Unit
# 7| 1: [MethodAccess] set(...)
# 7| -1: [TypeAccess] TestKt
# 7| 0: [VarAccess] arr
# 7| 1: [IntegerLiteral] 1
# 7| 2: [ClassInstanceExpr] new C(...)
# 7| -3: [TypeAccess] C
# 10| 2: [ExtensionMethod] get
# 10| 3: [TypeAccess] String
# 7| 2: [ExtensionMethod] get
# 7| 3: [TypeAccess] String
#-----| 4: (Parameters)
# 10| 0: [Parameter] <this>
# 10| 0: [TypeAccess] byte[]
# 10| 1: [Parameter] i
# 10| 0: [TypeAccess] int
# 10| 2: [Parameter] j
# 10| 0: [TypeAccess] int
# 7| 0: [Parameter] <this>
# 7| 0: [TypeAccess] byte[]
# 7| 1: [Parameter] i
# 7| 0: [TypeAccess] int
# 7| 2: [Parameter] j
# 7| 0: [TypeAccess] int
# 7| 5: [BlockStmt] { ... }
# 7| 0: [ReturnStmt] return ...
# 7| 0: [StringLiteral]
# 10| 2: [Class] C
# 10| 1: [Constructor] C
# 10| 5: [BlockStmt] { ... }
# 10| 0: [ReturnStmt] return ...
# 10| 0: [StringLiteral]
# 11| 3: [ExtensionMethod] set
# 10| 0: [SuperConstructorInvocationStmt] super(...)
# 10| 1: [BlockStmt] { ... }
# 11| 2: [Method] get
# 11| 3: [TypeAccess] String
#-----| 4: (Parameters)
# 11| 0: [Parameter] <this>
# 11| 0: [TypeAccess] byte[]
# 11| 1: [Parameter] i
# 11| 0: [Parameter] i
# 11| 0: [TypeAccess] int
# 11| 2: [Parameter] j
# 11| 0: [TypeAccess] int
# 11| 3: [Parameter] k
# 11| 1: [Parameter] j
# 11| 0: [TypeAccess] int
# 11| 5: [BlockStmt] { ... }
# 11| 0: [ReturnStmt] return ...
# 11| 0: [StringLiteral]
# 12| 4: [ExtensionMethod] set
# 12| 3: [TypeAccess] String
#-----| 4: (Parameters)
# 12| 0: [Parameter] <this>
# 12| 0: [TypeAccess] byte[]
# 12| 1: [Parameter] i
# 12| 0: [TypeAccess] int
# 12| 2: [Parameter] c
# 12| 0: [TypeAccess] C
# 12| 5: [BlockStmt] { ... }
# 12| 0: [ReturnStmt] return ...
# 12| 0: [StringLiteral]
# 15| 2: [Class] C
# 15| 1: [Constructor] C
# 15| 5: [BlockStmt] { ... }
# 15| 0: [SuperConstructorInvocationStmt] super(...)
# 15| 1: [BlockStmt] { ... }
# 16| 2: [Method] get
# 16| 3: [TypeAccess] String
#-----| 4: (Parameters)
# 16| 0: [Parameter] i
# 16| 0: [TypeAccess] int
# 16| 1: [Parameter] j
# 16| 0: [TypeAccess] int
# 16| 5: [BlockStmt] { ... }
# 16| 0: [ReturnStmt] return ...
# 16| 0: [StringLiteral]

View File

@@ -2,14 +2,9 @@ fun fn(arr: ByteArray, mt: C) {
arr[1]
arr[1, 2]
mt[1, 2]
arr[1, 2] = 3
arr[1] = C()
}
public operator fun ByteArray.get(i: Int, j: Int) = ""
public operator fun ByteArray.set(i: Int, j: Int, k: Int) = ""
public operator fun ByteArray.set(i: Int, c: C) = ""
public class C {

View File

@@ -1,11 +1,9 @@
diag
#select
| test.kt:1:84:1:89 | length(...) | java.lang.CharSequence | length |
| test.kt:1:97:1:100 | size(...) | java.util.Collection<String> | size |
| test.kt:1:108:1:111 | size(...) | java.util.Map<String,String> | size |
| test.kt:1:119:1:122 | keySet(...) | java.util.Map<String,String> | keySet |
| test.kt:1:124:1:127 | size(...) | java.util.Set<String> | size |
| test.kt:1:135:1:140 | values(...) | java.util.Map<String,String> | values |
| test.kt:1:142:1:145 | size(...) | java.util.Collection<String> | size |
| test.kt:1:153:1:159 | entrySet(...) | java.util.Map<String,String> | entrySet |
| test.kt:1:161:1:164 | size(...) | java.util.Set<Entry<String,String>> | size |
| test.kt:1:84:1:89 | length(...) | length |
| test.kt:1:97:1:100 | size(...) | size |
| test.kt:1:108:1:111 | size(...) | size |
| test.kt:1:119:1:122 | keySet(...) | keySet |
| test.kt:1:124:1:127 | size(...) | size |
| test.kt:1:135:1:140 | values(...) | values |
| test.kt:1:142:1:145 | size(...) | size |
| test.kt:1:153:1:159 | entrySet(...) | entrySet |
| test.kt:1:161:1:164 | size(...) | size |

View File

@@ -1,7 +1,4 @@
import java
import semmle.code.java.Diagnostics
from MethodAccess ma
select ma, ma.getCallee().getDeclaringType().getQualifiedName(), ma.getCallee().getName()
query predicate diag(Diagnostic d) { any() }
select ma, ma.getCallee().toString()

View File

@@ -1,697 +0,0 @@
package generatedtest;
import android.content.ContentProvider;
import android.content.ContentProviderClient;
import android.content.ContentProviderOperation;
import android.content.ContentProviderResult;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.CharArrayBuffer;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcel;
import java.util.ArrayList;
import java.util.List;
// Test case generated by GenerateFlowTestCase.ql
public class Test {
Object getMapKeyDefault(Object container) {
return null;
}
Object getMapValueDefault(Object container) {
return null;
}
Object newWithMapKeyDefault(Object element) {
return null;
}
Object newWithMapValueDefault(Object element) {
return null;
}
Object source() {
return null;
}
void sink(Object o) {}
public void test() throws Exception {
{
// "android.content;ContentProviderClient;true;applyBatch;;;Argument[-1];ReturnValue;taint;manual"
ContentProviderResult[] out = null;
ContentProviderClient in = (ContentProviderClient) source();
out = in.applyBatch(null);
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentProviderClient;true;applyBatch;;;Argument[-1];ReturnValue;taint;manual"
ContentProviderResult[] out = null;
ContentProviderClient in = (ContentProviderClient) source();
out = in.applyBatch(null, null);
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentProviderClient;true;call;;;Argument[-1];ReturnValue;taint;manual"
Bundle out = null;
ContentProviderClient in = (ContentProviderClient) source();
out = in.call(null, null, null);
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentProviderClient;true;call;;;Argument[-1];ReturnValue;taint;manual"
Bundle out = null;
ContentProviderClient in = (ContentProviderClient) source();
out = in.call(null, null, null, null);
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentProviderClient;true;canonicalize;;;Argument[-1];ReturnValue;taint;manual"
Uri out = null;
ContentProviderClient in = (ContentProviderClient) source();
out = in.canonicalize(null);
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentProviderClient;true;getLocalContentProvider;;;Argument[-1];ReturnValue;taint;manual"
ContentProvider out = null;
ContentProviderClient in = (ContentProviderClient) source();
out = in.getLocalContentProvider();
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentProviderClient;true;getStreamTypes;;;Argument[-1];ReturnValue;taint;manual"
String[] out = null;
ContentProviderClient in = (ContentProviderClient) source();
out = in.getStreamTypes(null, null);
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentProviderClient;true;insert;;;Argument[-1];ReturnValue;taint;manual"
Uri out = null;
ContentProviderClient in = (ContentProviderClient) source();
out = in.insert(null, null);
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentProviderClient;true;insert;;;Argument[-1];ReturnValue;taint;manual"
Uri out = null;
ContentProviderClient in = (ContentProviderClient) source();
out = in.insert(null, null, null);
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentProviderClient;true;query;;;Argument[-1];ReturnValue;taint;manual"
Cursor out = null;
ContentProviderClient in = (ContentProviderClient) source();
out = in.query(null, null, null, null);
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentProviderClient;true;query;;;Argument[-1];ReturnValue;taint;manual"
Cursor out = null;
ContentProviderClient in = (ContentProviderClient) source();
out = in.query(null, null, null, null, null);
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentProviderClient;true;query;;;Argument[-1];ReturnValue;taint;manual"
Cursor out = null;
ContentProviderClient in = (ContentProviderClient) source();
out = in.query(null, null, null, null, null, null);
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentProviderClient;true;uncanonicalize;;;Argument[-1];ReturnValue;taint;manual"
Uri out = null;
ContentProviderClient in = (ContentProviderClient) source();
out = in.uncanonicalize(null);
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentProviderOperation$Builder;false;build;;;Argument[-1];ReturnValue;taint;manual"
ContentProviderOperation out = null;
ContentProviderOperation.Builder in = (ContentProviderOperation.Builder) source();
out = in.build();
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentProviderOperation$Builder;false;withExceptionAllowed;;;Argument[-1];ReturnValue;value;manual"
ContentProviderOperation.Builder out = null;
ContentProviderOperation.Builder in = (ContentProviderOperation.Builder) source();
out = in.withExceptionAllowed(false);
sink(out); // $ hasValueFlow
}
{
// "android.content;ContentProviderOperation$Builder;false;withExpectedCount;;;Argument[-1];ReturnValue;value;manual"
ContentProviderOperation.Builder out = null;
ContentProviderOperation.Builder in = (ContentProviderOperation.Builder) source();
out = in.withExpectedCount(0);
sink(out); // $ hasValueFlow
}
{
// "android.content;ContentProviderOperation$Builder;false;withExtra;;;Argument[-1];ReturnValue;value;manual"
ContentProviderOperation.Builder out = null;
ContentProviderOperation.Builder in = (ContentProviderOperation.Builder) source();
out = in.withExtra(null, null);
sink(out); // $ hasValueFlow
}
{
// "android.content;ContentProviderOperation$Builder;false;withExtraBackReference;;;Argument[-1];ReturnValue;value;manual"
ContentProviderOperation.Builder out = null;
ContentProviderOperation.Builder in = (ContentProviderOperation.Builder) source();
out = in.withExtraBackReference(null, 0);
sink(out); // $ hasValueFlow
}
{
// "android.content;ContentProviderOperation$Builder;false;withExtraBackReference;;;Argument[-1];ReturnValue;value;manual"
ContentProviderOperation.Builder out = null;
ContentProviderOperation.Builder in = (ContentProviderOperation.Builder) source();
out = in.withExtraBackReference(null, 0, null);
sink(out); // $ hasValueFlow
}
{
// "android.content;ContentProviderOperation$Builder;false;withExtras;;;Argument[-1];ReturnValue;value;manual"
ContentProviderOperation.Builder out = null;
ContentProviderOperation.Builder in = (ContentProviderOperation.Builder) source();
out = in.withExtras(null);
sink(out); // $ hasValueFlow
}
{
// "android.content;ContentProviderOperation$Builder;false;withSelection;;;Argument[-1];ReturnValue;value;manual"
ContentProviderOperation.Builder out = null;
ContentProviderOperation.Builder in = (ContentProviderOperation.Builder) source();
out = in.withSelection(null, null);
sink(out); // $ hasValueFlow
}
{
// "android.content;ContentProviderOperation$Builder;false;withSelectionBackReference;;;Argument[-1];ReturnValue;value;manual"
ContentProviderOperation.Builder out = null;
ContentProviderOperation.Builder in = (ContentProviderOperation.Builder) source();
out = in.withSelectionBackReference(0, 0);
sink(out); // $ hasValueFlow
}
{
// "android.content;ContentProviderOperation$Builder;false;withSelectionBackReference;;;Argument[-1];ReturnValue;value;manual"
ContentProviderOperation.Builder out = null;
ContentProviderOperation.Builder in = (ContentProviderOperation.Builder) source();
out = in.withSelectionBackReference(0, 0, null);
sink(out); // $ hasValueFlow
}
{
// "android.content;ContentProviderOperation$Builder;false;withValue;;;Argument[-1];ReturnValue;value;manual"
ContentProviderOperation.Builder out = null;
ContentProviderOperation.Builder in = (ContentProviderOperation.Builder) source();
out = in.withValue(null, null);
sink(out); // $ hasValueFlow
}
{
// "android.content;ContentProviderOperation$Builder;false;withValueBackReference;;;Argument[-1];ReturnValue;value;manual"
ContentProviderOperation.Builder out = null;
ContentProviderOperation.Builder in = (ContentProviderOperation.Builder) source();
out = in.withValueBackReference(null, 0);
sink(out); // $ hasValueFlow
}
{
// "android.content;ContentProviderOperation$Builder;false;withValueBackReference;;;Argument[-1];ReturnValue;value;manual"
ContentProviderOperation.Builder out = null;
ContentProviderOperation.Builder in = (ContentProviderOperation.Builder) source();
out = in.withValueBackReference(null, 0, null);
sink(out); // $ hasValueFlow
}
{
// "android.content;ContentProviderOperation$Builder;false;withValues;;;Argument[-1];ReturnValue;value;manual"
ContentProviderOperation.Builder out = null;
ContentProviderOperation.Builder in = (ContentProviderOperation.Builder) source();
out = in.withValues(null);
sink(out); // $ hasValueFlow
}
{
// "android.content;ContentProviderOperation$Builder;false;withYieldAllowed;;;Argument[-1];ReturnValue;value;manual"
ContentProviderOperation.Builder out = null;
ContentProviderOperation.Builder in = (ContentProviderOperation.Builder) source();
out = in.withYieldAllowed(false);
sink(out); // $ hasValueFlow
}
{
// "android.content;ContentProviderOperation;false;apply;;;Argument[-1];ReturnValue;taint;manual"
ContentProviderResult out = null;
ContentProviderOperation in = (ContentProviderOperation) source();
out = in.apply(null, null, 0);
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentProviderOperation;false;apply;;;Argument[0];ReturnValue;taint;manual"
ContentProviderResult out = null;
ContentProvider in = (ContentProvider) source();
ContentProviderOperation instance = null;
out = instance.apply(in, null, 0);
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentProviderOperation;false;getUri;;;Argument[-1];ReturnValue;taint;manual"
Uri out = null;
ContentProviderOperation in = (ContentProviderOperation) source();
out = in.getUri();
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentProviderOperation;false;newAssertQuery;;;Argument[0];ReturnValue;taint;manual"
ContentProviderOperation.Builder out = null;
Uri in = (Uri) source();
out = ContentProviderOperation.newAssertQuery(in);
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentProviderOperation;false;newCall;;;Argument[0];ReturnValue;taint;manual"
ContentProviderOperation.Builder out = null;
Uri in = (Uri) source();
out = ContentProviderOperation.newCall(in, null, null);
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentProviderOperation;false;newDelete;;;Argument[0];ReturnValue;taint;manual"
ContentProviderOperation.Builder out = null;
Uri in = (Uri) source();
out = ContentProviderOperation.newDelete(in);
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentProviderOperation;false;newInsert;;;Argument[0];ReturnValue;taint;manual"
ContentProviderOperation.Builder out = null;
Uri in = (Uri) source();
out = ContentProviderOperation.newInsert(in);
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentProviderOperation;false;newUpdate;;;Argument[0];ReturnValue;taint;manual"
ContentProviderOperation.Builder out = null;
Uri in = (Uri) source();
out = ContentProviderOperation.newUpdate(in);
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentProviderOperation;false;resolveExtrasBackReferences;;;Argument[0];ReturnValue;taint;manual"
Bundle out = null;
ContentProviderResult[] in = (ContentProviderResult[]) source();
ContentProviderOperation instance = null;
out = instance.resolveExtrasBackReferences(in, 0);
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentProviderOperation;false;resolveSelectionArgsBackReferences;;;Argument[0];ReturnValue;taint;manual"
String[] out = null;
ContentProviderResult[] in = (ContentProviderResult[]) source();
ContentProviderOperation instance = null;
out = instance.resolveSelectionArgsBackReferences(in, 0);
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentProviderOperation;false;resolveValueBackReferences;;;Argument[0];ReturnValue;taint;manual"
ContentValues out = null;
ContentProviderResult[] in = (ContentProviderResult[]) source();
ContentProviderOperation instance = null;
out = instance.resolveValueBackReferences(in, 0);
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentProviderResult;false;ContentProviderResult;(Bundle);;Argument[0];Argument[-1].Field[android.content.ContentProviderResult.extras];value;manual"
ContentProviderResult out = null;
Bundle in = (Bundle) source();
out = new ContentProviderResult(in);
sink(out.extras); // $ hasValueFlow
}
{
// "android.content;ContentProviderResult;false;ContentProviderResult;(Parcel);;Argument[0];Argument[-1];taint;manual"
ContentProviderResult out = null;
Parcel in = (Parcel) source();
out = new ContentProviderResult(in);
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentProviderResult;false;ContentProviderResult;(Throwable);;Argument[0];Argument[-1].Field[android.content.ContentProviderResult.exception];value;manual"
ContentProviderResult out = null;
Throwable in = (Throwable) source();
out = new ContentProviderResult(in);
sink(out.exception); // $ hasValueFlow
}
{
// "android.content;ContentProviderResult;false;ContentProviderResult;(Uri);;Argument[0];Argument[-1].Field[android.content.ContentProviderResult.uri];value;manual"
ContentProviderResult out = null;
Uri in = (Uri) source();
out = new ContentProviderResult(in);
sink(out.uri); // $ hasValueFlow
}
{
// "android.content;ContentResolver;true;acquireContentProviderClient;;;Argument[0];ReturnValue;taint;manual"
ContentProviderClient out = null;
String in = (String) source();
ContentResolver instance = null;
out = instance.acquireContentProviderClient(in);
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentResolver;true;acquireContentProviderClient;;;Argument[0];ReturnValue;taint;manual"
ContentProviderClient out = null;
Uri in = (Uri) source();
ContentResolver instance = null;
out = instance.acquireContentProviderClient(in);
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentResolver;true;acquireUnstableContentProviderClient;;;Argument[0];ReturnValue;taint;manual"
ContentProviderClient out = null;
String in = (String) source();
ContentResolver instance = null;
out = instance.acquireUnstableContentProviderClient(in);
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentResolver;true;acquireUnstableContentProviderClient;;;Argument[0];ReturnValue;taint;manual"
ContentProviderClient out = null;
Uri in = (Uri) source();
ContentResolver instance = null;
out = instance.acquireUnstableContentProviderClient(in);
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentResolver;true;applyBatch;;;Argument[1];ReturnValue;taint;manual"
ContentProviderResult[] out = null;
ArrayList in = (ArrayList) source();
ContentResolver instance = null;
out = instance.applyBatch(null, in);
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentResolver;true;call;;;Argument[0];ReturnValue;taint;manual"
Bundle out = null;
String in = (String) source();
ContentResolver instance = null;
out = instance.call(in, (String) null, (String) null, (Bundle) null);
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentResolver;true;call;;;Argument[0];ReturnValue;taint;manual"
Bundle out = null;
Uri in = (Uri) source();
ContentResolver instance = null;
out = instance.call(in, (String) null, (String) null, (Bundle) null);
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentResolver;true;canonicalize;;;Argument[0];ReturnValue;taint;manual"
Uri out = null;
Uri in = (Uri) source();
ContentResolver instance = null;
out = instance.canonicalize(in);
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentResolver;true;getStreamTypes;;;Argument[0];ReturnValue;taint;manual"
String[] out = null;
Uri in = (Uri) source();
ContentResolver instance = null;
out = instance.getStreamTypes(in, null);
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentResolver;true;getType;;;Argument[0];ReturnValue;taint;manual"
String out = null;
Uri in = (Uri) source();
ContentResolver instance = null;
out = instance.getType(in);
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentResolver;true;insert;;;Argument[0];ReturnValue;taint;manual"
Uri out = null;
Uri in = (Uri) source();
ContentResolver instance = null;
out = instance.insert(in, null);
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentResolver;true;insert;;;Argument[0];ReturnValue;taint;manual"
Uri out = null;
Uri in = (Uri) source();
ContentResolver instance = null;
out = instance.insert(in, null, null);
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentResolver;true;query;;;Argument[0];ReturnValue;taint;manual"
Cursor out = null;
Uri in = (Uri) source();
ContentResolver instance = null;
out = instance.query(in, null, null, null);
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentResolver;true;query;;;Argument[0];ReturnValue;taint;manual"
Cursor out = null;
Uri in = (Uri) source();
ContentResolver instance = null;
out = instance.query(in, null, null, null, null);
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentResolver;true;query;;;Argument[0];ReturnValue;taint;manual"
Cursor out = null;
Uri in = (Uri) source();
ContentResolver instance = null;
out = instance.query(in, null, null, null, null, null);
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentResolver;true;uncanonicalize;;;Argument[0];ReturnValue;taint;manual"
Uri out = null;
Uri in = (Uri) source();
ContentResolver instance = null;
out = instance.uncanonicalize(in);
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentResolver;true;wrap;;;Argument[0];ReturnValue;taint;manual"
ContentResolver out = null;
ContentProvider in = (ContentProvider) source();
out = ContentResolver.wrap(in);
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentResolver;true;wrap;;;Argument[0];ReturnValue;taint;manual"
ContentResolver out = null;
ContentProviderClient in = (ContentProviderClient) source();
out = ContentResolver.wrap(in);
sink(out); // $ hasTaintFlow
}
{
// "android.content;ContentValues;false;put;;;Argument[0];Argument[-1].MapKey;value;manual"
ContentValues out = null;
String in = (String) source();
out.put(in, (Boolean) null);
sink(getMapKeyDefault(out)); // $ hasValueFlow
}
{
// "android.content;ContentValues;false;put;;;Argument[0];Argument[-1].MapKey;value;manual"
ContentValues out = null;
String in = (String) source();
out.put(in, (Byte) null);
sink(getMapKeyDefault(out)); // $ hasValueFlow
}
{
// "android.content;ContentValues;false;put;;;Argument[0];Argument[-1].MapKey;value;manual"
ContentValues out = null;
String in = (String) source();
out.put(in, (Double) null);
sink(getMapKeyDefault(out)); // $ hasValueFlow
}
{
// "android.content;ContentValues;false;put;;;Argument[0];Argument[-1].MapKey;value;manual"
ContentValues out = null;
String in = (String) source();
out.put(in, (Float) null);
sink(getMapKeyDefault(out)); // $ hasValueFlow
}
{
// "android.content;ContentValues;false;put;;;Argument[0];Argument[-1].MapKey;value;manual"
ContentValues out = null;
String in = (String) source();
out.put(in, (Integer) null);
sink(getMapKeyDefault(out)); // $ hasValueFlow
}
{
// "android.content;ContentValues;false;put;;;Argument[0];Argument[-1].MapKey;value;manual"
ContentValues out = null;
String in = (String) source();
out.put(in, (Long) null);
sink(getMapKeyDefault(out)); // $ hasValueFlow
}
{
// "android.content;ContentValues;false;put;;;Argument[0];Argument[-1].MapKey;value;manual"
ContentValues out = null;
String in = (String) source();
out.put(in, (Short) null);
sink(getMapKeyDefault(out)); // $ hasValueFlow
}
{
// "android.content;ContentValues;false;put;;;Argument[0];Argument[-1].MapKey;value;manual"
ContentValues out = null;
String in = (String) source();
out.put(in, (String) null);
sink(getMapKeyDefault(out)); // $ hasValueFlow
}
{
// "android.content;ContentValues;false;put;;;Argument[0];Argument[-1].MapKey;value;manual"
ContentValues out = null;
String in = (String) source();
out.put(in, (byte[]) null);
sink(getMapKeyDefault(out)); // $ hasValueFlow
}
{
// "android.content;ContentValues;false;put;;;Argument[1];Argument[-1].MapValue;value;manual"
ContentValues out = null;
Boolean in = (Boolean) source();
out.put((String) null, in);
sink(getMapValueDefault(out)); // $ hasValueFlow
}
{
// "android.content;ContentValues;false;put;;;Argument[1];Argument[-1].MapValue;value;manual"
ContentValues out = null;
Byte in = (Byte) source();
out.put((String) null, in);
sink(getMapValueDefault(out)); // $ hasValueFlow
}
{
// "android.content;ContentValues;false;put;;;Argument[1];Argument[-1].MapValue;value;manual"
ContentValues out = null;
Double in = (Double) source();
out.put((String) null, in);
sink(getMapValueDefault(out)); // $ hasValueFlow
}
{
// "android.content;ContentValues;false;put;;;Argument[1];Argument[-1].MapValue;value;manual"
ContentValues out = null;
Float in = (Float) source();
out.put((String) null, in);
sink(getMapValueDefault(out)); // $ hasValueFlow
}
{
// "android.content;ContentValues;false;put;;;Argument[1];Argument[-1].MapValue;value;manual"
ContentValues out = null;
Integer in = (Integer) source();
out.put((String) null, in);
sink(getMapValueDefault(out)); // $ hasValueFlow
}
{
// "android.content;ContentValues;false;put;;;Argument[1];Argument[-1].MapValue;value;manual"
ContentValues out = null;
Long in = (Long) source();
out.put((String) null, in);
sink(getMapValueDefault(out)); // $ hasValueFlow
}
{
// "android.content;ContentValues;false;put;;;Argument[1];Argument[-1].MapValue;value;manual"
ContentValues out = null;
Short in = (Short) source();
out.put((String) null, in);
sink(getMapValueDefault(out)); // $ hasValueFlow
}
{
// "android.content;ContentValues;false;put;;;Argument[1];Argument[-1].MapValue;value;manual"
ContentValues out = null;
String in = (String) source();
out.put((String) null, in);
sink(getMapValueDefault(out)); // $ hasValueFlow
}
{
// "android.content;ContentValues;false;put;;;Argument[1];Argument[-1].MapValue;value;manual"
ContentValues out = null;
byte[] in = (byte[]) source();
out.put((String) null, in);
sink(getMapValueDefault(out)); // $ hasValueFlow
}
{
// "android.content;ContentValues;false;putAll;;;Argument[0].MapKey;Argument[-1].MapKey;value;manual"
ContentValues out = null;
ContentValues in = (ContentValues) newWithMapKeyDefault(source());
out.putAll(in);
sink(getMapKeyDefault(out)); // $ hasValueFlow
}
{
// "android.content;ContentValues;false;putAll;;;Argument[0].MapValue;Argument[-1].MapValue;value;manual"
ContentValues out = null;
ContentValues in = (ContentValues) newWithMapValueDefault(source());
out.putAll(in);
sink(getMapValueDefault(out)); // $ hasValueFlow
}
{
// "android.database;Cursor;true;copyStringToBuffer;;;Argument[-1];Argument[1];taint;manual"
CharArrayBuffer out = null;
Cursor in = (Cursor) source();
in.copyStringToBuffer(0, out);
sink(out); // $ hasTaintFlow
}
{
// "android.database;Cursor;true;getBlob;;;Argument[-1];ReturnValue;taint;manual"
byte[] out = null;
Cursor in = (Cursor) source();
out = in.getBlob(0);
sink(out); // $ hasTaintFlow
}
{
// "android.database;Cursor;true;getColumnName;;;Argument[-1];ReturnValue;taint;manual"
String out = null;
Cursor in = (Cursor) source();
out = in.getColumnName(0);
sink(out); // $ hasTaintFlow
}
{
// "android.database;Cursor;true;getColumnNames;;;Argument[-1];ReturnValue;taint;manual"
String[] out = null;
Cursor in = (Cursor) source();
out = in.getColumnNames();
sink(out); // $ hasTaintFlow
}
{
// "android.database;Cursor;true;getExtras;;;Argument[-1];ReturnValue;taint;manual"
Bundle out = null;
Cursor in = (Cursor) source();
out = in.getExtras();
sink(out); // $ hasTaintFlow
}
{
// "android.database;Cursor;true;getNotificationUri;;;Argument[-1];ReturnValue;taint;manual"
Uri out = null;
Cursor in = (Cursor) source();
out = in.getNotificationUri();
sink(out); // $ hasTaintFlow
}
{
// "android.database;Cursor;true;getNotificationUris;;;Argument[-1];ReturnValue;taint;manual"
List out = null;
Cursor in = (Cursor) source();
out = in.getNotificationUris();
sink(out); // $ hasTaintFlow
}
{
// "android.database;Cursor;true;getString;;;Argument[-1];ReturnValue;taint;manual"
String out = null;
Cursor in = (Cursor) source();
out = in.getString(0);
sink(out); // $ hasTaintFlow
}
{
// "android.database;Cursor;true;respond;;;Argument[-1];ReturnValue;taint;manual"
Bundle out = null;
Cursor in = (Cursor) source();
out = in.respond(null);
sink(out); // $ hasTaintFlow
}
}
}

View File

@@ -1 +0,0 @@
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/google-android-9.0.0

View File

@@ -1,15 +0,0 @@
import java
import TestUtilities.InlineFlowTest
class SummaryModelTest extends SummaryModelCsv {
override predicate row(string row) {
row =
[
//"package;type;overrides;name;signature;ext;inputspec;outputspec;kind",
"generatedtest;Test;false;newWithMapValueDefault;(Object);;Argument[0];ReturnValue.MapValue;value;manual",
"generatedtest;Test;false;newWithMapKeyDefault;(Object);;Argument[0];ReturnValue.MapKey;value;manual",
"generatedtest;Test;false;getMapValueDefault;(Object);;Argument[0].MapValue;ReturnValue;value;manual",
"generatedtest;Test;false;getMapKeyDefault;(Object);;Argument[0].MapKey;ReturnValue;value;manual"
]
}
}

View File

@@ -2,7 +2,6 @@ package com.example.test;
import java.io.FileNotFoundException;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -218,28 +217,6 @@ public class ImplicitPendingIntentsTest {
}
public static void testPendingIntentInAnAlarm(Context ctx) {
AlarmManager aManager = (AlarmManager) ctx.getSystemService(Context.ALARM_SERVICE);
{
Intent baseIntent = new Intent();
PendingIntent pi = PendingIntent.getActivity(ctx, 0, baseIntent, 0);
aManager.set(0, 0, pi); // $hasImplicitPendingIntent
aManager.setAlarmClock(null, pi); // $hasImplicitPendingIntent
aManager.setAndAllowWhileIdle(0, 0, pi); // $hasImplicitPendingIntent
aManager.setExact(0, 0, pi); // $hasImplicitPendingIntent
aManager.setExactAndAllowWhileIdle(0, 0, pi); // $hasImplicitPendingIntent
aManager.setInexactRepeating(0, 0, 0, pi); // $hasImplicitPendingIntent
aManager.setRepeating(0, 0, 0, pi); // $hasImplicitPendingIntent
aManager.setWindow(0, 0, 0, pi); // $hasImplicitPendingIntent
}
{
Intent baseIntent = new Intent();
PendingIntent pi =
PendingIntent.getActivity(ctx, 0, baseIntent, PendingIntent.FLAG_IMMUTABLE); // Sanitizer
aManager.set(0, 0, pi); // Safe
}
}
static class TestActivity extends Activity {
@Override
public void onCreate(Bundle bundle) {

View File

@@ -1,54 +0,0 @@
// Generated automatically from android.app.AlarmManager for testing purposes
package android.app;
import android.app.PendingIntent;
import android.os.Handler;
import android.os.Parcel;
import android.os.Parcelable;
public class AlarmManager
{
public AlarmManager.AlarmClockInfo getNextAlarmClock(){ return null; }
public boolean canScheduleExactAlarms(){ return false; }
public static String ACTION_NEXT_ALARM_CLOCK_CHANGED = null;
public static String ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED = null;
public static int ELAPSED_REALTIME = 0;
public static int ELAPSED_REALTIME_WAKEUP = 0;
public static int RTC = 0;
public static int RTC_WAKEUP = 0;
public static long INTERVAL_DAY = 0;
public static long INTERVAL_FIFTEEN_MINUTES = 0;
public static long INTERVAL_HALF_DAY = 0;
public static long INTERVAL_HALF_HOUR = 0;
public static long INTERVAL_HOUR = 0;
public void cancel(AlarmManager.OnAlarmListener p0){}
public void cancel(PendingIntent p0){}
public void set(int p0, long p1, PendingIntent p2){}
public void set(int p0, long p1, String p2, AlarmManager.OnAlarmListener p3, Handler p4){}
public void setAlarmClock(AlarmManager.AlarmClockInfo p0, PendingIntent p1){}
public void setAndAllowWhileIdle(int p0, long p1, PendingIntent p2){}
public void setExact(int p0, long p1, PendingIntent p2){}
public void setExact(int p0, long p1, String p2, AlarmManager.OnAlarmListener p3, Handler p4){}
public void setExactAndAllowWhileIdle(int p0, long p1, PendingIntent p2){}
public void setInexactRepeating(int p0, long p1, long p2, PendingIntent p3){}
public void setRepeating(int p0, long p1, long p2, PendingIntent p3){}
public void setTime(long p0){}
public void setTimeZone(String p0){}
public void setWindow(int p0, long p1, long p2, PendingIntent p3){}
public void setWindow(int p0, long p1, long p2, String p3, AlarmManager.OnAlarmListener p4, Handler p5){}
static public class AlarmClockInfo implements Parcelable
{
protected AlarmClockInfo() {}
public AlarmClockInfo(long p0, PendingIntent p1){}
public PendingIntent getShowIntent(){ return null; }
public int describeContents(){ return 0; }
public long getTriggerTime(){ return 0; }
public static Parcelable.Creator<AlarmManager.AlarmClockInfo> CREATOR = null;
public void writeToParcel(Parcel p0, int p1){}
}
static public interface OnAlarmListener
{
void onAlarm();
}
}

View File

@@ -1,6 +1,6 @@
---
dependencies:
codeql/javascript-experimental-atm-model:
version: 0.2.0
dsp-testing/javascript-experimental-atm-model:
version: 0.0.117+2022-07-31-17h27m12s.orange-glass-s7gyz7ms.c105df16ee709495fb22500818b271fb47bb73008a593cb398c0dd4fe4ab437b
compiled: false
lockVersion: 1.0.0

View File

@@ -4,8 +4,8 @@ version: 0.3.3
suites: codeql-suites
defaultSuiteFile: codeql-suites/javascript-atm-code-scanning.qls
groups:
- javascript
- experimental
- javascript
- experimental
dependencies:
codeql/javascript-experimental-atm-lib: "*"
codeql/javascript-experimental-atm-model: "0.2.0"
codeql/javascript-experimental-atm-lib: "*"
dsp-testing/javascript-experimental-atm-model: 0.0.117+2022-07-31-17h27m12s.orange-glass-s7gyz7ms.c105df16ee709495fb22500818b271fb47bb73008a593cb398c0dd4fe4ab437b

View File

@@ -1495,7 +1495,7 @@ module API {
/** Gets the EntryPoint associated with this label. */
API::EntryPoint getEntryPoint() { result = e }
override string toString() { result = "entryPoint(\"" + e + "\")" }
override string toString() { result = "getASuccessor(Label::entryPoint(\"" + e + "\"))" }
}
/** A label that gets a promised value. */

View File

@@ -10,11 +10,6 @@ private import javascript
private import semmle.javascript.dataflow.TypeTracking
private import semmle.javascript.internal.CachedStages
/**
* An alias for `SourceNode`.
*/
class LocalSourceNode = SourceNode;
/**
* A source node for local data flow, that is, a node from which local data flow is tracked.
*

View File

@@ -72,8 +72,6 @@ private class Unit = Specific::Unit;
private module API = Specific::API;
private module DataFlow = Specific::DataFlow;
private import Specific::AccessPathSyntax
/** Module containing hooks for providing input data to be interpreted as a model. */
@@ -158,22 +156,6 @@ module ModelInput {
abstract predicate row(string row);
}
/**
* A unit class for adding additional type model rows from CodeQL models.
*/
class TypeModel extends Unit {
/**
* Gets a data-flow node that is a source of the type `package;type`.
*/
DataFlow::Node getASource(string package, string type) { none() }
/**
* Gets a data flow node that is a sink of the type `package;type`,
* usually because it is an argument passed to a parameter of that type.
*/
DataFlow::Node getASink(string package, string type) { none() }
}
/**
* A unit class for adding additional type variable model rows.
*/
@@ -386,57 +368,6 @@ private predicate invocationMatchesCallSiteFilter(Specific::InvokeNode invoke, A
Specific::invocationMatchesExtraCallSiteFilter(invoke, token)
}
private class TypeModelUseEntry extends API::EntryPoint {
private string package;
private string type;
TypeModelUseEntry() {
exists(any(TypeModel tm).getASource(package, type)) and
this = "TypeModelUseEntry;" + package + ";" + type
}
override DataFlow::LocalSourceNode getASource() {
result = any(TypeModel tm).getASource(package, type)
}
API::Node getNodeForType(string package_, string type_) {
package = package_ and type = type_ and result = this.getANode()
}
}
private class TypeModelDefEntry extends API::EntryPoint {
private string package;
private string type;
TypeModelDefEntry() {
exists(any(TypeModel tm).getASink(package, type)) and
this = "TypeModelDefEntry;" + package + ";" + type
}
override DataFlow::Node getASink() { result = any(TypeModel tm).getASink(package, type) }
API::Node getNodeForType(string package_, string type_) {
package = package_ and type = type_ and result = this.getANode()
}
}
/**
* Gets an API node identified by the given `(package,type)` pair.
*/
pragma[nomagic]
private API::Node getNodeFromType(string package, string type) {
exists(string package2, string type2, AccessPath path2 |
typeModel(package, type, package2, type2, path2) and
result = getNodeFromPath(package2, type2, path2)
)
or
result = any(TypeModelUseEntry e).getNodeForType(package, type)
or
result = any(TypeModelDefEntry e).getNodeForType(package, type)
or
result = Specific::getExtraNodeFromType(package, type)
}
/**
* Gets the API node identified by the first `n` tokens of `path` in the given `(package, type, path)` tuple.
*/
@@ -445,8 +376,12 @@ private API::Node getNodeFromPath(string package, string type, AccessPath path,
isRelevantFullPath(package, type, path) and
(
n = 0 and
result = getNodeFromType(package, type)
exists(string package2, string type2, AccessPath path2 |
typeModel(package, type, package2, type2, path2) and
result = getNodeFromPath(package2, type2, path2, path2.getNumToken())
)
or
// Language-specific cases, such as handling of global variables
result = Specific::getExtraNodeFromPath(package, type, path, n)
)
or
@@ -646,7 +581,12 @@ module ModelOutput {
* Holds if `node` is seen as an instance of `(package,type)` due to a type definition
* contributed by a CSV model.
*/
API::Node getATypeNode(string package, string type) { result = getNodeFromType(package, type) }
API::Node getATypeNode(string package, string type) {
exists(string package2, string type2, AccessPath path |
typeModel(package, type, package2, type2, path) and
result = getNodeFromPath(package2, type2, path)
)
}
/**
* Gets an error message relating to an invalid CSV row in a model.

View File

@@ -20,6 +20,7 @@
*/
private import javascript as JS
private import JS::DataFlow as DataFlow
private import ApiGraphModels
class Unit = JS::Unit;
@@ -28,7 +29,6 @@ class Unit = JS::Unit;
module API = JS::API;
import semmle.javascript.frameworks.data.internal.AccessPathSyntax as AccessPathSyntax
import JS::DataFlow as DataFlow
private import AccessPathSyntax
/**
@@ -77,6 +77,10 @@ private API::Node getGlobalNode(string globalName) {
/** Gets a JavaScript-specific interpretation of the `(package, type, path)` tuple after resolving the first `n` access path tokens. */
bindingset[package, type, path]
API::Node getExtraNodeFromPath(string package, string type, AccessPath path, int n) {
type = "" and
n = 0 and
result = API::moduleImport(package)
or
// Global variable accesses is via the 'global' package
exists(AccessPathToken token |
package = getAPackageAlias("global") and
@@ -86,15 +90,10 @@ API::Node getExtraNodeFromPath(string package, string type, AccessPath path, int
result = getGlobalNode(token.getAnArgument()) and
n = 1
)
}
/** Gets a JavaScript-specific interpretation of the `(package, type)` tuple. */
API::Node getExtraNodeFromType(string package, string type) {
type = "" and
result = API::moduleImport(package)
or
// Access instance of a type based on type annotations
result = API::Internal::getANodeOfTypeRaw(getAPackageAlias(package), type)
n = 0 and
result = API::Node::ofType(getAPackageAlias(package), type)
}
/**

View File

@@ -1,7 +1,6 @@
/**
* @name Insecure temporary file
* @description Creating a temporary file that is accessible by other users can
* lead to information disclosure and sometimes remote code execution.
* @description Creating a temporary file that is accessible by other users TODO:
* @kind path-problem
* @id js/insecure-temporary-file
* @problem.severity warning

View File

@@ -1 +1 @@
module.exports = CustomEntryPoint.foo; /* use=entryPoint("CustomEntryPoint") */
module.exports = CustomEntryPoint.foo; /* use=getASuccessor(Label::entryPoint("CustomEntryPoint")) */

View File

@@ -1,9 +1,4 @@
| body-parser | | index.ts:4:20:4:41 | require ... arser") |
| express | | index.ts:3:17:3:34 | require("express") |
| mongodb | | index.ts:1:8:1:19 | * as mongodb |
| mongodb | Collection | index.ts:14:3:14:17 | getCollection() |
| mongoose | | index.ts:17:8:17:20 | * as mongoose |
| mongoose | Model | index.ts:22:3:22:20 | getMongooseModel() |
| mongoose | Query | index.ts:23:3:23:20 | getMongooseQuery() |
| puppeteer | | index.ts:26:8:26:21 | * as puppeteer |
| puppeteer | Browser | index.ts:30:22:30:33 | this.browser |

View File

@@ -1,6 +1,4 @@
underlyingTypeNode
| foo | | file://:0:0:0:0 | use moduleImport("foo").getMember("exports") |
| foo | | foo.ts:1:8:1:10 | use moduleImport("foo").getMember("exports").getMember("default") |
| foo | Bar | foo.ts:3:1:5:1 | use moduleImport("foo").getMember("exports").getMember("Bar").getInstance() |
| foo | Bar | foo.ts:3:12:3:12 | use moduleImport("foo").getMember("exports").getMember("Bar").getInstance() |
#select

View File

@@ -125,7 +125,7 @@ getAffectedStateAccessPath
getADispatchFunctionNode
| react-redux.jsx:65:20:65:32 | use moduleImport("react-redux").getMember("exports").getMember("useDispatch").getReturn() |
getADispatchedValueNode
| react-redux.jsx:27:12:30:5 | def entryPoint("react-redux-connect").getParameter(1).getMember("manualAction").getReturn() |
| react-redux.jsx:27:12:30:5 | def getASuccessor(Label::entryPoint("react-redux-connect")).getParameter(1).getMember("manualAction").getReturn() |
| react-redux.jsx:69:18:69:39 | def moduleImport("react-redux").getMember("exports").getMember("useDispatch").getReturn().getParameter(0) |
| react-redux.jsx:70:18:70:38 | def moduleImport("react-redux").getMember("exports").getMember("useDispatch").getReturn().getParameter(0) |
getAnUntypedActionInReducer

View File

@@ -20,7 +20,7 @@ class Generator:
def printHelp(self):
print(f"""Usage:
python3 GenerateFlowModel.py <library-database> <outputQll> [<friendlyFrameworkName>] [--with-sinks] [--with-sources] [--with-summaries] [--dry-run]
python3 GenerateFlowModel.py <library-database> <outputQll> [--with-sinks] [--with-sources] [--with-summaries] [--dry-run]
This generates summary, source and sink models for the code in the database.
The files will be placed in `{self.language}/ql/lib/semmle/code/{self.language}/frameworks/<outputQll>` where
@@ -39,23 +39,18 @@ If none of these flags are specified, all models are generated.
Example invocations:
$ python3 GenerateFlowModel.py /tmp/dbs/my_library_db "mylibrary/Framework.qll"
$ python3 GenerateFlowModel.py /tmp/dbs/my_library_db "mylibrary/Framework.qll" "Friendly Name of Framework"
$ python3 GenerateFlowModel.py /tmp/dbs/my_library_db "mylibrary/FrameworkSinks.qll" --with-sinks
Requirements: `codeql` should both appear on your path.
""")
def setenvironment(self, target, database, friendlyName):
def setenvironment(self, target, database):
self.codeQlRoot = subprocess.check_output(["git", "rev-parse", "--show-toplevel"]).decode("utf-8").strip()
if not target.endswith(".qll"):
target += ".qll"
filename = os.path.basename(target)
dirname = os.path.dirname(target)
if friendlyName is not None:
self.friendlyname = friendlyName
else:
self.friendlyname = filename[:-4]
self.shortname = filename[:-4]
self.database = database
self.generatedFrameworks = os.path.join(
@@ -97,15 +92,11 @@ Requirements: `codeql` should both appear on your path.
if not generator.generateSinks and not generator.generateSources and not generator.generateSummaries and not generator.generateNegativeSummaries:
generator.generateSinks = generator.generateSources = generator.generateSummaries = generator.generateNegativeSummaries = True
if len(sys.argv) < 3 or len(sys.argv) > 4:
if len(sys.argv) != 3:
generator.printHelp()
sys.exit(1)
friendlyName = None
if len(sys.argv) == 4:
friendlyName = sys.argv[3]
generator.setenvironment(sys.argv[2], sys.argv[1], friendlyName)
generator.setenvironment(sys.argv[2], sys.argv[1])
return generator
@@ -187,7 +178,7 @@ private class {0}{1}Csv extends {2} {{
return f"""
/**
* THIS FILE IS AN AUTO-GENERATED MODELS AS DATA FILE. DO NOT EDIT.
* Definitions of taint steps in the {self.friendlyname} framework.
* Definitions of taint steps in the {self.shortname} framework.
*/
import {self.language}
@@ -209,7 +200,7 @@ private import semmle.code.{self.language}.dataflow.ExternalFlow
return f"""
/**
* THIS FILE IS AN AUTO-GENERATED MODELS AS DATA FILE. DO NOT EDIT.
* Definitions of negative summaries in the {self.friendlyname} framework.
* Definitions of negative summaries in the {self.shortname} framework.
*/
import {self.language}

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Reads of global/non-local variables (without annotations) inside functions defined on classes now works properly in the case where the class had an attribute defined with the same name as the non-local variable.

View File

@@ -453,30 +453,6 @@ module API {
int getNumArgument() { result = count(this.getArg(_)) }
}
/**
* An API entry point.
*
* By default, API graph nodes are only created for nodes that come from an external
* library or escape into an external library. The points where values are cross the boundary
* between codebases are called "entry points".
*
* Anything imported from an external package is considered to be an entry point, but
* additional entry points may be added by extending this class.
*/
abstract class EntryPoint extends string {
bindingset[this]
EntryPoint() { any() }
/** Gets a data-flow node corresponding to a use-node for this entry point. */
DataFlow::LocalSourceNode getASource() { none() }
/** Gets a data-flow node corresponding to a def-node for this entry point. */
DataFlow::Node getASink() { none() }
/** Gets an API-node for this entry point. */
API::Node getANode() { result = root().getASuccessor(Label::entryPoint(this)) }
}
/**
* Provides the actual implementation of API graphs, cached for performance.
*
@@ -676,12 +652,6 @@ module API {
|
lbl = Label::memberFromRef(aw)
)
or
exists(EntryPoint entry |
base = root() and
lbl = Label::entryPoint(entry) and
rhs = entry.getASink()
)
}
/**
@@ -765,12 +735,6 @@ module API {
ImportStar::namePossiblyDefinedInImportStar(ref.asCfgNode(), name, s)
))
)
or
exists(EntryPoint entry |
base = root() and
lbl = Label::entryPoint(entry) and
ref = entry.getASource()
)
}
/**
@@ -945,8 +909,7 @@ module API {
MkLabelSelfParameter() or
MkLabelReturn() or
MkLabelSubclass() or
MkLabelAwait() or
MkLabelEntryPoint(EntryPoint ep)
MkLabelAwait()
/** A label for a module. */
class LabelModule extends ApiLabel, MkLabelModule {
@@ -1020,15 +983,6 @@ module API {
class LabelAwait extends ApiLabel, MkLabelAwait {
override string toString() { result = "getAwaited()" }
}
/** A label for entry points. */
class LabelEntryPoint extends ApiLabel, MkLabelEntryPoint {
private EntryPoint entry;
LabelEntryPoint() { this = MkLabelEntryPoint(entry) }
override string toString() { result = "entryPoint(\"" + entry + "\")" }
}
}
/** Gets the edge label for the module `m`. */
@@ -1065,8 +1019,5 @@ module API {
/** Gets the `await` edge label. */
LabelAwait await() { any() }
/** Gets the label going from the root node to the nodes associated with the given entry point. */
LabelEntryPoint entryPoint(EntryPoint ep) { result = MkLabelEntryPoint(ep) }
}
}

View File

@@ -72,8 +72,6 @@ private class Unit = Specific::Unit;
private module API = Specific::API;
private module DataFlow = Specific::DataFlow;
private import Specific::AccessPathSyntax
/** Module containing hooks for providing input data to be interpreted as a model. */
@@ -158,22 +156,6 @@ module ModelInput {
abstract predicate row(string row);
}
/**
* A unit class for adding additional type model rows from CodeQL models.
*/
class TypeModel extends Unit {
/**
* Gets a data-flow node that is a source of the type `package;type`.
*/
DataFlow::Node getASource(string package, string type) { none() }
/**
* Gets a data flow node that is a sink of the type `package;type`,
* usually because it is an argument passed to a parameter of that type.
*/
DataFlow::Node getASink(string package, string type) { none() }
}
/**
* A unit class for adding additional type variable model rows.
*/
@@ -386,57 +368,6 @@ private predicate invocationMatchesCallSiteFilter(Specific::InvokeNode invoke, A
Specific::invocationMatchesExtraCallSiteFilter(invoke, token)
}
private class TypeModelUseEntry extends API::EntryPoint {
private string package;
private string type;
TypeModelUseEntry() {
exists(any(TypeModel tm).getASource(package, type)) and
this = "TypeModelUseEntry;" + package + ";" + type
}
override DataFlow::LocalSourceNode getASource() {
result = any(TypeModel tm).getASource(package, type)
}
API::Node getNodeForType(string package_, string type_) {
package = package_ and type = type_ and result = this.getANode()
}
}
private class TypeModelDefEntry extends API::EntryPoint {
private string package;
private string type;
TypeModelDefEntry() {
exists(any(TypeModel tm).getASink(package, type)) and
this = "TypeModelDefEntry;" + package + ";" + type
}
override DataFlow::Node getASink() { result = any(TypeModel tm).getASink(package, type) }
API::Node getNodeForType(string package_, string type_) {
package = package_ and type = type_ and result = this.getANode()
}
}
/**
* Gets an API node identified by the given `(package,type)` pair.
*/
pragma[nomagic]
private API::Node getNodeFromType(string package, string type) {
exists(string package2, string type2, AccessPath path2 |
typeModel(package, type, package2, type2, path2) and
result = getNodeFromPath(package2, type2, path2)
)
or
result = any(TypeModelUseEntry e).getNodeForType(package, type)
or
result = any(TypeModelDefEntry e).getNodeForType(package, type)
or
result = Specific::getExtraNodeFromType(package, type)
}
/**
* Gets the API node identified by the first `n` tokens of `path` in the given `(package, type, path)` tuple.
*/
@@ -445,8 +376,12 @@ private API::Node getNodeFromPath(string package, string type, AccessPath path,
isRelevantFullPath(package, type, path) and
(
n = 0 and
result = getNodeFromType(package, type)
exists(string package2, string type2, AccessPath path2 |
typeModel(package, type, package2, type2, path2) and
result = getNodeFromPath(package2, type2, path2, path2.getNumToken())
)
or
// Language-specific cases, such as handling of global variables
result = Specific::getExtraNodeFromPath(package, type, path, n)
)
or
@@ -646,7 +581,12 @@ module ModelOutput {
* Holds if `node` is seen as an instance of `(package,type)` due to a type definition
* contributed by a CSV model.
*/
API::Node getATypeNode(string package, string type) { result = getNodeFromType(package, type) }
API::Node getATypeNode(string package, string type) {
exists(string package2, string type2, AccessPath path |
typeModel(package, type, package2, type2, path) and
result = getNodeFromPath(package2, type2, path)
)
}
/**
* Gets an error message relating to an invalid CSV row in a model.

View File

@@ -20,6 +20,7 @@
*/
private import python as PY
private import semmle.python.dataflow.new.DataFlow
private import ApiGraphModels
import semmle.python.ApiGraphs::API as API
@@ -27,7 +28,6 @@ class Unit = PY::Unit;
// Re-export libraries needed by ApiGraphModels.qll
import semmle.python.frameworks.data.internal.AccessPathSyntax as AccessPathSyntax
import semmle.python.dataflow.new.DataFlow::DataFlow as DataFlow
private import AccessPathSyntax
/**
@@ -37,12 +37,11 @@ predicate isPackageUsed(string package) { exists(API::moduleImport(package)) }
/** Gets a Python-specific interpretation of the `(package, type, path)` tuple after resolving the first `n` access path tokens. */
bindingset[package, type, path]
API::Node getExtraNodeFromPath(string package, string type, AccessPath path, int n) { none() }
/** Gets a Python-specific interpretation of the `(package, type)` tuple. */
API::Node getExtraNodeFromType(string package, string type) {
API::Node getExtraNodeFromPath(string package, string type, AccessPath path, int n) {
type = "" and
result = API::moduleImport(package)
n = 0 and
result = API::moduleImport(package) and
exists(path)
}
/**

View File

@@ -12,7 +12,6 @@
*/
import python
import semmle.python.ApiGraphs
predicate empty_except(ExceptStmt ex) {
not exists(Stmt s | s = ex.getAStmt() and not s instanceof Pass)
@@ -29,7 +28,7 @@ predicate no_comment(ExceptStmt ex) {
}
predicate non_local_control_flow(ExceptStmt ex) {
ex.getType() = API::builtin("StopIteration").getAValueReachableFromSource().asExpr()
ex.getType().pointsTo(ClassValue::stopIteration())
}
predicate try_has_normal_exit(Try try) {
@@ -62,32 +61,27 @@ predicate subscript(Stmt s) {
s.(Delete).getATarget() instanceof Subscript
}
predicate encode_decode(Call ex, Expr type) {
predicate encode_decode(Call ex, ClassValue type) {
exists(string name | ex.getFunc().(Attribute).getName() = name |
name = "encode" and
type = API::builtin("UnicodeEncodeError").getAValueReachableFromSource().asExpr()
name = "encode" and type = ClassValue::unicodeEncodeError()
or
name = "decode" and
type = API::builtin("UnicodeDecodeError").getAValueReachableFromSource().asExpr()
name = "decode" and type = ClassValue::unicodeDecodeError()
)
}
predicate small_handler(ExceptStmt ex, Stmt s, Expr type) {
predicate small_handler(ExceptStmt ex, Stmt s, ClassValue type) {
not exists(ex.getTry().getStmt(1)) and
s = ex.getTry().getStmt(0) and
ex.getType() = type
ex.getType().pointsTo(type)
}
predicate focussed_handler(ExceptStmt ex) {
exists(Stmt s, Expr type | small_handler(ex, s, type) |
subscript(s) and
type = API::builtin("IndexError").getASubclass*().getAValueReachableFromSource().asExpr()
exists(Stmt s, ClassValue type | small_handler(ex, s, type) |
subscript(s) and type.getASuperType() = ClassValue::lookupError()
or
attribute_access(s) and
type = API::builtin("AttributeError").getAValueReachableFromSource().asExpr()
attribute_access(s) and type = ClassValue::attributeError()
or
s.(ExprStmt).getValue() instanceof Name and
type = API::builtin("NameError").getAValueReachableFromSource().asExpr()
s.(ExprStmt).getValue() instanceof Name and type = ClassValue::nameError()
or
encode_decode(s.(ExprStmt).getValue(), type)
)

View File

@@ -19,5 +19,5 @@ from
ModificationOfParameterWithDefault::Configuration config, DataFlow::PathNode source,
DataFlow::PathNode sink
where config.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "This expression mutates $@.", source.getNode(),
"a default value"
select sink.getNode(), source, sink, "$@ flows to here and is mutated.", source.getNode(),
"Default value"

View File

@@ -22,5 +22,5 @@ import DataFlow::PathGraph
from Configuration config, DataFlow::PathNode source, DataFlow::PathNode sink
where config.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "This path depends on $@.", source.getNode(),
"a user-provided value"
select sink.getNode(), source, sink, "$@ flows to here and is used in a path.", source.getNode(),
"User-provided value"

View File

@@ -18,5 +18,5 @@ import DataFlow::PathGraph
from Configuration config, DataFlow::PathNode source, DataFlow::PathNode sink
where config.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "This file extraction depends on $@", source.getNode(),
select sink.getNode(), source, sink, "Extraction of tarfile from $@", source.getNode(),
"a potentially untrusted source"

View File

@@ -20,5 +20,5 @@ import DataFlow::PathGraph
from Configuration config, DataFlow::PathNode source, DataFlow::PathNode sink
where config.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "This command line depends on $@.", source.getNode(),
"a user-provided value"
select sink.getNode(), source, sink, "$@ flows to here and is used in a command.", source.getNode(),
"User-provided value"

View File

@@ -23,5 +23,6 @@ where
or
any(FilterConfiguration filterConfig).hasFlowPath(source, sink) and
parameterName = "filter"
select sink.getNode(), source, sink, "$@ depends on $@.", sink.getNode(),
"LDAP query parameter (" + parameterName + ")", source.getNode(), "a user-provided value"
select sink.getNode(), source, sink,
"$@ LDAP query parameter (" + parameterName + ") comes from $@.", sink.getNode(), "This",
source.getNode(), "a user-provided value"

View File

@@ -20,5 +20,5 @@ import DataFlow::PathGraph
from Configuration config, DataFlow::PathNode source, DataFlow::PathNode sink
where config.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "This code execution depends on $@.", source.getNode(),
"a user-provided value"
select sink.getNode(), source, sink, "$@ flows to here and is interpreted as code.",
source.getNode(), "A user-provided value"

View File

@@ -17,5 +17,5 @@ import DataFlow::PathGraph
from Configuration config, DataFlow::PathNode source, DataFlow::PathNode sink
where config.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "This log entry depends on $@.", source.getNode(),
"a user-provided value"
select sink.getNode(), source, sink, "$@ flows to log entry.", source.getNode(),
"User-provided value"

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