mirror of
https://github.com/github/codeql.git
synced 2026-04-30 19:26:02 +02:00
Merge branch 'github:main' into jorgectf/python/deserialization
This commit is contained in:
4
python/old-change-notes/2021-08-26-bad-tag-filter.md
Normal file
4
python/old-change-notes/2021-08-26-bad-tag-filter.md
Normal file
@@ -0,0 +1,4 @@
|
||||
lgtm,codescanning
|
||||
* A new query, `py/bad-tag-filter`, has been added to the query suite,
|
||||
highlighting regular expressions that only match a subset of the HTML tags
|
||||
it is supposed to match.
|
||||
3
python/old-change-notes/2021-09-29-model-asyncpg.md
Normal file
3
python/old-change-notes/2021-09-29-model-asyncpg.md
Normal file
@@ -0,0 +1,3 @@
|
||||
lgtm,codescanning
|
||||
* Added modeling of `asyncpg` for sinks executing SQL and/or accessing the file system.
|
||||
* Corrected the API graph, such that all awaited values now are referred to via `getAwaited`.
|
||||
2
python/old-change-notes/2021-10-11-model-aiomysql.md
Normal file
2
python/old-change-notes/2021-10-11-model-aiomysql.md
Normal file
@@ -0,0 +1,2 @@
|
||||
lgtm,codescanning
|
||||
* Added modeling of `aiomysql` for sinks executing SQL
|
||||
@@ -0,0 +1,2 @@
|
||||
lgtm,codescanning
|
||||
* Added modeling of sources/sinks when using FastAPI to create web servers.
|
||||
2
python/old-change-notes/2021-10-28-flask-send_file.md
Normal file
2
python/old-change-notes/2021-10-28-flask-send_file.md
Normal file
@@ -0,0 +1,2 @@
|
||||
lgtm,codescanning
|
||||
* Added modeling of the `send_from_directory` and `send_file` functions from the `flask` PyPI package, resulting in additional sinks for the _Uncontrolled data used in path expression_ (`py/path-injection`) query. This addition was originally [submitted as an external contribution by @porcupineyhairs](https://github.com/github/codeql/pull/6330).
|
||||
@@ -0,0 +1,3 @@
|
||||
lgtm,codescanning
|
||||
* The query "Inefficient regular expression" (`py/redos`) has been promoted from experimental to the main query pack. Its results will now appear by default.
|
||||
* The query "Polynomial regular expression used on uncontrolled data" (`py/polynomial-redos`) has been promoted from experimental to the main query pack. Its results will now appear by default.
|
||||
@@ -0,0 +1,2 @@
|
||||
lgtm,codescanning
|
||||
* Added modeling of HTTP requests and responses when using the Django REST Framework (`djangorestframework` PyPI package), which leads to additional remote flow sources.
|
||||
@@ -1,4 +1,6 @@
|
||||
name: codeql/python-examples
|
||||
version: 0.0.2
|
||||
groups:
|
||||
- python
|
||||
- examples
|
||||
dependencies:
|
||||
codeql/python-all: "*"
|
||||
codeql/python-all: "*"
|
||||
|
||||
25
python/ql/lib/CHANGELOG.md
Normal file
25
python/ql/lib/CHANGELOG.md
Normal file
@@ -0,0 +1,25 @@
|
||||
## 0.0.7
|
||||
|
||||
## 0.0.6
|
||||
|
||||
## 0.0.5
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Added modeling of many functions from the `os` module that uses file system paths, such as `os.stat`, `os.chdir`, `os.mkdir`, and so on.
|
||||
* Added modeling of the `tempfile` module for creating temporary files and directories, such as the functions `tempfile.NamedTemporaryFile` and `tempfile.TemporaryDirectory`.
|
||||
* Extended the modeling of FastAPI such that custom subclasses of `fastapi.APIRouter` are recognized.
|
||||
* Extended the modeling of FastAPI such that `fastapi.responses.FileResponse` are considered `FileSystemAccess`.
|
||||
* Added modeling of the `posixpath`, `ntpath`, and `genericpath` modules for path operations (although these are not supposed to be used), resulting in new sinks.
|
||||
* Added modeling of `wsgiref.simple_server` applications, leading to new remote flow sources.
|
||||
|
||||
## 0.0.4
|
||||
|
||||
### Major Analysis Improvements
|
||||
|
||||
* Added modeling of `os.stat`, `os.lstat`, `os.statvfs`, `os.fstat`, and `os.fstatvfs`, which are new sinks for the _Uncontrolled data used in path expression_ (`py/path-injection`) query.
|
||||
* Added modeling of the `posixpath`, `ntpath`, and `genericpath` modules for path operations (although these are not supposed to be used), resulting in new sinks for the _Uncontrolled data used in path expression_ (`py/path-injection`) query.
|
||||
* Added modeling of `wsgiref.simple_server` applications, leading to new remote flow sources.
|
||||
* Added modeling of `aiopg` for sinks executing SQL.
|
||||
* Added modeling of HTTP requests and responses when using `flask_admin` (`Flask-Admin` PyPI package), which leads to additional remote flow sources.
|
||||
* Added modeling of the PyPI package `toml`, which provides encoding/decoding of TOML documents, leading to new taint-tracking steps.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: deprecated
|
||||
---
|
||||
* The `codeql/python-upgrades` CodeQL pack has been removed. All upgrades scripts have been merged into the `codeql/python-all` CodeQL pack.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: deprecated
|
||||
---
|
||||
* Moved the files defining regex injection configuration and customization, instead of `import semmle.python.security.injection.RegexInjection` please use `import semmle.python.security.dataflow.RegexInjection` (the same for `RegexInjectionCustomizations`).
|
||||
10
python/ql/lib/change-notes/released/0.0.4.md
Normal file
10
python/ql/lib/change-notes/released/0.0.4.md
Normal file
@@ -0,0 +1,10 @@
|
||||
## 0.0.4
|
||||
|
||||
### Major Analysis Improvements
|
||||
|
||||
* Added modeling of `os.stat`, `os.lstat`, `os.statvfs`, `os.fstat`, and `os.fstatvfs`, which are new sinks for the _Uncontrolled data used in path expression_ (`py/path-injection`) query.
|
||||
* Added modeling of the `posixpath`, `ntpath`, and `genericpath` modules for path operations (although these are not supposed to be used), resulting in new sinks for the _Uncontrolled data used in path expression_ (`py/path-injection`) query.
|
||||
* Added modeling of `wsgiref.simple_server` applications, leading to new remote flow sources.
|
||||
* Added modeling of `aiopg` for sinks executing SQL.
|
||||
* Added modeling of HTTP requests and responses when using `flask_admin` (`Flask-Admin` PyPI package), which leads to additional remote flow sources.
|
||||
* Added modeling of the PyPI package `toml`, which provides encoding/decoding of TOML documents, leading to new taint-tracking steps.
|
||||
10
python/ql/lib/change-notes/released/0.0.5.md
Normal file
10
python/ql/lib/change-notes/released/0.0.5.md
Normal file
@@ -0,0 +1,10 @@
|
||||
## 0.0.5
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Added modeling of many functions from the `os` module that uses file system paths, such as `os.stat`, `os.chdir`, `os.mkdir`, and so on.
|
||||
* Added modeling of the `tempfile` module for creating temporary files and directories, such as the functions `tempfile.NamedTemporaryFile` and `tempfile.TemporaryDirectory`.
|
||||
* Extended the modeling of FastAPI such that custom subclasses of `fastapi.APIRouter` are recognized.
|
||||
* Extended the modeling of FastAPI such that `fastapi.responses.FileResponse` are considered `FileSystemAccess`.
|
||||
* Added modeling of the `posixpath`, `ntpath`, and `genericpath` modules for path operations (although these are not supposed to be used), resulting in new sinks.
|
||||
* Added modeling of `wsgiref.simple_server` applications, leading to new remote flow sources.
|
||||
1
python/ql/lib/change-notes/released/0.0.6.md
Normal file
1
python/ql/lib/change-notes/released/0.0.6.md
Normal file
@@ -0,0 +1 @@
|
||||
## 0.0.6
|
||||
1
python/ql/lib/change-notes/released/0.0.7.md
Normal file
1
python/ql/lib/change-notes/released/0.0.7.md
Normal file
@@ -0,0 +1 @@
|
||||
## 0.0.7
|
||||
2
python/ql/lib/codeql-pack.release.yml
Normal file
2
python/ql/lib/codeql-pack.release.yml
Normal file
@@ -0,0 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.0.7
|
||||
@@ -0,0 +1,6 @@
|
||||
description: Add new statements and expressions for the match syntax.
|
||||
compatibility: backwards
|
||||
py_exprs.rel: run py_exprs.qlo
|
||||
py_stmts.rel: run py_stmts.qlo
|
||||
py_patterns.rel: delete
|
||||
py_patterns_lists.rel: delete
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,42 @@
|
||||
// First we need to wrap some database types
|
||||
class Location extends @location {
|
||||
/** Gets the start line of this location */
|
||||
int getStartLine() {
|
||||
locations_default(this, _, result, _, _, _) or
|
||||
locations_ast(this, _, result, _, _, _)
|
||||
}
|
||||
|
||||
string toString() { result = "<some file>" + ":" + this.getStartLine().toString() }
|
||||
}
|
||||
|
||||
class Expr_ extends @py_expr {
|
||||
string toString() { result = "Expr" }
|
||||
|
||||
Location getLocation() { py_locations(result, this) }
|
||||
}
|
||||
|
||||
class ExprParent_ extends @py_expr_parent {
|
||||
string toString() { result = "ExprParent" }
|
||||
}
|
||||
|
||||
/**
|
||||
* New kinds have been inserted such that
|
||||
* `@py_Name` which used to have index 18 now has index 19.
|
||||
* Entries with lower indices are unchanged.
|
||||
*/
|
||||
bindingset[new_index]
|
||||
int old_index(int new_index) {
|
||||
if new_index < 18 then result = new_index else result + (19 - 18) = new_index
|
||||
}
|
||||
|
||||
// The schema for py_exprs is:
|
||||
//
|
||||
// py_exprs(unique int id : @py_expr,
|
||||
// int kind: int ref,
|
||||
// int parent : @py_expr_parent ref,
|
||||
// int idx : int ref);
|
||||
from Expr_ expr, int new_kind, ExprParent_ parent, int idx, int old_kind
|
||||
where
|
||||
py_exprs(expr, new_kind, parent, idx) and
|
||||
old_kind = old_index(new_kind)
|
||||
select expr, old_kind, parent, idx
|
||||
@@ -0,0 +1,42 @@
|
||||
// First we need to wrap some database types
|
||||
class Location extends @location {
|
||||
/** Gets the start line of this location */
|
||||
int getStartLine() {
|
||||
locations_default(this, _, result, _, _, _) or
|
||||
locations_ast(this, _, result, _, _, _)
|
||||
}
|
||||
|
||||
string toString() { result = "<some file>" + ":" + this.getStartLine().toString() }
|
||||
}
|
||||
|
||||
class Stmt_ extends @py_stmt {
|
||||
string toString() { result = "Stmt" }
|
||||
|
||||
Location getLocation() { py_locations(result, this) }
|
||||
}
|
||||
|
||||
class StmtList_ extends @py_stmt_list {
|
||||
string toString() { result = "StmtList" }
|
||||
}
|
||||
|
||||
/**
|
||||
* New kinds have been inserted such that
|
||||
* `@py_Nonlocal` which used to have index 14 now has index 16.
|
||||
* Entries with lower indices are unchanged.
|
||||
*/
|
||||
bindingset[new_index]
|
||||
int old_index(int new_index) {
|
||||
if new_index < 14 then result = new_index else result + (16 - 14) = new_index
|
||||
}
|
||||
|
||||
// The schema for py_stmts is:
|
||||
//
|
||||
// py_stmts(unique int id : @py_stmt,
|
||||
// int kind: int ref,
|
||||
// int parent : @py_stmt_list ref,
|
||||
// int idx : int ref);
|
||||
from Stmt_ expr, int new_kind, StmtList_ parent, int idx, int old_kind
|
||||
where
|
||||
py_stmts(expr, new_kind, parent, idx) and
|
||||
old_kind = old_index(new_kind)
|
||||
select expr, old_kind, parent, idx
|
||||
@@ -10,6 +10,7 @@ import semmle.python.Class
|
||||
import semmle.python.Import
|
||||
import semmle.python.Stmts
|
||||
import semmle.python.Exprs
|
||||
import semmle.python.Patterns
|
||||
import semmle.python.Keywords
|
||||
import semmle.python.Comprehensions
|
||||
import semmle.python.Flow
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
name: codeql/python-all
|
||||
version: 0.0.2
|
||||
version: 0.0.8-dev
|
||||
groups: python
|
||||
dbscheme: semmlecode.python.dbscheme
|
||||
extractor: python
|
||||
library: true
|
||||
dependencies:
|
||||
codeql/python-upgrades: 0.0.2
|
||||
upgrades: upgrades
|
||||
|
||||
@@ -304,6 +304,8 @@ module API {
|
||||
* API graph node for the prefix `foo`), in accordance with the usual semantics of Python.
|
||||
*/
|
||||
|
||||
private import semmle.python.internal.Awaited
|
||||
|
||||
cached
|
||||
newtype TApiNode =
|
||||
/** The root of the API graph. */
|
||||
@@ -356,134 +358,26 @@ module API {
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the name of a known built-in. */
|
||||
private string getBuiltInName() {
|
||||
// These lists were created by inspecting the `builtins` and `__builtin__` modules in
|
||||
// Python 3 and 2 respectively, using the `dir` built-in.
|
||||
// Built-in functions and exceptions shared between Python 2 and 3
|
||||
result in [
|
||||
"abs", "all", "any", "bin", "bool", "bytearray", "callable", "chr", "classmethod",
|
||||
"compile", "complex", "delattr", "dict", "dir", "divmod", "enumerate", "eval", "filter",
|
||||
"float", "format", "frozenset", "getattr", "globals", "hasattr", "hash", "help", "hex",
|
||||
"id", "input", "int", "isinstance", "issubclass", "iter", "len", "list", "locals", "map",
|
||||
"max", "memoryview", "min", "next", "object", "oct", "open", "ord", "pow", "print",
|
||||
"property", "range", "repr", "reversed", "round", "set", "setattr", "slice", "sorted",
|
||||
"staticmethod", "str", "sum", "super", "tuple", "type", "vars", "zip", "__import__",
|
||||
// Exceptions
|
||||
"ArithmeticError", "AssertionError", "AttributeError", "BaseException", "BufferError",
|
||||
"BytesWarning", "DeprecationWarning", "EOFError", "EnvironmentError", "Exception",
|
||||
"FloatingPointError", "FutureWarning", "GeneratorExit", "IOError", "ImportError",
|
||||
"ImportWarning", "IndentationError", "IndexError", "KeyError", "KeyboardInterrupt",
|
||||
"LookupError", "MemoryError", "NameError", "NotImplemented", "NotImplementedError",
|
||||
"OSError", "OverflowError", "PendingDeprecationWarning", "ReferenceError", "RuntimeError",
|
||||
"RuntimeWarning", "StandardError", "StopIteration", "SyntaxError", "SyntaxWarning",
|
||||
"SystemError", "SystemExit", "TabError", "TypeError", "UnboundLocalError",
|
||||
"UnicodeDecodeError", "UnicodeEncodeError", "UnicodeError", "UnicodeTranslateError",
|
||||
"UnicodeWarning", "UserWarning", "ValueError", "Warning", "ZeroDivisionError",
|
||||
// Added for compatibility
|
||||
"exec"
|
||||
]
|
||||
or
|
||||
// Built-in constants shared between Python 2 and 3
|
||||
result in ["False", "True", "None", "NotImplemented", "Ellipsis", "__debug__"]
|
||||
or
|
||||
// Python 3 only
|
||||
result in [
|
||||
"ascii", "breakpoint", "bytes", "exec",
|
||||
// Exceptions
|
||||
"BlockingIOError", "BrokenPipeError", "ChildProcessError", "ConnectionAbortedError",
|
||||
"ConnectionError", "ConnectionRefusedError", "ConnectionResetError", "FileExistsError",
|
||||
"FileNotFoundError", "InterruptedError", "IsADirectoryError", "ModuleNotFoundError",
|
||||
"NotADirectoryError", "PermissionError", "ProcessLookupError", "RecursionError",
|
||||
"ResourceWarning", "StopAsyncIteration", "TimeoutError"
|
||||
]
|
||||
or
|
||||
// Python 2 only
|
||||
result in [
|
||||
"basestring", "cmp", "execfile", "file", "long", "raw_input", "reduce", "reload",
|
||||
"unichr", "unicode", "xrange"
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a data flow node that is likely to refer to a built-in with the name `name`.
|
||||
*
|
||||
* Currently this is an over-approximation, and may not account for things like overwriting a
|
||||
* built-in with a different value.
|
||||
*/
|
||||
private DataFlow::Node likely_builtin(string name) {
|
||||
exists(Module m |
|
||||
result.asCfgNode() =
|
||||
any(NameNode n |
|
||||
possible_builtin_accessed_in_module(n, name, m) and
|
||||
not possible_builtin_defined_in_module(name, m)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a global variable called `name` (which is also the name of a built-in) is assigned
|
||||
* a value in the module `m`.
|
||||
*/
|
||||
private predicate possible_builtin_defined_in_module(string name, Module m) {
|
||||
global_name_defined_in_module(name, m) and
|
||||
name = getBuiltInName()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` is an access of a global variable called `name` (which is also the name of a
|
||||
* built-in) inside the module `m`.
|
||||
*/
|
||||
private predicate possible_builtin_accessed_in_module(NameNode n, string name, Module m) {
|
||||
n.isGlobal() and
|
||||
n.isLoad() and
|
||||
name = n.getId() and
|
||||
name = getBuiltInName() and
|
||||
m = n.getEnclosingModule()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` is an access of a variable called `name` (which is _not_ the name of a
|
||||
* built-in, and which is _not_ a global defined in the enclosing module) inside the scope `s`.
|
||||
*/
|
||||
private predicate name_possibly_defined_in_import_star(NameNode n, string name, Scope s) {
|
||||
n.isLoad() and
|
||||
name = n.getId() and
|
||||
// Not already defined in an enclosing scope.
|
||||
not exists(LocalVariable v |
|
||||
v.getId() = name and v.getScope() = n.getScope().getEnclosingScope*()
|
||||
) and
|
||||
not name = getBuiltInName() and
|
||||
s = n.getScope().getEnclosingScope*() and
|
||||
exists(potential_import_star_base(s)) and
|
||||
not global_name_defined_in_module(name, n.getEnclosingModule())
|
||||
}
|
||||
|
||||
/** Holds if a global variable called `name` is assigned a value in the module `m`. */
|
||||
private predicate global_name_defined_in_module(string name, Module m) {
|
||||
exists(NameNode n |
|
||||
not exists(LocalVariable v | n.defines(v)) and
|
||||
n.isStore() and
|
||||
name = n.getId() and
|
||||
m = n.getEnclosingModule()
|
||||
)
|
||||
}
|
||||
private import semmle.python.dataflow.new.internal.Builtins
|
||||
private import semmle.python.dataflow.new.internal.ImportStar
|
||||
|
||||
/**
|
||||
* Gets the API graph node for all modules imported with `from ... import *` inside the scope `s`.
|
||||
*
|
||||
* For example, given
|
||||
*
|
||||
* `from foo.bar import *`
|
||||
* ```python
|
||||
* from foo.bar import *
|
||||
* ```
|
||||
*
|
||||
* this would be the API graph node with the path
|
||||
*
|
||||
* `moduleImport("foo").getMember("bar")`
|
||||
*/
|
||||
private TApiNode potential_import_star_base(Scope s) {
|
||||
exists(DataFlow::Node ref |
|
||||
ref.asCfgNode() = any(ImportStarNode n | n.getScope() = s).getModule() and
|
||||
use(result, ref)
|
||||
exists(DataFlow::Node n |
|
||||
n.asCfgNode() = ImportStar::potentialImportStarBase(s) and
|
||||
use(result, n)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -518,24 +412,23 @@ module API {
|
||||
)
|
||||
or
|
||||
// awaiting
|
||||
exists(Await await, DataFlow::Node awaitedValue |
|
||||
exists(DataFlow::Node awaitedValue |
|
||||
lbl = Label::await() and
|
||||
ref.asExpr() = await and
|
||||
await.getValue() = awaitedValue.asExpr() and
|
||||
ref = awaited(awaitedValue) and
|
||||
pred.flowsTo(awaitedValue)
|
||||
)
|
||||
)
|
||||
or
|
||||
// Built-ins, treated as members of the module `builtins`
|
||||
base = MkModuleImport("builtins") and
|
||||
lbl = Label::member(any(string name | ref = likely_builtin(name)))
|
||||
lbl = Label::member(any(string name | ref = Builtins::likelyBuiltin(name)))
|
||||
or
|
||||
// Unknown variables that may belong to a module imported with `import *`
|
||||
exists(Scope s |
|
||||
base = potential_import_star_base(s) and
|
||||
lbl =
|
||||
Label::member(any(string name |
|
||||
name_possibly_defined_in_import_star(ref.asCfgNode(), name, s)
|
||||
ImportStar::namePossiblyDefinedInImportStar(ref.asCfgNode(), name, s)
|
||||
))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -82,6 +82,12 @@ library class StrListParent extends StrListParent_ { }
|
||||
/** Internal implementation class */
|
||||
library class ExprParent extends ExprParent_ { }
|
||||
|
||||
/** Internal implementation class */
|
||||
class PatternListParent extends PatternListParent_ { }
|
||||
|
||||
/** Internal implementation class */
|
||||
library class PatternParent extends PatternParent_ { }
|
||||
|
||||
library class DictItem extends DictItem_, AstNode {
|
||||
override string toString() { result = DictItem_.super.toString() }
|
||||
|
||||
@@ -162,6 +168,9 @@ class ExprList extends ExprList_ {
|
||||
/* syntax: Expr, ... */
|
||||
}
|
||||
|
||||
/** A list of patterns */
|
||||
class PatternList extends PatternList_ { }
|
||||
|
||||
library class DictItemList extends DictItemList_ { }
|
||||
|
||||
library class DictItemListParent extends DictItemListParent_ { }
|
||||
|
||||
@@ -218,6 +218,26 @@ library class Call_ extends @py_Call, Expr {
|
||||
override string toString() { result = "Call" }
|
||||
}
|
||||
|
||||
/** INTERNAL: See the class `Case` for further information. */
|
||||
library class Case_ extends @py_Case, Stmt {
|
||||
/** Gets the pattern of this case statement. */
|
||||
Pattern getPattern() { py_patterns(result, _, this, 1) }
|
||||
|
||||
/** Gets the guard of this case statement. */
|
||||
Expr getGuard() { py_exprs(result, _, this, 2) }
|
||||
|
||||
/** Gets the body of this case statement. */
|
||||
StmtList getBody() { py_stmt_lists(result, this, 3) }
|
||||
|
||||
/** Gets the nth statement of this case statement. */
|
||||
Stmt getStmt(int index) { result = this.getBody().getItem(index) }
|
||||
|
||||
/** Gets a statement of this case statement. */
|
||||
Stmt getAStmt() { result = this.getBody().getAnItem() }
|
||||
|
||||
override string toString() { result = "Case" }
|
||||
}
|
||||
|
||||
/** INTERNAL: See the class `Class` for further information. */
|
||||
library class Class_ extends @py_Class {
|
||||
/** Gets the name of this class. */
|
||||
@@ -232,6 +252,7 @@ library class Class_ extends @py_Class {
|
||||
/** Gets a statement of this class. */
|
||||
Stmt getAStmt() { result = this.getBody().getAnItem() }
|
||||
|
||||
/** Gets a parent of this class */
|
||||
ClassExpr getParent() { py_Classes(this, result) }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
@@ -513,6 +534,7 @@ library class Function_ extends @py_Function {
|
||||
/** Whether the async property of this function is true. */
|
||||
predicate isAsync() { py_bools(this, 6) }
|
||||
|
||||
/** Gets a parent of this function */
|
||||
FunctionParent getParent() { py_Functions(this, result) }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
@@ -577,6 +599,14 @@ library class GtE_ extends @py_GtE, Cmpop {
|
||||
override string toString() { result = "GtE" }
|
||||
}
|
||||
|
||||
/** INTERNAL: See the class `Guard` for further information. */
|
||||
library class Guard_ extends @py_Guard, Expr {
|
||||
/** Gets the test of this guard expression. */
|
||||
Expr getTest() { py_exprs(result, _, this, 2) }
|
||||
|
||||
override string toString() { result = "Guard" }
|
||||
}
|
||||
|
||||
/** INTERNAL: See the class `If` for further information. */
|
||||
library class If_ extends @py_If, Stmt {
|
||||
/** Gets the test of this if statement. */
|
||||
@@ -790,6 +820,172 @@ library class MatMult_ extends @py_MatMult, Operator {
|
||||
override string toString() { result = "MatMult" }
|
||||
}
|
||||
|
||||
/** INTERNAL: See the class `MatchStmt` for further information. */
|
||||
library class MatchStmt_ extends @py_MatchStmt, Stmt {
|
||||
/** Gets the subject of this match statement. */
|
||||
Expr getSubject() { py_exprs(result, _, this, 1) }
|
||||
|
||||
/** Gets the cases of this match statement. */
|
||||
StmtList getCases() { py_stmt_lists(result, this, 2) }
|
||||
|
||||
/** Gets the nth case of this match statement. */
|
||||
Stmt getCase(int index) { result = this.getCases().getItem(index) }
|
||||
|
||||
/** Gets a case of this match statement. */
|
||||
Stmt getACase() { result = this.getCases().getAnItem() }
|
||||
|
||||
override string toString() { result = "MatchStmt" }
|
||||
}
|
||||
|
||||
/** INTERNAL: See the class `MatchAsPattern` for further information. */
|
||||
library class MatchAsPattern_ extends @py_MatchAsPattern, Pattern {
|
||||
/** Gets the pattern of this matchaspattern pattern. */
|
||||
Pattern getPattern() { py_patterns(result, _, this, 2) }
|
||||
|
||||
/** Gets the alias of this matchaspattern pattern. */
|
||||
Expr getAlias() { py_exprs(result, _, this, 3) }
|
||||
|
||||
override string toString() { result = "MatchAsPattern" }
|
||||
}
|
||||
|
||||
/** INTERNAL: See the class `MatchCapturePattern` for further information. */
|
||||
library class MatchCapturePattern_ extends @py_MatchCapturePattern, Pattern {
|
||||
/** Gets the variable of this matchcapturepattern pattern. */
|
||||
Expr getVariable() { py_exprs(result, _, this, 2) }
|
||||
|
||||
override string toString() { result = "MatchCapturePattern" }
|
||||
}
|
||||
|
||||
/** INTERNAL: See the class `MatchClassPattern` for further information. */
|
||||
library class MatchClassPattern_ extends @py_MatchClassPattern, Pattern {
|
||||
/** Gets the class of this matchclasspattern pattern. */
|
||||
Expr getClass() { py_exprs(result, _, this, 2) }
|
||||
|
||||
/** Gets the class_name of this matchclasspattern pattern. */
|
||||
Expr getClassName() { py_exprs(result, _, this, 3) }
|
||||
|
||||
/** Gets the positional of this matchclasspattern pattern. */
|
||||
PatternList getPositional() { py_pattern_lists(result, this, 4) }
|
||||
|
||||
/** Gets the nth positional of this matchclasspattern pattern. */
|
||||
Pattern getPositional(int index) { result = this.getPositional().getItem(index) }
|
||||
|
||||
/** Gets a positional of this matchclasspattern pattern. */
|
||||
Pattern getAPositional() { result = this.getPositional().getAnItem() }
|
||||
|
||||
/** Gets the keyword of this matchclasspattern pattern. */
|
||||
PatternList getKeyword() { py_pattern_lists(result, this, 5) }
|
||||
|
||||
/** Gets the nth keyword of this matchclasspattern pattern. */
|
||||
Pattern getKeyword(int index) { result = this.getKeyword().getItem(index) }
|
||||
|
||||
/** Gets a keyword of this matchclasspattern pattern. */
|
||||
Pattern getAKeyword() { result = this.getKeyword().getAnItem() }
|
||||
|
||||
override string toString() { result = "MatchClassPattern" }
|
||||
}
|
||||
|
||||
/** INTERNAL: See the class `MatchDoubleStarPattern` for further information. */
|
||||
library class MatchDoubleStarPattern_ extends @py_MatchDoubleStarPattern, Pattern {
|
||||
/** Gets the target of this matchdoublestarpattern pattern. */
|
||||
Pattern getTarget() { py_patterns(result, _, this, 2) }
|
||||
|
||||
override string toString() { result = "MatchDoubleStarPattern" }
|
||||
}
|
||||
|
||||
/** INTERNAL: See the class `MatchKeyValuePattern` for further information. */
|
||||
library class MatchKeyValuePattern_ extends @py_MatchKeyValuePattern, Pattern {
|
||||
/** Gets the key of this matchkeyvaluepattern pattern. */
|
||||
Pattern getKey() { py_patterns(result, _, this, 2) }
|
||||
|
||||
/** Gets the value of this matchkeyvaluepattern pattern. */
|
||||
Pattern getValue() { py_patterns(result, _, this, 3) }
|
||||
|
||||
override string toString() { result = "MatchKeyValuePattern" }
|
||||
}
|
||||
|
||||
/** INTERNAL: See the class `MatchKeywordPattern` for further information. */
|
||||
library class MatchKeywordPattern_ extends @py_MatchKeywordPattern, Pattern {
|
||||
/** Gets the attribute of this matchkeywordpattern pattern. */
|
||||
Expr getAttribute() { py_exprs(result, _, this, 2) }
|
||||
|
||||
/** Gets the value of this matchkeywordpattern pattern. */
|
||||
Pattern getValue() { py_patterns(result, _, this, 3) }
|
||||
|
||||
override string toString() { result = "MatchKeywordPattern" }
|
||||
}
|
||||
|
||||
/** INTERNAL: See the class `MatchLiteralPattern` for further information. */
|
||||
library class MatchLiteralPattern_ extends @py_MatchLiteralPattern, Pattern {
|
||||
/** Gets the literal of this matchliteralpattern pattern. */
|
||||
Expr getLiteral() { py_exprs(result, _, this, 2) }
|
||||
|
||||
override string toString() { result = "MatchLiteralPattern" }
|
||||
}
|
||||
|
||||
/** INTERNAL: See the class `MatchMappingPattern` for further information. */
|
||||
library class MatchMappingPattern_ extends @py_MatchMappingPattern, Pattern {
|
||||
/** Gets the mappings of this matchmappingpattern pattern. */
|
||||
PatternList getMappings() { py_pattern_lists(result, this, 2) }
|
||||
|
||||
/** Gets the nth mapping of this matchmappingpattern pattern. */
|
||||
Pattern getMapping(int index) { result = this.getMappings().getItem(index) }
|
||||
|
||||
/** Gets a mapping of this matchmappingpattern pattern. */
|
||||
Pattern getAMapping() { result = this.getMappings().getAnItem() }
|
||||
|
||||
override string toString() { result = "MatchMappingPattern" }
|
||||
}
|
||||
|
||||
/** INTERNAL: See the class `MatchOrPattern` for further information. */
|
||||
library class MatchOrPattern_ extends @py_MatchOrPattern, Pattern {
|
||||
/** Gets the patterns of this matchorpattern pattern. */
|
||||
PatternList getPatterns() { py_pattern_lists(result, this, 2) }
|
||||
|
||||
/** Gets the nth pattern of this matchorpattern pattern. */
|
||||
Pattern getPattern(int index) { result = this.getPatterns().getItem(index) }
|
||||
|
||||
/** Gets a pattern of this matchorpattern pattern. */
|
||||
Pattern getAPattern() { result = this.getPatterns().getAnItem() }
|
||||
|
||||
override string toString() { result = "MatchOrPattern" }
|
||||
}
|
||||
|
||||
/** INTERNAL: See the class `MatchSequencePattern` for further information. */
|
||||
library class MatchSequencePattern_ extends @py_MatchSequencePattern, Pattern {
|
||||
/** Gets the patterns of this matchsequencepattern pattern. */
|
||||
PatternList getPatterns() { py_pattern_lists(result, this, 2) }
|
||||
|
||||
/** Gets the nth pattern of this matchsequencepattern pattern. */
|
||||
Pattern getPattern(int index) { result = this.getPatterns().getItem(index) }
|
||||
|
||||
/** Gets a pattern of this matchsequencepattern pattern. */
|
||||
Pattern getAPattern() { result = this.getPatterns().getAnItem() }
|
||||
|
||||
override string toString() { result = "MatchSequencePattern" }
|
||||
}
|
||||
|
||||
/** INTERNAL: See the class `MatchStarPattern` for further information. */
|
||||
library class MatchStarPattern_ extends @py_MatchStarPattern, Pattern {
|
||||
/** Gets the target of this matchstarpattern pattern. */
|
||||
Pattern getTarget() { py_patterns(result, _, this, 2) }
|
||||
|
||||
override string toString() { result = "MatchStarPattern" }
|
||||
}
|
||||
|
||||
/** INTERNAL: See the class `MatchValuePattern` for further information. */
|
||||
library class MatchValuePattern_ extends @py_MatchValuePattern, Pattern {
|
||||
/** Gets the value of this matchvaluepattern pattern. */
|
||||
Expr getValue() { py_exprs(result, _, this, 2) }
|
||||
|
||||
override string toString() { result = "MatchValuePattern" }
|
||||
}
|
||||
|
||||
/** INTERNAL: See the class `MatchWildcardPattern` for further information. */
|
||||
library class MatchWildcardPattern_ extends @py_MatchWildcardPattern, Pattern {
|
||||
override string toString() { result = "MatchWildcardPattern" }
|
||||
}
|
||||
|
||||
/** INTERNAL: See the class `Mod` for further information. */
|
||||
library class Mod_ extends @py_Mod, Operator {
|
||||
override string toString() { result = "Mod" }
|
||||
@@ -1073,6 +1269,7 @@ library class StringPart_ extends @py_StringPart {
|
||||
/** Gets the location of this implicitly concatenated part. */
|
||||
Location getLocation() { py_locations(result, this) }
|
||||
|
||||
/** Gets a parent of this implicitly concatenated part */
|
||||
StringPartList getParent() { py_StringParts(this, result, _) }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
@@ -1081,6 +1278,7 @@ library class StringPart_ extends @py_StringPart {
|
||||
|
||||
/** INTERNAL: See the class `StringPartList` for further information. */
|
||||
library class StringPartList_ extends @py_StringPart_list {
|
||||
/** Gets a parent of this implicitly concatenated part list */
|
||||
BytesOrStr getParent() { py_StringPart_lists(this, result) }
|
||||
|
||||
/** Gets an item of this implicitly concatenated part list */
|
||||
@@ -1288,6 +1486,7 @@ library class Alias_ extends @py_alias {
|
||||
/** Gets the name of this alias. */
|
||||
Expr getAsname() { py_exprs(result, _, this, 1) }
|
||||
|
||||
/** Gets a parent of this alias */
|
||||
AliasList getParent() { py_aliases(this, result, _) }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
@@ -1296,6 +1495,7 @@ library class Alias_ extends @py_alias {
|
||||
|
||||
/** INTERNAL: See the class `AliasList` for further information. */
|
||||
library class AliasList_ extends @py_alias_list {
|
||||
/** Gets a parent of this alias list */
|
||||
Import getParent() { py_alias_lists(this, result) }
|
||||
|
||||
/** Gets an item of this alias list */
|
||||
@@ -1352,6 +1552,7 @@ library class Arguments_ extends @py_arguments {
|
||||
/** Gets a keyword-only annotation of this parameters definition. */
|
||||
Expr getAKwAnnotation() { result = this.getKwAnnotations().getAnItem() }
|
||||
|
||||
/** Gets a parent of this parameters definition */
|
||||
ArgumentsParent getParent() { py_arguments(this, result) }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
@@ -1378,6 +1579,7 @@ library class BoolParent_ extends @py_bool_parent {
|
||||
|
||||
/** INTERNAL: See the class `Boolop` for further information. */
|
||||
library class Boolop_ extends @py_boolop {
|
||||
/** Gets a parent of this boolean operator */
|
||||
BoolExpr getParent() { py_boolops(this, _, result) }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
@@ -1386,6 +1588,7 @@ library class Boolop_ extends @py_boolop {
|
||||
|
||||
/** INTERNAL: See the class `Cmpop` for further information. */
|
||||
library class Cmpop_ extends @py_cmpop {
|
||||
/** Gets a parent of this comparison operator */
|
||||
CmpopList getParent() { py_cmpops(this, _, result, _) }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
@@ -1394,6 +1597,7 @@ library class Cmpop_ extends @py_cmpop {
|
||||
|
||||
/** INTERNAL: See the class `CmpopList` for further information. */
|
||||
library class CmpopList_ extends @py_cmpop_list {
|
||||
/** Gets a parent of this comparison operator list */
|
||||
Compare getParent() { py_cmpop_lists(this, result) }
|
||||
|
||||
/** Gets an item of this comparison operator list */
|
||||
@@ -1426,6 +1630,7 @@ library class Comprehension_ extends @py_comprehension {
|
||||
/** Gets a condition of this comprehension. */
|
||||
Expr getAnIf() { result = this.getIfs().getAnItem() }
|
||||
|
||||
/** Gets a parent of this comprehension */
|
||||
ComprehensionList getParent() { py_comprehensions(this, result, _) }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
@@ -1434,6 +1639,7 @@ library class Comprehension_ extends @py_comprehension {
|
||||
|
||||
/** INTERNAL: See the class `ComprehensionList` for further information. */
|
||||
library class ComprehensionList_ extends @py_comprehension_list {
|
||||
/** Gets a parent of this comprehension list */
|
||||
ListComp getParent() { py_comprehension_lists(this, result) }
|
||||
|
||||
/** Gets an item of this comprehension list */
|
||||
@@ -1448,6 +1654,7 @@ library class ComprehensionList_ extends @py_comprehension_list {
|
||||
|
||||
/** INTERNAL: See the class `DictItem` for further information. */
|
||||
library class DictItem_ extends @py_dict_item {
|
||||
/** Gets a parent of this dict_item */
|
||||
DictItemList getParent() { py_dict_items(this, _, result, _) }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
@@ -1456,6 +1663,7 @@ library class DictItem_ extends @py_dict_item {
|
||||
|
||||
/** INTERNAL: See the class `DictItemList` for further information. */
|
||||
library class DictItemList_ extends @py_dict_item_list {
|
||||
/** Gets a parent of this dict_item list */
|
||||
DictItemListParent getParent() { py_dict_item_lists(this, result) }
|
||||
|
||||
/** Gets an item of this dict_item list */
|
||||
@@ -1482,6 +1690,7 @@ library class Expr_ extends @py_expr {
|
||||
/** Whether the parenthesised property of this expression is true. */
|
||||
predicate isParenthesised() { py_bools(this, 1) }
|
||||
|
||||
/** Gets a parent of this expression */
|
||||
ExprParent getParent() { py_exprs(this, _, result, _) }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
@@ -1490,6 +1699,7 @@ library class Expr_ extends @py_expr {
|
||||
|
||||
/** INTERNAL: See the class `ExprContext` for further information. */
|
||||
library class ExprContext_ extends @py_expr_context {
|
||||
/** Gets a parent of this expression context */
|
||||
ExprContextParent getParent() { py_expr_contexts(this, _, result) }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
@@ -1504,6 +1714,7 @@ library class ExprContextParent_ extends @py_expr_context_parent {
|
||||
|
||||
/** INTERNAL: See the class `ExprList` for further information. */
|
||||
library class ExprList_ extends @py_expr_list {
|
||||
/** Gets a parent of this expression list */
|
||||
ExprListParent getParent() { py_expr_lists(this, result, _) }
|
||||
|
||||
/** Gets an item of this expression list */
|
||||
@@ -1556,6 +1767,7 @@ library class LocationParent_ extends @py_location_parent {
|
||||
|
||||
/** INTERNAL: See the class `Operator` for further information. */
|
||||
library class Operator_ extends @py_operator {
|
||||
/** Gets a parent of this operator */
|
||||
BinaryExpr getParent() { py_operators(this, _, result) }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
@@ -1568,6 +1780,48 @@ library class Parameter_ extends @py_parameter {
|
||||
string toString() { result = "Parameter" }
|
||||
}
|
||||
|
||||
/** INTERNAL: See the class `Pattern` for further information. */
|
||||
library class Pattern_ extends @py_pattern {
|
||||
/** Gets the location of this pattern. */
|
||||
Location getLocation() { py_locations(result, this) }
|
||||
|
||||
/** Whether the parenthesised property of this pattern is true. */
|
||||
predicate isParenthesised() { py_bools(this, 1) }
|
||||
|
||||
/** Gets a parent of this pattern */
|
||||
PatternParent getParent() { py_patterns(this, _, result, _) }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = "Pattern" }
|
||||
}
|
||||
|
||||
/** INTERNAL: See the class `PatternList` for further information. */
|
||||
library class PatternList_ extends @py_pattern_list {
|
||||
/** Gets a parent of this pattern list */
|
||||
PatternListParent getParent() { py_pattern_lists(this, result, _) }
|
||||
|
||||
/** Gets an item of this pattern list */
|
||||
Pattern getAnItem() { py_patterns(result, _, this, _) }
|
||||
|
||||
/** Gets the nth item of this pattern list */
|
||||
Pattern getItem(int index) { py_patterns(result, _, this, index) }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = "PatternList" }
|
||||
}
|
||||
|
||||
/** INTERNAL: See the class `PatternListParent` for further information. */
|
||||
library class PatternListParent_ extends @py_pattern_list_parent {
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = "PatternListParent" }
|
||||
}
|
||||
|
||||
/** INTERNAL: See the class `PatternParent` for further information. */
|
||||
library class PatternParent_ extends @py_pattern_parent {
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = "PatternParent" }
|
||||
}
|
||||
|
||||
/** INTERNAL: See the class `Scope` for further information. */
|
||||
library class Scope_ extends @py_scope {
|
||||
/** Gets a textual representation of this element. */
|
||||
@@ -1579,6 +1833,7 @@ library class Stmt_ extends @py_stmt {
|
||||
/** Gets the location of this statement. */
|
||||
Location getLocation() { py_locations(result, this) }
|
||||
|
||||
/** Gets a parent of this statement */
|
||||
StmtList getParent() { py_stmts(this, _, result, _) }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
@@ -1587,6 +1842,7 @@ library class Stmt_ extends @py_stmt {
|
||||
|
||||
/** INTERNAL: See the class `StmtList` for further information. */
|
||||
library class StmtList_ extends @py_stmt_list {
|
||||
/** Gets a parent of this statement list */
|
||||
StmtListParent getParent() { py_stmt_lists(this, result, _) }
|
||||
|
||||
/** Gets an item of this statement list */
|
||||
@@ -1607,6 +1863,7 @@ library class StmtListParent_ extends @py_stmt_list_parent {
|
||||
|
||||
/** INTERNAL: See the class `StringList` for further information. */
|
||||
library class StringList_ extends @py_str_list {
|
||||
/** Gets a parent of this string list */
|
||||
StrListParent getParent() { py_str_lists(this, result) }
|
||||
|
||||
/** Gets an item of this string list */
|
||||
@@ -1633,6 +1890,7 @@ library class StrParent_ extends @py_str_parent {
|
||||
|
||||
/** INTERNAL: See the class `Unaryop` for further information. */
|
||||
library class Unaryop_ extends @py_unaryop {
|
||||
/** Gets a parent of this unary operation */
|
||||
UnaryExpr getParent() { py_unaryops(this, _, result) }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
|
||||
@@ -40,7 +40,7 @@ class Comment extends @py_comment {
|
||||
|
||||
private predicate comment_block_part(Comment start, Comment part, int i) {
|
||||
not exists(Comment prev | prev.getFollowing() = part) and
|
||||
exists(Comment following | part.getFollowing() = following) and
|
||||
exists(part.getFollowing()) and
|
||||
start = part and
|
||||
i = 1
|
||||
or
|
||||
|
||||
@@ -514,7 +514,7 @@ class ComparisonControlBlock extends ConditionBlock {
|
||||
|
||||
Comparison getTest() { this.getLastNode() = result }
|
||||
|
||||
/** Whether this conditional guard implies that, in block `b`, the result of `that` is `thatIsTrue` */
|
||||
/** Whether this conditional guard implies that, in block `b`, the result of `that` is `thatIsTrue` */
|
||||
predicate impliesThat(BasicBlock b, Comparison that, boolean thatIsTrue) {
|
||||
exists(boolean controlSense |
|
||||
this.controls(b, controlSense) and
|
||||
|
||||
@@ -326,9 +326,47 @@ module CodeExecution {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A data-flow node that constructs an SQL statement.
|
||||
* Often, it is worthy of an alert if an SQL statement is constructed such that
|
||||
* executing it would be a security risk.
|
||||
*
|
||||
* If it is important that the SQL statement is indeed executed, then use `SQLExecution`.
|
||||
*
|
||||
* Extend this class to refine existing API models. If you want to model new APIs,
|
||||
* extend `SqlConstruction::Range` instead.
|
||||
*/
|
||||
class SqlConstruction extends DataFlow::Node {
|
||||
SqlConstruction::Range range;
|
||||
|
||||
SqlConstruction() { this = range }
|
||||
|
||||
/** Gets the argument that specifies the SQL statements to be constructed. */
|
||||
DataFlow::Node getSql() { result = range.getSql() }
|
||||
}
|
||||
|
||||
/** Provides a class for modeling new SQL execution APIs. */
|
||||
module SqlConstruction {
|
||||
/**
|
||||
* A data-flow node that constructs an SQL statement.
|
||||
* Often, it is worthy of an alert if an SQL statement is constructed such that
|
||||
* executing it would be a security risk.
|
||||
*
|
||||
* Extend this class to model new APIs. If you want to refine existing API models,
|
||||
* extend `SqlExecution` instead.
|
||||
*/
|
||||
abstract class Range extends DataFlow::Node {
|
||||
/** Gets the argument that specifies the SQL statements to be constructed. */
|
||||
abstract DataFlow::Node getSql();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A data-flow node that executes SQL statements.
|
||||
*
|
||||
* If the context of interest is such that merely constructing an SQL statement
|
||||
* would be valuabe to report, then consider using `SqlConstruction`.
|
||||
*
|
||||
* Extend this class to refine existing API models. If you want to model new APIs,
|
||||
* extend `SqlExecution::Range` instead.
|
||||
*/
|
||||
@@ -346,6 +384,9 @@ module SqlExecution {
|
||||
/**
|
||||
* A data-flow node that executes SQL statements.
|
||||
*
|
||||
* If the context of interest is such that merely constructing an SQL statement
|
||||
* would be valuabe to report, then consider using `SqlConstruction`.
|
||||
*
|
||||
* Extend this class to model new APIs. If you want to refine existing API models,
|
||||
* extend `SqlExecution` instead.
|
||||
*/
|
||||
@@ -771,6 +812,72 @@ module HTTP {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Provides classes for modeling HTTP clients. */
|
||||
module Client {
|
||||
/**
|
||||
* A data-flow node that makes an outgoing HTTP request.
|
||||
*
|
||||
* Extend this class to refine existing API models. If you want to model new APIs,
|
||||
* extend `HTTP::Client::Request::Range` instead.
|
||||
*/
|
||||
class Request extends DataFlow::Node instanceof Request::Range {
|
||||
/**
|
||||
* Gets a data-flow node that contributes to the URL of the request.
|
||||
* Depending on the framework, a request may have multiple nodes which contribute to the URL.
|
||||
*/
|
||||
DataFlow::Node getAUrlPart() { result = super.getAUrlPart() }
|
||||
|
||||
/** Gets a string that identifies the framework used for this request. */
|
||||
string getFramework() { result = super.getFramework() }
|
||||
|
||||
/**
|
||||
* Holds if this request is made using a mode that disables SSL/TLS
|
||||
* certificate validation, where `disablingNode` represents the point at
|
||||
* which the validation was disabled, and `argumentOrigin` represents the origin
|
||||
* of the argument that disabled the validation (which could be the same node as
|
||||
* `disablingNode`).
|
||||
*/
|
||||
predicate disablesCertificateValidation(
|
||||
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
|
||||
) {
|
||||
super.disablesCertificateValidation(disablingNode, argumentOrigin)
|
||||
}
|
||||
}
|
||||
|
||||
/** Provides a class for modeling new HTTP requests. */
|
||||
module Request {
|
||||
/**
|
||||
* A data-flow node that makes an outgoing HTTP request.
|
||||
*
|
||||
* Extend this class to model new APIs. If you want to refine existing API models,
|
||||
* extend `HTTP::Client::Request` instead.
|
||||
*/
|
||||
abstract class Range extends DataFlow::Node {
|
||||
/**
|
||||
* Gets a data-flow node that contributes to the URL of the request.
|
||||
* Depending on the framework, a request may have multiple nodes which contribute to the URL.
|
||||
*/
|
||||
abstract DataFlow::Node getAUrlPart();
|
||||
|
||||
/** Gets a string that identifies the framework used for this request. */
|
||||
abstract string getFramework();
|
||||
|
||||
/**
|
||||
* Holds if this request is made using a mode that disables SSL/TLS
|
||||
* certificate validation, where `disablingNode` represents the point at
|
||||
* which the validation was disabled, and `argumentOrigin` represents the origin
|
||||
* of the argument that disabled the validation (which could be the same node as
|
||||
* `disablingNode`).
|
||||
*/
|
||||
abstract predicate disablesCertificateValidation(
|
||||
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
|
||||
);
|
||||
}
|
||||
}
|
||||
// TODO: investigate whether we should treat responses to client requests as
|
||||
// remote-flow-sources in general.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -718,6 +718,12 @@ class FormattedValue extends FormattedValue_ {
|
||||
}
|
||||
}
|
||||
|
||||
/** A guard in a case statement */
|
||||
class Guard extends Guard_ {
|
||||
/* syntax: if Expr */
|
||||
override Expr getASubExpression() { result = this.getTest() }
|
||||
}
|
||||
|
||||
/* Expression Contexts */
|
||||
/** A context in which an expression used */
|
||||
class ExprContext extends ExprContext_ { }
|
||||
|
||||
@@ -6,13 +6,18 @@
|
||||
// `docs/codeql/support/reusables/frameworks.rst`
|
||||
private import semmle.python.frameworks.Aioch
|
||||
private import semmle.python.frameworks.Aiohttp
|
||||
private import semmle.python.frameworks.Aiomysql
|
||||
private import semmle.python.frameworks.Aiopg
|
||||
private import semmle.python.frameworks.Asyncpg
|
||||
private import semmle.python.frameworks.ClickhouseDriver
|
||||
private import semmle.python.frameworks.Cryptodome
|
||||
private import semmle.python.frameworks.Cryptography
|
||||
private import semmle.python.frameworks.Dill
|
||||
private import semmle.python.frameworks.Django
|
||||
private import semmle.python.frameworks.Fabric
|
||||
private import semmle.python.frameworks.FastApi
|
||||
private import semmle.python.frameworks.Flask
|
||||
private import semmle.python.frameworks.FlaskAdmin
|
||||
private import semmle.python.frameworks.FlaskSqlAlchemy
|
||||
private import semmle.python.frameworks.Idna
|
||||
private import semmle.python.frameworks.Invoke
|
||||
@@ -23,12 +28,17 @@ private import semmle.python.frameworks.Mysql
|
||||
private import semmle.python.frameworks.MySQLdb
|
||||
private import semmle.python.frameworks.Peewee
|
||||
private import semmle.python.frameworks.Psycopg2
|
||||
private import semmle.python.frameworks.Pydantic
|
||||
private import semmle.python.frameworks.PyMySQL
|
||||
private import semmle.python.frameworks.Requests
|
||||
private import semmle.python.frameworks.RestFramework
|
||||
private import semmle.python.frameworks.Rsa
|
||||
private import semmle.python.frameworks.RuamelYaml
|
||||
private import semmle.python.frameworks.Simplejson
|
||||
private import semmle.python.frameworks.SqlAlchemy
|
||||
private import semmle.python.frameworks.Starlette
|
||||
private import semmle.python.frameworks.Stdlib
|
||||
private import semmle.python.frameworks.Toml
|
||||
private import semmle.python.frameworks.Tornado
|
||||
private import semmle.python.frameworks.Twisted
|
||||
private import semmle.python.frameworks.Ujson
|
||||
|
||||
@@ -18,7 +18,7 @@ class Function extends Function_, Scope, AstNode {
|
||||
override Scope getScope() { result = this.getEnclosingScope() }
|
||||
|
||||
/** Whether this function is declared in a class */
|
||||
predicate isMethod() { exists(Class cls | this.getEnclosingScope() = cls) }
|
||||
predicate isMethod() { this.getEnclosingScope() instanceof Class }
|
||||
|
||||
/** Whether this is a special method, that is does its name have the form `__xxx__` (except `__init__`) */
|
||||
predicate isSpecialMethod() {
|
||||
|
||||
@@ -98,7 +98,7 @@ class LShift extends LShift_ {
|
||||
override string getSpecialMethodName() { result = "__lshift__" }
|
||||
}
|
||||
|
||||
/** A modulo (`%`) binary operator, which includes string formatting */
|
||||
/** A modulo (`%`) binary operator, which includes string formatting */
|
||||
class Mod extends Mod_ {
|
||||
override string getSpecialMethodName() { result = "__mod__" }
|
||||
}
|
||||
|
||||
118
python/ql/lib/semmle/python/Patterns.qll
Normal file
118
python/ql/lib/semmle/python/Patterns.qll
Normal file
@@ -0,0 +1,118 @@
|
||||
/**
|
||||
* Wrapping generated AST classes: `Pattern_` and subclasses.
|
||||
*/
|
||||
|
||||
import python
|
||||
|
||||
/** A pattern in a match statement */
|
||||
class Pattern extends Pattern_, AstNode {
|
||||
/** Gets the scope of this pattern */
|
||||
override Scope getScope() { result = this.getCase().getScope() }
|
||||
|
||||
/** Gets the case statement containing this pattern */
|
||||
Case getCase() { result.contains(this) }
|
||||
|
||||
override string toString() { result = "Pattern" }
|
||||
|
||||
/** Gets the module enclosing this pattern */
|
||||
Module getEnclosingModule() { result = this.getScope().getEnclosingModule() }
|
||||
|
||||
/** Whether the parenthesized property of this expression is true. */
|
||||
predicate isParenthesized() { Pattern_.super.isParenthesised() }
|
||||
|
||||
override Location getLocation() { result = Pattern_.super.getLocation() }
|
||||
|
||||
/** Gets an immediate (non-nested) sub-expression of this pattern */
|
||||
Expr getASubExpression() { none() }
|
||||
|
||||
/** Gets an immediate (non-nested) sub-statement of this pattern */
|
||||
Stmt getASubStatement() { none() }
|
||||
|
||||
/** Gets an immediate (non-nested) sub-pattern of this pattern */
|
||||
Pattern getASubPattern() { none() }
|
||||
|
||||
override AstNode getAChildNode() {
|
||||
result = this.getASubExpression()
|
||||
or
|
||||
result = this.getASubStatement()
|
||||
or
|
||||
result = this.getASubPattern()
|
||||
}
|
||||
}
|
||||
|
||||
/** An as-pattern in a match statement: `<subpattern> as alias` */
|
||||
class MatchAsPattern extends MatchAsPattern_ {
|
||||
override Pattern getASubPattern() { result = this.getPattern() }
|
||||
|
||||
override Expr getASubExpression() { result = this.getAlias() }
|
||||
|
||||
override Name getAlias() { result = super.getAlias() }
|
||||
}
|
||||
|
||||
/** An or-pattern in a match statement: `(<pattern1>|<pattern2>)` */
|
||||
class MatchOrPattern extends MatchOrPattern_ {
|
||||
override Pattern getASubPattern() { result = this.getAPattern() }
|
||||
}
|
||||
|
||||
/** A literal pattern in a match statement: `42` */
|
||||
class MatchLiteralPattern extends MatchLiteralPattern_ {
|
||||
override Expr getASubExpression() { result = this.getLiteral() }
|
||||
}
|
||||
|
||||
/** A capture pattern in a match statement: `var` */
|
||||
class MatchCapturePattern extends MatchCapturePattern_ {
|
||||
/* syntax: varname */
|
||||
override Expr getASubExpression() { result = this.getVariable() }
|
||||
|
||||
/** Gets the variable that is bound by this capture pattern */
|
||||
override Name getVariable() { result = super.getVariable() }
|
||||
}
|
||||
|
||||
/** A wildcard pattern in a match statement: `_` */
|
||||
class MatchWildcardPattern extends MatchWildcardPattern_ { }
|
||||
|
||||
/** A value pattern in a match statement: `Http.OK` */
|
||||
class MatchValuePattern extends MatchValuePattern_ {
|
||||
override Expr getASubExpression() { result = this.getValue() }
|
||||
}
|
||||
|
||||
/** A sequence pattern in a match statement `<p1>, <p2>` */
|
||||
class MatchSequencePattern extends MatchSequencePattern_ {
|
||||
override Pattern getASubPattern() { result = this.getAPattern() }
|
||||
}
|
||||
|
||||
/** A star pattern in a match statement: `(..., *)` */
|
||||
class MatchStarPattern extends MatchStarPattern_ {
|
||||
override Pattern getASubPattern() { result = this.getTarget() }
|
||||
}
|
||||
|
||||
/** A mapping pattern in a match statement: `{'a': var}` */
|
||||
class MatchMappingPattern extends MatchMappingPattern_ {
|
||||
override Pattern getASubPattern() { result = this.getAMapping() }
|
||||
}
|
||||
|
||||
/** A double star pattern in a match statement: `{..., **}` */
|
||||
class MatchDoubleStarPattern extends MatchDoubleStarPattern_ {
|
||||
override Pattern getASubPattern() { result = this.getTarget() }
|
||||
}
|
||||
|
||||
/** A key-value pattern inside a mapping pattern: `a: var` */
|
||||
class MatchKeyValuePattern extends MatchKeyValuePattern_ {
|
||||
override Pattern getASubPattern() { result = this.getKey() or result = this.getValue() }
|
||||
}
|
||||
|
||||
/** A class pattern in a match statement: `Circle(radius = 3)` */
|
||||
class MatchClassPattern extends MatchClassPattern_ {
|
||||
override Expr getASubExpression() { result = this.getClassName() }
|
||||
|
||||
override Pattern getASubPattern() {
|
||||
result = this.getAPositional() or result = this.getAKeyword()
|
||||
}
|
||||
}
|
||||
|
||||
/** A keyword pattern inside a class pattern: `radius = 3` */
|
||||
class MatchKeywordPattern extends MatchKeywordPattern_ {
|
||||
override Expr getASubExpression() { result = this.getAttribute() }
|
||||
|
||||
override Pattern getASubPattern() { result = this.getValue() }
|
||||
}
|
||||
@@ -76,7 +76,7 @@ class PrintAstNode extends TPrintAstNode {
|
||||
/**
|
||||
* Gets a child of this node.
|
||||
*/
|
||||
final PrintAstNode getAChild() { result = getChild(_) }
|
||||
final PrintAstNode getAChild() { result = this.getChild(_) }
|
||||
|
||||
/**
|
||||
* Gets the parent of this node, if any.
|
||||
@@ -94,7 +94,7 @@ class PrintAstNode extends TPrintAstNode {
|
||||
*/
|
||||
string getProperty(string key) {
|
||||
key = "semmle.label" and
|
||||
result = toString()
|
||||
result = this.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -103,7 +103,7 @@ class PrintAstNode extends TPrintAstNode {
|
||||
* this.
|
||||
*/
|
||||
string getChildEdgeLabel(int childIndex) {
|
||||
exists(getChild(childIndex)) and
|
||||
exists(this.getChild(childIndex)) and
|
||||
result = childIndex.toString()
|
||||
}
|
||||
}
|
||||
@@ -157,13 +157,13 @@ class AstElementNode extends PrintAstNode, TElementNode {
|
||||
|
||||
override PrintAstNode getChild(int childIndex) {
|
||||
exists(AstNode el | result.(AstElementNode).getAstNode() = el |
|
||||
el = this.getChildNode(childIndex) and not el = getStmtList(_, _).getAnItem()
|
||||
el = this.getChildNode(childIndex) and not el = this.getStmtList(_, _).getAnItem()
|
||||
)
|
||||
or
|
||||
// displaying all `StmtList` after the other children.
|
||||
exists(int offset | offset = 1 + max([0, any(int index | exists(this.getChildNode(index)))]) |
|
||||
exists(int index | childIndex = index + offset |
|
||||
result.(StmtListNode).getList() = getStmtList(index, _)
|
||||
result.(StmtListNode).getList() = this.getStmtList(index, _)
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -299,7 +299,7 @@ class StmtListNode extends PrintAstNode, TStmtListNode {
|
||||
|
||||
private string getLabel() { this.getList() = any(AstElementNode node).getStmtList(_, result) }
|
||||
|
||||
override string toString() { result = "(StmtList) " + getLabel() }
|
||||
override string toString() { result = "(StmtList) " + this.getLabel() }
|
||||
|
||||
override PrintAstNode getChild(int childIndex) {
|
||||
exists(AstNode el | result.(AstElementNode).getAstNode() = el | el = list.getItem(childIndex))
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user