Merge branch 'main' into orm

This commit is contained in:
Rasmus Wriedt Larsen
2022-03-16 11:22:55 +01:00
1194 changed files with 66044 additions and 50563 deletions

View File

@@ -1,3 +1,13 @@
## 0.0.11
### Minor Analysis Improvements
* Added new SSRF sinks for `httpx`, `pycurl`, `urllib`, `urllib2`, `urllib3`, and `libtaxii`. This improvement was [submitted by @haby0](https://github.com/github/codeql/pull/8275).
* The regular expression parser now groups sequences of normal characters. This reduces the number of instances of `RegExpNormalChar`.
* Fixed taint propagation for attribute assignment. In the assignment `x.foo = tainted` we no longer treat the entire object `x` as tainted, just because the attribute `foo` contains tainted data. This leads to slightly fewer false positives.
* Improved analysis of attributes for data-flow and taint tracking queries, so `getattr`/`setattr` are supported, and a write to an attribute properly stops flow for the old value in that attribute.
* Added post-update nodes (`DataFlow::PostUpdateNode`) for arguments in calls that can't be resolved.
## 0.0.10
### Deprecated APIs

View File

@@ -1,5 +0,0 @@
---
category: minorAnalysis
---
* Improved analysis of attributes for data-flow and taint tracking queries, so `getattr`/`setattr` are supported, and a write to an attribute properly stops flow for the old value in that attribute.
* Added post-update nodes (`DataFlow::PostUpdateNode`) for arguments in calls that can't be resolved.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* All deprecated predicates/classes/modules that have been deprecated for over a year have been deleted.

View File

@@ -0,0 +1,5 @@
---
category: deprecated
---
* Many classes/predicates/modules that had upper-case acronyms have been renamed to follow our style-guide.
The old name still exists as a deprecated alias.

View File

@@ -0,0 +1,5 @@
---
category: deprecated
---
* Some modules that started with a lowercase letter have been renamed to follow our style-guide.
The old name still exists as a deprecated alias.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Fixed taint propagation for attribute assignment. In the assignment `x.foo = tainted` we no longer treat the entire object `x` as tainted, just because the attribute `foo` contains tainted data. This leads to slightly fewer false positives.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* The regular expression parser now groups sequences of normal characters. This reduces the number of instances of `RegExpNormalChar`.

View File

@@ -0,0 +1,4 @@
---
category: breaking
---
* The flow state variants of `isBarrier` and `isAdditionalFlowStep` are no longer exposed in the taint tracking library. The `isSanitizer` and `isAdditionalTaintStep` predicates should be used instead.

View File

@@ -0,0 +1,9 @@
## 0.0.11
### Minor Analysis Improvements
* Added new SSRF sinks for `httpx`, `pycurl`, `urllib`, `urllib2`, `urllib3`, and `libtaxii`. This improvement was [submitted by @haby0](https://github.com/github/codeql/pull/8275).
* The regular expression parser now groups sequences of normal characters. This reduces the number of instances of `RegExpNormalChar`.
* Fixed taint propagation for attribute assignment. In the assignment `x.foo = tainted` we no longer treat the entire object `x` as tainted, just because the attribute `foo` contains tainted data. This leads to slightly fewer false positives.
* Improved analysis of attributes for data-flow and taint tracking queries, so `getattr`/`setattr` are supported, and a write to an attribute properly stops flow for the old value in that attribute.
* Added post-update nodes (`DataFlow::PostUpdateNode`) for arguments in calls that can't be resolved.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.0.10
lastReleaseVersion: 0.0.11

View File

@@ -1,5 +1,5 @@
name: codeql/python-all
version: 0.0.11-dev
version: 0.0.12-dev
groups: python
dbscheme: semmlecode.python.dbscheme
extractor: python

View File

@@ -1,6 +1,6 @@
import python
/** Syntactic node (Class, Function, Module, Expr, Stmt or Comprehension) corresponding to a flow node */
/** A syntactic node (Class, Function, Module, Expr, Stmt or Comprehension) corresponding to a flow node */
abstract class AstNode extends AstNode_ {
/*
* Special comment for documentation generation.
@@ -61,31 +61,31 @@ abstract class AstNode extends AstNode_ {
}
/* Parents */
/** Internal implementation class */
/** The parent of a `Function`. Internal implementation class */
class FunctionParent extends FunctionParent_ { }
/** Internal implementation class */
/** The parent of an `Arguments` node. Internal implementation class */
class ArgumentsParent extends ArgumentsParent_ { }
/** Internal implementation class */
/** The parent of an `ExprList`. Internal implementation class */
class ExprListParent extends ExprListParent_ { }
/** Internal implementation class */
/** The parent of an `ExprContext`. Internal implementation class */
class ExprContextParent extends ExprContextParent_ { }
/** Internal implementation class */
/** The parent of a `StmtList`. Internal implementation class */
class StmtListParent extends StmtListParent_ { }
/** Internal implementation class */
/** The parent of a `StrList`. Internal implementation class */
class StrListParent extends StrListParent_ { }
/** Internal implementation class */
/** The parent of an `Expr`. Internal implementation class */
class ExprParent extends ExprParent_ { }
/** Internal implementation class */
/** The parent of a `PatternList`. Internal implementation class */
class PatternListParent extends PatternListParent_ { }
/** Internal implementation class */
/** The parent of a `Pattern`. Internal implementation class */
class PatternParent extends PatternParent_ { }
class DictItem extends DictItem_, AstNode {
@@ -120,7 +120,7 @@ class Comprehension extends Comprehension_, AstNode {
class BytesOrStr extends BytesOrStr_ { }
/**
* Part of a string literal formed by implicit concatenation.
* A part of a string literal formed by implicit concatenation.
* For example the string literal "abc" expressed in the source as `"a" "b" "c"`
* would be composed of three `StringPart`s.
*/

View File

@@ -85,12 +85,6 @@ class ClassDef extends Assign {
/** The scope of a class. This is the scope of all the statements within the class definition */
class Class extends Class_, Scope, AstNode {
/**
* Use getADecorator() instead of getDefinition().getADecorator()
* Use getMetaClass() instead of getDefinition().getMetaClass()
*/
deprecated ClassExpr getDefinition() { result = this.getParent() }
/** Gets a defined init method of this class */
Function getInitMethod() { result.getScope() = this and result.isInitMethod() }

View File

@@ -59,7 +59,7 @@ class CommentBlock extends @py_comment {
/** Gets a textual representation of this element. */
string toString() { result = "Comment block" }
/** The length of this comment block (in comments) */
/** Gets the length of this comment block (in comments) */
int length() { result = max(int i | comment_block_part(this, _, i)) }
/**

View File

@@ -76,22 +76,22 @@ class CompareOp extends int {
}
}
/** The `CompareOp` for "equals". */
/** Gets the `CompareOp` for "equals". */
CompareOp eq() { result = 1 }
/** The `CompareOp` for "not equals". */
/** Gets the `CompareOp` for "not equals". */
CompareOp ne() { result = 2 }
/** The `CompareOp` for "less than". */
/** Gets the `CompareOp` for "less than". */
CompareOp lt() { result = 3 }
/** The `CompareOp` for "less than or equal to". */
/** Gets the `CompareOp` for "less than or equal to". */
CompareOp le() { result = 4 }
/** The `CompareOp` for "greater than". */
/** Gets the `CompareOp` for "greater than". */
CompareOp gt() { result = 5 }
/** The `CompareOp` for "greater than or equal to". */
/** Gets the `CompareOp` for "greater than or equal to". */
CompareOp ge() { result = 6 }
/* Workaround precision limits in floating point numbers */

View File

@@ -1,6 +1,6 @@
import python
/** Base class for list, set and dictionary comprehensions, and generator expressions. */
/** The base class for list, set and dictionary comprehensions, and generator expressions. */
abstract class Comp extends Expr {
abstract Function getFunction();

View File

@@ -334,6 +334,7 @@ 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.
*
@@ -355,11 +356,14 @@ class SqlConstruction extends DataFlow::Node {
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.
*
* If it is important that the SQL statement is indeed executed, then use `SQLExecution`.
*
* Extend this class to model new APIs. If you want to refine existing API models,
* extend `SqlExecution` instead.
* extend `SqlConstruction` instead.
*/
abstract class Range extends DataFlow::Node {
/** Gets the argument that specifies the SQL statements to be constructed. */
@@ -449,6 +453,105 @@ module RegexExecution {
}
}
/** Provides classes for modeling XML-related APIs. */
module XML {
/**
* A data-flow node that constructs an XPath expression.
*
* Often, it is worthy of an alert if an XPath expression is constructed such that
* executing it would be a security risk.
*
* If it is important that the XPath expression is indeed executed, then use `XPathExecution`.
*
* Extend this class to refine existing API models. If you want to model new APIs,
* extend `XPathConstruction::Range` instead.
*/
class XPathConstruction extends DataFlow::Node {
XPathConstruction::Range range;
XPathConstruction() { this = range }
/** Gets the argument that specifies the XPath expressions to be constructed. */
DataFlow::Node getXPath() { result = range.getXPath() }
/**
* Gets the name of this XPath expression construction, typically the name of an executing method.
* This is used for nice alert messages and should include the module if possible.
*/
string getName() { result = range.getName() }
}
/** Provides a class for modeling new XPath construction APIs. */
module XPathConstruction {
/**
* A data-flow node that constructs an XPath expression.
*
* Often, it is worthy of an alert if an XPath expression 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 `XPathConstruction` instead.
*/
abstract class Range extends DataFlow::Node {
/** Gets the argument that specifies the XPath expressions to be constructed. */
abstract DataFlow::Node getXPath();
/**
* Gets the name of this XPath expression construction, typically the name of an executing method.
* This is used for nice alert messages and should include the module if possible.
*/
abstract string getName();
}
}
/**
* A data-flow node that executes a xpath expression.
*
* If the context of interest is such that merely constructing an XPath expression
* would be valuabe to report, then consider using `XPathConstruction`.
*
* Extend this class to refine existing API models. If you want to model new APIs,
* extend `XPathExecution::Range` instead.
*/
class XPathExecution extends DataFlow::Node {
XPathExecution::Range range;
XPathExecution() { this = range }
/** Gets the data flow node for the XPath expression being executed by this node. */
DataFlow::Node getXPath() { result = range.getXPath() }
/**
* Gets the name of this XPath expression execution, typically the name of an executing method.
* This is used for nice alert messages and should include the module if possible.
*/
string getName() { result = range.getName() }
}
/** Provides classes for modeling new regular-expression execution APIs. */
module XPathExecution {
/**
* A data-flow node that executes a XPath expression.
*
* If the context of interest is such that merely constructing an XPath expression
* would be valuabe to report, then consider using `XPathConstruction`.
*
* Extend this class to model new APIs. If you want to refine existing API models,
* extend `XPathExecution` instead.
*/
abstract class Range extends DataFlow::Node {
/** Gets the data flow node for the XPath expression being executed by this node. */
abstract DataFlow::Node getXPath();
/**
* Gets the name of this xpath expression execution, typically the name of an executing method.
* This is used for nice alert messages and should include the module if possible.
*/
abstract string getName();
}
}
}
/** Provides classes for modeling LDAP-related APIs. */
module LDAP {
/**

View File

@@ -30,9 +30,6 @@ class Expr extends Expr_, AstNode {
/** Whether this expression is a constant */
predicate isConstant() { not this.isVariable() }
/** Use isParenthesized instead. */
deprecated override predicate isParenthesised() { this.isParenthesized() }
/** Whether the parenthesized property of this expression is true. */
predicate isParenthesized() { Expr_.super.isParenthesised() }
@@ -49,9 +46,6 @@ class Expr extends Expr_, AstNode {
/** Gets an immediate (non-nested) sub-expression of this expression */
Expr getASubExpression() { none() }
/** Use StrConst.getText() instead */
deprecated string strValue() { none() }
override AstNode getAChildNode() { result = this.getASubExpression() }
/**
@@ -315,7 +309,7 @@ class Ellipsis extends Ellipsis_ {
}
/**
* Immutable literal expressions (except tuples).
* An immutable literal expression (except tuples).
* Consists of string (both unicode and byte) literals and numeric literals.
*/
abstract class ImmutableLiteral extends Expr {
@@ -446,6 +440,8 @@ class Unicode extends StrConst {
}
/**
* Gets the quoted representation fo this string.
*
* The extractor puts quotes into the name of each string (to prevent "0" clashing with 0).
* The following predicate help us match up a string/byte literals in the source
* which the equivalent object.
@@ -620,8 +616,6 @@ class StrConst extends Str_, ImmutableLiteral {
)
}
deprecated override string strValue() { result = this.getS() }
override Expr getASubExpression() { none() }
override AstNode getAChildNode() { result = this.getAnImplicitlyConcatenatedPart() }
@@ -685,7 +679,7 @@ class False extends BooleanLiteral {
override boolean booleanValue() { result = false }
}
/** `None` */
/** The `None` constant. */
class None extends NameConstant {
/* syntax: None */
None() { name_consts(this, "None") }
@@ -728,20 +722,20 @@ class Guard extends Guard_ {
/** A context in which an expression used */
class ExprContext extends ExprContext_ { }
/** Load context, the context of var in len(var) */
/** The load context, the context of var in len(var) */
class Load extends Load_ { }
/** Store context, the context of var in var = 0 */
/** The store context, the context of var in var = 0 */
class Store extends Store_ { }
/** Delete context, the context of var in del var */
/** The delete context, the context of var in del var */
class Del extends Del_ { }
/** This is an artifact of the Python grammar which includes an AugLoad context, even though it is never used. */
library class AugLoad extends AugLoad_ { }
/** The context of an augmented load. This is an artifact of the Python grammar which includes an AugLoad context, even though it is never used. */
class AugLoad extends AugLoad_ { }
/** Augmented store context, the context of var in var += 1 */
/** The augmented store context, the context of var in var += 1 */
class AugStore extends AugStore_ { }
/** Parameter context, the context of var in def f(var): pass */
/** The parameter context, the context of var in def f(var): pass */
class Param extends Param_ { }

View File

@@ -2,12 +2,6 @@ import python
/** A file */
class File extends Container, @file {
/** DEPRECATED: Use `getAbsolutePath` instead. */
deprecated override string getName() { result = this.getAbsolutePath() }
/** DEPRECATED: Use `getAbsolutePath` instead. */
deprecated string getFullName() { result = this.getAbsolutePath() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
@@ -115,9 +109,6 @@ private predicate occupied_line(File f, int n) {
/** A folder (directory) */
class Folder extends Container, @folder {
/** DEPRECATED: Use `getAbsolutePath` instead. */
deprecated override string getName() { result = this.getAbsolutePath() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
@@ -156,9 +147,6 @@ class Folder extends Container, @folder {
abstract class Container extends @container {
Container getParent() { containerparent(result, this) }
/** Gets a child of this container */
deprecated Container getChild() { containerparent(this, result) }
/**
* Gets a textual representation of the path of this container.
*
@@ -166,8 +154,11 @@ abstract class Container extends @container {
*/
string toString() { result = this.getAbsolutePath() }
/** Gets the name of this container */
abstract string getName();
/**
* Gets the name of this container.
* DEPRECATED: Use `getAbsolutePath` instead.
*/
deprecated string getName() { result = this.getAbsolutePath() }
/**
* Gets the relative path of this file or folder from the root folder of the
@@ -339,7 +330,7 @@ abstract class Container extends @container {
* paths. The list of paths is composed of the paths passed to the extractor and
* `sys.path`.
*/
predicate isImportRoot(int n) { this.getName() = import_path_element(n) }
predicate isImportRoot(int n) { this.getAbsolutePath() = import_path_element(n) }
/** Holds if this folder is the root folder for the standard library. */
predicate isStdLibRoot(int major, int minor) {

View File

@@ -82,30 +82,12 @@ class ControlFlowNode extends @py_flow_node {
toAst(this) instanceof NameConstant
}
/** Use NameNode.isLoad() instead */
deprecated predicate isUse() { toAst(this) instanceof Name and this.isLoad() }
/** Use NameNode.isStore() */
deprecated predicate isDefinition() { toAst(this) instanceof Name and this.isStore() }
/** Whether this flow node corresponds to an attribute expression */
predicate isAttribute() { toAst(this) instanceof Attribute }
/** Use AttrNode.isLoad() instead */
deprecated predicate isAttributeLoad() { toAst(this) instanceof Attribute and this.isLoad() }
/** Use AttrNode.isStore() instead */
deprecated predicate isAttributeStore() { toAst(this) instanceof Attribute and this.isStore() }
/** Whether this flow node corresponds to an subscript expression */
predicate isSubscript() { toAst(this) instanceof Subscript }
/** Use SubscriptNode.isLoad() instead */
deprecated predicate isSubscriptLoad() { toAst(this) instanceof Subscript and this.isLoad() }
/** Use SubscriptNode.isStore() instead */
deprecated predicate isSubscriptStore() { toAst(this) instanceof Subscript and this.isStore() }
/** Whether this flow node corresponds to an import member */
predicate isImportMember() { toAst(this) instanceof ImportMember }
@@ -155,7 +137,7 @@ class ControlFlowNode extends @py_flow_node {
/** Whether this flow node is the first in its scope */
predicate isEntryNode() { py_scope_flow(this, _, -1) }
/** The value that this ControlFlowNode points-to. */
/** Gets the value that this ControlFlowNode points-to. */
predicate pointsTo(Value value) { this.pointsTo(_, value, _) }
/** Gets the value that this ControlFlowNode points-to. */
@@ -164,10 +146,10 @@ class ControlFlowNode extends @py_flow_node {
/** Gets a value that this ControlFlowNode may points-to. */
Value inferredValue() { this.pointsTo(_, result, _) }
/** The value and origin that this ControlFlowNode points-to. */
/** Gets the value and origin that this ControlFlowNode points-to. */
predicate pointsTo(Value value, ControlFlowNode origin) { this.pointsTo(_, value, origin) }
/** The value and origin that this ControlFlowNode points-to, given the context. */
/** Gets the value and origin that this ControlFlowNode points-to, given the context. */
predicate pointsTo(Context context, Value value, ControlFlowNode origin) {
PointsTo::pointsTo(this, context, value, origin)
}
@@ -317,7 +299,7 @@ class ControlFlowNode extends @py_flow_node {
exists(BasicBlock b, int i, int j | this = b.getNode(i) and other = b.getNode(j) and i < j)
}
/* Holds if this CFG node is a branch */
/** Holds if this CFG node is a branch */
predicate isBranch() { py_true_successors(this, _) or py_false_successors(this, _) }
ControlFlowNode getAChild() { result = this.getExprChild(this.getBasicBlock()) }
@@ -439,12 +421,6 @@ class AttrNode extends ControlFlowNode {
)
}
/** Use getObject() instead */
deprecated ControlFlowNode getValue() { result = this.getObject() }
/** Use getObject(name) instead */
deprecated ControlFlowNode getValue(string name) { result = this.getObject(name) }
/**
* Gets the flow node corresponding to the object of the attribute expression corresponding to this flow node,
* with the matching name
@@ -507,18 +483,6 @@ class ImportStarNode extends ControlFlowNode {
class SubscriptNode extends ControlFlowNode {
SubscriptNode() { toAst(this) instanceof Subscript }
/**
* DEPRECATED: Use `getObject()` instead.
* This will be formally deprecated before the end 2018 and removed in 2019.
*/
deprecated ControlFlowNode getValue() {
exists(Subscript s |
this.getNode() = s and
s.getObject() = result.getNode() and
result.getBasicBlock().dominates(this.getBasicBlock())
)
}
/** flow node corresponding to the value of the sequence in a subscript operation */
ControlFlowNode getObject() {
exists(Subscript s |
@@ -950,10 +914,6 @@ class NameNode extends ControlFlowNode {
/** A control flow node corresponding to a named constant, one of `None`, `True` or `False`. */
class NameConstantNode extends NameNode {
NameConstantNode() { exists(NameConstant n | py_flow_bb_node(this, n, _, _)) }
deprecated override predicate defines(Variable v) { none() }
deprecated override predicate deletes(Variable v) { none() }
/*
* We ought to override uses as well, but that has
* a serious performance impact.
@@ -1009,12 +969,6 @@ private module Scopes {
scope = n.getEnclosingModule()
}
private predicate maybe_defined(SsaVariable var) {
exists(var.getDefinition()) and not py_ssa_phi(var, _) and not var.getDefinition().isDelete()
or
exists(SsaVariable input | input = var.getAPhiInput() | maybe_defined(input))
}
private predicate maybe_undefined(SsaVariable var) {
not exists(var.getDefinition()) and not py_ssa_phi(var, _)
or

View File

@@ -19,17 +19,22 @@ 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.Httpx
private import semmle.python.frameworks.Idna
private import semmle.python.frameworks.Invoke
private import semmle.python.frameworks.Jmespath
private import semmle.python.frameworks.Ldap
private import semmle.python.frameworks.Ldap3
private import semmle.python.frameworks.Libtaxii
private import semmle.python.frameworks.Libxml2
private import semmle.python.frameworks.Lxml
private import semmle.python.frameworks.MarkupSafe
private import semmle.python.frameworks.Multidict
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.Pycurl
private import semmle.python.frameworks.Pydantic
private import semmle.python.frameworks.PyMySQL
private import semmle.python.frameworks.Requests
@@ -44,5 +49,6 @@ private import semmle.python.frameworks.Toml
private import semmle.python.frameworks.Tornado
private import semmle.python.frameworks.Twisted
private import semmle.python.frameworks.Ujson
private import semmle.python.frameworks.Urllib3
private import semmle.python.frameworks.Yaml
private import semmle.python.frameworks.Yarl

View File

@@ -5,11 +5,11 @@ import python
* It is the syntactic entity that is compiled to a code object.
*/
class Function extends Function_, Scope, AstNode {
/** The expression defining this function */
/** Gets the expression defining this function */
CallableExpr getDefinition() { result = this.getParent() }
/**
* The scope in which this function occurs, will be a class for a method,
* Gets the scope in which this function occurs. This will be a class for a method,
* another function for nested functions, generator expressions or comprehensions,
* or a module for a plain function.
*/
@@ -183,8 +183,8 @@ class FunctionDef extends Assign {
override Stmt getLastStatement() { result = this.getDefinedFunction().getLastStatement() }
}
/** A function that uses 'fast' locals, stored in the frame not in a dictionary. */
class FastLocalsFunction extends Function {
/** A function that uses 'fast' locals, stored in the frame not in a dictionary. */
FastLocalsFunction() {
not exists(ImportStar i | i.getScope() = this) and
not exists(Exec e | e.getScope() = this)

View File

@@ -35,6 +35,8 @@ class ImportExpr extends ImportExpr_ {
}
/**
* Gets the level of this import.
*
* The language specifies level as -1 if relative imports are to be tried first, 0 for absolute imports,
* and level > 0 for explicit relative imports.
*/
@@ -165,13 +167,6 @@ class Import extends Import_ {
result = this.getAName().getValue().(ImportMember).getModule()
}
/**
* Use getAnImportedModuleName(),
* possibly combined with ModuleObject.importedAs()
* Gets a module imported by this import statement
*/
deprecated Module getAModule() { result.getName() = this.getAnImportedModuleName() }
/** Whether this a `from ... import ...` statement */
predicate isFromImport() { this.getAName().getValue() instanceof ImportMember }
@@ -216,13 +211,6 @@ class ImportStar extends ImportStar_ {
override string toString() { result = "from " + this.getModuleExpr().getName() + " import *" }
/**
* Use getAnImportedModuleName(),
* possibly combined with ModuleObject.importedAs()
* Gets the module imported by this import * statement
*/
deprecated Module getTheModule() { result.getName() = this.getImportedModuleName() }
override Expr getASubExpression() { result = this.getModule() }
override Stmt getASubStatement() { none() }

View File

@@ -18,7 +18,7 @@ class FunctionMetrics extends Function {
int getNumberOfLinesOfDocStrings() { py_docstringlines(this, result) }
/**
* Cyclomatic complexity:
* Gets the cyclomatic complexity of the function:
* The number of linearly independent paths through the source code.
* Computed as E - N + 2P,
* where
@@ -27,9 +27,9 @@ class FunctionMetrics extends Function {
* P = the number of connected components, which for a single function is 1.
*/
int getCyclomaticComplexity() {
exists(int E, int N |
N = count(BasicBlock b | b = this.getABasicBlock() and b.likelyReachable()) and
E =
exists(int e, int n |
n = count(BasicBlock b | b = this.getABasicBlock() and b.likelyReachable()) and
e =
count(BasicBlock b1, BasicBlock b2 |
b1 = this.getABasicBlock() and
b1.likelyReachable() and
@@ -39,7 +39,7 @@ class FunctionMetrics extends Function {
not b1.unlikelySuccessor(b2)
)
|
result = E - N + 2
result = e - n + 2
)
}
@@ -130,13 +130,13 @@ class ClassMetrics extends Class {
}
/**
* The afferent coupling of a class is the number of classes that
* Gets the afferent coupling of a class -- the number of classes that
* directly depend on it.
*/
int getAfferentCoupling() { result = count(ClassMetrics t | t.dependsOn(this)) }
/**
* The efferent coupling of a class is the number of classes that
* Gets the efferent coupling of a class -- the number of classes that
* it directly depends on.
*/
int getEfferentCoupling() { result = count(ClassMetrics t | this.dependsOn(t)) }
@@ -273,13 +273,13 @@ class ModuleMetrics extends Module {
int getNumberOfLinesOfDocStrings() { py_docstringlines(this, result) }
/**
* The afferent coupling of a class is the number of classes that
* Gets the afferent coupling of a class -- the number of classes that
* directly depend on it.
*/
int getAfferentCoupling() { result = count(ModuleMetrics t | t.dependsOn(this)) }
/**
* The efferent coupling of a class is the number of classes that
* Gets the efferent coupling of a class -- the number of classes that
* it directly depends on.
*/
int getEfferentCoupling() { result = count(ModuleMetrics t | this.dependsOn(t)) }

View File

@@ -22,12 +22,13 @@ class Module extends Module_, Scope, AstNode {
}
/**
* Gets the enclosing scope of this module (always none).
*
* This method will be deprecated in the next release. Please use `getEnclosingScope()` instead.
* The enclosing scope of this module (always none)
*/
override Scope getScope() { none() }
/** The enclosing scope of this module (always none) */
/** Gets the enclosing scope of this module (always none) */
override Scope getEnclosingScope() { none() }
/** Gets the statements forming the body of this module */
@@ -98,12 +99,6 @@ class Module extends Module_, Scope, AstNode {
/** Gets the metrics for this module */
ModuleMetrics getMetrics() { result = this }
/**
* Use ModuleObject.getAnImportedModule() instead.
* Gets a module imported by this module
*/
deprecated Module getAnImportedModule() { result.getName() = this.getAnImportedModuleName() }
string getAnImportedModuleName() {
exists(Import i | i.getEnclosingModule() = this | result = i.getAnImportedModuleName())
or
@@ -196,7 +191,7 @@ private predicate isPotentialSourcePackage(Folder f) {
private predicate isPotentialPackage(Folder f) {
exists(f.getFile("__init__.py"))
or
py_flags_versioned("options.respect_init", "False", _) and major_version() = 2
py_flags_versioned("options.respect_init", "False", _) and major_version() = 2 and exists(f)
}
private string moduleNameFromBase(Container file) {

View File

@@ -1,6 +1,6 @@
import python
/** Base class for operators */
/** The base class for operators */
class Operator extends Operator_ {
/** Gets the name of the special method used to implement this operator */
string getSpecialMethodName() { none() }
@@ -131,7 +131,7 @@ class Compare extends Compare_ {
}
}
/** List of comparison operators in a comparison */
/** A list of comparison operators in a comparison */
class CmpopList extends CmpopList_ { }
/** A comparison operator */

View File

@@ -10,6 +10,7 @@ class Pattern extends Pattern_, AstNode {
override Scope getScope() { result = this.getCase().getScope() }
/** Gets the case statement containing this pattern */
pragma[nomagic]
Case getCase() { result.contains(this) }
override string toString() { result = "Pattern" }

View File

@@ -9,11 +9,12 @@ class Scope extends Scope_ {
Module getEnclosingModule() { result = this.getEnclosingScope().getEnclosingModule() }
/**
* Gets the scope enclosing this scope (modules have no enclosing scope).
*
* This method will be deprecated in the next release. Please use `getEnclosingScope()` instead.
* The reason for this is to avoid confusion around use of `x.getScope+()` where `x` might be an
* `AstNode` or a `Variable`. Forcing the users to write `x.getScope().getEnclosingScope*()` ensures that
* the apparent semantics and the actual semantics coincide.
* [ Gets the scope enclosing this scope (modules have no enclosing scope) ]
*/
Scope getScope() { none() }

View File

@@ -31,7 +31,7 @@ private predicate self_attribute(Attribute attr, Class cls) {
)
}
/** Helper class for UndefinedClassAttribute.ql &amp; MaybeUndefinedClassAttribute.ql */
/** A helper class for UndefinedClassAttribute.ql &amp; MaybeUndefinedClassAttribute.ql */
class SelfAttributeRead extends SelfAttribute {
SelfAttributeRead() {
this.getCtx() instanceof Load and

View File

@@ -112,6 +112,6 @@ class SpecialMethodCallNode extends PotentialSpecialMethodCallNode {
)
}
/** The method that is called. */
/** Gets the method that is called. */
Value getResolvedSpecialMethod() { result = resolvedSpecialMethod }
}

View File

@@ -323,7 +323,7 @@ class Raise extends Raise_ {
override Expr getASubExpression() { py_exprs(result, _, this, _) }
/**
* The expression immediately following the `raise`, this is the
* Gets the expression immediately following the `raise`. This is the
* exception raised, but not accounting for tuples in Python 2.
*/
Expr getException() {
@@ -332,7 +332,7 @@ class Raise extends Raise_ {
result = this.getExc()
}
/** The exception raised, accounting for tuples in Python 2. */
/** Gets the exception raised, accounting for tuples in Python 2. */
Expr getRaised() {
exists(Expr raw | raw = this.getException() |
if not major_version() = 2 or not exists(raw.(Tuple).getAnElt())

View File

@@ -227,7 +227,7 @@ private module SensitiveDataModeling {
}
/**
* Any kind of variable assignment (also including with/for) where the name indicates
* A variable assignment (also including with/for) where the name indicates
* it contains sensitive data.
*
* Note: We _could_ make any access to a variable with a sensitive name a source of

View File

@@ -6,14 +6,14 @@
private import python
private import internal.TypeTracker as Internal
/** Any string that may appear as the name of an attribute or access path. */
/** A string that may appear as the name of an attribute or access path. */
class AttributeName = Internal::ContentName;
/** Either an attribute name, or the empty string (representing no attribute). */
/** An attribute name, or the empty string (representing no attribute). */
class OptionalAttributeName = Internal::OptionalContentName;
/**
* Summary of the steps needed to track a value to a given dataflow node.
* The summary of the steps needed to track a value to a given dataflow node.
*
* This can be used to track objects that implement a certain API in order to
* recognize calls to that API. Note that type-tracking does not by itself provide a

View File

@@ -49,8 +49,11 @@ predicate isArgumentNode(ArgumentNode arg, DataFlowCall c, ArgumentPosition pos)
//--------
predicate isExpressionNode(ControlFlowNode node) { node.getNode() instanceof Expr }
/** DEPRECATED: Alias for `SyntheticPreUpdateNode` */
deprecated module syntheticPreUpdateNode = SyntheticPreUpdateNode;
/** A module collecting the different reasons for synthesising a pre-update node. */
module syntheticPreUpdateNode {
module SyntheticPreUpdateNode {
class SyntheticPreUpdateNode extends Node, TSyntheticPreUpdateNode {
NeedsSyntheticPreUpdateNode post;
@@ -73,7 +76,7 @@ module syntheticPreUpdateNode {
override Node getPreUpdateNode() { result.(SyntheticPreUpdateNode).getPostUpdateNode() = this }
/**
* A label for this kind of node. This will figure in the textual representation of the synthesized pre-update node.
* Gets the label for this kind of node. This will figure in the textual representation of the synthesized pre-update node.
*
* There is currently only one reason for needing a pre-update node, so we always use that as the label.
*/
@@ -88,10 +91,13 @@ module syntheticPreUpdateNode {
CfgNode objectCreationNode() { result.getNode().(CallNode) = any(ClassCall c).getNode() }
}
import syntheticPreUpdateNode
import SyntheticPreUpdateNode
/** DEPRECATED: Alias for `SyntheticPostUpdateNode` */
deprecated module syntheticPostUpdateNode = SyntheticPostUpdateNode;
/** A module collecting the different reasons for synthesising a post-update node. */
module syntheticPostUpdateNode {
module SyntheticPostUpdateNode {
/** A post-update node is synthesized for all nodes which satisfy `NeedsSyntheticPostUpdateNode`. */
class SyntheticPostUpdateNode extends PostUpdateNode, TSyntheticPostUpdateNode {
NeedsSyntheticPostUpdateNode pre;
@@ -118,7 +124,7 @@ module syntheticPostUpdateNode {
}
/**
* A label for this kind of node. This will figure in the textual representation of the synthesized post-update node.
* Gets the label for this kind of node. This will figure in the textual representation of the synthesized post-update node.
* We favour being an arguments as the reason for the post-update node in case multiple reasons apply.
*/
string label() {
@@ -132,6 +138,8 @@ module syntheticPostUpdateNode {
}
/**
* Gets the pre-update node for this node.
*
* An argument might have its value changed as a result of a call.
* Certain arguments, such as implicit self arguments are already post-update nodes
* and should not have an extra node synthesised.
@@ -153,7 +161,7 @@ module syntheticPostUpdateNode {
)
}
/** An object might have its value changed after a store. */
/** Gets the pre-update node associated with a store. This is used for when an object might have its value changed after a store. */
CfgNode storePreUpdateNode() {
exists(Attribute a |
result.getNode() = a.getObject().getAFlowNode() and
@@ -162,7 +170,7 @@ module syntheticPostUpdateNode {
}
/**
* A node marking the state change of an object after a read.
* Gets a node marking the state change of an object after a read.
*
* A reverse read happens when the result of a read is modified, e.g. in
* ```python
@@ -185,7 +193,7 @@ module syntheticPostUpdateNode {
}
}
import syntheticPostUpdateNode
import SyntheticPostUpdateNode
class DataFlowExpr = Expr;
@@ -621,7 +629,7 @@ newtype TDataFlowCallable =
TLambda(Function lambda) { lambda.isLambda() } or
TModule(Module m)
/** Represents a callable. */
/** A callable. */
abstract class DataFlowCallable extends TDataFlowCallable {
/** Gets a textual representation of this element. */
abstract string toString();
@@ -722,7 +730,7 @@ newtype TDataFlowCall =
TClassCall(CallNode call) { call = any(ClassValue c | not c.isAbsent()).getACall() } or
TSpecialCall(SpecialMethodCallNode special)
/** Represents a call. */
/** A call. */
abstract class DataFlowCall extends TDataFlowCall {
/** Gets a textual representation of this element. */
abstract string toString();
@@ -747,7 +755,7 @@ abstract class DataFlowCall extends TDataFlowCall {
}
/**
* Represents a call to a function/lambda.
* A call to a function/lambda.
* This excludes calls to bound methods, classes, and special methods.
* Bound method calls and class calls insert an argument for the explicit
* `self` parameter, and special method calls have special argument passing.
@@ -834,7 +842,7 @@ class ClassCall extends DataFlowCall, TClassCall {
override DataFlowCallable getEnclosingCallable() { result.getScope() = call.getScope() }
}
/** Represents a call to a special method. */
/** A call to a special method. */
class SpecialCall extends DataFlowCall, TSpecialCall {
SpecialMethodCallNode special;
@@ -1706,6 +1714,8 @@ import IterableUnpacking
*/
module MatchUnpacking {
/**
* Holds when there is flow from the subject `nodeFrom` to the (top-level) pattern `nodeTo` of a `match` statement.
*
* The subject of a match flows to each top-level pattern
* (a pattern directly under a `case` statement).
*

View File

@@ -34,7 +34,8 @@ private module Cached {
CallStep() or
ReturnStep() or
StoreStep(ContentName content) or
LoadStep(ContentName content)
LoadStep(ContentName content) or
JumpStep()
/** Gets the summary resulting from appending `step` to type-tracking summary `tt`. */
cached
@@ -49,6 +50,9 @@ private module Cached {
step = LoadStep(content) and result = MkTypeTracker(hasCall, "")
or
exists(string p | step = StoreStep(p) and content = "" and result = MkTypeTracker(hasCall, p))
or
step = JumpStep() and
result = MkTypeTracker(false, content)
)
}
@@ -67,6 +71,9 @@ private module Cached {
)
or
step = StoreStep(content) and result = MkTypeBackTracker(hasReturn, "")
or
step = JumpStep() and
result = MkTypeBackTracker(false, content)
)
}
@@ -110,12 +117,17 @@ class StepSummary extends TStepSummary {
exists(string content | this = StoreStep(content) | result = "store " + content)
or
exists(string content | this = LoadStep(content) | result = "load " + content)
or
this instanceof JumpStep and result = "jump"
}
}
pragma[noinline]
private predicate smallstepNoCall(Node nodeFrom, TypeTrackingNode nodeTo, StepSummary summary) {
jumpStep(nodeFrom, nodeTo) and
summary = JumpStep()
or
levelStep(nodeFrom, nodeTo) and
summary = LevelStep()
or
exists(string content |

View File

@@ -14,6 +14,9 @@ predicate simpleLocalFlowStep = DataFlowPrivate::simpleLocalFlowStep/2;
predicate jumpStep = DataFlowPrivate::jumpStepSharedWithTypeTracker/2;
/** Holds if there is a level step from `pred` to `succ`. */
predicate levelStep(Node pred, Node succ) { none() }
/**
* Gets the name of a possible piece of content. For Python, this is currently only attribute names,
* using the name of the attribute for the corresponding content.

View File

@@ -64,13 +64,30 @@ abstract class Configuration extends DataFlow::Configuration {
override predicate isSource(DataFlow::Node source) { none() }
/**
* Holds if `sink` is a relevant taint sink.
* Holds if `source` is a relevant taint source with the given initial
* `state`.
*
* The smaller this predicate is, the faster `hasFlow()` will converge.
*/
// overridden to provide taint-tracking specific qldoc
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) { none() }
/**
* Holds if `sink` is a relevant taint sink
*
* The smaller this predicate is, the faster `hasFlow()` will converge.
*/
// overridden to provide taint-tracking specific qldoc
override predicate isSink(DataFlow::Node sink) { none() }
/**
* Holds if `sink` is a relevant taint sink accepting `state`.
*
* The smaller this predicate is, the faster `hasFlow()` will converge.
*/
// overridden to provide taint-tracking specific qldoc
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) { none() }
/** Holds if the node `node` is a taint sanitizer. */
predicate isSanitizer(DataFlow::Node node) { none() }
@@ -79,6 +96,16 @@ abstract class Configuration extends DataFlow::Configuration {
defaultTaintSanitizer(node)
}
/**
* Holds if the node `node` is a taint sanitizer when the flow state is
* `state`.
*/
predicate isSanitizer(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizer(node, state)
}
/** Holds if taint propagation into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }
@@ -107,6 +134,25 @@ abstract class Configuration extends DataFlow::Configuration {
defaultAdditionalTaintStep(node1, node2)
}
/**
* Holds if the additional taint propagation step from `node1` to `node2`
* must be taken into account in the analysis. This step is only applicable
* in `state1` and updates the flow state to `state2`.
*/
predicate isAdditionalTaintStep(
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
DataFlow::FlowState state2
) {
none()
}
final override predicate isAdditionalFlowStep(
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
DataFlow::FlowState state2
) {
this.isAdditionalTaintStep(node1, state1, node2, state2)
}
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
defaultImplicitTaintRead(node, c)

View File

@@ -64,13 +64,30 @@ abstract class Configuration extends DataFlow::Configuration {
override predicate isSource(DataFlow::Node source) { none() }
/**
* Holds if `sink` is a relevant taint sink.
* Holds if `source` is a relevant taint source with the given initial
* `state`.
*
* The smaller this predicate is, the faster `hasFlow()` will converge.
*/
// overridden to provide taint-tracking specific qldoc
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) { none() }
/**
* Holds if `sink` is a relevant taint sink
*
* The smaller this predicate is, the faster `hasFlow()` will converge.
*/
// overridden to provide taint-tracking specific qldoc
override predicate isSink(DataFlow::Node sink) { none() }
/**
* Holds if `sink` is a relevant taint sink accepting `state`.
*
* The smaller this predicate is, the faster `hasFlow()` will converge.
*/
// overridden to provide taint-tracking specific qldoc
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) { none() }
/** Holds if the node `node` is a taint sanitizer. */
predicate isSanitizer(DataFlow::Node node) { none() }
@@ -79,6 +96,16 @@ abstract class Configuration extends DataFlow::Configuration {
defaultTaintSanitizer(node)
}
/**
* Holds if the node `node` is a taint sanitizer when the flow state is
* `state`.
*/
predicate isSanitizer(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizer(node, state)
}
/** Holds if taint propagation into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }
@@ -107,6 +134,25 @@ abstract class Configuration extends DataFlow::Configuration {
defaultAdditionalTaintStep(node1, node2)
}
/**
* Holds if the additional taint propagation step from `node1` to `node2`
* must be taken into account in the analysis. This step is only applicable
* in `state1` and updates the flow state to `state2`.
*/
predicate isAdditionalTaintStep(
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
DataFlow::FlowState state2
) {
none()
}
final override predicate isAdditionalFlowStep(
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
DataFlow::FlowState state2
) {
this.isAdditionalTaintStep(node1, state1, node2, state2)
}
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
defaultImplicitTaintRead(node, c)

View File

@@ -64,13 +64,30 @@ abstract class Configuration extends DataFlow::Configuration {
override predicate isSource(DataFlow::Node source) { none() }
/**
* Holds if `sink` is a relevant taint sink.
* Holds if `source` is a relevant taint source with the given initial
* `state`.
*
* The smaller this predicate is, the faster `hasFlow()` will converge.
*/
// overridden to provide taint-tracking specific qldoc
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) { none() }
/**
* Holds if `sink` is a relevant taint sink
*
* The smaller this predicate is, the faster `hasFlow()` will converge.
*/
// overridden to provide taint-tracking specific qldoc
override predicate isSink(DataFlow::Node sink) { none() }
/**
* Holds if `sink` is a relevant taint sink accepting `state`.
*
* The smaller this predicate is, the faster `hasFlow()` will converge.
*/
// overridden to provide taint-tracking specific qldoc
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) { none() }
/** Holds if the node `node` is a taint sanitizer. */
predicate isSanitizer(DataFlow::Node node) { none() }
@@ -79,6 +96,16 @@ abstract class Configuration extends DataFlow::Configuration {
defaultTaintSanitizer(node)
}
/**
* Holds if the node `node` is a taint sanitizer when the flow state is
* `state`.
*/
predicate isSanitizer(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizer(node, state)
}
/** Holds if taint propagation into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }
@@ -107,6 +134,25 @@ abstract class Configuration extends DataFlow::Configuration {
defaultAdditionalTaintStep(node1, node2)
}
/**
* Holds if the additional taint propagation step from `node1` to `node2`
* must be taken into account in the analysis. This step is only applicable
* in `state1` and updates the flow state to `state2`.
*/
predicate isAdditionalTaintStep(
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
DataFlow::FlowState state2
) {
none()
}
final override predicate isAdditionalFlowStep(
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
DataFlow::FlowState state2
) {
this.isAdditionalTaintStep(node1, state1, node2, state2)
}
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
defaultImplicitTaintRead(node, c)

View File

@@ -64,13 +64,30 @@ abstract class Configuration extends DataFlow::Configuration {
override predicate isSource(DataFlow::Node source) { none() }
/**
* Holds if `sink` is a relevant taint sink.
* Holds if `source` is a relevant taint source with the given initial
* `state`.
*
* The smaller this predicate is, the faster `hasFlow()` will converge.
*/
// overridden to provide taint-tracking specific qldoc
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) { none() }
/**
* Holds if `sink` is a relevant taint sink
*
* The smaller this predicate is, the faster `hasFlow()` will converge.
*/
// overridden to provide taint-tracking specific qldoc
override predicate isSink(DataFlow::Node sink) { none() }
/**
* Holds if `sink` is a relevant taint sink accepting `state`.
*
* The smaller this predicate is, the faster `hasFlow()` will converge.
*/
// overridden to provide taint-tracking specific qldoc
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) { none() }
/** Holds if the node `node` is a taint sanitizer. */
predicate isSanitizer(DataFlow::Node node) { none() }
@@ -79,6 +96,16 @@ abstract class Configuration extends DataFlow::Configuration {
defaultTaintSanitizer(node)
}
/**
* Holds if the node `node` is a taint sanitizer when the flow state is
* `state`.
*/
predicate isSanitizer(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizer(node, state)
}
/** Holds if taint propagation into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }
@@ -107,6 +134,25 @@ abstract class Configuration extends DataFlow::Configuration {
defaultAdditionalTaintStep(node1, node2)
}
/**
* Holds if the additional taint propagation step from `node1` to `node2`
* must be taken into account in the analysis. This step is only applicable
* in `state1` and updates the flow state to `state2`.
*/
predicate isAdditionalTaintStep(
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
DataFlow::FlowState state2
) {
none()
}
final override predicate isAdditionalFlowStep(
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
DataFlow::FlowState state2
) {
this.isAdditionalTaintStep(node1, state1, node2, state2)
}
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
defaultImplicitTaintRead(node, c)

View File

@@ -119,16 +119,6 @@ module TaintTracking {
this.(TaintTrackingImplementation).hasFlowPath(src, sink)
}
/* Old query API */
/* deprecated */
deprecated predicate hasFlow(Source src, Sink sink) {
exists(PathSource psrc, PathSink psink |
this.hasFlowPath(psrc, psink) and
src = psrc.getNode().asCfgNode() and
sink = psink.getNode().asCfgNode()
)
}
/* New query API */
predicate hasSimpleFlow(DataFlow::Node src, DataFlow::Node sink) {
exists(PathSource psrc, PathSink psink |

View File

@@ -79,7 +79,7 @@ abstract class AttributePath extends TAttributePath {
predicate noAttribute() { this = TNoAttribute() }
}
/** AttributePath for no attribute. */
/** The `AttributePath` for no attribute. */
class NoAttribute extends TNoAttribute, AttributePath {
override string toString() { result = "no attribute" }
@@ -88,7 +88,7 @@ class NoAttribute extends TNoAttribute, AttributePath {
override AttributePath fromAttribute(string name) { none() }
}
/** AttributePath for an attribute. */
/** The `AttributePath` for an attribute. */
class NamedAttributePath extends TAttribute, AttributePath {
override string toString() {
exists(string attr |
@@ -124,8 +124,8 @@ newtype TTaintTrackingNode =
}
/**
* Class representing the (node, context, path, kind) tuple.
* Used for context-sensitive path-aware taint-tracking.
* A class representing the (node, context, path, kind) tuple.
* Used for context-sensitive path-aware taint-tracking.
*/
class TaintTrackingNode extends TTaintTrackingNode {
/** Gets a textual representation of this element. */
@@ -900,22 +900,6 @@ private class EssaTaintTracking extends string {
or
result = this.testEvaluates(defn, not_operand(test), use, src).booleanNot()
}
/**
* Holds if `test` is the test in a branch and `use` is that test
* with all the `not` prefixes removed.
*/
private predicate boolean_filter(ControlFlowNode test, ControlFlowNode use) {
any(PyEdgeRefinement ref).getTest() = test and
(
use = test
or
exists(ControlFlowNode notuse |
this.boolean_filter(test, notuse) and
use = not_operand(notuse)
)
)
}
}
private predicate testEvaluatesMaybe(ControlFlowNode test, ControlFlowNode use) {
@@ -991,7 +975,7 @@ int iterable_unpacking_descent(SequenceNode left_parent, ControlFlowNode left_de
}
module Implementation {
/* A call that returns a copy (or similar) of the argument */
/** Holds if `tonode` is a call that returns a copy (or similar) of the argument `fromnode` */
predicate copyCall(ControlFlowNode fromnode, CallNode tonode) {
tonode.getFunction().(AttrNode).getObject("copy") = fromnode
or

View File

@@ -2,24 +2,7 @@ import semmle.python.dataflow.TaintTracking
private import semmle.python.objects.ObjectInternal
import semmle.python.dataflow.Implementation
/* For backwards compatibility -- Use `TaintTrackingContext` instead. */
deprecated class CallContext extends TaintTrackingContext {
TaintTrackingContext getCallee(CallNode call) { result.getCaller(call) = this }
predicate appliesToScope(Scope s) {
exists(PythonFunctionObjectInternal func, TaintKind param, AttributePath path, int n |
this = TParamContext(param, path, n) and
exists(TaintTrackingImplementation impl |
impl.callWithTaintedArgument(_, _, _, func, n, path, param) and
s = func.getScope()
)
)
or
this.isTop()
}
}
/* Backwards compatibility with config-less taint-tracking */
/** A configuration that provides backwards compatibility with config-less taint-tracking */
private class LegacyConfiguration extends TaintTracking::Configuration {
LegacyConfiguration() {
/* A name that won't be accidentally chosen by users */

View File

@@ -138,9 +138,6 @@ abstract class TaintKind extends string {
exists(TaintedNode n | n.getTaintKind() = this and n.getCfgNode() = expr)
}
/** DEPRECATED -- Use getType() instead */
deprecated ClassObject getClass() { none() }
/**
* Gets the class of this kind of taint.
* For example, if this were a kind of string taint
@@ -180,7 +177,7 @@ abstract class TaintKind extends string {
}
/**
* Alias of `TaintKind`, so the two types can be used interchangeably.
* An Alias of `TaintKind`, so the two types can be used interchangeably.
*/
class FlowLabel = TaintKind;
@@ -561,7 +558,7 @@ module DataFlowExtension {
ControlFlowNode getACalleeSuccessorNode(CallNode call) { none() }
}
/** Data flow variable that modifies the basic data-flow. */
/** A data flow variable that modifies the basic data-flow. */
class DataFlowVariable extends EssaVariable {
/**
* Gets a successor node for data-flow.
@@ -608,49 +605,11 @@ private import semmle.python.pointsto.PointsTo
*/
module DataFlow {
/**
* Generic taint kind, source and sink classes for convenience and
* The generic taint kind, source and sink classes for convenience and
* compatibility with other language libraries
*/
class Extension = DataFlowExtension::DataFlowNode;
abstract deprecated class Configuration extends string {
bindingset[this]
Configuration() { this = this }
abstract predicate isSource(ControlFlowNode source);
abstract predicate isSink(ControlFlowNode sink);
private predicate hasFlowPath(TaintedNode source, TaintedNode sink) {
source.getConfiguration() = this and
this.isSource(source.getCfgNode()) and
this.isSink(sink.getCfgNode()) and
source.flowsTo(sink)
}
predicate hasFlow(ControlFlowNode source, ControlFlowNode sink) {
exists(TaintedNode psource, TaintedNode psink |
psource.getCfgNode() = source and
psink.getCfgNode() = sink and
this.isSource(source) and
this.isSink(sink) and
this.hasFlowPath(psource, psink)
)
}
}
deprecated private class ConfigurationAdapter extends TaintTracking::Configuration instanceof Configuration {
override predicate isSource(DataFlow::Node node, TaintKind kind) {
Configuration.super.isSource(node.asCfgNode()) and
kind instanceof DataFlowType
}
override predicate isSink(DataFlow::Node node, TaintKind kind) {
Configuration.super.isSink(node.asCfgNode()) and
kind instanceof DataFlowType
}
}
private newtype TDataFlowNode =
TEssaNode(EssaVariable var) or
TCfgNode(ControlFlowNode node)
@@ -670,9 +629,6 @@ module DataFlow {
abstract Location getLocation();
AstNode asAstNode() { result = this.asCfgNode().getNode() }
/** For backwards compatibility -- Use asAstNode() instead */
deprecated AstNode getNode() { result = this.asAstNode() }
}
class CfgNode extends Node, TCfgNode {
@@ -709,9 +665,10 @@ module DataFlow {
}
deprecated private class DataFlowType extends TaintKind {
// this only exists to avoid an empty recursion error in the type checker
DataFlowType() {
this = "Data flow" and
exists(DataFlow::Configuration c)
1 = 2
}
}

View File

@@ -158,13 +158,13 @@ private predicate defn_of_instance_attribute(Assign asgn, Class c, string name)
)
}
/* Whether asgn defines an attribute of a class */
/** Holds if asgn defines an attribute of a class */
private predicate defn_of_class_attribute(Assign asgn, Class c, string name) {
asgn.getScope() = c and
asgn.getATarget().(Name).getId() = name
}
/* Holds if `value` is a value assigned to the `name`d attribute of module `m`. */
/** Holds if `value` is a value assigned to the `name`d attribute of module `m`. */
private predicate defn_of_module_attribute(ControlFlowNode value, Module m, string name) {
exists(DefinitionNode def |
def.getScope() = m and

View File

@@ -134,7 +134,7 @@ private newtype TEssaDefinition =
TPhiFunction(SsaSourceVariable v, BasicBlock b) { EssaDefinitions::phiNode(v, b) }
/**
* Definition of an extended-SSA (ESSA) variable.
* A definition of an extended-SSA (ESSA) variable.
* There is exactly one definition for each variable,
* and exactly one variable for each definition.
*/
@@ -171,6 +171,9 @@ abstract class EssaDefinition extends TEssaDefinition {
EssaVariable getVariable() { result.getDefinition() = this }
abstract BasicBlock getBasicBlock();
/** Gets the name of the primary QL class for this element. */
string getAPrimaryQlClass() { result = "EssaDefinition" }
}
/**
@@ -216,13 +219,15 @@ class EssaEdgeRefinement extends EssaDefinition, TEssaEdgeDefinition {
}
override string getRepresentation() {
result = this.getAQlClass() + "(" + this.getInput().getRepresentation() + ")"
result = this.getAPrimaryQlClass() + "(" + this.getInput().getRepresentation() + ")"
}
/** Gets the scope of the variable defined by this definition. */
override Scope getScope() { result = this.getPredecessor().getScope() }
override BasicBlock getBasicBlock() { result = this.getSuccessor() }
override string getAPrimaryQlClass() { result = "EssaEdgeRefinement" }
}
/** A Phi-function as specified in classic SSA form. */
@@ -366,6 +371,8 @@ class PhiFunction extends EssaDefinition, TPhiFunction {
)
)
}
override string getAPrimaryQlClass() { result = "PhiFunction" }
}
/**
@@ -396,7 +403,7 @@ class EssaNodeDefinition extends EssaDefinition, TEssaNodeDefinition {
override Location getLocation() { result = this.getDefiningNode().getLocation() }
override string getRepresentation() { result = this.getAQlClass() }
override string getRepresentation() { result = this.getAPrimaryQlClass() }
override Scope getScope() {
exists(BasicBlock defb |
@@ -414,6 +421,8 @@ class EssaNodeDefinition extends EssaDefinition, TEssaNodeDefinition {
}
override BasicBlock getBasicBlock() { result = this.getDefiningNode().getBasicBlock() }
override string getAPrimaryQlClass() { result = "EssaNodeDefinition" }
}
/** A definition of an ESSA variable that takes another ESSA variable as an input. */
@@ -448,10 +457,10 @@ class EssaNodeRefinement extends EssaDefinition, TEssaNodeRefinement {
override Location getLocation() { result = this.getDefiningNode().getLocation() }
override string getRepresentation() {
result = this.getAQlClass() + "(" + this.getInput().getRepresentation() + ")"
result = this.getAPrimaryQlClass() + "(" + this.getInput().getRepresentation() + ")"
or
not exists(this.getInput()) and
result = this.getAQlClass() + "(" + this.getSourceVariable().getName() + "??)"
result = this.getAPrimaryQlClass() + "(" + this.getSourceVariable().getName() + "??)"
}
override Scope getScope() {
@@ -470,6 +479,8 @@ class EssaNodeRefinement extends EssaDefinition, TEssaNodeRefinement {
}
override BasicBlock getBasicBlock() { result = this.getDefiningNode().getBasicBlock() }
override string getAPrimaryQlClass() { result = "EssaNodeRefinement" }
}
pragma[noopt]
@@ -483,12 +494,6 @@ private EssaVariable potential_input(EssaNodeRefinement ref) {
)
}
/* For backwards compatibility */
deprecated class PyNodeDefinition = EssaNodeDefinition;
/* For backwards compatibility */
deprecated class PyNodeRefinement = EssaNodeRefinement;
/** An assignment to a variable `v = val` */
class AssignmentDefinition extends EssaNodeDefinition {
AssignmentDefinition() {
@@ -500,9 +505,11 @@ class AssignmentDefinition extends EssaNodeDefinition {
}
override string getRepresentation() { result = this.getValue().getNode().toString() }
override string getAPrimaryQlClass() { result = "AssignmentDefinition" }
}
/** Capture of a raised exception `except ExceptionType ex:` */
/** A capture of a raised exception `except ExceptionType ex:` */
class ExceptionCapture extends EssaNodeDefinition {
ExceptionCapture() {
SsaSource::exception_capture(this.getSourceVariable(), this.getDefiningNode())
@@ -516,6 +523,8 @@ class ExceptionCapture extends EssaNodeDefinition {
}
override string getRepresentation() { result = "except " + this.getSourceVariable().getName() }
override string getAPrimaryQlClass() { result = "ExceptionCapture" }
}
/** An assignment to a variable as part of a multiple assignment `..., v, ... = val` */
@@ -536,6 +545,8 @@ class MultiAssignmentDefinition extends EssaNodeDefinition {
SsaSource::multi_assignment_definition(this.getSourceVariable(), this.getDefiningNode(), index,
lhs)
}
override string getAPrimaryQlClass() { result = "MultiAssignmentDefinition" }
}
/** A definition of a variable in a `with` statement */
@@ -543,6 +554,8 @@ class WithDefinition extends EssaNodeDefinition {
WithDefinition() { SsaSource::with_definition(this.getSourceVariable(), this.getDefiningNode()) }
override string getRepresentation() { result = "with" }
override string getAPrimaryQlClass() { result = "WithDefinition" }
}
/** A definition of a variable via a capture pattern */
@@ -552,6 +565,8 @@ class PatternCaptureDefinition extends EssaNodeDefinition {
}
override string getRepresentation() { result = "pattern capture" }
override string getAPrimaryQlClass() { result = "PatternCaptureDefinition" }
}
/** A definition of a variable via a pattern alias */
@@ -561,6 +576,8 @@ class PatternAliasDefinition extends EssaNodeDefinition {
}
override string getRepresentation() { result = "pattern alias" }
override string getAPrimaryQlClass() { result = "PatternAliasDefinition" }
}
/** A definition of a variable by declaring it as a parameter */
@@ -594,6 +611,8 @@ class ParameterDefinition extends EssaNodeDefinition {
/** Gets the `Parameter` this `ParameterDefinition` represents. */
Parameter getParameter() { result = this.getDefiningNode().getNode() }
override string getAPrimaryQlClass() { result = "ParameterDefinition" }
}
/** A deletion of a variable `del v` */
@@ -601,10 +620,12 @@ class DeletionDefinition extends EssaNodeDefinition {
DeletionDefinition() {
SsaSource::deletion_definition(this.getSourceVariable(), this.getDefiningNode())
}
override string getAPrimaryQlClass() { result = "DeletionDefinition" }
}
/**
* Definition of variable at the entry of a scope. Usually this represents the transfer of
* A definition of variable at the entry of a scope. Usually this represents the transfer of
* a global or non-local variable from one scope to another.
*/
class ScopeEntryDefinition extends EssaNodeDefinition {
@@ -614,16 +635,20 @@ class ScopeEntryDefinition extends EssaNodeDefinition {
}
override Scope getScope() { result.getEntryNode() = this.getDefiningNode() }
override string getAPrimaryQlClass() { result = "ScopeEntryDefinition" }
}
/** Possible redefinition of variable via `from ... import *` */
/** A possible redefinition of variable via `from ... import *` */
class ImportStarRefinement extends EssaNodeRefinement {
ImportStarRefinement() {
SsaSource::import_star_refinement(this.getSourceVariable(), _, this.getDefiningNode())
}
override string getAPrimaryQlClass() { result = "ImportStarRefinement" }
}
/** Assignment of an attribute `obj.attr = val` */
/** An assignment of an attribute `obj.attr = val` */
class AttributeAssignment extends EssaNodeRefinement {
AttributeAssignment() {
SsaSource::attribute_assignment_refinement(this.getSourceVariable(), _, this.getDefiningNode())
@@ -635,12 +660,16 @@ class AttributeAssignment extends EssaNodeRefinement {
override string getRepresentation() {
result =
this.getAQlClass() + " '" + this.getName() + "'(" + this.getInput().getRepresentation() + ")"
this.getAPrimaryQlClass() + " '" + this.getName() + "'(" + this.getInput().getRepresentation()
+ ")"
or
not exists(this.getInput()) and
result =
this.getAQlClass() + " '" + this.getName() + "'(" + this.getSourceVariable().getName() + "??)"
this.getAPrimaryQlClass() + " '" + this.getName() + "'(" + this.getSourceVariable().getName() +
"??)"
}
override string getAPrimaryQlClass() { result = "AttributeAssignment" }
}
/** A use of a variable as an argument, `foo(v)`, which might modify the object referred to. */
@@ -654,15 +683,19 @@ class ArgumentRefinement extends EssaNodeRefinement {
ControlFlowNode getArgument() { result = argument }
CallNode getCall() { result = this.getDefiningNode() }
override string getAPrimaryQlClass() { result = "ArgumentRefinement" }
}
/** Deletion of an attribute `del obj.attr`. */
/** A deletion of an attribute `del obj.attr`. */
class EssaAttributeDeletion extends EssaNodeRefinement {
EssaAttributeDeletion() {
SsaSource::attribute_deletion_refinement(this.getSourceVariable(), _, this.getDefiningNode())
}
string getName() { result = this.getDefiningNode().(AttrNode).getName() }
override string getAPrimaryQlClass() { result = "EssaAttributeDeletion" }
}
/** A pi-node (guard) with only one successor. */
@@ -690,10 +723,12 @@ class SingleSuccessorGuard extends EssaNodeRefinement {
test = this.getDefiningNode() and
SsaSource::test_refinement(this.getSourceVariable(), use, test)
}
override string getAPrimaryQlClass() { result = "SingleSuccessorGuard" }
}
/**
* Implicit definition of the names of sub-modules in a package.
* An implicit definition of the names of sub-modules in a package.
* Although the interpreter does not pre-define these names, merely populating them
* as they are imported, this is a good approximation for static analysis.
*/
@@ -701,11 +736,13 @@ class ImplicitSubModuleDefinition extends EssaNodeDefinition {
ImplicitSubModuleDefinition() {
SsaSource::init_module_submodule_defn(this.getSourceVariable(), this.getDefiningNode())
}
override string getAPrimaryQlClass() { result = "ImplicitSubModuleDefinition" }
}
/** An implicit (possible) definition of an escaping variable at a call-site */
class CallsiteRefinement extends EssaNodeRefinement {
override string toString() { result = "CallsiteRefinement" }
override string toString() { result = "CallSiteRefinement" }
CallsiteRefinement() {
exists(SsaSourceVariable var, ControlFlowNode defn |
@@ -718,6 +755,8 @@ class CallsiteRefinement extends EssaNodeRefinement {
}
CallNode getCall() { this.getDefiningNode() = result }
override string getAPrimaryQlClass() { result = "CallsiteRefinement" }
}
/** An implicit (possible) modification of the object referred at a method call */
@@ -728,14 +767,18 @@ class MethodCallsiteRefinement extends EssaNodeRefinement {
}
CallNode getCall() { this.getDefiningNode() = result }
override string getAPrimaryQlClass() { result = "MethodCallsiteRefinement" }
}
/** An implicit (possible) modification of `self` at a method call */
class SelfCallsiteRefinement extends MethodCallsiteRefinement {
SelfCallsiteRefinement() { this.getSourceVariable().(Variable).isSelf() }
override string getAPrimaryQlClass() { result = "SelfCallsiteRefinement" }
}
/** Python specific sub-class of generic EssaEdgeRefinement */
/** A Python specific sub-class of generic EssaEdgeRefinement */
class PyEdgeRefinement extends EssaEdgeRefinement {
override string getRepresentation() {
/*
@@ -750,4 +793,6 @@ class PyEdgeRefinement extends EssaEdgeRefinement {
}
ControlFlowNode getTest() { result = this.getPredecessor().getLastNode() }
override string getAPrimaryQlClass() { result = "PyEdgeRefinement" }
}

View File

@@ -139,7 +139,7 @@ private module SsaComputeImpl {
Liveness::liveAtEntry(v, succ)
}
/** A phi node for `v` at the beginning of basic block `b`. */
/** Holds if there is a phi node for `v` at the beginning of basic block `b`. */
cached
predicate phiNode(SsaSourceVariable v, BasicBlock b) {
(
@@ -175,8 +175,8 @@ private module SsaComputeImpl {
}
/**
* A ranking of the indices `i` at which there is an SSA definition or use of
* `v` in the basic block `b`.
* Holds if the `rankix`th definition or use of the SSA variable `v` in the basic block `b` occurs
* at index `i`.
*
* Basic block indices are translated to rank indices in order to skip
* irrelevant indices at which there is no definition or use when traversing
@@ -187,14 +187,14 @@ private module SsaComputeImpl {
i = rank[rankix](int j | variableDef(v, _, b, j) or variableUse(v, _, b, j))
}
/** A definition of a variable occurring at the specified rank index in basic block `b`. */
/** Holds if there is a definition of a variable occurring at the specified rank index in basic block `b`. */
cached
predicate defRank(SsaSourceVariable v, BasicBlock b, int rankix, int i) {
variableDef(v, _, b, i) and
defUseRank(v, b, rankix, i)
}
/** A variable access `use` of `v` in `b` at index `i`. */
/** Holds if there is a variable access `use` of `v` in `b` at index `i`. */
cached
predicate variableUse(SsaSourceVariable v, ControlFlowNode use, BasicBlock b, int i) {
(v.getAUse() = use or v.hasRefinement(use, _)) and
@@ -205,7 +205,7 @@ private module SsaComputeImpl {
}
/**
* A definition of an SSA variable occurring at the specified position.
* Holds if there is a definition of an SSA variable occurring at the specified position.
* This is either a phi node, a `VariableUpdate`, or a parameter.
*/
cached
@@ -227,7 +227,7 @@ private module SsaComputeImpl {
* dominance.
*/
/** The maximum rank index for the given variable and basic block. */
/** Gets the maximum rank index for the given variable and basic block. */
cached
int lastRank(SsaSourceVariable v, BasicBlock b) {
result = max(int rankix | defUseRank(v, b, rankix, _))
@@ -253,7 +253,7 @@ private module SsaComputeImpl {
i = piIndex()
}
/** The SSA definition reaches the rank index `rankix` in its own basic block `b`. */
/** Holds if the SSA definition reaches the rank index `rankix` in its own basic block `b`. */
cached
predicate ssaDefReachesRank(SsaSourceVariable v, BasicBlock b, int i, int rankix) {
ssaDefRank(v, b, rankix, i)
@@ -264,7 +264,7 @@ private module SsaComputeImpl {
}
/**
* The SSA definition of `v` at `def` reaches `use` in the same basic block
* Holds if the SSA definition of `v` at `def` reaches `use` in the same basic block
* without crossing another SSA definition of `v`.
*/
cached
@@ -303,7 +303,7 @@ private module SsaComputeImpl {
}
/**
* The SSA definition of `v` at `def` reaches the end of a basic block `b`, at
* Holds if the SSA definition of `v` at `def` reaches the end of a basic block `b`, at
* which point it is still live, without crossing another SSA definition of `v`.
*/
cached
@@ -320,7 +320,7 @@ private module SsaComputeImpl {
}
/**
* The SSA definition of `v` at `(defbb, defindex)` reaches `use` without crossing another
* Holds if the SSA definition of `v` at `(defbb, defindex)` reaches `use` without crossing another
* SSA definition of `v`.
*/
cached
@@ -360,7 +360,7 @@ private module SsaComputeImpl {
i = rank[rankix](int j | variableDefine(v, _, b, j) or variableSourceUse(v, _, b, j))
}
/** A variable access `use` of `v` in `b` at index `i`. */
/** Holds if there is a variable access `use` of `v` in `b` at index `i`. */
cached
predicate variableSourceUse(SsaSourceVariable v, ControlFlowNode use, BasicBlock b, int i) {
v.getASourceUse() = use and

View File

@@ -14,7 +14,7 @@ abstract class GeneratedFile extends File {
* There is no formal reason for the above, it just seems to work well in practice.
*/
library class GenericGeneratedFile extends GeneratedFile {
class GenericGeneratedFile extends GeneratedFile {
GenericGeneratedFile() {
not this instanceof SpecificGeneratedFile and
(
@@ -103,7 +103,7 @@ private predicate auto_generated(File f) {
/**
* A file generated by a template engine
*/
abstract library class SpecificGeneratedFile extends GeneratedFile {
abstract class SpecificGeneratedFile extends GeneratedFile {
/*
* Currently cover Spitfire, Pyxl and Mako.
* Django templates are not compiled to Python.
@@ -112,7 +112,7 @@ abstract library class SpecificGeneratedFile extends GeneratedFile {
}
/** File generated by the spitfire templating engine */
/** A file generated by the spitfire templating engine */
class SpitfireGeneratedFile extends SpecificGeneratedFile {
SpitfireGeneratedFile() {
exists(Module m | m.getFile() = this and not m instanceof SpitfireTemplate |
@@ -127,14 +127,14 @@ class SpitfireGeneratedFile extends SpecificGeneratedFile {
override string getTool() { result = "spitfire" }
}
/** File generated by the pyxl templating engine */
/** A file generated by the pyxl templating engine */
class PyxlGeneratedFile extends SpecificGeneratedFile {
PyxlGeneratedFile() { this.getSpecifiedEncoding() = "pyxl" }
override string getTool() { result = "pyxl" }
}
/** File generated by the mako templating engine */
/** A file generated by the mako templating engine */
class MakoGeneratedFile extends SpecificGeneratedFile {
MakoGeneratedFile() {
exists(Module m | m.getFile() = this |
@@ -166,7 +166,7 @@ string from_mako_import(Module m) {
)
}
/** File generated by Google's protobuf tool. */
/** A file generated by Google's protobuf tool. */
class ProtobufGeneratedFile extends SpecificGeneratedFile {
ProtobufGeneratedFile() {
this.getAbsolutePath().regexpMatch(".*_pb2?.py") and

View File

@@ -15,7 +15,7 @@ class UnitTestClass extends TestScope {
abstract class Test extends TestScope { }
/** Class of test function that uses the `unittest` framework */
/** A test function that uses the `unittest` framework */
class UnitTestFunction extends Test {
UnitTestFunction() {
this.getScope+() instanceof UnitTestClass and
@@ -37,7 +37,7 @@ class NoseTestFunction extends Test {
}
}
/** Class of functions that are clearly tests, but don't belong to a specific framework */
/** A function that is clearly a test, but doesn't belong to a specific framework */
class UnknownTestFunction extends Test {
UnknownTestFunction() {
this.(Function).getName().matches("test%") and

View File

@@ -639,3 +639,53 @@ module AiohttpWebModel {
override DataFlow::Node getValueArg() { result = value }
}
}
/**
* Provides models for the web server part (`aiohttp.client`) of the `aiohttp` PyPI package.
* See https://docs.aiohttp.org/en/stable/client.html
*/
private module AiohttpClientModel {
/**
* Provides models for the `aiohttp.ClientSession` class
*
* See https://docs.aiohttp.org/en/stable/client_reference.html#aiohttp.ClientSession.
*/
module ClientSession {
/** Gets a reference to the `aiohttp.ClientSession` class. */
private API::Node classRef() {
result = API::moduleImport("aiohttp").getMember("ClientSession")
}
/** Gets a reference to an instance of `aiohttp.ClientSession`. */
private API::Node instance() { result = classRef().getReturn() }
/** A method call on a ClientSession that sends off a request */
private class OutgoingRequestCall extends HTTP::Client::Request::Range, DataFlow::CallCfgNode {
string methodName;
OutgoingRequestCall() {
methodName in [HTTP::httpVerbLower(), "request"] and
this = instance().getMember(methodName).getACall()
}
override DataFlow::Node getAUrlPart() {
result = this.getArgByName("url")
or
not methodName = "request" and
result = this.getArg(0)
or
methodName = "request" and
result = this.getArg(1)
}
override string getFramework() { result = "aiohttp.ClientSession" }
override predicate disablesCertificateValidation(
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
) {
// TODO: Look into disabling certificate validation
none()
}
}
}
}

View File

@@ -15,7 +15,7 @@ private module Aiomysql {
private import semmle.python.internal.Awaited
/**
* A `ConectionPool` is created when the result of `aiomysql.create_pool()` is awaited.
* Gets a `ConnectionPool` that is created when the result of `aiomysql.create_pool()` is awaited.
* See https://aiomysql.readthedocs.io/en/stable/pool.html
*/
API::Node connectionPool() {
@@ -23,7 +23,7 @@ private module Aiomysql {
}
/**
* A `Connection` is created when
* Gets a `Connection` that is created when
* - the result of `aiomysql.connect()` is awaited.
* - the result of calling `aquire` on a `ConnectionPool` is awaited.
* See https://aiomysql.readthedocs.io/en/stable/connection.html#connection
@@ -35,7 +35,7 @@ private module Aiomysql {
}
/**
* A `Cursor` is created when
* Gets a `Cursor` that is created when
* - the result of calling `cursor` on a `ConnectionPool` is awaited.
* - the result of calling `cursor` on a `Connection` is awaited.
* See https://aiomysql.readthedocs.io/en/stable/cursors.html
@@ -47,7 +47,7 @@ private module Aiomysql {
}
/**
* Calling `execute` on a `Cursor` constructs a query.
* A query. Calling `execute` on a `Cursor` constructs a query.
* See https://aiomysql.readthedocs.io/en/stable/cursors.html#Cursor.execute
*/
class CursorExecuteCall extends SqlConstruction::Range, DataFlow::CallCfgNode {
@@ -73,7 +73,7 @@ private module Aiomysql {
}
/**
* Awaiting the result of calling `execute` executes the query.
* An awaited query. Awaiting the result of calling `execute` executes the query.
* See https://aiomysql.readthedocs.io/en/stable/cursors.html#Cursor.execute
*/
class AwaitedCursorExecuteCall extends SqlExecution::Range {
@@ -85,7 +85,7 @@ private module Aiomysql {
}
/**
* An `Engine` is created when the result of calling `aiomysql.sa.create_engine` is awaited.
* Gets an `Engine` that is created when the result of calling `aiomysql.sa.create_engine` is awaited.
* See https://aiomysql.readthedocs.io/en/stable/sa.html#engine
*/
API::Node engine() {
@@ -98,13 +98,13 @@ private module Aiomysql {
}
/**
* A `SAConnection` is created when the result of calling `aquire` on an `Engine` is awaited.
* Gets an `SAConnection` that is created when the result of calling `aquire` on an `Engine` is awaited.
* See https://aiomysql.readthedocs.io/en/stable/sa.html#connection
*/
API::Node saConnection() { result = engine().getMember("acquire").getReturn().getAwaited() }
/**
* Calling `execute` on a `SAConnection` constructs a query.
* A query. Calling `execute` on a `SAConnection` constructs a query.
* See https://aiomysql.readthedocs.io/en/stable/sa.html#aiomysql.sa.SAConnection.execute
*/
class SAConnectionExecuteCall extends SqlConstruction::Range, DataFlow::CallCfgNode {
@@ -132,7 +132,7 @@ private module Aiomysql {
}
/**
* Awaiting the result of calling `execute` executes the query.
* An awaited query. Awaiting the result of calling `execute` executes the query.
* See https://aiomysql.readthedocs.io/en/stable/sa.html#aiomysql.sa.SAConnection.execute
*/
class AwaitedSAConnectionExecuteCall extends SqlExecution::Range {

View File

@@ -15,7 +15,7 @@ private module Aiopg {
private import semmle.python.internal.Awaited
/**
* A `ConectionPool` is created when the result of `aiopg.create_pool()` is awaited.
* Gets a `ConnectionPool` that is created when the result of `aiopg.create_pool()` is awaited.
* See https://aiopg.readthedocs.io/en/stable/core.html#pool
*/
API::Node connectionPool() {
@@ -23,7 +23,7 @@ private module Aiopg {
}
/**
* A `Connection` is created when
* Gets a `Connection` that is created when
* - the result of `aiopg.connect()` is awaited.
* - the result of calling `aquire` on a `ConnectionPool` is awaited.
* See https://aiopg.readthedocs.io/en/stable/core.html#connection
@@ -35,7 +35,7 @@ private module Aiopg {
}
/**
* A `Cursor` is created when
* Gets a `Cursor` that is created when
* - the result of calling `cursor` on a `ConnectionPool` is awaited.
* - the result of calling `cursor` on a `Connection` is awaited.
* See https://aiopg.readthedocs.io/en/stable/core.html#cursor
@@ -47,7 +47,7 @@ private module Aiopg {
}
/**
* Calling `execute` on a `Cursor` constructs a query.
* A query. Calling `execute` on a `Cursor` constructs a query.
* See https://aiopg.readthedocs.io/en/stable/core.html#aiopg.Cursor.execute
*/
class CursorExecuteCall extends SqlConstruction::Range, DataFlow::CallCfgNode {
@@ -73,7 +73,7 @@ private module Aiopg {
}
/**
* Awaiting the result of calling `execute` executes the query.
* An awaited query. Awaiting the result of calling `execute` executes the query.
* See https://aiopg.readthedocs.io/en/stable/core.html#aiopg.Cursor.execute
*/
class AwaitedCursorExecuteCall extends SqlExecution::Range {
@@ -85,7 +85,7 @@ private module Aiopg {
}
/**
* An `Engine` is created when the result of calling `aiopg.sa.create_engine` is awaited.
* Gets an `Engine` that is created when the result of calling `aiopg.sa.create_engine` is awaited.
* See https://aiopg.readthedocs.io/en/stable/sa.html#engine
*/
API::Node engine() {
@@ -94,13 +94,13 @@ private module Aiopg {
}
/**
* A `SAConnection` is created when the result of calling `aquire` on an `Engine` is awaited.
* Gets an `SAConnection` that is created when the result of calling `aquire` on an `Engine` is awaited.
* See https://aiopg.readthedocs.io/en/stable/sa.html#connection
*/
API::Node saConnection() { result = engine().getMember("acquire").getReturn().getAwaited() }
/**
* Calling `execute` on a `SAConnection` constructs a query.
* A query. Calling `execute` on a `SAConnection` constructs a query.
* See https://aiopg.readthedocs.io/en/stable/sa.html#aiopg.sa.SAConnection.execute
*/
class SAConnectionExecuteCall extends SqlConstruction::Range, DataFlow::CallCfgNode {
@@ -128,7 +128,7 @@ private module Aiopg {
}
/**
* Awaiting the result of calling `execute` executes the query.
* An awaited query. Awaiting the result of calling `execute` executes the query.
* See https://aiopg.readthedocs.io/en/stable/sa.html#aiopg.sa.SAConnection.execute
*/
class AwaitedSAConnectionExecuteCall extends SqlExecution::Range {

View File

@@ -12,13 +12,13 @@ private import semmle.python.ApiGraphs
private module Asyncpg {
private import semmle.python.internal.Awaited
/** A `ConectionPool` is created when the result of `asyncpg.create_pool()` is awaited. */
/** Gets a `ConnectionPool` that is created when the result of `asyncpg.create_pool()` is awaited. */
API::Node connectionPool() {
result = API::moduleImport("asyncpg").getMember("create_pool").getReturn().getAwaited()
}
/**
* A `Connection` is created when
* Gets a `Connection` that is created when
* - the result of `asyncpg.connect()` is awaited.
* - the result of calling `aquire` on a `ConnectionPool` is awaited.
*/
@@ -46,7 +46,7 @@ private module Asyncpg {
}
}
/** `Connection`s and `ConnectionPool`s provide some methods that access the file system. */
/** A model of `Connection` and `ConnectionPool`, which provide some methods that access the file system. */
class FileAccessOnConnection extends FileSystemAccess::Range, DataFlow::MethodCallNode {
string methodName;

View File

@@ -20,7 +20,7 @@ private import semmle.python.frameworks.PEP249
*/
module ClickhouseDriver {
/**
* `clickhouse_driver` implements PEP249,
* A model of `clickhouse-driver`, which implements PEP249,
* providing ways to execute SQL statements against a database.
*/
class ClickHouseDriverPEP249 extends PEP249::PEP249ModuleApiNode {

View File

@@ -526,8 +526,11 @@ module PrivateDjango {
/** Gets a reference to the `django` module. */
API::Node django() { result = API::moduleImport("django") }
/** DEPRECATED: Alias for `DjangoImpl` */
deprecated module django = DjangoImpl;
/** Provides models for the `django` module. */
module django {
module DjangoImpl {
// -------------------------------------------------------------------------
// django.db
// -------------------------------------------------------------------------
@@ -541,8 +544,11 @@ module PrivateDjango {
DjangoDb() { this = API::moduleImport("django").getMember("db") }
}
/** DEPRECATED: Alias for `DB` */
deprecated module db = DB;
/** Provides models for the `django.db` module. */
module db {
module DB {
/** Gets a reference to the `django.db.connection` object. */
API::Node connection() { result = db().getMember("connection") }
@@ -557,8 +563,11 @@ module PrivateDjango {
/** Gets a reference to the `django.db.models` module. */
API::Node models() { result = db().getMember("models") }
/** DEPRECATED: Alias for `Models` */
deprecated module models = Models;
/** Provides models for the `django.db.models` module. */
module models {
module Models {
/**
* Provides models for the `django.db.models.Model` class and subclasses.
*
@@ -770,10 +779,13 @@ module PrivateDjango {
/** Gets a reference to the `django.db.models.expressions` module. */
API::Node expressions() { result = models().getMember("expressions") }
/** DEPRECATED: Alias for `Expressions` */
deprecated module expressions = Expressions;
/** Provides models for the `django.db.models.expressions` module. */
module expressions {
/** Provides models for the `django.db.models.expressions.RawSQL` class. */
module RawSQL {
module Expressions {
/** Provides models for the `django.db.models.expressions.RawSql` class. */
module RawSql {
/**
* Gets an reference to the `django.db.models.expressions.RawSQL` class.
*/
@@ -806,6 +818,9 @@ module PrivateDjango {
instance(DataFlow::TypeTracker::end(), sql).flowsTo(result)
}
}
/** DEPRECATED: Alias for RawSql */
deprecated module RawSQL = RawSql;
}
/** This internal module provides data-flow modeling of Django ORM. */
@@ -981,8 +996,8 @@ module PrivateDjango {
DataFlow::Node sql;
ObjectsAnnotate() {
this = django::db::models::querySetReturningMethod(_, "annotate").getACall() and
django::db::models::expressions::RawSQL::instance(sql) in [
this = DjangoImpl::DB::Models::querySetReturningMethod(_, "annotate").getACall() and
DjangoImpl::DB::Models::Expressions::RawSql::instance(sql) in [
this.getArg(_), this.getArgByName(_)
]
}
@@ -999,8 +1014,8 @@ module PrivateDjango {
DataFlow::Node sql;
ObjectsAlias() {
this = django::db::models::querySetReturningMethod(_, "alias").getACall() and
django::db::models::expressions::RawSQL::instance(sql) in [
this = DjangoImpl::DB::Models::querySetReturningMethod(_, "alias").getACall() and
DjangoImpl::DB::Models::Expressions::RawSql::instance(sql) in [
this.getArg(_), this.getArgByName(_)
]
}
@@ -1016,7 +1031,7 @@ module PrivateDjango {
* - https://docs.djangoproject.com/en/3.1/ref/models/querysets/#raw
*/
private class ObjectsRaw extends SqlExecution::Range, DataFlow::CallCfgNode {
ObjectsRaw() { this = django::db::models::querySetReturningMethod(_, "raw").getACall() }
ObjectsRaw() { this = DjangoImpl::DB::Models::querySetReturningMethod(_, "raw").getACall() }
override DataFlow::Node getSql() { result = this.getArg(0) }
}
@@ -1027,7 +1042,9 @@ module PrivateDjango {
* See https://docs.djangoproject.com/en/3.1/ref/models/querysets/#extra
*/
private class ObjectsExtra extends SqlExecution::Range, DataFlow::CallCfgNode {
ObjectsExtra() { this = django::db::models::querySetReturningMethod(_, "extra").getACall() }
ObjectsExtra() {
this = DjangoImpl::DB::Models::querySetReturningMethod(_, "extra").getACall()
}
override DataFlow::Node getSql() {
result in [
@@ -1042,8 +1059,11 @@ module PrivateDjango {
/** Gets a reference to the `django.urls` module. */
API::Node urls() { result = django().getMember("urls") }
/** DEPRECATED: Alias for `Urls` */
deprecated module urls = Urls;
/** Provides models for the `django.urls` module */
module urls {
module Urls {
/**
* Gets a reference to the `django.urls.path` function.
* See https://docs.djangoproject.com/en/3.0/ref/urls/#path
@@ -1063,10 +1083,16 @@ module PrivateDjango {
/** Gets a reference to the `django.conf` module. */
API::Node conf() { result = django().getMember("conf") }
/** DEPRECATED: Alias for `Conf` */
deprecated module conf = Conf;
/** Provides models for the `django.conf` module */
module conf {
module Conf {
/** DEPRECATED: Alias for `ConfUrls` */
deprecated module conf_urls = ConfUrls;
/** Provides models for the `django.conf.urls` module */
module conf_urls {
module ConfUrls {
// -------------------------------------------------------------------------
// django.conf.urls
// -------------------------------------------------------------------------
@@ -1089,16 +1115,22 @@ module PrivateDjango {
/** Gets a reference to the `django.http` module. */
API::Node http() { result = django().getMember("http") }
/** DEPRECATED: Alias for `Http` */
deprecated module http = Http;
/** Provides models for the `django.http` module */
module http {
module Http {
// ---------------------------------------------------------------------------
// django.http.request
// ---------------------------------------------------------------------------
/** Gets a reference to the `django.http.request` module. */
API::Node request() { result = http().getMember("request") }
/** DEPRECATED: Alias for `Request` */
deprecated module request = Request;
/** Provides models for the `django.http.request` module. */
module request {
module Request {
/**
* Provides models for the `django.http.request.HttpRequest` class
*
@@ -1179,7 +1211,7 @@ module PrivateDjango {
// special handling of the `build_absolute_uri` method, see
// https://docs.djangoproject.com/en/3.0/ref/request-response/#django.http.HttpRequest.build_absolute_uri
exists(DataFlow::AttrRead attr, DataFlow::CallCfgNode call, DataFlow::Node instance |
instance = django::http::request::HttpRequest::instance() and
instance = DjangoImpl::Http::Request::HttpRequest::instance() and
attr.getObject() = instance
|
attr.getAttributeName() = "build_absolute_uri" and
@@ -1256,8 +1288,11 @@ module PrivateDjango {
/** Gets a reference to the `django.http.response` module. */
API::Node response() { result = http().getMember("response") }
/** DEPRECATED: Alias for `Response` */
deprecated module response = Response;
/** Provides models for the `django.http.response` module */
module response {
module Response {
/**
* Provides models for the `django.http.response.HttpResponse` class
*
@@ -1991,17 +2026,17 @@ module PrivateDjango {
/** Gets a reference to the `django.http.response.HttpResponse.write` function. */
private DataFlow::TypeTrackingNode write(
django::http::response::HttpResponse::InstanceSource instance, DataFlow::TypeTracker t
DjangoImpl::Http::Response::HttpResponse::InstanceSource instance, DataFlow::TypeTracker t
) {
t.startInAttr("write") and
instance = django::http::response::HttpResponse::instance() and
instance = DjangoImpl::Http::Response::HttpResponse::instance() and
result = instance
or
exists(DataFlow::TypeTracker t2 | result = write(instance, t2).track(t2, t))
}
/** Gets a reference to the `django.http.response.HttpResponse.write` function. */
DataFlow::Node write(django::http::response::HttpResponse::InstanceSource instance) {
DataFlow::Node write(DjangoImpl::Http::Response::HttpResponse::InstanceSource instance) {
write(instance, DataFlow::TypeTracker::end()).flowsTo(result)
}
@@ -2011,7 +2046,7 @@ module PrivateDjango {
* See https://docs.djangoproject.com/en/3.1/ref/request-response/#django.http.HttpResponse.write
*/
class HttpResponseWriteCall extends HTTP::Server::HttpResponse::Range, DataFlow::CallCfgNode {
django::http::response::HttpResponse::InstanceSource instance;
DjangoImpl::Http::Response::HttpResponse::InstanceSource instance;
HttpResponseWriteCall() { this.getFunction() = write(instance) }
@@ -2032,7 +2067,7 @@ module PrivateDjango {
class DjangoResponseSetCookieCall extends HTTP::Server::CookieWrite::Range,
DataFlow::MethodCallNode {
DjangoResponseSetCookieCall() {
this.calls(django::http::response::HttpResponse::instance(), "set_cookie")
this.calls(DjangoImpl::Http::Response::HttpResponse::instance(), "set_cookie")
}
override DataFlow::Node getHeaderArg() { none() }
@@ -2052,7 +2087,7 @@ module PrivateDjango {
class DjangoResponseDeleteCookieCall extends HTTP::Server::CookieWrite::Range,
DataFlow::MethodCallNode {
DjangoResponseDeleteCookieCall() {
this.calls(django::http::response::HttpResponse::instance(), "delete_cookie")
this.calls(DjangoImpl::Http::Response::HttpResponse::instance(), "delete_cookie")
}
override DataFlow::Node getHeaderArg() { none() }
@@ -2079,7 +2114,7 @@ module PrivateDjango {
this.asCfgNode() = subscript
|
cookieLookup.getAttributeName() = "cookies" and
cookieLookup.getObject() = django::http::response::HttpResponse::instance() and
cookieLookup.getObject() = DjangoImpl::Http::Response::HttpResponse::instance() and
exists(DataFlow::Node subscriptObj |
subscriptObj.asCfgNode() = subscript.getObject()
|
@@ -2105,8 +2140,11 @@ module PrivateDjango {
/** Gets a reference to the `django.shortcuts` module. */
API::Node shortcuts() { result = django().getMember("shortcuts") }
/** DEPRECATED: Alias for `Shortcuts` */
deprecated module shortcuts = Shortcuts;
/** Provides models for the `django.shortcuts` module */
module shortcuts {
module Shortcuts {
/**
* Gets a reference to the `django.shortcuts.redirect` function
*
@@ -2184,7 +2222,8 @@ module PrivateDjango {
// routing modeling
// ---------------------------------------------------------------------------
/**
* In order to recognize a class as being a django view class, based on the `as_view`
* A class that may be a django view class. In order to recognize a class as being a django view class,
* based on the `as_view`
* call, we need to be able to track such calls on _any_ class. This is provided by
* the member predicates of this QL class.
*
@@ -2195,7 +2234,7 @@ module PrivateDjango {
/** Gets a reference to this class. */
private DataFlow::TypeTrackingNode getARef(DataFlow::TypeTracker t) {
t.start() and
result.asExpr().(ClassExpr) = this.getParent()
result.asExpr() = this.getParent()
or
exists(DataFlow::TypeTracker t2 | result = this.getARef(t2).track(t2, t))
}
@@ -2295,7 +2334,7 @@ module PrivateDjango {
/** Provides a class for modeling new django route handlers. */
module DjangoRouteHandler {
/**
* Extend this class to model new APIs. If you want to refine existing API models,
* A django route handler. Extend this class to model new APIs. If you want to refine existing API models,
* extend `DjangoRouteHandler` instead.
*/
abstract class Range extends Function { }
@@ -2381,7 +2420,7 @@ module PrivateDjango {
* See https://docs.djangoproject.com/en/3.0/ref/urls/#path
*/
private class DjangoUrlsPathCall extends DjangoRouteSetup, DataFlow::CallCfgNode {
DjangoUrlsPathCall() { this = django::urls::path().getACall() }
DjangoUrlsPathCall() { this = DjangoImpl::Urls::path().getACall() }
override DataFlow::Node getUrlPatternArg() {
result in [this.getArg(0), this.getArgByName("route")]
@@ -2464,7 +2503,7 @@ module PrivateDjango {
*/
private class DjangoUrlsRePathCall extends DjangoRegexRouteSetup, DataFlow::CallCfgNode {
DjangoUrlsRePathCall() {
this = django::urls::re_path().getACall() and
this = DjangoImpl::Urls::re_path().getACall() and
// `django.conf.urls.url` (which we support directly with
// `DjangoConfUrlsUrlCall`), is implemented in Django 2+ as backward compatibility
// using `django.urls.re_path`. See
@@ -2494,7 +2533,7 @@ module PrivateDjango {
* See https://docs.djangoproject.com/en/1.11/ref/urls/#django.conf.urls.url
*/
private class DjangoConfUrlsUrlCall extends DjangoRegexRouteSetup, DataFlow::CallCfgNode {
DjangoConfUrlsUrlCall() { this = django::conf::conf_urls::url().getACall() }
DjangoConfUrlsUrlCall() { this = DjangoImpl::Conf::ConfUrls::url().getACall() }
override DataFlow::Node getUrlPatternArg() {
result in [this.getArg(0), this.getArgByName("regex")]
@@ -2507,7 +2546,7 @@ module PrivateDjango {
// HttpRequest taint modeling
// ---------------------------------------------------------------------------
/** A parameter that will receive the django `HttpRequest` instance when a request handler is invoked. */
private class DjangoRequestHandlerRequestParam extends django::http::request::HttpRequest::InstanceSource,
private class DjangoRequestHandlerRequestParam extends DjangoImpl::Http::Request::HttpRequest::InstanceSource,
RemoteFlowSource::Range, DataFlow::ParameterNode {
DjangoRequestHandlerRequestParam() {
this.getParameter() = any(DjangoRouteSetup setup).getARequestHandler().getRequestParam()
@@ -2524,7 +2563,7 @@ module PrivateDjango {
*
* See https://docs.djangoproject.com/en/3.1/topics/class-based-views/generic-display/#dynamic-filtering
*/
private class DjangoViewClassRequestAttributeRead extends django::http::request::HttpRequest::InstanceSource,
private class DjangoViewClassRequestAttributeRead extends DjangoImpl::Http::Request::HttpRequest::InstanceSource,
RemoteFlowSource::Range, DataFlow::Node {
DjangoViewClassRequestAttributeRead() {
exists(DataFlow::AttrRead read | this = read |
@@ -2571,7 +2610,7 @@ module PrivateDjango {
*/
private class DjangoShortcutsRedirectCall extends HTTP::Server::HttpRedirectResponse::Range,
DataFlow::CallCfgNode {
DjangoShortcutsRedirectCall() { this = django::shortcuts::redirect().getACall() }
DjangoShortcutsRedirectCall() { this = DjangoImpl::Shortcuts::redirect().getACall() }
/**
* Gets the data-flow node that specifies the location of this HTTP redirect response.

View File

@@ -24,7 +24,7 @@ private module FabricV1 {
API::Node fabric() { result = API::moduleImport("fabric") }
/** Provides models for the `fabric` module. */
module fabric {
module Fabric {
// -------------------------------------------------------------------------
// fabric.api
// -------------------------------------------------------------------------
@@ -32,7 +32,7 @@ private module FabricV1 {
API::Node api() { result = fabric().getMember("api") }
/** Provides models for the `fabric.api` module */
module api {
module Api {
/**
* A call to either
* - `fabric.api.local`
@@ -66,7 +66,7 @@ private module FabricV2 {
API::Node fabric() { result = API::moduleImport("fabric") }
/** Provides models for the `fabric` module. */
module fabric {
module Fabric {
// -------------------------------------------------------------------------
// fabric.connection
// -------------------------------------------------------------------------
@@ -74,13 +74,13 @@ private module FabricV2 {
API::Node connection() { result = fabric().getMember("connection") }
/** Provides models for the `fabric.connection` module */
module connection {
module Connection {
/**
* Provides models for the `fabric.connection.Connection` class
*
* See https://docs.fabfile.org/en/2.5/api/connection.html#fabric.connection.Connection.
*/
module Connection {
module ConnectionClass {
/** Gets a reference to the `fabric.connection.Connection` class. */
API::Node classRef() {
result = fabric().getMember("Connection")
@@ -155,7 +155,7 @@ private module FabricV2 {
private class FabricConnectionRunSudoLocalCall extends SystemCommandExecution::Range,
DataFlow::CallCfgNode {
FabricConnectionRunSudoLocalCall() {
this.getFunction() = fabric::connection::Connection::instanceRunMethods()
this.getFunction() = Fabric::Connection::ConnectionClass::instanceRunMethods()
}
override DataFlow::Node getCommand() {
@@ -170,16 +170,16 @@ private module FabricV2 {
API::Node tasks() { result = fabric().getMember("tasks") }
/** Provides models for the `fabric.tasks` module */
module tasks {
module Tasks {
/** Gets a reference to the `fabric.tasks.task` decorator. */
API::Node task() { result in [tasks().getMember("task"), fabric().getMember("task")] }
}
class FabricTaskFirstParamConnectionInstance extends fabric::connection::Connection::InstanceSource,
class FabricTaskFirstParamConnectionInstance extends Fabric::Connection::ConnectionClass::InstanceSource,
DataFlow::ParameterNode {
FabricTaskFirstParamConnectionInstance() {
exists(Function func |
func.getADecorator() = fabric::tasks::task().getAUse().asExpr() and
func.getADecorator() = Fabric::Tasks::task().getAUse().asExpr() and
this.getParameter() = func.getArg(0)
)
}
@@ -192,7 +192,7 @@ private module FabricV2 {
API::Node group() { result = fabric().getMember("group") }
/** Provides models for the `fabric.group` module */
module group {
module Group {
/**
* Provides models for the `fabric.group.Group` class and its subclasses.
*
@@ -204,7 +204,7 @@ private module FabricV2 {
* - https://docs.fabfile.org/en/2.5/api/group.html#fabric.group.SerialGroup
* - https://docs.fabfile.org/en/2.5/api/group.html#fabric.group.ThreadingGroup
*/
module Group {
module GroupClass {
/**
* A source of instances of a subclass of `fabric.group, extend this class to model new instances.Group`
*
@@ -236,7 +236,9 @@ private module FabricV2 {
* See https://docs.fabfile.org/en/2.5/api/group.html#fabric.group.Group.run
*/
private class FabricGroupRunCall extends SystemCommandExecution::Range, DataFlow::CallCfgNode {
FabricGroupRunCall() { this = fabric::group::Group::subclassInstanceRunMethod().getACall() }
FabricGroupRunCall() {
this = Fabric::Group::GroupClass::subclassInstanceRunMethod().getACall()
}
override DataFlow::Node getCommand() {
result = [this.getArg(0), this.getArgByName("command")]
@@ -249,7 +251,7 @@ private module FabricV2 {
* See https://docs.fabfile.org/en/2.5/api/group.html#fabric.group.SerialGroup.
*/
module SerialGroup {
private class ClassInstantiation extends Group::ModeledSubclass {
private class ClassInstantiation extends GroupClass::ModeledSubclass {
ClassInstantiation() {
this = group().getMember("SerialGroup")
or
@@ -264,7 +266,7 @@ private module FabricV2 {
* See https://docs.fabfile.org/en/2.5/api/group.html#fabric.group.ThreadingGroup.
*/
module ThreadingGroup {
private class ClassInstantiation extends Group::ModeledSubclass {
private class ClassInstantiation extends GroupClass::ModeledSubclass {
ClassInstantiation() {
this = group().getMember("ThreadingGroup")
or

View File

@@ -30,13 +30,16 @@ private module FastApi {
*
* See https://fastapi.tiangolo.com/tutorial/bigger-applications/.
*/
module APIRouter {
/** Gets a reference to an instance of `fastapi.APIRouter`. */
module ApiRouter {
/** Gets a reference to an instance of `fastapi.ApiRouter`. */
API::Node instance() {
result = API::moduleImport("fastapi").getMember("APIRouter").getASubclass*().getReturn()
}
}
/** DEPRECATED: Alias for ApiRouter */
deprecated module APIRouter = ApiRouter;
// ---------------------------------------------------------------------------
// routing modeling
// ---------------------------------------------------------------------------
@@ -54,7 +57,7 @@ private module FastApi {
|
this = App::instance().getMember(routeAddingMethod).getACall()
or
this = APIRouter::instance().getMember(routeAddingMethod).getACall()
this = ApiRouter::instance().getMember(routeAddingMethod).getACall()
)
}

View File

@@ -193,7 +193,7 @@ module Flask {
FlaskViewClass() {
this.getABase() = Views::View::subclassRef().getAUse().asExpr() and
api_node.getAnImmediateUse().asExpr().(ClassExpr) = this.getParent()
api_node.getAnImmediateUse().asExpr() = this.getParent()
}
/** Gets a function that could handle incoming requests, if any. */
@@ -218,7 +218,7 @@ module Flask {
class FlaskMethodViewClass extends FlaskViewClass {
FlaskMethodViewClass() {
this.getABase() = Views::MethodView::subclassRef().getAUse().asExpr() and
api_node.getAnImmediateUse().asExpr().(ClassExpr) = this.getParent()
api_node.getAnImmediateUse().asExpr() = this.getParent()
}
override Function getARequestHandler() {
@@ -299,7 +299,7 @@ module Flask {
override Function getARequestHandler() {
exists(DataFlow::LocalSourceNode func_src |
func_src.flowsTo(this.getViewArg()) and
func_src.asExpr().(CallableExpr) = result.getDefinition()
func_src.asExpr() = result.getDefinition()
)
or
exists(FlaskViewClass vc |

View File

@@ -0,0 +1,88 @@
/**
* Provides classes modeling security-relevant aspects of the `httpx` PyPI package.
*
* See
* - https://pypi.org/project/httpx/
* - https://www.python-httpx.org/
*/
private import python
private import semmle.python.Concepts
private import semmle.python.ApiGraphs
/**
* Provides models for the `httpx` PyPI package.
*
* See
* - https://pypi.org/project/httpx/
* - https://www.python-httpx.org/
*/
private module HttpxModel {
private class RequestCall extends HTTP::Client::Request::Range, DataFlow::CallCfgNode {
string methodName;
RequestCall() {
methodName in [HTTP::httpVerbLower(), "request", "stream"] and
this = API::moduleImport("httpx").getMember(methodName).getACall()
}
override DataFlow::Node getAUrlPart() {
result = this.getArgByName("url")
or
if methodName in ["request", "stream"]
then result = this.getArg(1)
else result = this.getArg(0)
}
override string getFramework() { result = "httpx" }
override predicate disablesCertificateValidation(
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
) {
// TODO: Look into disabling certificate validation
none()
}
}
/**
* Provides models for the `httpx.[Async]Client` class
*
* See https://www.python-httpx.org/async/
*/
module Client {
/** Get a reference to the `httpx.Client` or `httpx.AsyncClient` class. */
private API::Node classRef() {
result = API::moduleImport("httpx").getMember(["Client", "AsyncClient"])
}
/** Get a reference to an `httpx.Client` or `httpx.AsyncClient` instance. */
private API::Node instance() { result = classRef().getReturn() }
/** A method call on a Client that sends off a request */
private class OutgoingRequestCall extends HTTP::Client::Request::Range, DataFlow::CallCfgNode {
string methodName;
OutgoingRequestCall() {
methodName in [HTTP::httpVerbLower(), "request", "stream"] and
this = instance().getMember(methodName).getACall()
}
override DataFlow::Node getAUrlPart() {
result = this.getArgByName("url")
or
if methodName in ["request", "stream"]
then result = this.getArg(1)
else result = this.getArg(0)
}
override string getFramework() { result = "httpx.[Async]Client" }
override predicate disablesCertificateValidation(
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
) {
// TODO: Look into disabling certificate validation
none()
}
}
}
}

View File

@@ -20,14 +20,11 @@ private module Invoke {
API::Node invoke() { result = API::moduleImport("invoke") }
/** Provides models for the `invoke` module. */
module invoke {
/** Gets a reference to the `invoke.context` module. */
API::Node context() { result = invoke().getMember("context") }
module InvokeModule {
/** Provides models for the `invoke.context` module */
module context {
module Context {
/** Provides models for the `invoke.context.Context` class */
module Context {
module ContextClass {
/** Gets a reference to the `invoke.context.Context` class. */
API::Node classRef() {
result = API::moduleImport("invoke").getMember("context").getMember("Context")
@@ -39,7 +36,7 @@ private module Invoke {
private DataFlow::TypeTrackingNode instance(DataFlow::TypeTracker t) {
t.start() and
(
result = invoke::context::Context::classRef().getACall()
result = InvokeModule::Context::ContextClass::classRef().getACall()
or
exists(Function func |
func.getADecorator() = invoke().getMember("task").getAUse().asExpr() and
@@ -56,7 +53,7 @@ private module Invoke {
/** Gets a reference to the `run` or `sudo` methods on a `invoke.context.Context` instance. */
private DataFlow::TypeTrackingNode instanceRunMethods(DataFlow::TypeTracker t) {
t.startInAttr(["run", "sudo"]) and
result = invoke::context::Context::instance()
result = InvokeModule::Context::ContextClass::instance()
or
exists(DataFlow::TypeTracker t2 | result = instanceRunMethods(t2).track(t2, t))
}
@@ -77,7 +74,7 @@ private module Invoke {
private class InvokeRunCommandCall extends SystemCommandExecution::Range, DataFlow::CallCfgNode {
InvokeRunCommandCall() {
this = invoke().getMember(["run", "sudo"]).getACall() or
this.getFunction() = invoke::context::Context::instanceRunMethods()
this.getFunction() = InvokeModule::Context::ContextClass::instanceRunMethods()
}
override DataFlow::Node getCommand() {

View File

@@ -0,0 +1,42 @@
/**
* Provides classes modeling security-relevant aspects of the `libtaxii` PyPI package.
*
* See
* - https://pypi.org/project/libtaxii/
* - https://github.com/TAXIIProject/libtaxii
*/
private import python
private import semmle.python.Concepts
private import semmle.python.ApiGraphs
/**
* Provides models for the `libtaxii` PyPI package.
*
* See
* - https://pypi.org/project/libtaxii/
* - https://github.com/TAXIIProject/libtaxii
*/
private module Libtaxii {
/**
* A call to `libtaxii.common.parse`.
* When the `allow_url` parameter value is set to `True`, there is an SSRF vulnerability..
*/
private class ParseCall extends HTTP::Client::Request::Range, DataFlow::CallCfgNode {
ParseCall() {
this = API::moduleImport("libtaxii").getMember("common").getMember("parse").getACall() and
this.getArgByName("allow_url").getALocalSource().asExpr() = any(True t)
}
override DataFlow::Node getAUrlPart() { result in [this.getArg(0), this.getArgByName("s")] }
override string getFramework() { result = "libtaxii.common.parse" }
override predicate disablesCertificateValidation(
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
) {
// TODO: Look into disabling certificate validation
none()
}
}
}

View File

@@ -0,0 +1,45 @@
/**
* Provides classes modeling security-relevant aspects of the `libxml2` PyPI package.
*
* See
* - https://pypi.org/project/libxml2-python3/
* - http://xmlsoft.org/python.html
*/
private import python
private import semmle.python.dataflow.new.DataFlow
private import semmle.python.Concepts
private import semmle.python.ApiGraphs
/**
* Provides classes modeling security-relevant aspects of the `libxml2` PyPI package
*
* See
* - https://pypi.org/project/libxml2-python3/
* - http://xmlsoft.org/python.html
*/
private module Libxml2 {
/**
* A call to the `xpathEval` method of a parsed document.
*
* import libxml2
* tree = libxml2.parseFile("file.xml")
* r = tree.xpathEval('`sink`')
*
* See http://xmlsoft.org/python.html
*/
class XpathEvalCall extends XML::XPathExecution::Range, DataFlow::CallCfgNode {
XpathEvalCall() {
this =
API::moduleImport("libxml2")
.getMember("parseFile")
.getReturn()
.getMember("xpathEval")
.getACall()
}
override DataFlow::Node getXPath() { result = this.getArg(0) }
override string getName() { result = "libxml2" }
}
}

View File

@@ -0,0 +1,88 @@
/**
* Provides classes modeling security-relevant aspects of the `lxml` PyPI package.
*
* See
* - https://pypi.org/project/lxml/
* - https://lxml.de/tutorial.html
*/
private import python
private import semmle.python.dataflow.new.DataFlow
private import semmle.python.Concepts
private import semmle.python.ApiGraphs
/**
* Provides classes modeling security-relevant aspects of the `lxml` PyPI package
*
* See
* - https://pypi.org/project/lxml/
* - https://lxml.de/tutorial.html
*/
private module Lxml {
/**
* A class constructor compiling an XPath expression.
*
* from lxml import etree
* find_text = etree.XPath("`sink`")
* find_text = etree.ETXPath("`sink`")
*
* See
* - https://lxml.de/apidoc/lxml.etree.html#lxml.etree.XPath
* - https://lxml.de/apidoc/lxml.etree.html#lxml.etree.ETXPath
*/
private class XPathClassCall extends XML::XPathConstruction::Range, DataFlow::CallCfgNode {
XPathClassCall() {
this = API::moduleImport("lxml").getMember("etree").getMember(["XPath", "ETXPath"]).getACall()
}
override DataFlow::Node getXPath() { result in [this.getArg(0), this.getArgByName("path")] }
override string getName() { result = "lxml.etree" }
}
/**
* A call to the `xpath` method of a parsed document.
*
* from lxml import etree
* root = etree.fromstring(file(XML_DB).read(), XMLParser())
* find_text = root.xpath("`sink`")
*
* See https://lxml.de/apidoc/lxml.etree.html#lxml.etree._ElementTree.xpath
* as well as
* - https://lxml.de/apidoc/lxml.etree.html#lxml.etree.parse
* - https://lxml.de/apidoc/lxml.etree.html#lxml.etree.fromstring
* - https://lxml.de/apidoc/lxml.etree.html#lxml.etree.fromstringlist
* - https://lxml.de/apidoc/lxml.etree.html#lxml.etree.HTML
* - https://lxml.de/apidoc/lxml.etree.html#lxml.etree.XML
*/
class XPathCall extends XML::XPathExecution::Range, DataFlow::CallCfgNode {
XPathCall() {
this =
API::moduleImport("lxml")
.getMember("etree")
.getMember(["parse", "fromstring", "fromstringlist", "HTML", "XML"])
.getReturn()
.getMember("xpath")
.getACall()
}
override DataFlow::Node getXPath() { result in [this.getArg(0), this.getArgByName("_path")] }
override string getName() { result = "lxml.etree" }
}
class XPathEvaluatorCall extends XML::XPathExecution::Range, DataFlow::CallCfgNode {
XPathEvaluatorCall() {
this =
API::moduleImport("lxml")
.getMember("etree")
.getMember("XPathEvaluator")
.getReturn()
.getACall()
}
override DataFlow::Node getXPath() { result = this.getArg(0) }
override string getName() { result = "lxml.etree" }
}
}

View File

@@ -27,7 +27,10 @@ private module MySQLdb {
// ---------------------------------------------------------------------------
// MySQLdb
// ---------------------------------------------------------------------------
/** MySQLdb implements PEP 249, providing ways to execute SQL statements against a database. */
/**
* A model for MySQLdb as a module that implements PEP 249, providing ways to execute SQL statements
* against a database.
*/
class MySQLdb extends PEP249::PEP249ModuleApiNode {
MySQLdb() { this = API::moduleImport("MySQLdb") }
}

View File

@@ -25,7 +25,7 @@ private module Mysql {
// mysql
// ---------------------------------------------------------------------------
/** Provides models for the `mysql` module. */
module mysql {
module MysqlMod {
/**
* The mysql.connector module
* See https://dev.mysql.com/doc/connector-python/en/connector-python-example-connecting.html

View File

@@ -22,7 +22,10 @@ private module Psycopg2 {
// ---------------------------------------------------------------------------
// Psycopg
// ---------------------------------------------------------------------------
/** psycopg2 implements PEP 249, providing ways to execute SQL statements against a database. */
/**
* A model of psycopg2 as a module that implements PEP 249, providing ways to execute SQL statements
* against a database.
*/
class Psycopg2 extends PEP249::PEP249ModuleApiNode {
Psycopg2() { this = API::moduleImport("psycopg2") }
}

View File

@@ -14,8 +14,11 @@ private import semmle.python.frameworks.PEP249
* Provides models for the `PyMySQL` PyPI package.
* See https://pypi.org/project/PyMySQL/
*/
private module PyMySQL {
/** PyMySQL implements PEP 249, providing ways to execute SQL statements against a database. */
private module PyMySql {
/**
* A model of PyMySQL as a module that implements PEP 249, providing ways to execute SQL statements
* against a database.
*/
class PyMySQLPEP249 extends PEP249::PEP249ModuleApiNode {
PyMySQLPEP249() { this = API::moduleImport("pymysql") }
}

View File

@@ -0,0 +1,59 @@
/**
* Provides classes modeling security-relevant aspects of the `pycurl` PyPI package.
*
* See
* - https://pypi.org/project/pycurl/
* - https://pycurl.io/docs/latest/
*/
private import python
private import semmle.python.Concepts
private import semmle.python.ApiGraphs
/**
* Provides models for the `pycurl` PyPI package.
*
* See
* - https://pypi.org/project/pycurl/
* - https://pycurl.io/docs/latest/
*/
private module Pycurl {
/**
* Provides models for the `pycurl.Curl` class
*
* See https://pycurl.io/docs/latest/curl.html.
*/
module Curl {
/** Gets a reference to the `pycurl.Curl` class. */
private API::Node classRef() { result = API::moduleImport("pycurl").getMember("Curl") }
/** Gets a reference to an instance of `pycurl.Curl`. */
private API::Node instance() { result = classRef().getReturn() }
/**
* When the first parameter value of the `setopt` function is set to `pycurl.URL`,
* the second parameter value is the request resource link.
*
* See http://pycurl.io/docs/latest/curlobject.html#pycurl.Curl.setopt.
*/
private class OutgoingRequestCall extends HTTP::Client::Request::Range, DataFlow::CallCfgNode {
OutgoingRequestCall() {
this = instance().getMember("setopt").getACall() and
this.getArg(0).asCfgNode().(AttrNode).getName() = "URL"
}
override DataFlow::Node getAUrlPart() {
result in [this.getArg(1), this.getArgByName("value")]
}
override string getFramework() { result = "pycurl.Curl" }
override predicate disablesCertificateValidation(
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
) {
// TODO: Look into disabling certificate validation
none()
}
}
}
}

View File

@@ -220,7 +220,7 @@ private module RestFramework {
*
* Use the predicate `Request::instance()` to get references to instances of `rest_framework.request.Request`.
*/
abstract class InstanceSource extends PrivateDjango::django::http::request::HttpRequest::InstanceSource {
abstract class InstanceSource extends PrivateDjango::DjangoImpl::Http::Request::HttpRequest::InstanceSource {
}
/** A direct instantiation of `rest_framework.request.Request`. */
@@ -295,19 +295,8 @@ private module RestFramework {
result = API::moduleImport("rest_framework").getMember("response").getMember("Response")
}
/**
* A source of instances of `rest_framework.response.Response`, extend this class to model new instances.
*
* This can include instantiations of the class, return values from function
* calls, or a special parameter that will be set when functions are called by an external
* library.
*
* Use the predicate `Response::instance()` to get references to instances of `rest_framework.response.Response`.
*/
abstract class InstanceSource extends DataFlow::LocalSourceNode { }
/** A direct instantiation of `rest_framework.response.Response`. */
private class ClassInstantiation extends PrivateDjango::django::http::response::HttpResponse::InstanceSource,
private class ClassInstantiation extends PrivateDjango::DjangoImpl::Http::Response::HttpResponse::InstanceSource,
DataFlow::CallCfgNode {
ClassInstantiation() { this = classRef().getACall() }
@@ -329,8 +318,8 @@ private module RestFramework {
*
* See https://www.django-rest-framework.org/api-guide/exceptions/#api-reference
*/
module APIException {
/** A direct instantiation of `rest_framework.exceptions.APIException` or subclass. */
module ApiException {
/** A direct instantiation of `rest_framework.exceptions.ApiException` or subclass. */
private class ClassInstantiation extends HTTP::Server::HttpResponse::Range,
DataFlow::CallCfgNode {
string className;
@@ -366,4 +355,7 @@ private module RestFramework {
override string getMimetypeDefault() { none() }
}
}
/** DEPRECATED: Alias for ApiException */
deprecated module APIException = ApiException;
}

View File

@@ -137,7 +137,7 @@ module SqlAlchemy {
*
* See https://docs.sqlalchemy.org/en/14/core/connections.html#dbapi-connections.
*/
module DBAPIConnection {
module DBApiConnection {
/**
* A source of instances of DB-API Connections, extend this class to model new instances.
*
@@ -149,8 +149,8 @@ module SqlAlchemy {
*/
abstract class InstanceSource extends DataFlow::LocalSourceNode { }
private class DBAPIConnectionSources extends InstanceSource, PEP249::Connection::InstanceSource {
DBAPIConnectionSources() {
private class DBApiConnectionSources extends InstanceSource, PEP249::Connection::InstanceSource {
DBApiConnectionSources() {
this.(DataFlow::MethodCallNode).calls(Engine::instance(), "raw_connection")
or
this.(DataFlow::AttrRead).accesses(Connection::instance(), "connection")
@@ -169,6 +169,9 @@ module SqlAlchemy {
DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) }
}
/** DEPRECATED: Alias for DBApiConnection */
deprecated module DBAPIConnection = DBApiConnection;
/**
* Provides models for the `sqlalchemy.orm.Session` class
*

View File

@@ -13,6 +13,9 @@ private import semmle.python.frameworks.PEP249
private import semmle.python.frameworks.internal.PoorMansFunctionResolution
private import semmle.python.frameworks.internal.SelfRefMixin
private import semmle.python.frameworks.internal.InstanceTaintStepsHelper
// modeling split over multiple files to keep this file from becoming too big
private import semmle.python.frameworks.Stdlib.Urllib
private import semmle.python.frameworks.Stdlib.Urllib2
/** Provides models for the Python standard library. */
module Stdlib {
@@ -87,7 +90,7 @@ module Stdlib {
* https://github.com/python/cpython/blob/64f54b7ccd49764b0304e076bfd79b5482988f53/Lib/http/client.py#L175
* and https://docs.python.org/3.9/library/email.compat32-message.html#email.message.Message
*/
module HTTPMessage {
module HttpMessage {
/**
* A source of instances of `http.client.HTTPMessage`, extend this class to model new instances.
*
@@ -99,7 +102,7 @@ module Stdlib {
*/
abstract class InstanceSource extends DataFlow::LocalSourceNode { }
/** Gets a reference to an instance of `http.client.HTTPMessage`. */
/** Gets a reference to an instance of `http.client.HttpMessage`. */
private DataFlow::TypeTrackingNode instance(DataFlow::TypeTracker t) {
t.start() and
result instanceof InstanceSource
@@ -107,7 +110,7 @@ module Stdlib {
exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t))
}
/** Gets a reference to an instance of `http.client.HTTPMessage`. */
/** Gets a reference to an instance of `http.client.HttpMessage`. */
DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) }
/**
@@ -126,6 +129,9 @@ module Stdlib {
}
}
/** DEPRECATED: Alias for HttpMessage */
deprecated module HTTPMessage = HttpMessage;
/**
* Provides models for the `http.cookies.Morsel` class
*
@@ -302,7 +308,7 @@ private module StdlibPrivate {
API::Node os() { result = API::moduleImport("os") }
/** Provides models for the `os` module. */
module os {
module OS {
/** Gets a reference to the `os.path` module. */
API::Node path() {
result = os().getMember("path")
@@ -317,7 +323,7 @@ private module StdlibPrivate {
}
/** Provides models for the `os.path` module */
module path {
module OsPath {
/** Gets a reference to the `os.path.join` function. */
API::Node join() { result = path().getMember("join") }
}
@@ -939,7 +945,7 @@ private module StdlibPrivate {
// these raise errors if the file does not exist
"getatime", "getmtime", "getctime", "getsize"
] and
this = os::path().getMember(name).getACall()
this = OS::path().getMember(name).getACall()
}
override DataFlow::Node getAPathArgument() {
@@ -955,7 +961,7 @@ private module StdlibPrivate {
/** A call to `os.path.samefile` will raise an exception if an `os.stat()` call on either pathname fails. */
private class OsPathSamefileCall extends FileSystemAccess::Range, DataFlow::CallCfgNode {
OsPathSamefileCall() { this = os::path().getMember("samefile").getACall() }
OsPathSamefileCall() { this = OS::path().getMember("samefile").getACall() }
override DataFlow::Node getAPathArgument() {
result in [
@@ -989,7 +995,7 @@ private module StdlibPrivate {
OsPathComputation() {
methodName = pathComputation() and
this = os::path().getMember(methodName).getACall()
this = OS::path().getMember(methodName).getACall()
}
DataFlow::Node getPathArg() {
@@ -1016,7 +1022,7 @@ private module StdlibPrivate {
* See https://docs.python.org/3/library/os.path.html#os.path.normpath
*/
private class OsPathNormpathCall extends Path::PathNormalization::Range, DataFlow::CallCfgNode {
OsPathNormpathCall() { this = os::path().getMember("normpath").getACall() }
OsPathNormpathCall() { this = OS::path().getMember("normpath").getACall() }
override DataFlow::Node getPathArg() { result in [this.getArg(0), this.getArgByName("path")] }
}
@@ -1026,7 +1032,7 @@ private module StdlibPrivate {
* See https://docs.python.org/3/library/os.path.html#os.path.abspath
*/
private class OsPathAbspathCall extends Path::PathNormalization::Range, DataFlow::CallCfgNode {
OsPathAbspathCall() { this = os::path().getMember("abspath").getACall() }
OsPathAbspathCall() { this = OS::path().getMember("abspath").getACall() }
override DataFlow::Node getPathArg() { result in [this.getArg(0), this.getArgByName("path")] }
}
@@ -1036,7 +1042,7 @@ private module StdlibPrivate {
* See https://docs.python.org/3/library/os.path.html#os.path.realpath
*/
private class OsPathRealpathCall extends Path::PathNormalization::Range, DataFlow::CallCfgNode {
OsPathRealpathCall() { this = os::path().getMember("realpath").getACall() }
OsPathRealpathCall() { this = OS::path().getMember("realpath").getACall() }
override DataFlow::Node getPathArg() { result in [this.getArg(0), this.getArgByName("path")] }
}
@@ -1137,7 +1143,7 @@ private module StdlibPrivate {
override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
exists(CallNode call |
nodeTo.asCfgNode() = call and
call = os::path::join().getACall().asCfgNode() and
call = OS::OsPath::join().getACall().asCfgNode() and
call.getAnArg() = nodeFrom.asCfgNode()
)
// TODO: Handle pathlib (like we do for os.path.join)
@@ -1656,7 +1662,7 @@ private module StdlibPrivate {
API::Node cgi() { result = API::moduleImport("cgi") }
/** Provides models for the `cgi` module. */
module cgi {
module Cgi {
/**
* Provides models for the `cgi.FieldStorage` class
*
@@ -1780,42 +1786,63 @@ private module StdlibPrivate {
// ---------------------------------------------------------------------------
// BaseHTTPServer (Python 2 only)
// ---------------------------------------------------------------------------
/** Gets a reference to the `BaseHTTPServer` module. */
API::Node baseHTTPServer() { result = API::moduleImport("BaseHTTPServer") }
/** Gets a reference to the `BaseHttpServer` module. */
API::Node baseHttpServer() { result = API::moduleImport("BaseHTTPServer") }
/** Provides models for the `BaseHTTPServer` module. */
module BaseHTTPServer {
/** DEPRECATED: Alias for baseHttpServer */
deprecated API::Node baseHTTPServer() { result = baseHttpServer() }
/** Provides models for the `BaseHttpServer` module. */
module BaseHttpServer {
/**
* Provides models for the `BaseHTTPServer.BaseHTTPRequestHandler` class (Python 2 only).
*/
module BaseHTTPRequestHandler {
/** Gets a reference to the `BaseHTTPServer.BaseHTTPRequestHandler` class. */
API::Node classRef() { result = baseHTTPServer().getMember("BaseHTTPRequestHandler") }
module BaseHttpRequestHandler {
/** Gets a reference to the `BaseHttpServer.BaseHttpRequestHandler` class. */
API::Node classRef() { result = baseHttpServer().getMember("BaseHTTPRequestHandler") }
}
/** DEPRECATED: Alias for BaseHttpRequestHandler */
deprecated module BaseHTTPRequestHandler = BaseHttpRequestHandler;
}
/** DEPRECATED: Alias for BaseHttpServer */
deprecated module BaseHTTPServer = BaseHttpServer;
// ---------------------------------------------------------------------------
// SimpleHTTPServer (Python 2 only)
// ---------------------------------------------------------------------------
/** Gets a reference to the `SimpleHTTPServer` module. */
API::Node simpleHTTPServer() { result = API::moduleImport("SimpleHTTPServer") }
/** Gets a reference to the `SimpleHttpServer` module. */
API::Node simpleHttpServer() { result = API::moduleImport("SimpleHTTPServer") }
/** Provides models for the `SimpleHTTPServer` module. */
module SimpleHTTPServer {
/** DEPRECATED: Alias for simpleHttpServer */
deprecated API::Node simpleHTTPServer() { result = simpleHttpServer() }
/** Provides models for the `SimpleHttpServer` module. */
module SimpleHttpServer {
/**
* Provides models for the `SimpleHTTPServer.SimpleHTTPRequestHandler` class (Python 2 only).
*/
module SimpleHTTPRequestHandler {
/** Gets a reference to the `SimpleHTTPServer.SimpleHTTPRequestHandler` class. */
API::Node classRef() { result = simpleHTTPServer().getMember("SimpleHTTPRequestHandler") }
module SimpleHttpRequestHandler {
/** Gets a reference to the `SimpleHttpServer.SimpleHttpRequestHandler` class. */
API::Node classRef() { result = simpleHttpServer().getMember("SimpleHTTPRequestHandler") }
}
/** DEPRECATED: Alias for SimpleHttpRequestHandler */
deprecated module SimpleHTTPRequestHandler = SimpleHttpRequestHandler;
}
/** DEPRECATED: Alias for SimpleHttpServer */
deprecated module SimpleHTTPServer = SimpleHttpServer;
// ---------------------------------------------------------------------------
// CGIHTTPServer (Python 2 only)
// ---------------------------------------------------------------------------
/** Gets a reference to the `CGIHTTPServer` module. */
API::Node cgiHTTPServer() { result = API::moduleImport("CGIHTTPServer") }
API::Node cgiHttpServer() { result = API::moduleImport("CGIHTTPServer") }
/** DEPRECATED: Alias for cgiHttpServer */
deprecated API::Node cgiHTTPServer() { result = cgiHttpServer() }
/** Provides models for the `CGIHTTPServer` module. */
module CGIHTTPServer {
@@ -1824,7 +1851,7 @@ private module StdlibPrivate {
*/
module CGIHTTPRequestHandler {
/** Gets a reference to the `CGIHTTPServer.CGIHTTPRequestHandler` class. */
API::Node classRef() { result = cgiHTTPServer().getMember("CGIHTTPRequestHandler") }
API::Node classRef() { result = cgiHttpServer().getMember("CGIHTTPRequestHandler") }
}
}
@@ -1835,7 +1862,7 @@ private module StdlibPrivate {
API::Node http() { result = API::moduleImport("http") }
/** Provides models for the `http` module. */
module http {
module Http {
// -------------------------------------------------------------------------
// http.server
// -------------------------------------------------------------------------
@@ -1843,27 +1870,33 @@ private module StdlibPrivate {
API::Node server() { result = http().getMember("server") }
/** Provides models for the `http.server` module */
module server {
module Server {
/**
* Provides models for the `http.server.BaseHTTPRequestHandler` class (Python 3 only).
*
* See https://docs.python.org/3.9/library/http.server.html#http.server.BaseHTTPRequestHandler.
*/
module BaseHTTPRequestHandler {
/** Gets a reference to the `http.server.BaseHTTPRequestHandler` class. */
module BaseHttpRequestHandler {
/** Gets a reference to the `http.server.BaseHttpRequestHandler` class. */
API::Node classRef() { result = server().getMember("BaseHTTPRequestHandler") }
}
/** DEPRECATED: Alias for BaseHttpRequestHandler */
deprecated module BaseHTTPRequestHandler = BaseHttpRequestHandler;
/**
* Provides models for the `http.server.SimpleHTTPRequestHandler` class (Python 3 only).
*
* See https://docs.python.org/3.9/library/http.server.html#http.server.SimpleHTTPRequestHandler.
*/
module SimpleHTTPRequestHandler {
/** Gets a reference to the `http.server.SimpleHTTPRequestHandler` class. */
module SimpleHttpRequestHandler {
/** Gets a reference to the `http.server.SimpleHttpRequestHandler` class. */
API::Node classRef() { result = server().getMember("SimpleHTTPRequestHandler") }
}
/** DEPRECATED: Alias for SimpleHttpRequestHandler */
deprecated module SimpleHTTPRequestHandler = SimpleHttpRequestHandler;
/**
* Provides models for the `http.server.CGIHTTPRequestHandler` class (Python 3 only).
*
@@ -1883,27 +1916,30 @@ private module StdlibPrivate {
* - https://docs.python.org/3.9/library/http.server.html#http.server.BaseHTTPRequestHandler
* - https://docs.python.org/2.7/library/basehttpserver.html#BaseHTTPServer.BaseHTTPRequestHandler
*/
private module HTTPRequestHandler {
/** Gets a reference to the `BaseHTTPRequestHandler` class or any subclass. */
private module HttpRequestHandler {
/** Gets a reference to the `BaseHttpRequestHandler` class or any subclass. */
API::Node subclassRef() {
result =
[
// Python 2
BaseHTTPServer::BaseHTTPRequestHandler::classRef(),
SimpleHTTPServer::SimpleHTTPRequestHandler::classRef(),
BaseHttpServer::BaseHttpRequestHandler::classRef(),
SimpleHttpServer::SimpleHttpRequestHandler::classRef(),
CGIHTTPServer::CGIHTTPRequestHandler::classRef(),
// Python 3
http::server::BaseHTTPRequestHandler::classRef(),
http::server::SimpleHTTPRequestHandler::classRef(),
http::server::CGIHTTPRequestHandler::classRef()
Http::Server::BaseHttpRequestHandler::classRef(),
Http::Server::SimpleHttpRequestHandler::classRef(),
Http::Server::CGIHTTPRequestHandler::classRef()
].getASubclass*()
}
/** A HTTPRequestHandler class definition (most likely in project code). */
class HTTPRequestHandlerClassDef extends Class {
HTTPRequestHandlerClassDef() { this.getParent() = subclassRef().getAUse().asExpr() }
/** A HttpRequestHandler class definition (most likely in project code). */
class HttpRequestHandlerClassDef extends Class {
HttpRequestHandlerClassDef() { this.getParent() = subclassRef().getAUse().asExpr() }
}
/** DEPRECATED: Alias for HttpRequestHandlerClassDef */
deprecated class HTTPRequestHandlerClassDef = HttpRequestHandlerClassDef;
/**
* A source of instances of the `BaseHTTPRequestHandler` class or any subclass, extend this class to model new instances.
*
@@ -1915,16 +1951,16 @@ private module StdlibPrivate {
*/
abstract class InstanceSource extends DataFlow::Node { }
/** The `self` parameter in a method on the `BaseHTTPRequestHandler` class or any subclass. */
/** The `self` parameter in a method on the `BaseHttpRequestHandler` class or any subclass. */
private class SelfParam extends InstanceSource, RemoteFlowSource::Range, DataFlow::ParameterNode {
SelfParam() {
exists(HTTPRequestHandlerClassDef cls | cls.getAMethod().getArg(0) = this.getParameter())
exists(HttpRequestHandlerClassDef cls | cls.getAMethod().getArg(0) = this.getParameter())
}
override string getSourceType() { result = "stdlib HTTPRequestHandler" }
}
/** Gets a reference to an instance of the `BaseHTTPRequestHandler` class or any subclass. */
/** Gets a reference to an instance of the `BaseHttpRequestHandler` class or any subclass. */
private DataFlow::TypeTrackingNode instance(DataFlow::TypeTracker t) {
t.start() and
result instanceof InstanceSource
@@ -1932,7 +1968,7 @@ private module StdlibPrivate {
exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t))
}
/** Gets a reference to an instance of the `BaseHTTPRequestHandler` class or any subclass. */
/** Gets a reference to an instance of the `BaseHttpRequestHandler` class or any subclass. */
DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) }
private class AdditionalTaintStep extends TaintTracking::AdditionalTaintStep {
@@ -1953,16 +1989,16 @@ private module StdlibPrivate {
}
}
/** An `HTTPMessage` instance that originates from a `BaseHTTPRequestHandler` instance. */
private class BaseHTTPRequestHandlerHeadersInstances extends Stdlib::HTTPMessage::InstanceSource {
BaseHTTPRequestHandlerHeadersInstances() {
/** An `HttpMessage` instance that originates from a `BaseHttpRequestHandler` instance. */
private class BaseHttpRequestHandlerHeadersInstances extends Stdlib::HttpMessage::InstanceSource {
BaseHttpRequestHandlerHeadersInstances() {
this.(DataFlow::AttrRead).accesses(instance(), "headers")
}
}
/** A file-like object that originates from a `BaseHTTPRequestHandler` instance. */
private class BaseHTTPRequestHandlerFileLikeObjectInstances extends Stdlib::FileLikeObject::InstanceSource {
BaseHTTPRequestHandlerFileLikeObjectInstances() {
/** A file-like object that originates from a `BaseHttpRequestHandler` instance. */
private class BaseHttpRequestHandlerFileLikeObjectInstances extends Stdlib::FileLikeObject::InstanceSource {
BaseHttpRequestHandlerFileLikeObjectInstances() {
this.(DataFlow::AttrRead).accesses(instance(), "rfile")
}
}
@@ -1974,7 +2010,7 @@ private module StdlibPrivate {
*/
private class RequestHandlerFunc extends HTTP::Server::RequestHandler::Range {
RequestHandlerFunc() {
this = any(HTTPRequestHandlerClassDef cls).getAMethod() and
this = any(HttpRequestHandlerClassDef cls).getAMethod() and
this.getName() = "do_" + HTTP::httpVerb()
}
@@ -2152,8 +2188,8 @@ private module StdlibPrivate {
* - https://docs.python.org/2.7/library/httplib.html#httplib.HTTPConnection
* - https://docs.python.org/2.7/library/httplib.html#httplib.HTTPSConnection
*/
module HTTPConnection {
/** Gets a reference to the `http.client.HTTPConnection` class. */
module HttpConnection {
/** Gets a reference to the `http.client.HttpConnection` class. */
private API::Node classRef() {
exists(string className | className in ["HTTPConnection", "HTTPSConnection"] |
// Python 3
@@ -2181,7 +2217,7 @@ private module StdlibPrivate {
abstract DataFlow::Node getHostArgument();
}
/** A direct instantiation of `http.client.HTTPConnection`. */
/** A direct instantiation of `http.client.HttpConnection`. */
private class ClassInstantiation extends InstanceSource, DataFlow::CallCfgNode {
ClassInstantiation() { this = classRef().getACall() }
@@ -2209,7 +2245,7 @@ private module StdlibPrivate {
instance(DataFlow::TypeTracker::end(), hostArg).flowsTo(result)
}
/** A method call on a HTTPConnection that sends off a request */
/** A method call on a HttpConnection that sends off a request */
private class RequestCall extends HTTP::Client::Request::Range, DataFlow::MethodCallNode {
RequestCall() { this.calls(instance(_), ["request", "_send_request", "putrequest"]) }
@@ -2235,7 +2271,7 @@ private module StdlibPrivate {
/** A call to the `getresponse` method. */
private class HttpConnectionGetResponseCall extends DataFlow::MethodCallNode,
HTTPResponse::InstanceSource {
HttpResponse::InstanceSource {
HttpConnectionGetResponseCall() { this.calls(instance(_), "getresponse") }
}
@@ -2266,6 +2302,9 @@ private module StdlibPrivate {
}
}
/** DEPRECATED: Alias for HttpConnection */
deprecated module HTTPConnection = HttpConnection;
/**
* Provides models for the `http.client.HTTPResponse` class
*
@@ -2273,8 +2312,8 @@ private module StdlibPrivate {
* - https://docs.python.org/3.10/library/http.client.html#httpresponse-objects
* - https://docs.python.org/3/library/http.client.html#http.client.HTTPResponse.
*/
module HTTPResponse {
/** Gets a reference to the `http.client.HTTPResponse` class. */
module HttpResponse {
/** Gets a reference to the `http.client.HttpResponse` class. */
private API::Node classRef() {
result = API::moduleImport("http").getMember("client").getMember("HTTPResponse")
}
@@ -2293,12 +2332,12 @@ private module StdlibPrivate {
abstract class InstanceSource extends Stdlib::FileLikeObject::InstanceSource,
DataFlow::LocalSourceNode { }
/** A direct instantiation of `http.client.HTTPResponse`. */
/** A direct instantiation of `http.client.HttpResponse`. */
private class ClassInstantiation extends InstanceSource, DataFlow::CallCfgNode {
ClassInstantiation() { this = classRef().getACall() }
}
/** Gets a reference to an instance of `http.client.HTTPResponse`. */
/** Gets a reference to an instance of `http.client.HttpResponse`. */
private DataFlow::TypeTrackingNode instance(DataFlow::TypeTracker t) {
t.start() and
result instanceof InstanceSource
@@ -2306,7 +2345,7 @@ private module StdlibPrivate {
exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t))
}
/** Gets a reference to an instance of `http.client.HTTPResponse`. */
/** Gets a reference to an instance of `http.client.HttpResponse`. */
DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) }
/**
@@ -2324,9 +2363,9 @@ private module StdlibPrivate {
override string getAsyncMethodName() { none() }
}
/** An attribute read that is a HTTPMessage instance. */
private class HTTPMessageInstances extends Stdlib::HTTPMessage::InstanceSource {
HTTPMessageInstances() {
/** An attribute read that is a HttpMessage instance. */
private class HttpMessageInstances extends Stdlib::HttpMessage::InstanceSource {
HttpMessageInstances() {
this.(DataFlow::AttrRead).accesses(instance(), ["headers", "msg"])
or
this.(DataFlow::MethodCallNode).calls(instance(), "info")
@@ -2334,11 +2373,15 @@ private module StdlibPrivate {
}
}
/** DEPRECATED: Alias for HttpResponse */
deprecated module HTTPResponse = HttpResponse;
// ---------------------------------------------------------------------------
// sqlite3
// ---------------------------------------------------------------------------
/**
* sqlite3 implements PEP 249, providing ways to execute SQL statements against a database.
* A model of sqlite3 as a module that implements PEP 249, providing ways to execute SQL statements
* against a database.
*
* See https://devdocs.io/python~3.9/library/sqlite3
*/
@@ -2836,6 +2879,70 @@ private module StdlibPrivate {
override string getKind() { result = Escaping::getRegexKind() }
}
// ---------------------------------------------------------------------------
// xml.etree.ElementTree
// ---------------------------------------------------------------------------
/**
* An instance of `xml.etree.ElementTree.ElementTree`.
*
* See https://docs.python.org/3.10/library/xml.etree.elementtree.html#xml.etree.ElementTree.ElementTree
*/
private API::Node elementTreeInstance() {
//parse to a tree
result =
API::moduleImport("xml")
.getMember("etree")
.getMember("ElementTree")
.getMember("parse")
.getReturn()
or
// construct a tree without parsing
result =
API::moduleImport("xml")
.getMember("etree")
.getMember("ElementTree")
.getMember("ElementTree")
.getReturn()
}
/**
* An instance of `xml.etree.ElementTree.Element`.
*
* See https://docs.python.org/3.10/library/xml.etree.elementtree.html#xml.etree.ElementTree.Element
*/
private API::Node elementInstance() {
// parse or go to the root of a tree
result = elementTreeInstance().getMember(["parse", "getroot"]).getReturn()
or
// parse directly to an element
result =
API::moduleImport("xml")
.getMember("etree")
.getMember("ElementTree")
.getMember(["fromstring", "fromstringlist", "XML"])
.getReturn()
}
/**
* A call to a find method on a tree or an element will execute an XPath expression.
*/
private class ElementTreeFindCall extends XML::XPathExecution::Range, DataFlow::CallCfgNode {
string methodName;
ElementTreeFindCall() {
methodName in ["find", "findall", "findtext"] and
(
this = elementTreeInstance().getMember(methodName).getACall()
or
this = elementInstance().getMember(methodName).getACall()
)
}
override DataFlow::Node getXPath() { result in [this.getArg(0), this.getArgByName("match")] }
override string getName() { result = "xml.etree" }
}
// ---------------------------------------------------------------------------
// urllib
// ---------------------------------------------------------------------------

View File

@@ -0,0 +1,71 @@
/**
* Provides classes modeling security-relevant aspects of the `urllib` module, part of
* the Python standard library.
*
* See
* - https://docs.python.org/2/library/urllib.html
* - https://docs.python.org/3/library/urllib.html
*/
private import python
private import semmle.python.Concepts
private import semmle.python.ApiGraphs
/**
* Provides models for the `urllib` module, part of
* the Python standard library.
*
* See
* - https://docs.python.org/2/library/urllib.html
* - https://docs.python.org/3/library/urllib.html
*/
private module Urllib {
/**
* Provides models for the `urllib.request` extension library
*
* See https://docs.python.org/3.9/library/urllib.request.html
*/
module Request {
/**
* See
* - https://docs.python.org/3.9/library/urllib.request.html#urllib.request.Request
*/
private class RequestCall extends HTTP::Client::Request::Range, DataFlow::CallCfgNode {
RequestCall() {
this = API::moduleImport("urllib").getMember("request").getMember("Request").getACall()
}
override DataFlow::Node getAUrlPart() { result in [this.getArg(0), this.getArgByName("url")] }
override string getFramework() { result = "urllib.request.Request" }
override predicate disablesCertificateValidation(
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
) {
// TODO: Look into disabling certificate validation
none()
}
}
/**
* See
* - https://docs.python.org/3.9/library/urllib.request.html#urllib.request.urlopen
*/
private class UrlOpenCall extends HTTP::Client::Request::Range, DataFlow::CallCfgNode {
UrlOpenCall() {
this = API::moduleImport("urllib").getMember("request").getMember("urlopen").getACall()
}
override DataFlow::Node getAUrlPart() { result in [this.getArg(0), this.getArgByName("url")] }
override string getFramework() { result = "urllib.request.urlopen" }
override predicate disablesCertificateValidation(
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
) {
// TODO: Look into disabling certificate validation
none()
}
}
}
}

View File

@@ -0,0 +1,56 @@
/**
* Provides classes modeling security-relevant aspects of the `urllib2` module, part of
* the Python 2 standard library.
*
* See https://docs.python.org/2/library/urllib2.html
*/
private import python
private import semmle.python.Concepts
private import semmle.python.ApiGraphs
/**
* Provides models for the the `urllib2` module, part of
* the Python 2 standard library.
*
* See https://docs.python.org/2/library/urllib2.html
*/
private module Urllib2 {
/**
* See
* - https://docs.python.org/2/library/urllib2.html#urllib2.Request
*/
private class RequestCall extends HTTP::Client::Request::Range, DataFlow::CallCfgNode {
RequestCall() { this = API::moduleImport("urllib2").getMember("Request").getACall() }
override DataFlow::Node getAUrlPart() { result in [this.getArg(0), this.getArgByName("url")] }
override string getFramework() { result = "urllib2.Request" }
override predicate disablesCertificateValidation(
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
) {
// TODO: Look into disabling certificate validation
none()
}
}
/**
* See
* - https://docs.python.org/2/library/urllib2.html#urllib2.urlopen
*/
private class UrlOpenCall extends HTTP::Client::Request::Range, DataFlow::CallCfgNode {
UrlOpenCall() { this = API::moduleImport("urllib2").getMember("urlopen").getACall() }
override DataFlow::Node getAUrlPart() { result in [this.getArg(0), this.getArgByName("url")] }
override string getFramework() { result = "urllib2.urlopen" }
override predicate disablesCertificateValidation(
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
) {
// TODO: Look into disabling certificate validation
none()
}
}
}

View File

@@ -23,7 +23,7 @@ private module Tornado {
*
* See https://www.tornadoweb.org/en/stable/httputil.html#tornado.httputil.HTTPHeaders.
*/
module HTTPHeaders {
module HttpHeaders {
/**
* A source of instances of `tornado.httputil.HTTPHeaders`, extend this class to model new instances.
*
@@ -35,7 +35,7 @@ private module Tornado {
*/
abstract class InstanceSource extends DataFlow::LocalSourceNode { }
/** Gets a reference to an instance of `tornado.httputil.HTTPHeaders`. */
/** Gets a reference to an instance of `tornado.httputil.HttpHeaders`. */
private DataFlow::TypeTrackingNode instance(DataFlow::TypeTracker t) {
t.start() and
result instanceof InstanceSource
@@ -43,7 +43,7 @@ private module Tornado {
exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t))
}
/** Gets a reference to an instance of `tornado.httputil.HTTPHeaders`. */
/** Gets a reference to an instance of `tornado.httputil.HttpHeaders`. */
DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) }
/**
@@ -62,6 +62,9 @@ private module Tornado {
}
}
/** DEPRECATED: Alias for HttpHeaders */
deprecated module HTTPHeaders = HttpHeaders;
// ---------------------------------------------------------------------------
// tornado
// ---------------------------------------------------------------------------
@@ -69,7 +72,7 @@ private module Tornado {
API::Node tornado() { result = API::moduleImport("tornado") }
/** Provides models for the `tornado` module. */
module tornado {
module TornadoModule {
// -------------------------------------------------------------------------
// tornado.web
// -------------------------------------------------------------------------
@@ -77,7 +80,7 @@ private module Tornado {
API::Node web() { result = tornado().getMember("web") }
/** Provides models for the `tornado.web` module */
module web {
module Web {
/**
* Provides models for the `tornado.web.RequestHandler` class and subclasses.
*
@@ -102,7 +105,7 @@ private module Tornado {
/** Gets a reference to this class. */
private DataFlow::TypeTrackingNode getARef(DataFlow::TypeTracker t) {
t.start() and
result.asExpr().(ClassExpr) = this.getParent()
result.asExpr() = this.getParent()
or
exists(DataFlow::TypeTracker t2 | result = this.getARef(t2).track(t2, t))
}
@@ -196,7 +199,7 @@ private module Tornado {
override string getAsyncMethodName() { none() }
}
private class RequestAttrAccess extends tornado::httputil::HttpServerRequest::InstanceSource {
private class RequestAttrAccess extends TornadoModule::HttpUtil::HttpServerRequest::InstanceSource {
RequestAttrAccess() {
this.(DataFlow::AttrRead).getObject() = instance() and
this.(DataFlow::AttrRead).getAttributeName() = "request"
@@ -260,7 +263,7 @@ private module Tornado {
API::Node httputil() { result = tornado().getMember("httputil") }
/** Provides models for the `tornado.httputil` module */
module httputil {
module HttpUtil {
/**
* Provides models for the `tornado.httputil.HttpServerRequest` class
*
@@ -323,9 +326,9 @@ private module Tornado {
override string getAsyncMethodName() { none() }
}
/** An `HTTPHeaders` instance that originates from a Tornado request. */
private class TornadoRequestHTTPHeadersInstances extends HTTPHeaders::InstanceSource {
TornadoRequestHTTPHeadersInstances() {
/** An `HttpHeaders` instance that originates from a Tornado request. */
private class TornadoRequestHttpHeadersInstances extends HttpHeaders::InstanceSource {
TornadoRequestHttpHeadersInstances() {
this.(DataFlow::AttrRead).accesses(instance(), "headers")
}
}
@@ -354,14 +357,16 @@ private module Tornado {
// ---------------------------------------------------------------------------
// routing
// ---------------------------------------------------------------------------
/** A sequence that defines a number of route rules */
/** Gets a sequence that defines a number of route rules */
SequenceNode routeSetupRuleList() {
exists(CallNode call | call = any(tornado::web::Application::ClassInstantiation c).asCfgNode() |
exists(CallNode call |
call = any(TornadoModule::Web::Application::ClassInstantiation c).asCfgNode()
|
result in [call.getArg(0), call.getArgByName("handlers")]
)
or
exists(CallNode call |
call.getFunction() = tornado::web::Application::add_handlers().asCfgNode()
call.getFunction() = TornadoModule::Web::Application::add_handlers().asCfgNode()
|
result in [call.getArg(1), call.getArgByName("host_handlers")]
)
@@ -403,7 +408,7 @@ private module Tornado {
override DataFlow::Node getUrlPatternArg() { result.asCfgNode() = node.getElement(0) }
override Function getARequestHandler() {
exists(tornado::web::RequestHandler::RequestHandlerClass cls |
exists(TornadoModule::Web::RequestHandler::RequestHandlerClass cls |
cls.getARef().asCfgNode() = node.getElement(1) and
result = cls.getARequestHandler()
)
@@ -434,7 +439,7 @@ private module Tornado {
/** A request handler defined in a tornado RequestHandler class, that has no known route. */
private class TornadoRequestHandlerWithoutKnownRoute extends HTTP::Server::RequestHandler::Range {
TornadoRequestHandlerWithoutKnownRoute() {
exists(tornado::web::RequestHandler::RequestHandlerClass cls |
exists(TornadoModule::Web::RequestHandler::RequestHandlerClass cls |
cls.getARequestHandler() = this
) and
not exists(TornadoRouteSetup setup | setup.getARequestHandler() = this)
@@ -462,7 +467,7 @@ private module Tornado {
private class TornadoRequestHandlerRedirectCall extends HTTP::Server::HttpRedirectResponse::Range,
DataFlow::CallCfgNode {
TornadoRequestHandlerRedirectCall() {
this.getFunction() = tornado::web::RequestHandler::redirectMethod()
this.getFunction() = TornadoModule::Web::RequestHandler::redirectMethod()
}
override DataFlow::Node getRedirectLocation() {
@@ -484,7 +489,7 @@ private module Tornado {
private class TornadoRequestHandlerWriteCall extends HTTP::Server::HttpResponse::Range,
DataFlow::CallCfgNode {
TornadoRequestHandlerWriteCall() {
this.getFunction() = tornado::web::RequestHandler::writeMethod()
this.getFunction() = TornadoModule::Web::RequestHandler::writeMethod()
}
override DataFlow::Node getBody() { result in [this.getArg(0), this.getArgByName("chunk")] }
@@ -502,7 +507,7 @@ private module Tornado {
class TornadoRequestHandlerSetCookieCall extends HTTP::Server::CookieWrite::Range,
DataFlow::MethodCallNode {
TornadoRequestHandlerSetCookieCall() {
this.calls(tornado::web::RequestHandler::instance(), "set_cookie")
this.calls(TornadoModule::Web::RequestHandler::instance(), "set_cookie")
}
override DataFlow::Node getHeaderArg() { none() }

View File

@@ -0,0 +1,75 @@
/**
* Provides classes modeling security-relevant aspects of the `urllib3` PyPI package.
*
* See
* - https://pypi.org/project/urllib3/
* - https://urllib3.readthedocs.io/en/stable/reference/
*/
private import python
private import semmle.python.Concepts
private import semmle.python.ApiGraphs
/**
* Provides models for the `urllib3` PyPI package.
*
* See
* - https://pypi.org/project/urllib3/
* - https://urllib3.readthedocs.io/en/stable/reference/
*/
private module Urllib3 {
/**
* Provides models for the `urllib3.request.RequestMethods` class and subclasses, such
* as the `urllib3.PoolManager` class
*
* See
* - https://urllib3.readthedocs.io/en/stable/reference/urllib3.request.html#urllib3.request.RequestMethods
*
*
* https://urllib3.readthedocs.io/en/stable/reference/urllib3.poolmanager.html.
*/
module PoolManager {
/** Gets a reference to the `urllib3.PoolManager` class. */
private API::Node classRef() {
result =
API::moduleImport("urllib3")
.getMember(["PoolManager", "ProxyManager", "HTTPConnectionPool", "HTTPSConnectionPool"])
or
result =
API::moduleImport("urllib3")
.getMember("request")
.getMember("RequestMethods")
.getASubclass+()
}
/** Gets a reference to an instance of a `urllib3.request.RequestMethods` subclass. */
private API::Node instance() { result = classRef().getReturn() }
/**
* A call to a method making an outgoing request.
*
* See
* - https://urllib3.readthedocs.io/en/stable/reference/urllib3.request.html#urllib3.request.RequestMethods
* - https://urllib3.readthedocs.io/en/stable/reference/urllib3.connectionpool.html#urllib3.HTTPConnectionPool.urlopen
*/
private class RequestCall extends HTTP::Client::Request::Range, DataFlow::CallCfgNode {
RequestCall() {
this =
instance()
.getMember(["request", "request_encode_url", "request_encode_body", "urlopen"])
.getACall()
}
override DataFlow::Node getAUrlPart() { result in [this.getArg(1), this.getArgByName("url")] }
override string getFramework() { result = "urllib3.PoolManager" }
override predicate disablesCertificateValidation(
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
) {
// TODO: Look into disabling certificate validation
none()
}
}
}
}

View File

@@ -34,7 +34,7 @@ private module NotExposed {
concat(string newModelFullyQualified |
newModel(any(MySpec spec), newModelFullyQualified, _, _, _)
|
fullyQualifiedToAPIGraphPath(newModelFullyQualified), " or this = API::"
fullyQualifiedToApiGraphPath(newModelFullyQualified), " or this = API::"
)
}
@@ -69,10 +69,15 @@ private module NotExposed {
//
//
bindingset[fullyQaulified]
string fullyQualifiedToAPIGraphPath(string fullyQaulified) {
string fullyQualifiedToApiGraphPath(string fullyQaulified) {
result = "moduleImport(\"" + fullyQaulified.replaceAll(".", "\").getMember(\"") + "\")"
}
/** DEPRECATED: Alias for fullyQualifiedToApiGraphPath */
deprecated string fullyQualifiedToAPIGraphPath(string fullyQaulified) {
result = fullyQualifiedToApiGraphPath(fullyQaulified)
}
bindingset[this]
abstract class FindSubclassesSpec extends string {
abstract API::Node getAlreadyModeledClass();
@@ -99,13 +104,13 @@ private module NotExposed {
or
exists(string newSubclassName |
newModel(spec, newSubclassName, _, _, _) and
result.getPath() = fullyQualifiedToAPIGraphPath(newSubclassName)
result.getPath() = fullyQualifiedToApiGraphPath(newSubclassName)
)
}
bindingset[fullyQualifiedName]
predicate alreadyModeled(FindSubclassesSpec spec, string fullyQualifiedName) {
fullyQualifiedToAPIGraphPath(fullyQualifiedName) = spec.getAlreadyModeledClass().getPath()
fullyQualifiedToApiGraphPath(fullyQualifiedName) = spec.getAlreadyModeledClass().getPath()
}
predicate isNonTestProjectCode(AstNode ast) {

View File

@@ -3,26 +3,6 @@
import python
private import semmle.python.pointsto.PointsTo
/** A method that to a sub-class of `zope.interface.Interface` */
deprecated class ZopeInterfaceMethod extends PyFunctionObject {
/** Holds if this method belongs to a class that sub-classes `zope.interface.Interface` */
ZopeInterfaceMethod() {
exists(Object interface, ClassObject owner |
interface = ModuleObject::named("zope.interface").attr("Interface") and
owner.declaredAttribute(_) = this and
owner.getAnImproperSuperType().getABaseType() = interface
)
}
override int minParameters() { result = super.minParameters() + 1 }
override int maxParameters() {
if exists(this.getFunction().getVararg())
then result = super.maxParameters()
else result = super.maxParameters() + 1
}
}
/** A method that belongs to a sub-class of `zope.interface.Interface` */
class ZopeInterfaceMethodValue extends PythonFunctionValue {
/** Holds if this method belongs to a class that sub-classes `zope.interface.Interface` */

View File

@@ -53,7 +53,7 @@ abstract class CallableObjectInternal extends ObjectInternal {
override ObjectInternal getIterNext() { none() }
}
/** Class representing Python functions */
/** A Python function. */
class PythonFunctionObjectInternal extends CallableObjectInternal, TPythonFunctionObject {
override Function getScope() {
exists(CallableExpr expr |
@@ -167,7 +167,7 @@ private BasicBlock blockReturningNone(Function func) {
)
}
/** Class representing built-in functions such as `len` or `print`. */
/** A built-in function such as `len` or `print`. */
class BuiltinFunctionObjectInternal extends CallableObjectInternal, TBuiltinFunctionObject {
override Builtin getBuiltin() { this = TBuiltinFunctionObject(result) }
@@ -290,7 +290,7 @@ private Builtin getBuiltinFunctionReturnType(Builtin func) {
)
}
/** Class representing methods of built-in classes (otherwise known as method-descriptors) such as `list.append`. */
/** A method of a built-in class (otherwise known as method-descriptors) such as `list.append`. */
class BuiltinMethodObjectInternal extends CallableObjectInternal, TBuiltinMethodObject {
override Builtin getBuiltin() { this = TBuiltinMethodObject(result) }
@@ -380,7 +380,7 @@ class BuiltinMethodObjectInternal extends CallableObjectInternal, TBuiltinMethod
}
/**
* Class representing bound-methods.
* A bound-method.
* Note that built-in methods, such as `[].append` are also represented as bound-methods.
* Although built-in methods and bound-methods are distinct classes in CPython, their behavior
* is the same and we treat them identically.

View File

@@ -6,7 +6,7 @@ private import semmle.python.pointsto.PointsToContext
private import semmle.python.pointsto.MRO
private import semmle.python.types.Builtins
/** Class representing classes */
/** A class. */
abstract class ClassObjectInternal extends ObjectInternal {
override string getName() { result = this.getClassDeclaration().getName() }
@@ -109,7 +109,7 @@ abstract class ClassObjectInternal extends ObjectInternal {
override predicate isNotSubscriptedType() { any() }
}
/** Class representing Python source classes */
/** A class that is defined in Python source. */
class PythonClassObjectInternal extends ClassObjectInternal, TPythonClassObject {
/** Gets the scope for this Python class */
Class getScope() {
@@ -163,7 +163,7 @@ class PythonClassObjectInternal extends ClassObjectInternal, TPythonClassObject
}
}
/** Class representing built-in classes, except `type` */
/** A built-in class, except `type`. */
class BuiltinClassObjectInternal extends ClassObjectInternal, TBuiltinClassObject {
override Builtin getBuiltin() { this = TBuiltinClassObject(result) }

View File

@@ -7,7 +7,7 @@ private import semmle.python.pointsto.PointsToContext
private import semmle.python.types.Builtins
/**
* Class representing constants.
* A constant.
* Includes `None`, `True` and `False` as
* well as strings and integers.
*/

View File

@@ -6,7 +6,7 @@ private import semmle.python.pointsto.PointsToContext
private import semmle.python.pointsto.MRO
private import semmle.python.types.Builtins
/** Class representing property objects in Python */
/** A property object. */
class PropertyInternal extends ObjectInternal, TProperty {
/** Gets the name of this property */
override string getName() { result = this.getGetter().getName() }

View File

@@ -178,7 +178,6 @@ class SelfInstanceInternal extends TSelfInstance, InstanceObject {
result = "self instance of " + this.getClass().(ClassObjectInternal).getName()
}
/** The boolean value of this object, if it has one */
override boolean booleanValue() {
//result = this.getClass().instancesBooleanValue()
result = maybe()

View File

@@ -18,7 +18,7 @@ private import semmle.python.types.Builtins
class ObjectSource = Object;
/* Aliases for scopes */
/** An alias for Function used for scopes */
class FunctionScope = Function;
class ClassScope = Class;
@@ -26,7 +26,7 @@ class ClassScope = Class;
class ModuleScope = Module;
/**
* Class representing values in the Python program
* A value in the Python program.
* Each `Value` is a static approximation to a set of one or more real objects.
*/
class Value extends TObject {
@@ -144,7 +144,7 @@ class Value extends TObject {
}
/**
* Class representing modules in the Python program
* A module in the Python program.
* Each `ModuleValue` represents a module object in the Python program.
*/
class ModuleValue extends Value instanceof ModuleObjectInternal {
@@ -339,7 +339,7 @@ module Value {
}
/**
* Class representing callables in the Python program
* A callable in the Python program.
* Callables include Python functions, built-in functions and bound-methods,
* but not classes.
*/
@@ -447,7 +447,7 @@ class CallableValue extends Value {
}
/**
* Class representing bound-methods, such as `o.func`, where `o` is an instance
* A bound-method, such as `o.func`, where `o` is an instance
* of a class that has a callable attribute `func`.
*/
class BoundMethodValue extends CallableValue instanceof BoundMethodObjectInternal {
@@ -468,7 +468,7 @@ class BoundMethodValue extends CallableValue instanceof BoundMethodObjectInterna
}
/**
* Class representing classes in the Python program, both Python and built-in.
* A class in the Python program, both Python and built-in.
*/
class ClassValue extends Value {
ClassValue() { this.(ObjectInternal).isClass() = true }
@@ -655,7 +655,7 @@ class ClassValue extends Value {
}
/**
* Class representing functions in the Python program, both Python and built-in.
* A function in the Python program, both Python and built-in.
* Note that this does not include other callables such as bound-methods.
*/
abstract class FunctionValue extends CallableValue {
@@ -721,7 +721,7 @@ abstract class FunctionValue extends CallableValue {
predicate isLambda() { this.getOrigin().getNode() instanceof Lambda }
}
/** Class representing Python functions */
/** A Python function. */
class PythonFunctionValue extends FunctionValue {
PythonFunctionValue() { this instanceof PythonFunctionObjectInternal }
@@ -769,7 +769,7 @@ class PythonFunctionValue extends FunctionValue {
}
}
/** Class representing builtin functions, such as `len` or `print` */
/** A builtin function, such as `len` or `print`. */
class BuiltinFunctionValue extends FunctionValue {
BuiltinFunctionValue() { this instanceof BuiltinFunctionObjectInternal }
@@ -796,7 +796,7 @@ class BuiltinFunctionValue extends FunctionValue {
}
}
/** Class representing builtin methods, such as `list.append` or `set.add` */
/** A builtin method, such as `list.append` or `set.add` */
class BuiltinMethodValue extends FunctionValue {
BuiltinMethodValue() { this instanceof BuiltinMethodObjectInternal }

View File

@@ -21,7 +21,7 @@ class ObjectInternal extends TObject {
abstract string toString();
/**
* The boolean value of this object, this may be both
* Gets the boolean value of this object. This may be both
* true and false if the "object" represents a set of possible objects.
*/
abstract boolean booleanValue();
@@ -88,14 +88,14 @@ class ObjectInternal extends TObject {
abstract predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin);
/**
* The integer value of things that have integer values and whose integer value is
* Gets the integer value of things that have integer values and whose integer value is
* tracked.
* That is, some ints, mainly small numbers, and bools.
*/
abstract int intValue();
/**
* The string value of things that have string values.
* Gets the string value of things that have string values.
* That is, strings.
*/
abstract string strValue();
@@ -497,7 +497,7 @@ module ObjectInternal {
ObjectInternal superType() { result = TBuiltinClassObject(Builtin::special("super")) }
/** The old-style class type (Python 2 only) */
/** Gets the old-style class type (Python 2 only) */
ObjectInternal classType() { result = TBuiltinClassObject(Builtin::special("ClassType")) }
ObjectInternal emptyTuple() { result.(BuiltinTupleObjectInternal).length() = 0 }

View File

@@ -90,16 +90,8 @@ abstract class TupleObjectInternal extends SequenceObjectInternal {
none()
}
/**
* The integer value of things that have integer values.
* That is, ints and bools.
*/
override int intValue() { none() }
/**
* The integer value of things that have integer values.
* That is, strings.
*/
override string strValue() { none() }
override predicate calleeAndOffset(Function scope, int paramOffset) { none() }
@@ -241,16 +233,8 @@ class SysVersionInfoObjectInternal extends TSysVersionInfo, SequenceObjectIntern
none()
}
/**
* The integer value of things that have integer values.
* That is, ints and bools.
*/
override int intValue() { none() }
/**
* The integer value of things that have integer values.
* That is, strings.
*/
override string strValue() { none() }
override predicate calleeAndOffset(Function scope, int paramOffset) { none() }
@@ -261,10 +245,6 @@ class SysVersionInfoObjectInternal extends TSysVersionInfo, SequenceObjectIntern
override predicate subscriptUnknown() { none() }
/**
* Gets the length of the sequence that this "object" represents.
* Always returns a value for a sequence, will be -1 if object has no fixed length.
*/
override int length() { result = 5 }
override predicate functionAndOffset(CallableObjectInternal function, int offset) { none() }

View File

@@ -453,7 +453,7 @@ predicate common_module_name(string name) { name = ["zope.interface", "six.moves
* This acts as a helper for ClassObjectInternal allowing some lookup without
* recursion.
*/
library class ClassDecl extends @py_object {
class ClassDecl extends @py_object {
ClassDecl() {
this.(Builtin).isClass() and not this = Builtin::unknownType()
or

View File

@@ -25,13 +25,13 @@ module BasePointsTo {
}
}
/** The kwargs parameter (**kwargs) in a function definition is always a dict */
/** Gets the kwargs parameter (`**kwargs`). In a function definition this is always a dict. */
predicate kwargs_points_to(ControlFlowNode f, ClassObject cls) {
exists(Function func | func.getKwarg() = f.getNode()) and
cls = theDictType()
}
/** The varargs (*varargs) in a function definition is always a tuple */
/** Gets the varargs parameter (`*varargs`). In a function definition this is always a tuple. */
predicate varargs_points_to(ControlFlowNode f, ClassObject cls) {
exists(Function func | func.getVararg() = f.getNode()) and
cls = theTupleType()
@@ -120,11 +120,11 @@ int version_tuple_compare(Object t) {
version_tuple_value(t) > major_minor() and result = 1
}
/* Holds if `cls` is a new-style class if it were to have no explicit base classes */
/** Holds if `cls` is a new-style class if it were to have no explicit base classes */
predicate baseless_is_new_style(ClassObject cls) {
cls.isBuiltin()
or
major_version() = 3
major_version() = 3 and exists(cls)
or
exists(cls.declaredMetaClass())
}
@@ -185,22 +185,6 @@ predicate function_can_never_return(FunctionObject func) {
func = ModuleObject::named("sys").attr("exit")
}
private newtype TIterationDefinition =
TIterationDefinition_(SsaSourceVariable var, ControlFlowNode def, ControlFlowNode sequence) {
SsaSource::iteration_defined_variable(var, def, sequence)
}
/**
* DEPRECATED. For backwards compatibility only.
* A definition of a variable in a for loop `for v in ...:`
*/
deprecated class IterationDefinition extends TIterationDefinition {
/** Gets a textual representation of this element. */
string toString() { result = "IterationDefinition" }
ControlFlowNode getSequence() { this = TIterationDefinition_(_, _, result) }
}
/** Hold if outer contains inner, both are contained within a test and inner is a use is a plain use or an attribute lookup */
pragma[noinline]
predicate contains_interesting_expression_within_test(ControlFlowNode outer, ControlFlowNode inner) {

View File

@@ -23,6 +23,8 @@ private newtype TTInvocation =
}
/**
* A function invocation.
*
* This class represents a static approximation to the
* dynamic call-graph. A `FunctionInvocation` represents
* all calls made to a function for a given context.

View File

@@ -1,5 +1,2 @@
/* For backwards compatibility */
import PointsTo::PointsTo as P
/** DEPRECATED: Use `PointsTo` instead */
deprecated module FinalPointsTo = P;

View File

@@ -114,49 +114,33 @@ class ClassList extends TClassList {
this = Empty() and result = Empty()
}
predicate legalMergeHead(ClassObjectInternal cls) {
this.getTail().doesNotContain(cls)
or
this = Empty()
}
predicate contains(ClassObjectInternal cls) {
cls = this.getHead()
or
this.getTail().contains(cls)
}
/** Use negative formulation to avoid negative recursion */
predicate doesNotContain(ClassObjectInternal cls) {
this.relevantForContains(cls) and
cls != this.getHead() and
this.getTail().doesNotContain(cls)
or
this = Empty()
}
private predicate relevantForContains(ClassObjectInternal cls) {
exists(ClassListList list |
list.getItem(_).getHead() = cls and
list.getItem(_) = this
)
or
exists(ClassList l |
l.relevantForContains(cls) and
this = l.getTail()
)
}
pragma[nomagic]
ClassObjectInternal findDeclaringClass(string name) {
exists(ClassDecl head | head = this.getHead().getClassDeclaration() |
if head.declaresAttribute(name)
then result = this.getHead()
else result = this.getTail().findDeclaringClass(name)
exists(ClassObjectInternal head, ClassList tail, ClassDecl decl |
this = Cons(head, tail) and decl = head.getClassDeclaration()
|
if decl.declaresAttribute(name) then result = head else result = tail.findDeclaringClass(name)
)
}
pragma[noinline]
private ClassObjectInternal findDeclaringClassAttribute(string name) {
result = this.findDeclaringClass(name) and
(
exists(any(Builtin b).getMember(name))
or
declaredAttributeVar(_, name, _)
)
}
predicate lookup(string name, ObjectInternal value, CfgOrigin origin) {
exists(ClassObjectInternal decl | decl = this.findDeclaringClass(name) |
exists(ClassObjectInternal decl | decl = this.findDeclaringClassAttribute(name) |
Types::declaredAttribute(decl, name, value, origin)
)
}
@@ -199,12 +183,18 @@ class ClassList extends TClassList {
or
this.duplicate(n) and result = this.deduplicate(n + 1)
or
exists(ClassObjectInternal cls |
n = this.firstIndex(cls) and
result = Cons(cls, this.deduplicate(n + 1))
exists(ClassObjectInternal cls, ClassList tail |
this.deduplicateCons(n, cls, tail) and
result = Cons(cls, tail)
)
}
pragma[nomagic]
private predicate deduplicateCons(int n, ClassObjectInternal cls, ClassList tail) {
n = this.firstIndex(cls) and
tail = this.deduplicate(n + 1)
}
predicate isEmpty() { this = Empty() }
ClassList reverse() { reverse_step(this, Empty(), result) }
@@ -273,6 +263,24 @@ private class ClassListList extends TClassListList {
result = this.getTail().getItem(n - 1)
}
/**
* Same as
*
* ```ql
* result = this.getItem(n) and n = this.length() - 1
* ```
*
* but avoids non-linear recursion.
*/
ClassList getLastItem(int n) {
n = 0 and this = ConsList(result, EmptyList())
or
exists(ClassListList tail |
this = ConsList(_, tail) and
result = tail.getLastItem(n - 1)
)
}
private ClassObjectInternal getAHead() {
result = this.getHead().getHead()
or
@@ -295,38 +303,63 @@ private class ClassListList extends TClassListList {
ClassObjectInternal cls, ClassList removed_head, ClassListList removed_tail, int n
) {
cls = this.bestMergeCandidate() and
n = this.length() - 1 and
removed_head = this.getItem(n).removeHead(cls) and
removed_head = this.getLastItem(n).removeHead(cls) and
removed_tail = EmptyList()
or
removed_head = this.removedClassPartsCons1(cls, removed_tail, n).removeHead(cls)
}
pragma[nomagic]
predicate removedClassPartsCons0(ClassObjectInternal cls, ClassListList removed_tail, int n) {
exists(ClassList prev_head, ClassListList prev_tail |
this.removedClassParts(cls, prev_head, prev_tail, n + 1) and
removed_head = this.getItem(n).removeHead(cls) and
removed_tail = ConsList(prev_head, prev_tail)
)
}
pragma[nomagic]
ClassList removedClassPartsCons1(ClassObjectInternal cls, ClassListList removed_tail, int n) {
this.removedClassPartsCons0(cls, removed_tail, n) and
result = this.getItem(n)
}
ClassListList remove(ClassObjectInternal cls) {
exists(ClassList removed_head, ClassListList removed_tail |
this.removedClassParts(cls, removed_head, removed_tail, 0) and
result = ConsList(removed_head, removed_tail)
)
or
this = EmptyList() and result = EmptyList()
this = EmptyList() and result = EmptyList() and exists(cls)
}
predicate legalMergeCandidate(ClassObjectInternal cls, int n) {
cls = this.getAHead() and n = this.length()
pragma[nomagic]
private predicate legalMergeCandidateNonEmpty(
ClassObjectInternal cls, ClassListList remainingList, ClassList remaining
) {
this.legalMergeCandidate(cls, ConsList(Cons(_, remaining), remainingList))
or
this.getItem(n).legalMergeHead(cls) and
this.legalMergeCandidate(cls, n + 1)
exists(ClassObjectInternal head |
this.legalMergeCandidateNonEmpty(cls, remainingList, Cons(head, remaining)) and
cls != head
)
}
predicate legalMergeCandidate(ClassObjectInternal cls) { this.legalMergeCandidate(cls, 0) }
private predicate legalMergeCandidate(ClassObjectInternal cls, ClassListList remaining) {
cls = this.getAHead() and remaining = this
or
this.legalMergeCandidate(cls, ConsList(Empty(), remaining))
or
this.legalMergeCandidateNonEmpty(cls, remaining, Empty())
}
pragma[noinline]
predicate legalMergeCandidate(ClassObjectInternal cls) {
this.legalMergeCandidate(cls, EmptyList())
}
pragma[noinline]
predicate illegalMergeCandidate(ClassObjectInternal cls) {
cls = this.getAHead() and
this.getItem(_).getTail().contains(cls)
this.legalMergeCandidateNonEmpty(cls, _, Cons(cls, _))
}
ClassObjectInternal bestMergeCandidate(int n) {
@@ -337,6 +370,7 @@ private class ClassListList extends TClassListList {
)
}
pragma[noinline]
ClassObjectInternal bestMergeCandidate() { result = this.bestMergeCandidate(0) }
/**
@@ -417,16 +451,27 @@ private predicate merge_step(
remaining_list = original
or
/* Removes the best merge candidate from `remaining_list` and prepends it to `reversed_mro` */
exists(ClassObjectInternal head, ClassList prev_reverse_mro, ClassListList prev_list |
merge_step(prev_reverse_mro, prev_list, original) and
head = prev_list.bestMergeCandidate() and
reversed_mro = Cons(head, prev_reverse_mro) and
remaining_list = prev_list.remove(head)
exists(ClassObjectInternal head, ClassList prev_reverse_mro |
merge_stepCons(head, prev_reverse_mro, remaining_list, original) and
reversed_mro = Cons(head, prev_reverse_mro)
)
or
merge_step(reversed_mro, ConsList(Empty(), remaining_list), original)
}
pragma[nomagic]
private predicate merge_stepCons(
ClassObjectInternal head, ClassList prev_reverse_mro, ClassListList remaining_list,
ClassListList original
) {
/* Removes the best merge candidate from `remaining_list` and prepends it to `reversed_mro` */
exists(ClassListList prev_list |
merge_step(prev_reverse_mro, prev_list, original) and
head = prev_list.bestMergeCandidate() and
remaining_list = prev_list.remove(head)
)
}
/* Helpers for `ClassList.reverse()` */
private predicate needs_reversing(ClassList lst) {
merge_step(lst, EmptyList(), _)
@@ -439,10 +484,17 @@ private predicate reverse_step(ClassList lst, ClassList remainder, ClassList rev
or
exists(ClassObjectInternal head, ClassList tail |
reversed = Cons(head, tail) and
reverse_step(lst, Cons(head, remainder), tail)
reverse_stepCons(lst, remainder, head, tail)
)
}
pragma[nomagic]
private predicate reverse_stepCons(
ClassList lst, ClassList remainder, ClassObjectInternal head, ClassList tail
) {
reverse_step(lst, Cons(head, remainder), tail)
}
module Mro {
cached
ClassList newStyleMro(ClassObjectInternal cls) {

View File

@@ -8,7 +8,7 @@ private import semmle.python.types.Builtins
private import semmle.python.types.Extensions
/* Use this version for speed */
library class CfgOrigin extends @py_object {
class CfgOrigin extends @py_object {
/** Gets a textual representation of this element. */
string toString() {
/* Not to be displayed */
@@ -145,24 +145,6 @@ module PointsTo {
)
}
deprecated predicate ssa_variable_points_to(
EssaVariable var, PointsToContext context, Object obj, ClassObject cls, CfgOrigin origin
) {
exists(ObjectInternal value |
PointsToInternal::variablePointsTo(var, context, value, origin) and
cls = value.getClass().getSource()
|
obj = value.getSource()
)
}
deprecated CallNode get_a_call(Object func, PointsToContext context) {
exists(ObjectInternal value |
result = value.(Value).getACall(context) and
func = value.getSource()
)
}
cached
predicate moduleExports(ModuleObjectInternal mod, string name) {
InterModulePointsTo::moduleExportsBoolean(mod, name) = true
@@ -1076,7 +1058,7 @@ module InterProceduralPointsTo {
/** Helper for default_parameter_points_to */
pragma[noinline]
private predicate context_for_default_value(ParameterDefinition def, PointsToContext context) {
context.isRuntime()
context.isRuntime() and exists(def)
or
exists(PointsToContext caller, CallNode call, PythonFunctionObjectInternal func, int n |
context.fromCall(call, func, caller) and
@@ -1429,20 +1411,51 @@ module Expressions {
}
pragma[noinline]
predicate subscriptPointsTo(
private predicate indexPointsToInt(ControlFlowNode index, PointsToContext context, int n) {
index = any(SubscriptNode subscr).getIndex() and
PointsToInternal::pointsTo(index, context, TInt(n), _)
}
pragma[noinline]
private predicate getItemSequenceObjectInternal(
ObjectInternal value, SequenceObjectInternal objvalue, int n
) {
value = objvalue.getItem(n)
}
pragma[noinline]
private predicate subscriptObjectAndIndexPointsToInt(
SubscriptNode subscr, PointsToContext context, ControlFlowNode obj, ObjectInternal objvalue,
int n
) {
exists(ControlFlowNode index |
subscriptObjectAndIndex(subscr, context, obj, objvalue, index) and
indexPointsToInt(index, context, n)
)
}
deprecated predicate subscriptPointsTo(
SubscriptNode subscr, PointsToContext context, ObjectInternal value, ControlFlowNode origin,
ControlFlowNode obj, ObjectInternal objvalue
) {
subscriptPointsTo(subscr, context, value, obj, objvalue) and
origin = subscr
}
pragma[noinline]
private predicate subscriptPointsTo(
SubscriptNode subscr, PointsToContext context, ObjectInternal value, ControlFlowNode obj,
ObjectInternal objvalue
) {
exists(ControlFlowNode index | subscriptObjectAndIndex(subscr, context, obj, objvalue, index) |
objvalue.subscriptUnknown() and
value = ObjectInternal::unknown()
or
exists(int n |
PointsToInternal::pointsTo(index, context, TInt(n), _) and
value = objvalue.(SequenceObjectInternal).getItem(n)
)
) and
origin = subscr
)
or
exists(int n |
subscriptObjectAndIndexPointsToInt(subscr, context, obj, objvalue, n) and
getItemSequenceObjectInternal(value, objvalue, n)
)
}
predicate subscriptPartsPointsTo(
@@ -1466,15 +1479,22 @@ module Expressions {
index = subscr.getIndex()
}
deprecated predicate binaryPointsTo(
BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode origin,
ControlFlowNode operand, ObjectInternal opvalue
) {
binaryPointsTo(b, context, value, operand, opvalue) and
origin = b
}
/**
* Tracking too many binary expressions is likely to kill performance, so just say anything other than addition or bitwise or is 'unknown'.
*/
pragma[noinline]
predicate binaryPointsTo(
BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode origin,
ControlFlowNode operand, ObjectInternal opvalue
private predicate binaryPointsTo(
BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode operand,
ObjectInternal opvalue
) {
origin = b and
operand = genericBinaryOperand(b) and
PointsToInternal::pointsTo(operand, context, opvalue, _) and
value = ObjectInternal::unknown()
@@ -1491,12 +1511,19 @@ module Expressions {
)
}
pragma[noinline]
predicate addPointsTo(
deprecated predicate addPointsTo(
BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode origin,
ControlFlowNode operand, ObjectInternal opvalue
) {
origin = b and
addPointsTo(b, context, value, operand, opvalue) and
origin = b
}
pragma[noinline]
private predicate addPointsTo(
BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode operand,
ObjectInternal opvalue
) {
exists(Operator op |
b.operands(operand, op, _)
or
@@ -1508,12 +1535,19 @@ module Expressions {
)
}
pragma[noinline]
predicate bitOrPointsTo(
deprecated predicate bitOrPointsTo(
BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode origin,
ControlFlowNode operand, ObjectInternal opvalue
) {
origin = b and
bitOrPointsTo(b, context, value, operand, opvalue) and
origin = b
}
pragma[noinline]
private predicate bitOrPointsTo(
BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode operand,
ObjectInternal opvalue
) {
exists(Operator op, ControlFlowNode other |
b.operands(operand, op, other)
or
@@ -1533,10 +1567,18 @@ module Expressions {
value = obj.intValue()
}
pragma[noinline]
predicate unaryPointsTo(
deprecated predicate unaryPointsTo(
UnaryExprNode u, PointsToContext context, ObjectInternal value, ControlFlowNode origin,
ControlFlowNode operand, ObjectInternal opvalue
) {
unaryPointsTo(u, context, value, operand, opvalue) and
origin = u
}
pragma[noinline]
private predicate unaryPointsTo(
UnaryExprNode u, PointsToContext context, ObjectInternal value, ControlFlowNode operand,
ObjectInternal opvalue
) {
exists(Unaryop op |
op = u.getNode().getOp() and
@@ -1548,14 +1590,21 @@ module Expressions {
op instanceof USub and value = ObjectInternal::fromInt(-opvalue.intValue())
or
not op instanceof Not and opvalue = ObjectInternal::unknown() and value = opvalue
) and
origin = u
)
}
deprecated predicate builtinCallPointsTo(
CallNode call, PointsToContext context, ObjectInternal value, ControlFlowNode origin,
ControlFlowNode arg, ObjectInternal argvalue
) {
builtinCallPointsTo(call, context, value, arg, argvalue) and
origin = call
}
pragma[noinline]
predicate builtinCallPointsTo(
CallNode call, PointsToContext context, ObjectInternal value, ControlFlowNode origin,
ControlFlowNode arg, ObjectInternal argvalue
private predicate builtinCallPointsTo(
CallNode call, PointsToContext context, ObjectInternal value, ControlFlowNode arg,
ObjectInternal argvalue
) {
PointsToInternal::pointsTo(arg, context, argvalue, _) and
arg = call.getArg(0) and
@@ -1569,8 +1618,7 @@ module Expressions {
callable != ObjectInternal::builtin("hasattr") and
callable.isClass() = false and
value = ObjectInternal::unknown()
) and
origin = call
)
}
pragma[noinline]
@@ -1585,11 +1633,10 @@ module Expressions {
pragma[noinline]
private predicate lenCallPointsTo(
CallNode call, PointsToContext context, ObjectInternal value, ControlFlowNode origin,
ControlFlowNode arg, ObjectInternal argvalue
CallNode call, PointsToContext context, ObjectInternal value, ControlFlowNode arg,
ObjectInternal argvalue
) {
len_call(call, arg, context, argvalue) and
origin = call and
exists(int len | len = argvalue.length() |
value = TInt(len) and len >= 0
or
@@ -1815,19 +1862,26 @@ module Expressions {
) {
attributePointsTo(expr, context, value, origin, subexpr, subvalue)
or
subscriptPointsTo(expr, context, value, origin, subexpr, subvalue)
subscriptPointsTo(expr, context, value, subexpr, subvalue) and
origin = expr
or
addPointsTo(expr, context, value, origin, subexpr, subvalue)
addPointsTo(expr, context, value, subexpr, subvalue) and
origin = expr
or
bitOrPointsTo(expr, context, value, origin, subexpr, subvalue)
bitOrPointsTo(expr, context, value, subexpr, subvalue) and
origin = expr
or
binaryPointsTo(expr, context, value, origin, subexpr, subvalue)
binaryPointsTo(expr, context, value, subexpr, subvalue) and
origin = expr
or
unaryPointsTo(expr, context, value, origin, subexpr, subvalue)
unaryPointsTo(expr, context, value, subexpr, subvalue) and
origin = expr
or
builtinCallPointsTo(expr, context, value, origin, subexpr, subvalue)
builtinCallPointsTo(expr, context, value, subexpr, subvalue) and
origin = expr
or
lenCallPointsTo(expr, context, value, origin, subexpr, subvalue)
lenCallPointsTo(expr, context, value, subexpr, subvalue) and
origin = expr
or
typeCallPointsTo(expr, context, value, origin, subexpr, subvalue)
or
@@ -2068,6 +2122,12 @@ module Conditionals {
}
}
/** INTERNAL: Do not use. */
predicate declaredAttributeVar(PythonClassObjectInternal cls, string name, EssaVariable var) {
name = var.getName() and
var.getAUse() = cls.getScope().getANormalExit()
}
cached
module Types {
cached
@@ -2163,8 +2223,7 @@ module Types {
or
value != ObjectInternal::undefined() and
exists(EssaVariable var |
name = var.getName() and
var.getAUse() = cls.(PythonClassObjectInternal).getScope().getANormalExit() and
declaredAttributeVar(cls, name, var) and
PointsToInternal::variablePointsTo(var, _, value, origin)
)
}
@@ -2209,7 +2268,7 @@ module Types {
func != six_add_metaclass_function() and result = false
)
or
not exists(Module m | m.getName() = "six") and result = false
not exists(Module m | m.getName() = "six") and result = false and exists(cls)
or
exists(Class pycls |
pycls = cls.getScope() and
@@ -2336,7 +2395,7 @@ module Types {
)
}
/* Holds if type inference failed to compute the full class hierarchy for this class for the reason given. */
/** Holds if type inference failed to compute the full class hierarchy for this class for the reason given. */
private predicate failedInference(ClassObjectInternal cls, string reason, int priority) {
strictcount(cls.(PythonClassObjectInternal).getScope().getADecorator()) > 1 and
reason = "Multiple decorators" and

View File

@@ -126,7 +126,7 @@ module Context {
}
/**
* Points-to context. Context can be one of:
* A points-to context. Context can be one of:
* * "main": Used for scripts.
* * "import": Use for non-script modules.
* * "default": Use for functions and methods without caller context.

View File

@@ -176,8 +176,8 @@ private module RegexpMatching {
}
/** A class to test whether a regular expression matches certain HTML tags. */
class HTMLMatchingRegExp extends RegexpMatching::MatchedRegExp {
HTMLMatchingRegExp() {
class HtmlMatchingRegExp extends RegexpMatching::MatchedRegExp {
HtmlMatchingRegExp() {
// the regexp must mention "<" and ">" explicitly.
forall(string angleBracket | angleBracket = ["<", ">"] |
any(RegExpConstant term | term.getValue().matches("%" + angleBracket + "%")).getRootTerm() =
@@ -204,12 +204,15 @@ class HTMLMatchingRegExp extends RegexpMatching::MatchedRegExp {
}
}
/** DEPRECATED: Alias for HtmlMatchingRegExp */
deprecated class HTMLMatchingRegExp = HtmlMatchingRegExp;
/**
* Holds if `regexp` matches some HTML tags, but misses some HTML tags that it should match.
*
* When adding a new case to this predicate, make sure the test string used in `matches(..)` calls are present in `HTMLMatchingRegExp::test` / `HTMLMatchingRegExp::testWithGroups`.
*/
predicate isBadRegexpFilter(HTMLMatchingRegExp regexp, string msg) {
predicate isBadRegexpFilter(HtmlMatchingRegExp regexp, string msg) {
// CVE-2021-33829 - matching both "<!-- foo -->" and "<!-- foo --!>", but in different capture groups
regexp.matches("<!-- foo -->") and
regexp.matches("<!-- foo --!>") and

View File

@@ -47,7 +47,7 @@ module PathInjection {
override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
override predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) {
override predicate isSanitizer(DataFlow::Node node, DataFlow::FlowState state) {
// Block `NotNormalized` paths here, since they change state to `NormalizedUnchecked`
node instanceof Path::PathNormalization and
state instanceof NotNormalized
@@ -60,7 +60,7 @@ module PathInjection {
guard instanceof SanitizerGuard
}
override predicate isAdditionalFlowStep(
override predicate isAdditionalTaintStep(
DataFlow::Node nodeFrom, DataFlow::FlowState stateFrom, DataFlow::Node nodeTo,
DataFlow::FlowState stateTo
) {

View File

@@ -13,8 +13,8 @@ import semmle.python.dataflow.new.TaintTracking
/**
* Provides a taint-tracking configuration for detecting "reflected server-side cross-site scripting" vulnerabilities.
*/
module ReflectedXSS {
import ReflectedXSSCustomizations::ReflectedXSS
module ReflectedXss {
import ReflectedXSSCustomizations::ReflectedXss
/**
* A taint-tracking configuration for detecting "reflected server-side cross-site scripting" vulnerabilities.
@@ -34,9 +34,12 @@ module ReflectedXSS {
}
}
/** DEPRECATED: Alias for ReflectedXss */
deprecated module ReflectedXSS = ReflectedXss;
/**
* DEPRECATED: Don't extend this class for customization, since this will lead to bad
* performance, instead use the new `ReflectedXSSCustomizations.qll` file, and extend
* its' classes.
*/
deprecated class ReflectedXssConfiguration = ReflectedXSS::Configuration;
deprecated class ReflectedXssConfiguration = ReflectedXss::Configuration;

View File

@@ -15,7 +15,7 @@ private import semmle.python.dataflow.new.BarrierGuards
* "reflected server-side cross-site scripting"
* vulnerabilities, as well as extension points for adding your own.
*/
module ReflectedXSS {
module ReflectedXss {
/**
* A data flow source for "reflected server-side cross-site scripting" vulnerabilities.
*/
@@ -74,3 +74,6 @@ module ReflectedXSS {
*/
class StringConstCompareAsSanitizerGuard extends SanitizerGuard, StringConstCompare { }
}
/** DEPRECATED: Alias for ReflectedXss */
deprecated module ReflectedXSS = ReflectedXss;

View File

@@ -39,4 +39,7 @@ module SqlInjection {
* performance, instead use the new `SqlInjectionCustomizations.qll` file, and extend
* its' classes.
*/
deprecated class SQLInjectionConfiguration = SqlInjection::Configuration;
deprecated class SqlInjectionConfiguration = SqlInjection::Configuration;
/** DEPRECATED: Alias for SqlInjectionConfiguration */
deprecated class SQLInjectionConfiguration = SqlInjectionConfiguration;

View File

@@ -0,0 +1,55 @@
/**
* Provides class and predicates to track external data that
* may represent malicious xpath query objects.
*
* This module is intended to be imported into a taint-tracking query.
*/
private import python
private import semmle.python.dataflow.new.TaintTracking
private import semmle.python.Concepts
private import semmle.python.ApiGraphs
private import semmle.python.dataflow.new.RemoteFlowSources
private import semmle.python.dataflow.new.BarrierGuards
/** Models Xpath Injection related classes and functions */
module XpathInjection {
/**
* A data flow source for "XPath injection" vulnerabilities.
*/
abstract class Source extends DataFlow::Node { }
/**
* A data flow sink for "XPath injection" vulnerabilities.
*/
abstract class Sink extends DataFlow::Node { }
/**
* A sanitizer for "XPath injection" vulnerabilities.
*/
abstract class Sanitizer extends DataFlow::Node { }
/**
* A sanitizer guard for "XPath injection" vulnerabilities.
*/
abstract class SanitizerGuard extends DataFlow::BarrierGuard { }
/**
* A source of remote user input, considered as a flow source.
*/
class RemoteFlowSourceAsSource extends Source, RemoteFlowSource { }
/**
* A construction of an XPath expression, considered as a sink.
*/
class XPathConstructionArg extends Sink {
XPathConstructionArg() { this = any(XML::XPathConstruction c).getXPath() }
}
/**
* An execution of an XPath expression, considered as a sink.
*/
class XPathExecutionArg extends Sink {
XPathExecutionArg() { this = any(XML::XPathExecution e).getXPath() }
}
}

View File

@@ -119,18 +119,18 @@ class EmptyPositiveSubPatttern extends RegExpSubPattern {
* whose root node is not a disjunction.
*/
class RegExpRoot extends RegExpTerm {
RegExpParent parent;
RegExpRoot() {
exists(RegExpAlt alt |
alt.isRootTerm() and
this = alt.getAChild() and
parent = alt.getParent()
exists(RegExpParent parent |
exists(RegExpAlt alt |
alt.isRootTerm() and
this = alt.getAChild() and
parent = alt.getParent()
)
or
this.isRootTerm() and
not this instanceof RegExpAlt and
parent = this.getParent()
)
or
this.isRootTerm() and
not this instanceof RegExpAlt and
parent = this.getParent()
}
/**
@@ -466,13 +466,14 @@ private module CharacterClasses {
* An implementation of `CharacterClass` for \d, \s, and \w.
*/
private class PositiveCharacterClassEscape extends CharacterClass {
RegExpTerm cc;
string charClass;
PositiveCharacterClassEscape() {
isEscapeClass(cc, charClass) and
this = getCanonicalCharClass(cc) and
charClass = ["d", "s", "w"]
exists(RegExpTerm cc |
isEscapeClass(cc, charClass) and
this = getCanonicalCharClass(cc) and
charClass = ["d", "s", "w"]
)
}
override string getARelevantChar() {
@@ -504,13 +505,14 @@ private module CharacterClasses {
* An implementation of `CharacterClass` for \D, \S, and \W.
*/
private class NegativeCharacterClassEscape extends CharacterClass {
RegExpTerm cc;
string charClass;
NegativeCharacterClassEscape() {
isEscapeClass(cc, charClass) and
this = getCanonicalCharClass(cc) and
charClass = ["D", "S", "W"]
exists(RegExpTerm cc |
isEscapeClass(cc, charClass) and
this = getCanonicalCharClass(cc) and
charClass = ["D", "S", "W"]
)
}
override string getARelevantChar() {

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